fix: download report assets upon package build such that reports become possible offline (cont. of #2904)#3026
Conversation
…me possible offline
WalkthroughThe recent updates enhance asset management and package distribution in the Snakemake framework. Key modifications include adjustments to the Changes
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (invoked as PR comments)
Additionally, you can add CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 5
Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Files selected for processing (3)
- setup.cfg (2 hunks)
- snakemake/report/html_reporter/data/packages.py (3 hunks)
- snakemake/report/html_reporter/template/index.html.jinja2 (2 hunks)
Additional context used
Path-based instructions (1)
snakemake/report/html_reporter/data/packages.py (1)
Pattern
**/*.py: Do not suggest to add trailing commas.
Do not suggest type annotations for functions that are defined inside of functions or methods.
Do not suggest type annotation of theselfargument of methods.
Do not suggest type annotation of theclsargument of classmethods.
Ruff
snakemake/report/html_reporter/data/packages.py
4-4:
snakemake.report.html_reporter.common.get_resource_as_stringimported but unusedRemove unused import:
snakemake.report.html_reporter.common.get_resource_as_string(F401)
7-7:
osimported but unusedRemove unused import:
os(F401)
76-76: Missing return type annotation for special method
__init__Add return type annotation:
None(ANN204)
77-77: Missing type annotation for
selfin method(ANN101)
77-77: Missing type annotation for function argument
version(ANN001)
77-77: Missing type annotation for function argument
license_path(ANN001)
77-77: Missing type annotation for function argument
source_path(ANN001)
77-77: Missing type annotation for
**source_paths(ANN003)
77-77: Trailing comma missing
Add trailing comma
(COM812)
79-79: Missing return type annotation for private function
read_source(ANN202)
Additional comments not posted (6)
snakemake/report/html_reporter/data/packages.py (2)
18-56: LGTM! Theget_packagesfunction changes align with offline access goals.The use of local paths for licenses and sources supports the offline functionality objective of the PR.
76-93: LGTM! ThePackageclass constructor changes enhance maintainability.The use of local paths and a helper function for reading files aligns with the PR objectives and improves code maintainability.
Tools
Ruff
76-76: Missing return type annotation for special method
__init__Add return type annotation:
None(ANN204)
77-77: Missing type annotation for
selfin method(ANN101)
77-77: Missing type annotation for function argument
version(ANN001)
77-77: Missing type annotation for function argument
license_path(ANN001)
77-77: Missing type annotation for function argument
source_path(ANN001)
77-77: Missing type annotation for
**source_paths(ANN003)
77-77: Trailing comma missing
Add trailing comma
(COM812)
79-79: Missing return type annotation for private function
read_source(ANN202)
snakemake/report/html_reporter/template/index.html.jinja2 (2)
12-12: Streamlined resource inclusion fortailwindcss.The change to directly use
packages["tailwindcss"].sourcesimplifies resource inclusion and aligns with the PR objectives.
34-39: Streamlined resource inclusion for JavaScript libraries.The direct access to
sourcesfor React, Prop-Types, Vega, Vega-Lite, and Vega-Embed simplifies the template and aligns with the PR objectives.setup.cfg (2)
66-66: Addition ofsetup_requiresforsetuptools-download.The inclusion of
setuptools-downloadenhances dependency management by ensuring necessary tools are available during setup.
68-117: Addition of[setuptools_download]section for asset management.The structured list of
download_data_filesensures that necessary assets are fetched and verified during setup, aligning with the PR objectives.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 5
Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Files selected for processing (5)
- .gitignore (1 hunks)
- setup.cfg (2 hunks)
- setup.py (1 hunks)
- snakemake/assets/init.py (1 hunks)
- snakemake/report/html_reporter/data/packages.py (3 hunks)
Files skipped from review due to trivial changes (1)
- .gitignore
Additional context used
Path-based instructions (3)
setup.py (1)
Pattern
**/*.py: Do not try to improve formatting.
Do not suggest type annotations for functions that are defined inside of functions or methods.
Do not suggest type annotation of theselfargument of methods.
Do not suggest type annotation of theclsargument of classmethods.
Do not suggest return type annotation if a function or method does not contain areturnstatement.snakemake/report/html_reporter/data/packages.py (1)
Pattern
**/*.py: Do not try to improve formatting.
Do not suggest type annotations for functions that are defined inside of functions or methods.
Do not suggest type annotation of theselfargument of methods.
Do not suggest type annotation of theclsargument of classmethods.
Do not suggest return type annotation if a function or method does not contain areturnstatement.snakemake/assets/__init__.py (1)
Pattern
**/*.py: Do not try to improve formatting.
Do not suggest type annotations for functions that are defined inside of functions or methods.
Do not suggest type annotation of theselfargument of methods.
Do not suggest type annotation of theclsargument of classmethods.
Do not suggest return type annotation if a function or method does not contain areturnstatement.
Ruff
snakemake/report/html_reporter/data/packages.py
2-2:
pathlib.Pathimported but unusedRemove unused import:
pathlib.Path(F401)
snakemake/assets/__init__.py
3-3:
pathlib.Pathimported but unused(F401)
4-4:
shutilimported but unused(F401)
Additional comments not posted (13)
setup.py (3)
12-12: LGTM!The import statement for the
Assetsclass is correct and necessary.
14-15: LGTM!The
Assets.deploy()method invocation is correct and ensures that assets are downloaded during the setup process.
21-21: LGTM!The
package_dataparameter update is correct and ensures that all files within theassets/datadirectory are included in the package.setup.cfg (2)
32-32: LGTM!The change to the
include_package_dataoption is correct and ensures that package data is included in the distribution.
53-53: LGTM!The formatting adjustment in the
install_requiressection is minor but contributes to a cleaner configuration file.snakemake/report/html_reporter/data/packages.py (8)
6-6: LGTM!The import statement for the
Assetsclass is correct and necessary.
7-7: LGTM!The addition of the blank line improves readability by separating the import statements from the function definitions.
23-23: LGTM!The addition of the
license_pathparameter to thePackageinstances is correct and ensures that the license information is sourced from local files.Also applies to: 27-27, 30-30, 34-34, 40-40, 44-44, 48-48, 51-51, 55-55
31-31: LGTM!The addition of the
source_pathparameter to thePackageinstances is correct and ensures that the source information is sourced from local files.Also applies to: 39-39, 43-43, 47-47, 54-54
75-77: LGTM!The update to the
__init__method is correct and ensures that the package information is sourced from local assets.
80-80: LGTM!The assignment of the
licenseattribute using theAssets.get_contentmethod is correct and ensures that the license content is retrieved from local assets.
81-82: LGTM!The conditional assignment of the
sourceattribute using theAssets.get_contentmethod is correct and ensures that the source content is retrieved from local assets if thesource_pathparameter is provided.
84-86: LGTM!The assignment of the
sourcesattribute using a dictionary comprehension with theAssets.get_contentmethod is correct and ensures that the source contents are retrieved from local assets for each item in thesource_pathsdictionary.
snakemake/assets/__init__.py
Outdated
| class Assets: | ||
| base_path = importlib.resources.files("snakemake.assets") / "data" | ||
| spec = { | ||
| "snakemake/LICENSE.md": Asset( | ||
| url="https://raw.githubusercontent.com/snakemake/snakemake/main/LICENSE.md", | ||
| sha256="84a1a82b05c80637744d3fe8257235c15380efa6cc32608adf4b21f17af5d2b8", | ||
| ), | ||
| "pygments/LICENSE": Asset( | ||
| url="https://raw.githubusercontent.com/pygments/pygments/master/LICENSE", | ||
| sha256="a9d66f1d526df02e29dce73436d34e56e8632f46c275bbdffc70569e882f9f17", | ||
| ), | ||
| "tailwindcss/LICENSE": Asset( | ||
| url="https://raw.githubusercontent.com/tailwindlabs/tailwindcss/master/LICENSE", | ||
| sha256="60e0b68c0f35c078eef3a5d29419d0b03ff84ec1df9c3f9d6e39a519a5ae7985", | ||
| ), | ||
| "tailwindcss/tailwind.css": Asset( | ||
| url="https://cdn.tailwindcss.com/3.0.23?plugins=forms@0.4.0,typography@0.5.2", | ||
| sha256="8a597dc918fb62e05db23a5f810327a045a62c57cfda16646075138a6ac696fa", | ||
| ), | ||
| "react/LICENSE": Asset( | ||
| url="https://raw.githubusercontent.com/facebook/react/main/LICENSE", | ||
| sha256="da6d3703ed11cbe42bd212c725957c98da23cbff1998c05fa4b3d976d1a58e93", | ||
| ), | ||
| "react/react.production.min.js": Asset( | ||
| url="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js", | ||
| sha256="4b4969fa4ef3594324da2c6d78ce8766fbbc2fd121fff395aedf997db0a99a06", | ||
| ), | ||
| "react/react-dom.production.min.js": Asset( | ||
| url="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js", | ||
| sha256="21758ed084cd0e37e735722ee4f3957ea960628a29dfa6c3ce1a1d47a2d6e4f7", | ||
| ), | ||
| "vega/vega.js": Asset( | ||
| url="https://cdnjs.cloudflare.com/ajax/libs/vega/5.21.0/vega.js", | ||
| sha256="b34c43055ef5d39a093e937522955dc359fbaec6c5b0259ae2de4c9da698e9fe", | ||
| ), | ||
| "vega/LICENSE": Asset( | ||
| url="https://raw.githubusercontent.com/vega/vega/main/LICENSE", | ||
| sha256="63727832aaf62004a2b249c933e327f3c90caf49e41a72f4bf436edf632cbda8", | ||
| ), | ||
| "vega-lite/vega-lite.js": Asset( | ||
| url="https://cdnjs.cloudflare.com/ajax/libs/vega-lite/5.2.0/vega-lite.js", | ||
| sha256="6eb7f93121cd9f44cf8640244f87c5e143f87c7a0b6cd113da4a9e41e3adf0aa", | ||
| ), | ||
| "vega-lite/LICENSE": Asset( | ||
| url="https://raw.githubusercontent.com/vega/vega-lite/next/LICENSE", | ||
| sha256="f618900fd0d64046963b29f40590cdd1e341a2f41449f99110d82fd81fea808c", | ||
| ), | ||
| "vega-embed/vega-embed.js": Asset( | ||
| url="https://cdnjs.cloudflare.com/ajax/libs/vega-embed/6.20.8/vega-embed.js", | ||
| sha256="4e546c1f86eb200333606440e92f76e2940b905757018d9672cd1708e4e6ff0a", | ||
| ), | ||
| "vega-embed/LICENSE": Asset( | ||
| url="https://raw.githubusercontent.com/vega/vega-embed/next/LICENSE", | ||
| sha256="32df67148f0fc3db0eb9e263a7b75d07f1eb14c61955005a4a39c6918d10d137", | ||
| ), | ||
| "heroicons/LICENSE": Asset( | ||
| url="https://raw.githubusercontent.com/tailwindlabs/heroicons/master/LICENSE", | ||
| sha256="60e0b68c0f35c078eef3a5d29419d0b03ff84ec1df9c3f9d6e39a519a5ae7985", | ||
| ), | ||
| "prop-types/prop-types.min.js": Asset( | ||
| url="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.7.2/prop-types.min.js", | ||
| sha256="4c88350517ee82aa4f3368e67ef1a453ca6636dcfa6449b4e3d6faa5c877066e", | ||
| ), | ||
| "prop-types/LICENSE": Asset( | ||
| url="https://raw.githubusercontent.com/facebook/prop-types/main/LICENSE", | ||
| sha256="f657f99d3fb9647db92628e96007aabb46e5f04f33e49999075aab8e250ca7ce", | ||
| ), | ||
| } | ||
|
|
||
| @classmethod | ||
| def deploy(cls) -> None: | ||
| for asset_path, asset in cls.spec.items(): | ||
| target_path = cls.base_path / asset_path | ||
| target_path.parent.mkdir(parents=True, exist_ok=True) | ||
| with open(target_path, "wb") as fout: | ||
| fout.write(asset.get_content()) | ||
|
|
||
| @classmethod | ||
| def get_content(cls, asset_path: str) -> str: | ||
| try: | ||
| return (cls.base_path / asset_path).read_text() | ||
| except FileNotFoundError: | ||
| logger.warning( | ||
| f"Asset {asset_path} not found (development setup?), downloading..." | ||
| ) | ||
| return cls.spec[asset_path].get_content().decode() |
There was a problem hiding this comment.
Add type annotations for class attributes and methods.
Adding type annotations improves code readability and maintainability.
Apply this diff to add type annotations:
class Assets:
- base_path = importlib.resources.files("snakemake.assets") / "data"
- spec = {
+ base_path: Path = importlib.resources.files("snakemake.assets") / "data"
+ spec: dict[str, Asset] = {
...
}
@classmethod
- def deploy(cls) -> None:
+ def deploy(cls: type[Assets]) -> None:
...
@classmethod
- def get_content(cls, asset_path: str) -> str:
+ def get_content(cls: type[Assets], asset_path: str) -> str:
...Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| class Assets: | |
| base_path = importlib.resources.files("snakemake.assets") / "data" | |
| spec = { | |
| "snakemake/LICENSE.md": Asset( | |
| url="https://raw.githubusercontent.com/snakemake/snakemake/main/LICENSE.md", | |
| sha256="84a1a82b05c80637744d3fe8257235c15380efa6cc32608adf4b21f17af5d2b8", | |
| ), | |
| "pygments/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/pygments/pygments/master/LICENSE", | |
| sha256="a9d66f1d526df02e29dce73436d34e56e8632f46c275bbdffc70569e882f9f17", | |
| ), | |
| "tailwindcss/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/tailwindlabs/tailwindcss/master/LICENSE", | |
| sha256="60e0b68c0f35c078eef3a5d29419d0b03ff84ec1df9c3f9d6e39a519a5ae7985", | |
| ), | |
| "tailwindcss/tailwind.css": Asset( | |
| url="https://cdn.tailwindcss.com/3.0.23?plugins=forms@0.4.0,typography@0.5.2", | |
| sha256="8a597dc918fb62e05db23a5f810327a045a62c57cfda16646075138a6ac696fa", | |
| ), | |
| "react/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/facebook/react/main/LICENSE", | |
| sha256="da6d3703ed11cbe42bd212c725957c98da23cbff1998c05fa4b3d976d1a58e93", | |
| ), | |
| "react/react.production.min.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js", | |
| sha256="4b4969fa4ef3594324da2c6d78ce8766fbbc2fd121fff395aedf997db0a99a06", | |
| ), | |
| "react/react-dom.production.min.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js", | |
| sha256="21758ed084cd0e37e735722ee4f3957ea960628a29dfa6c3ce1a1d47a2d6e4f7", | |
| ), | |
| "vega/vega.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/vega/5.21.0/vega.js", | |
| sha256="b34c43055ef5d39a093e937522955dc359fbaec6c5b0259ae2de4c9da698e9fe", | |
| ), | |
| "vega/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/vega/vega/main/LICENSE", | |
| sha256="63727832aaf62004a2b249c933e327f3c90caf49e41a72f4bf436edf632cbda8", | |
| ), | |
| "vega-lite/vega-lite.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/vega-lite/5.2.0/vega-lite.js", | |
| sha256="6eb7f93121cd9f44cf8640244f87c5e143f87c7a0b6cd113da4a9e41e3adf0aa", | |
| ), | |
| "vega-lite/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/vega/vega-lite/next/LICENSE", | |
| sha256="f618900fd0d64046963b29f40590cdd1e341a2f41449f99110d82fd81fea808c", | |
| ), | |
| "vega-embed/vega-embed.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/vega-embed/6.20.8/vega-embed.js", | |
| sha256="4e546c1f86eb200333606440e92f76e2940b905757018d9672cd1708e4e6ff0a", | |
| ), | |
| "vega-embed/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/vega/vega-embed/next/LICENSE", | |
| sha256="32df67148f0fc3db0eb9e263a7b75d07f1eb14c61955005a4a39c6918d10d137", | |
| ), | |
| "heroicons/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/tailwindlabs/heroicons/master/LICENSE", | |
| sha256="60e0b68c0f35c078eef3a5d29419d0b03ff84ec1df9c3f9d6e39a519a5ae7985", | |
| ), | |
| "prop-types/prop-types.min.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.7.2/prop-types.min.js", | |
| sha256="4c88350517ee82aa4f3368e67ef1a453ca6636dcfa6449b4e3d6faa5c877066e", | |
| ), | |
| "prop-types/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/facebook/prop-types/main/LICENSE", | |
| sha256="f657f99d3fb9647db92628e96007aabb46e5f04f33e49999075aab8e250ca7ce", | |
| ), | |
| } | |
| @classmethod | |
| def deploy(cls) -> None: | |
| for asset_path, asset in cls.spec.items(): | |
| target_path = cls.base_path / asset_path | |
| target_path.parent.mkdir(parents=True, exist_ok=True) | |
| with open(target_path, "wb") as fout: | |
| fout.write(asset.get_content()) | |
| @classmethod | |
| def get_content(cls, asset_path: str) -> str: | |
| try: | |
| return (cls.base_path / asset_path).read_text() | |
| except FileNotFoundError: | |
| logger.warning( | |
| f"Asset {asset_path} not found (development setup?), downloading..." | |
| ) | |
| return cls.spec[asset_path].get_content().decode() | |
| class Assets: | |
| base_path: Path = importlib.resources.files("snakemake.assets") / "data" | |
| spec: dict[str, Asset] = { | |
| "snakemake/LICENSE.md": Asset( | |
| url="https://raw.githubusercontent.com/snakemake/snakemake/main/LICENSE.md", | |
| sha256="84a1a82b05c80637744d3fe8257235c15380efa6cc32608adf4b21f17af5d2b8", | |
| ), | |
| "pygments/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/pygments/pygments/master/LICENSE", | |
| sha256="a9d66f1d526df02e29dce73436d34e56e8632f46c275bbdffc70569e882f9f17", | |
| ), | |
| "tailwindcss/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/tailwindlabs/tailwindcss/master/LICENSE", | |
| sha256="60e0b68c0f35c078eef3a5d29419d0b03ff84ec1df9c3f9d6e39a519a5ae7985", | |
| ), | |
| "tailwindcss/tailwind.css": Asset( | |
| url="https://cdn.tailwindcss.com/3.0.23?plugins=forms@0.4.0,typography@0.5.2", | |
| sha256="8a597dc918fb62e05db23a5f810327a045a62c57cfda16646075138a6ac696fa", | |
| ), | |
| "react/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/facebook/react/main/LICENSE", | |
| sha256="da6d3703ed11cbe42bd212c725957c98da23cbff1998c05fa4b3d976d1a58e93", | |
| ), | |
| "react/react.production.min.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js", | |
| sha256="4b4969fa4ef3594324da2c6d78ce8766fbbc2fd121fff395aedf997db0a99a06", | |
| ), | |
| "react/react-dom.production.min.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js", | |
| sha256="21758ed084cd0e37e735722ee4f3957ea960628a29dfa6c3ce1a1d47a2d6e4f7", | |
| ), | |
| "vega/vega.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/vega/5.21.0/vega.js", | |
| sha256="b34c43055ef5d39a093e937522955dc359fbaec6c5b0259ae2de4c9da698e9fe", | |
| ), | |
| "vega/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/vega/vega/main/LICENSE", | |
| sha256="63727832aaf62004a2b249c933e327f3c90caf49e41a72f4bf436edf632cbda8", | |
| ), | |
| "vega-lite/vega-lite.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/vega-lite/5.2.0/vega-lite.js", | |
| sha256="6eb7f93121cd9f44cf8640244f87c5e143f87c7a0b6cd113da4a9e41e3adf0aa", | |
| ), | |
| "vega-lite/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/vega/vega-lite/next/LICENSE", | |
| sha256="f618900fd0d64046963b29f40590cdd1e341a2f41449f99110d82fd81fea808c", | |
| ), | |
| "vega-embed/vega-embed.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/vega-embed/6.20.8/vega-embed.js", | |
| sha256="4e546c1f86eb200333606440e92f76e2940b905757018d9672cd1708e4e6ff0a", | |
| ), | |
| "vega-embed/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/vega/vega-embed/next/LICENSE", | |
| sha256="32df67148f0fc3db0eb9e263a7b75d07f1eb14c61955005a4a39c6918d10d137", | |
| ), | |
| "heroicons/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/tailwindlabs/heroicons/master/LICENSE", | |
| sha256="60e0b68c0f35c078eef3a5d29419d0b03ff84ec1df9c3f9d6e39a519a5ae7985", | |
| ), | |
| "prop-types/prop-types.min.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.7.2/prop-types.min.js", | |
| sha256="4c88350517ee82aa4f3368e67ef1a453ca6636dcfa6449b4e3d6faa5c877066e", | |
| ), | |
| "prop-types/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/facebook/prop-types/main/LICENSE", | |
| sha256="f657f99d3fb9647db92628e96007aabb46e5f04f33e49999075aab8e250ca7ce", | |
| ), | |
| } | |
| @classmethod | |
| def deploy(cls: type[Assets]) -> None: | |
| for asset_path, asset in cls.spec.items(): | |
| target_path = cls.base_path / asset_path | |
| target_path.parent.mkdir(parents=True, exist_ok=True) | |
| with open(target_path, "wb") as fout: | |
| fout.write(asset.get_content()) | |
| @classmethod | |
| def get_content(cls: type[Assets], asset_path: str) -> str: | |
| try: | |
| return (cls.base_path / asset_path).read_text() | |
| except FileNotFoundError: | |
| logger.warning( | |
| f"Asset {asset_path} not found (development setup?), downloading..." | |
| ) | |
| return cls.spec[asset_path].get_content().decode() |
There was a problem hiding this comment.
Do not suggest type annotations for cls arguments.
There was a problem hiding this comment.
@johanneskoester, understood! I will make sure not to suggest type annotations for cls arguments in future reviews.
Learnings added
Learnt from: johanneskoester
PR: snakemake/snakemake#3026
File: snakemake/assets/__init__.py:0-0
Timestamp: 2024-08-27T20:15:58.527Z
Learning: Do not suggest type annotations for `cls` arguments in class methods when reviewing code for the Snakemake project.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
|
Please format your code with black: |
There was a problem hiding this comment.
Actionable comments posted: 0
Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Files selected for processing (1)
- snakemake/assets/init.py (1 hunks)
Files skipped from review as they are similar to previous changes (1)
- snakemake/assets/init.py
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…nto fix/asset-download
There was a problem hiding this comment.
Actionable comments posted: 0
Outside diff range, codebase verification and nitpick comments (1)
snakemake/common/__init__.py (1)
20-20: Inconsistent Removal ofPIP_DEPLOYMENTS_PATH:The
PIP_DEPLOYMENTS_PATHis still referenced in the following locations, indicating that its removal might not be consistent across the codebase:
snakemake/__init__.py: Defined and used insys.path.append(PIP_DEPLOYMENTS_PATH).snakemake/spawn_jobs.py: Referenced in a string formatting context.Please ensure that the removal of
PIP_DEPLOYMENTS_PATHis handled consistently to avoid potential issues.Analysis chain
Check: Removal of
PIP_DEPLOYMENTS_PATH.The removal of
PIP_DEPLOYMENTS_PATHfrom this file suggests a change in how deployment paths are managed. Verify that this change is consistent across the system and does not impact functionality.Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify the removal of `PIP_DEPLOYMENTS_PATH` and its impact on the system. # Test: Search for any remaining references to `PIP_DEPLOYMENTS_PATH`. Expect: No inconsistent usage. rg --type python 'PIP_DEPLOYMENTS_PATH'Length of output: 70
Script:
#!/bin/bash # Description: Verify the removal of `PIP_DEPLOYMENTS_PATH` and its impact on the system. # Test: Search for any remaining references to `PIP_DEPLOYMENTS_PATH` in Python files. rg 'PIP_DEPLOYMENTS_PATH' --glob '*.py'Length of output: 284
Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Files selected for processing (4)
- setup.py (1 hunks)
- snakemake/init.py (1 hunks)
- snakemake/assets/init.py (1 hunks)
- snakemake/common/init.py (2 hunks)
Files skipped from review as they are similar to previous changes (1)
- setup.py
Additional context used
Path-based instructions (3)
snakemake/__init__.py (1)
Pattern
**/*.py: Do not try to improve formatting.
Do not suggest type annotations for functions that are defined inside of functions or methods.
Do not suggest type annotation of theselfargument of methods.
Do not suggest type annotation of theclsargument of classmethods.
Do not suggest return type annotation if a function or method does not contain areturnstatement.snakemake/assets/__init__.py (1)
Pattern
**/*.py: Do not try to improve formatting.
Do not suggest type annotations for functions that are defined inside of functions or methods.
Do not suggest type annotation of theselfargument of methods.
Do not suggest type annotation of theclsargument of classmethods.
Do not suggest return type annotation if a function or method does not contain areturnstatement.snakemake/common/__init__.py (1)
Pattern
**/*.py: Do not try to improve formatting.
Do not suggest type annotations for functions that are defined inside of functions or methods.
Do not suggest type annotation of theselfargument of methods.
Do not suggest type annotation of theclsargument of classmethods.
Do not suggest return type annotation if a function or method does not contain areturnstatement.
Ruff
snakemake/assets/__init__.py
22-22: Within an
exceptclause, raise exceptions withraise ... from errorraise ... from Noneto distinguish them from errors in exception handling(B904)
Additional comments not posted (5)
snakemake/__init__.py (2)
8-11: Refactor: Improved version management usingget_versions.The dynamic fetching of the version using
get_versions()fromsnakemake._versionis a good practice as it centralizes version management. Deleting theget_versionsfunction after its use helps clean up the namespace, preventing potential conflicts or misuse in the larger codebase.The changes are well-integrated and improve maintainability.
13-13: Consistency Check:PIP_DEPLOYMENTS_PATHremains unchanged.It's noted that
PIP_DEPLOYMENTS_PATHremains unchanged. Ensure this consistency is intentional and well-documented, especially if there are related changes elsewhere in the system that might affect how deployment paths are handled.Verification successful
Consistency of
PIP_DEPLOYMENTS_PATHis maintained.The
PIP_DEPLOYMENTS_PATHis consistently used in the codebase to modify the system path and as a target directory for pip installations. This confirms that its usage is intentional and aligns with its purpose as a deployment path. No further action is required.Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check for references to `PIP_DEPLOYMENTS_PATH` to ensure consistency across the project. # Test: Search for references to `PIP_DEPLOYMENTS_PATH`. Expect: Consistent usage across the project. rg --type python 'PIP_DEPLOYMENTS_PATH'Length of output: 70
Script:
#!/bin/bash # Description: Check for references to `PIP_DEPLOYMENTS_PATH` to ensure consistency across the project. # Test: Search for references to `PIP_DEPLOYMENTS_PATH`. Expect: Consistent usage across the project. rg 'PIP_DEPLOYMENTS_PATH'Length of output: 270
snakemake/assets/__init__.py (2)
15-25: Enhancement: Robust asset fetching with error handling.The implementation of error handling in the
get_contentmethod for assets is robust, usingrequests.getwith proper exception handling and checksum verification. This ensures that asset fetching is reliable and secure, which is crucial for the offline capabilities of the system.The changes are well-implemented and enhance the system's robustness.
Tools
Ruff
22-22: Within an
exceptclause, raise exceptions withraise ... from errorraise ... from Noneto distinguish them from errors in exception handling(B904)
97-115: Methodology: Asset deployment and retrieval.The
deployandget_contentclass methods in theAssetsclass handle the deployment and retrieval of assets effectively. The use ofPathfor file operations and the structured handling of file not found exceptions are good practices that enhance the code's readability and maintainability.The asset management system is correctly implemented and integrates well with the overall system architecture.
snakemake/common/__init__.py (1)
20-20: Refinement: Simplified version retrieval.Directly importing
__version__fromsnakemakesimplifies the version management process by eliminating unnecessary function calls, which can reduce overhead and potential errors.The simplification is a positive change that enhances code clarity and performance.
There was a problem hiding this comment.
Actionable comments posted: 2
Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Files selected for processing (2)
- snakemake/assets/init.py (1 hunks)
- snakemake/report/html_reporter/data/packages.py (3 hunks)
Additional context used
Path-based instructions (2)
snakemake/report/html_reporter/data/packages.py (1)
Pattern
**/*.py: Do not try to improve formatting.
Do not suggest type annotations for functions that are defined inside of functions or methods.
Do not suggest type annotation of theselfargument of methods.
Do not suggest type annotation of theclsargument of classmethods.
Do not suggest return type annotation if a function or method does not contain areturnstatement.snakemake/assets/__init__.py (1)
Pattern
**/*.py: Do not try to improve formatting.
Do not suggest type annotations for functions that are defined inside of functions or methods.
Do not suggest type annotation of theselfargument of methods.
Do not suggest type annotation of theclsargument of classmethods.
Do not suggest return type annotation if a function or method does not contain areturnstatement.
Ruff
snakemake/report/html_reporter/data/packages.py
2-2:
pathlib.Pathimported but unusedRemove unused import:
pathlib.Path(F401)
7-7: Redefinition of unused
WorkflowErrorfrom line 3(F811)
91-91: Within an
exceptclause, raise exceptions withraise ... from errorraise ... from Noneto distinguish them from errors in exception handling(B904)
snakemake/assets/__init__.py
27-27: Within an
exceptclause, raise exceptions withraise ... from errorraise ... from Noneto distinguish them from errors in exception handling(B904)
Additional comments not posted (6)
snakemake/report/html_reporter/data/packages.py (2)
18-56: LGTM!The function is correctly implemented and aligns with the objective of improving offline capabilities.
The code changes are approved.
Line range hint
58-66: LGTM!The class is correctly implemented.
The code changes are approved.
snakemake/assets/__init__.py (4)
1-7: LGTM!All imports are used in the code.
The code changes are approved.
10-11: LGTM!The class is correctly implemented.
The code changes are approved.
35-122: Add error handling forrequests.getcall.The
requests.getcall should handle potential exceptions to ensure robustness.def get_content(cls, asset_path: str) -> str: try: - return (cls.base_path / asset_path).read_text() + return (cls.base_path / Path(asset_path)).read_text() except FileNotFoundError: logger.warning( f"Asset {asset_path} not found (development setup?), downloading..." ) - return cls.spec[asset_path].get_content().decode() + try: + response = requests.get(cls.spec[asset_path].url) + response.raise_for_status() + content = response.content + except requests.RequestException as e: + raise ValueError(f"Failed to download asset {cls.spec[asset_path].url}: {e}") + if cls.spec[asset_path].sha256 != hashlib.sha256(content).hexdigest(): + raise ValueError(f"Checksum mismatch when downloading asset {cls.spec[asset_path].url}") + return content.decode()Likely invalid or redundant comment.
14-32: Add error handling forurllib.request.urlopencall.The
urllib.request.urlopencall should handle potential exceptions to ensure robustness.def get_content(self) -> bytes: """Get and validate asset content.""" - req = urllib.request.Request(self.url, headers={"User-Agent": "snakemake"}) - try: - resp = urllib.request.urlopen(req) - content = resp.read() - except urllib.error.URLError as e: - raise AssetDownloadError(f"Failed to download asset {self.url}: {e}") - if self.sha256 != hashlib.sha256(content).hexdigest(): - raise AssetDownloadError( - f"Checksum mismatch when downloading asset {self.url}" - ) - return content + req = urllib.request.Request(self.url, headers={"User-Agent": "snakemake"}) + try: + resp = urllib.request.urlopen(req) + resp.raise_for_status() + content = resp.read() + except urllib.error.URLError as e: + raise AssetDownloadError(f"Failed to download asset {self.url}: {e}") from e + if self.sha256 != hashlib.sha256(content).hexdigest(): + raise AssetDownloadError( + f"Checksum mismatch when downloading asset {self.url}" + ) + return contentLikely invalid or redundant comment.
Tools
Ruff
27-27: Within an
exceptclause, raise exceptions withraise ... from errorraise ... from Noneto distinguish them from errors in exception handling(B904)
There was a problem hiding this comment.
Actionable comments posted: 2
Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Files selected for processing (3)
- setup.py (1 hunks)
- snakemake/assets/init.py (1 hunks)
- snakemake/report/html_reporter/data/packages.py (3 hunks)
Files skipped from review as they are similar to previous changes (1)
- setup.py
Additional context used
Path-based instructions (2)
snakemake/report/html_reporter/data/packages.py (1)
Pattern
**/*.py: Do not try to improve formatting.
Do not suggest type annotations for functions that are defined inside of functions or methods.
Do not suggest type annotation of theselfargument of methods.
Do not suggest type annotation of theclsargument of classmethods.
Do not suggest return type annotation if a function or method does not contain areturnstatement.snakemake/assets/__init__.py (1)
Pattern
**/*.py: Do not try to improve formatting.
Do not suggest type annotations for functions that are defined inside of functions or methods.
Do not suggest type annotation of theselfargument of methods.
Do not suggest type annotation of theclsargument of classmethods.
Do not suggest return type annotation if a function or method does not contain areturnstatement.
Ruff
snakemake/report/html_reporter/data/packages.py
89-89: Within an
exceptclause, raise exceptions withraise ... from errorraise ... from Noneto distinguish them from errors in exception handling(B904)
snakemake/assets/__init__.py
27-27: Within an
exceptclause, raise exceptions withraise ... from errorraise ... from Noneto distinguish them from errors in exception handling(B904)
Additional comments not posted (2)
snakemake/report/html_reporter/data/packages.py (2)
74-89: LGTM! But verify the class usage in the codebase.The class is correctly implemented. However, ensure that all instances of the
Packageclass are updated to reflect the new constructor parameters.The code changes are approved.
Run the following script to verify the class usage:
Verification successful
Class usage is correctly updated.
The
Packageclass constructor changes are correctly reflected in the codebase, with the updated parameters used insnakemake/report/html_reporter/data/packages.py. No other instances require modification.
snakemake/report/html_reporter/data/packages.py: Correct usage of the updated constructor parameters.Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify all instances of the `Package` class are updated to reflect the new constructor parameters. # Test: Search for the class usage. Expect: Only occurrences of the new implementation. rg --type python -A 5 $'Package'Length of output: 62
Script:
#!/bin/bash # Description: Verify all instances of the `Package` class are updated to reflect the new constructor parameters. # Test: Search for the class usage. Expect: Only occurrences of the new implementation. rg -A 5 'Package'Length of output: 9807
Tools
Ruff
89-89: Within an
exceptclause, raise exceptions withraise ... from errorraise ... from Noneto distinguish them from errors in exception handling(B904)
Line range hint
4-54: LGTM! But verify the function usage in the codebase.The function is correctly implemented. However, ensure that all function calls to
get_packagesare updated to reflect the new local paths for licenses and source files.The code changes are approved.
Run the following script to verify the function usage:
| @dataclass | ||
| class Asset: | ||
| url: str | ||
| sha256: str | ||
|
|
||
| def get_content(self) -> bytes: | ||
| """Get and validate asset content.""" | ||
|
|
||
| req = urllib.request.Request(self.url, headers={"User-Agent": "snakemake"}) | ||
| try: | ||
| resp = urllib.request.urlopen(req) | ||
| content = resp.read() | ||
| except urllib.error.URLError as e: | ||
| raise AssetDownloadError(f"Failed to download asset {self.url}: {e}") | ||
| if self.sha256 != hashlib.sha256(content).hexdigest(): | ||
| raise AssetDownloadError( | ||
| f"Checksum mismatch when downloading asset {self.url}" | ||
| ) | ||
| return content |
There was a problem hiding this comment.
Improve exception handling.
The urllib.request.urlopen call should handle potential exceptions to ensure robustness. Additionally, use raise ... from syntax for exception chaining.
Apply this diff to improve the exception handling:
def get_content(self) -> bytes:
"""Get and validate asset content."""
req = urllib.request.Request(self.url, headers={"User-Agent": "snakemake"})
try:
resp = urllib.request.urlopen(req)
content = resp.read()
except urllib.error.URLError as e:
- raise AssetDownloadError(f"Failed to download asset {self.url}: {e}")
+ raise AssetDownloadError(f"Failed to download asset {self.url}") from e
if self.sha256 != hashlib.sha256(content).hexdigest():
raise AssetDownloadError(
f"Checksum mismatch when downloading asset {self.url}"
)
return contentCommittable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @dataclass | |
| class Asset: | |
| url: str | |
| sha256: str | |
| def get_content(self) -> bytes: | |
| """Get and validate asset content.""" | |
| req = urllib.request.Request(self.url, headers={"User-Agent": "snakemake"}) | |
| try: | |
| resp = urllib.request.urlopen(req) | |
| content = resp.read() | |
| except urllib.error.URLError as e: | |
| raise AssetDownloadError(f"Failed to download asset {self.url}: {e}") | |
| if self.sha256 != hashlib.sha256(content).hexdigest(): | |
| raise AssetDownloadError( | |
| f"Checksum mismatch when downloading asset {self.url}" | |
| ) | |
| return content | |
| @dataclass | |
| class Asset: | |
| url: str | |
| sha256: str | |
| def get_content(self) -> bytes: | |
| """Get and validate asset content.""" | |
| req = urllib.request.Request(self.url, headers={"User-Agent": "snakemake"}) | |
| try: | |
| resp = urllib.request.urlopen(req) | |
| content = resp.read() | |
| except urllib.error.URLError as e: | |
| raise AssetDownloadError(f"Failed to download asset {self.url}") from e | |
| if self.sha256 != hashlib.sha256(content).hexdigest(): | |
| raise AssetDownloadError( | |
| f"Checksum mismatch when downloading asset {self.url}" | |
| ) | |
| return content |
Tools
Ruff
27-27: Within an
exceptclause, raise exceptions withraise ... from errorraise ... from Noneto distinguish them from errors in exception handling(B904)
| class Assets: | ||
| _base_path: Optional[Path] = None | ||
| spec: Dict[str, Asset] = { | ||
| "snakemake/LICENSE.md": Asset( | ||
| url="https://raw.githubusercontent.com/snakemake/snakemake/main/LICENSE.md", | ||
| sha256="84a1a82b05c80637744d3fe8257235c15380efa6cc32608adf4b21f17af5d2b8", | ||
| ), | ||
| "pygments/LICENSE": Asset( | ||
| url="https://raw.githubusercontent.com/pygments/pygments/master/LICENSE", | ||
| sha256="a9d66f1d526df02e29dce73436d34e56e8632f46c275bbdffc70569e882f9f17", | ||
| ), | ||
| "tailwindcss/LICENSE": Asset( | ||
| url="https://raw.githubusercontent.com/tailwindlabs/tailwindcss/master/LICENSE", | ||
| sha256="60e0b68c0f35c078eef3a5d29419d0b03ff84ec1df9c3f9d6e39a519a5ae7985", | ||
| ), | ||
| "tailwindcss/tailwind.css": Asset( | ||
| url="https://cdn.tailwindcss.com/3.0.23?plugins=forms@0.4.0,typography@0.5.2", | ||
| sha256="8a597dc918fb62e05db23a5f810327a045a62c57cfda16646075138a6ac696fa", | ||
| ), | ||
| "react/LICENSE": Asset( | ||
| url="https://raw.githubusercontent.com/facebook/react/main/LICENSE", | ||
| sha256="da6d3703ed11cbe42bd212c725957c98da23cbff1998c05fa4b3d976d1a58e93", | ||
| ), | ||
| "react/react.production.min.js": Asset( | ||
| url="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js", | ||
| sha256="4b4969fa4ef3594324da2c6d78ce8766fbbc2fd121fff395aedf997db0a99a06", | ||
| ), | ||
| "react/react-dom.production.min.js": Asset( | ||
| url="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js", | ||
| sha256="21758ed084cd0e37e735722ee4f3957ea960628a29dfa6c3ce1a1d47a2d6e4f7", | ||
| ), | ||
| "vega/vega.js": Asset( | ||
| url="https://cdnjs.cloudflare.com/ajax/libs/vega/5.21.0/vega.js", | ||
| sha256="b34c43055ef5d39a093e937522955dc359fbaec6c5b0259ae2de4c9da698e9fe", | ||
| ), | ||
| "vega/LICENSE": Asset( | ||
| url="https://raw.githubusercontent.com/vega/vega/main/LICENSE", | ||
| sha256="63727832aaf62004a2b249c933e327f3c90caf49e41a72f4bf436edf632cbda8", | ||
| ), | ||
| "vega-lite/vega-lite.js": Asset( | ||
| url="https://cdnjs.cloudflare.com/ajax/libs/vega-lite/5.2.0/vega-lite.js", | ||
| sha256="6eb7f93121cd9f44cf8640244f87c5e143f87c7a0b6cd113da4a9e41e3adf0aa", | ||
| ), | ||
| "vega-lite/LICENSE": Asset( | ||
| url="https://raw.githubusercontent.com/vega/vega-lite/next/LICENSE", | ||
| sha256="f618900fd0d64046963b29f40590cdd1e341a2f41449f99110d82fd81fea808c", | ||
| ), | ||
| "vega-embed/vega-embed.js": Asset( | ||
| url="https://cdnjs.cloudflare.com/ajax/libs/vega-embed/6.20.8/vega-embed.js", | ||
| sha256="4e546c1f86eb200333606440e92f76e2940b905757018d9672cd1708e4e6ff0a", | ||
| ), | ||
| "vega-embed/LICENSE": Asset( | ||
| url="https://raw.githubusercontent.com/vega/vega-embed/next/LICENSE", | ||
| sha256="32df67148f0fc3db0eb9e263a7b75d07f1eb14c61955005a4a39c6918d10d137", | ||
| ), | ||
| "heroicons/LICENSE": Asset( | ||
| url="https://raw.githubusercontent.com/tailwindlabs/heroicons/master/LICENSE", | ||
| sha256="60e0b68c0f35c078eef3a5d29419d0b03ff84ec1df9c3f9d6e39a519a5ae7985", | ||
| ), | ||
| "prop-types/prop-types.min.js": Asset( | ||
| url="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.7.2/prop-types.min.js", | ||
| sha256="4c88350517ee82aa4f3368e67ef1a453ca6636dcfa6449b4e3d6faa5c877066e", | ||
| ), | ||
| "prop-types/LICENSE": Asset( | ||
| url="https://raw.githubusercontent.com/facebook/prop-types/main/LICENSE", | ||
| sha256="f657f99d3fb9647db92628e96007aabb46e5f04f33e49999075aab8e250ca7ce", | ||
| ), | ||
| } | ||
|
|
||
| @classmethod | ||
| def deploy(cls) -> None: | ||
| base_path = Path(__file__).parent / "data" | ||
| for asset_path, asset in cls.spec.items(): | ||
| target_path = base_path / asset_path | ||
| target_path.parent.mkdir(parents=True, exist_ok=True) | ||
| with open(target_path, "wb") as fout: | ||
| fout.write(asset.get_content()) | ||
|
|
||
| @classmethod | ||
| def get_content(cls, asset_path: str) -> str: | ||
| try: | ||
| return (cls.base_path / asset_path).read_text() | ||
| except FileNotFoundError: | ||
| from snakemake.logging import logger | ||
|
|
||
| logger.warning( | ||
| f"Asset {asset_path} not found (development setup?), downloading..." | ||
| ) | ||
| return cls.spec[asset_path].get_content().decode() | ||
|
|
||
| @classmethod | ||
| def base_path(cls) -> Path: | ||
| if cls._base_path is None: | ||
| cls._base_path = importlib.resources.files("snakemake.assets") / "data" | ||
| return cls._base_path |
There was a problem hiding this comment.
Improve base path initialization.
The base path initialization can be simplified by using a class variable.
Apply this diff to simplify the base path initialization:
class Assets:
- _base_path: Optional[Path] = None
+ base_path: Path = importlib.resources.files("snakemake.assets") / "data"
spec: Dict[str, Asset] = {
...
}
@classmethod
def deploy(cls) -> None:
base_path = Path(__file__).parent / "data"
for asset_path, asset in cls.spec.items():
target_path = base_path / asset_path
target_path.parent.mkdir(parents=True, exist_ok=True)
with open(target_path, "wb") as fout:
fout.write(asset.get_content())
@classmethod
def get_content(cls, asset_path: str) -> str:
try:
- return (cls.base_path / asset_path).read_text()
+ return (cls.base_path / Path(asset_path)).read_text()
except FileNotFoundError:
from snakemake.logging import logger
logger.warning(
f"Asset {asset_path} not found (development setup?), downloading..."
)
return cls.spec[asset_path].get_content().decode()
@classmethod
def base_path(cls) -> Path:
- if cls._base_path is None:
- cls._base_path = importlib.resources.files("snakemake.assets") / "data"
- return cls._base_path
+ return cls.base_pathCommittable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| class Assets: | |
| _base_path: Optional[Path] = None | |
| spec: Dict[str, Asset] = { | |
| "snakemake/LICENSE.md": Asset( | |
| url="https://raw.githubusercontent.com/snakemake/snakemake/main/LICENSE.md", | |
| sha256="84a1a82b05c80637744d3fe8257235c15380efa6cc32608adf4b21f17af5d2b8", | |
| ), | |
| "pygments/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/pygments/pygments/master/LICENSE", | |
| sha256="a9d66f1d526df02e29dce73436d34e56e8632f46c275bbdffc70569e882f9f17", | |
| ), | |
| "tailwindcss/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/tailwindlabs/tailwindcss/master/LICENSE", | |
| sha256="60e0b68c0f35c078eef3a5d29419d0b03ff84ec1df9c3f9d6e39a519a5ae7985", | |
| ), | |
| "tailwindcss/tailwind.css": Asset( | |
| url="https://cdn.tailwindcss.com/3.0.23?plugins=forms@0.4.0,typography@0.5.2", | |
| sha256="8a597dc918fb62e05db23a5f810327a045a62c57cfda16646075138a6ac696fa", | |
| ), | |
| "react/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/facebook/react/main/LICENSE", | |
| sha256="da6d3703ed11cbe42bd212c725957c98da23cbff1998c05fa4b3d976d1a58e93", | |
| ), | |
| "react/react.production.min.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js", | |
| sha256="4b4969fa4ef3594324da2c6d78ce8766fbbc2fd121fff395aedf997db0a99a06", | |
| ), | |
| "react/react-dom.production.min.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js", | |
| sha256="21758ed084cd0e37e735722ee4f3957ea960628a29dfa6c3ce1a1d47a2d6e4f7", | |
| ), | |
| "vega/vega.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/vega/5.21.0/vega.js", | |
| sha256="b34c43055ef5d39a093e937522955dc359fbaec6c5b0259ae2de4c9da698e9fe", | |
| ), | |
| "vega/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/vega/vega/main/LICENSE", | |
| sha256="63727832aaf62004a2b249c933e327f3c90caf49e41a72f4bf436edf632cbda8", | |
| ), | |
| "vega-lite/vega-lite.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/vega-lite/5.2.0/vega-lite.js", | |
| sha256="6eb7f93121cd9f44cf8640244f87c5e143f87c7a0b6cd113da4a9e41e3adf0aa", | |
| ), | |
| "vega-lite/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/vega/vega-lite/next/LICENSE", | |
| sha256="f618900fd0d64046963b29f40590cdd1e341a2f41449f99110d82fd81fea808c", | |
| ), | |
| "vega-embed/vega-embed.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/vega-embed/6.20.8/vega-embed.js", | |
| sha256="4e546c1f86eb200333606440e92f76e2940b905757018d9672cd1708e4e6ff0a", | |
| ), | |
| "vega-embed/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/vega/vega-embed/next/LICENSE", | |
| sha256="32df67148f0fc3db0eb9e263a7b75d07f1eb14c61955005a4a39c6918d10d137", | |
| ), | |
| "heroicons/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/tailwindlabs/heroicons/master/LICENSE", | |
| sha256="60e0b68c0f35c078eef3a5d29419d0b03ff84ec1df9c3f9d6e39a519a5ae7985", | |
| ), | |
| "prop-types/prop-types.min.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.7.2/prop-types.min.js", | |
| sha256="4c88350517ee82aa4f3368e67ef1a453ca6636dcfa6449b4e3d6faa5c877066e", | |
| ), | |
| "prop-types/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/facebook/prop-types/main/LICENSE", | |
| sha256="f657f99d3fb9647db92628e96007aabb46e5f04f33e49999075aab8e250ca7ce", | |
| ), | |
| } | |
| @classmethod | |
| def deploy(cls) -> None: | |
| base_path = Path(__file__).parent / "data" | |
| for asset_path, asset in cls.spec.items(): | |
| target_path = base_path / asset_path | |
| target_path.parent.mkdir(parents=True, exist_ok=True) | |
| with open(target_path, "wb") as fout: | |
| fout.write(asset.get_content()) | |
| @classmethod | |
| def get_content(cls, asset_path: str) -> str: | |
| try: | |
| return (cls.base_path / asset_path).read_text() | |
| except FileNotFoundError: | |
| from snakemake.logging import logger | |
| logger.warning( | |
| f"Asset {asset_path} not found (development setup?), downloading..." | |
| ) | |
| return cls.spec[asset_path].get_content().decode() | |
| @classmethod | |
| def base_path(cls) -> Path: | |
| if cls._base_path is None: | |
| cls._base_path = importlib.resources.files("snakemake.assets") / "data" | |
| return cls._base_path | |
| class Assets: | |
| base_path: Path = importlib.resources.files("snakemake.assets") / "data" | |
| spec: Dict[str, Asset] = { | |
| "snakemake/LICENSE.md": Asset( | |
| url="https://raw.githubusercontent.com/snakemake/snakemake/main/LICENSE.md", | |
| sha256="84a1a82b05c80637744d3fe8257235c15380efa6cc32608adf4b21f17af5d2b8", | |
| ), | |
| "pygments/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/pygments/pygments/master/LICENSE", | |
| sha256="a9d66f1d526df02e29dce73436d34e56e8632f46c275bbdffc70569e882f9f17", | |
| ), | |
| "tailwindcss/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/tailwindlabs/tailwindcss/master/LICENSE", | |
| sha256="60e0b68c0f35c078eef3a5d29419d0b03ff84ec1df9c3f9d6e39a519a5ae7985", | |
| ), | |
| "tailwindcss/tailwind.css": Asset( | |
| url="https://cdn.tailwindcss.com/3.0.23?plugins=forms@0.4.0,typography@0.5.2", | |
| sha256="8a597dc918fb62e05db23a5f810327a045a62c57cfda16646075138a6ac696fa", | |
| ), | |
| "react/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/facebook/react/main/LICENSE", | |
| sha256="da6d3703ed11cbe42bd212c725957c98da23cbff1998c05fa4b3d976d1a58e93", | |
| ), | |
| "react/react.production.min.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js", | |
| sha256="4b4969fa4ef3594324da2c6d78ce8766fbbc2fd121fff395aedf997db0a99a06", | |
| ), | |
| "react/react-dom.production.min.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js", | |
| sha256="21758ed084cd0e37e735722ee4f3957ea960628a29dfa6c3ce1a1d47a2d6e4f7", | |
| ), | |
| "vega/vega.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/vega/5.21.0/vega.js", | |
| sha256="b34c43055ef5d39a093e937522955dc359fbaec6c5b0259ae2de4c9da698e9fe", | |
| ), | |
| "vega/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/vega/vega/main/LICENSE", | |
| sha256="63727832aaf62004a2b249c933e327f3c90caf49e41a72f4bf436edf632cbda8", | |
| ), | |
| "vega-lite/vega-lite.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/vega-lite/5.2.0/vega-lite.js", | |
| sha256="6eb7f93121cd9f44cf8640244f87c5e143f87c7a0b6cd113da4a9e41e3adf0aa", | |
| ), | |
| "vega-lite/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/vega/vega-lite/next/LICENSE", | |
| sha256="f618900fd0d64046963b29f40590cdd1e341a2f41449f99110d82fd81fea808c", | |
| ), | |
| "vega-embed/vega-embed.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/vega-embed/6.20.8/vega-embed.js", | |
| sha256="4e546c1f86eb200333606440e92f76e2940b905757018d9672cd1708e4e6ff0a", | |
| ), | |
| "vega-embed/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/vega/vega-embed/next/LICENSE", | |
| sha256="32df67148f0fc3db0eb9e263a7b75d07f1eb14c61955005a4a39c6918d10d137", | |
| ), | |
| "heroicons/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/tailwindlabs/heroicons/master/LICENSE", | |
| sha256="60e0b68c0f35c078eef3a5d29419d0b03ff84ec1df9c3f9d6e39a519a5ae7985", | |
| ), | |
| "prop-types/prop-types.min.js": Asset( | |
| url="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.7.2/prop-types.min.js", | |
| sha256="4c88350517ee82aa4f3368e67ef1a453ca6636dcfa6449b4e3d6faa5c877066e", | |
| ), | |
| "prop-types/LICENSE": Asset( | |
| url="https://raw.githubusercontent.com/facebook/prop-types/main/LICENSE", | |
| sha256="f657f99d3fb9647db92628e96007aabb46e5f04f33e49999075aab8e250ca7ce", | |
| ), | |
| } | |
| @classmethod | |
| def deploy(cls) -> None: | |
| base_path = Path(__file__).parent / "data" | |
| for asset_path, asset in cls.spec.items(): | |
| target_path = base_path / asset_path | |
| target_path.parent.mkdir(parents=True, exist_ok=True) | |
| with open(target_path, "wb") as fout: | |
| fout.write(asset.get_content()) | |
| @classmethod | |
| def get_content(cls, asset_path: str) -> str: | |
| try: | |
| return (cls.base_path / Path(asset_path)).read_text() | |
| except FileNotFoundError: | |
| from snakemake.logging import logger | |
| logger.warning( | |
| f"Asset {asset_path} not found (development setup?), downloading..." | |
| ) | |
| return cls.spec[asset_path].get_content().decode() | |
| @classmethod | |
| def base_path(cls) -> Path: | |
| return cls.base_path |
|
There was a problem hiding this comment.
Actionable comments posted: 2
Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Files selected for processing (1)
- snakemake/assets/init.py (1 hunks)
Additional context used
Path-based instructions (1)
snakemake/assets/__init__.py (1)
Pattern
**/*.py: Do not try to improve formatting.
Do not suggest type annotations for functions that are defined inside of functions or methods.
Do not suggest type annotation of theselfargument of methods.
Do not suggest type annotation of theclsargument of classmethods.
Do not suggest return type annotation if a function or method does not contain areturnstatement.
Ruff
snakemake/assets/__init__.py
27-27: Within an
exceptclause, raise exceptions withraise ... from errorraise ... from Noneto distinguish them from errors in exception handling(B904)
Additional comments not posted (3)
snakemake/assets/__init__.py (3)
10-11: LGTM!The custom exception class
AssetDownloadErroris correctly implemented.The code changes are approved.
105-113: LGTM!The
deploymethod is correctly implemented.The code changes are approved.
128-132: LGTM!The
base_pathmethod is correctly implemented.The code changes are approved.
🤖 I have created a release *beep* *boop* --- ## [8.19.0](v8.18.2...v8.19.0) (2024-08-29) ### Features * check consistency of output file mtimes (must be newer than input files) ([#3050](#3050)) ([666cf62](666cf62)) * print host name when executing workflow ([#3048](#3048)) ([b0ff787](b0ff787)) ### Bug Fixes * `mem` and `disk` inference fixes ([#3040](#3040)) ([7530794](7530794)) * avoid error accessing superclass in ioutils ([#3056](#3056)) ([a66a5f5](a66a5f5)) * disable execute after print compilation ([#3041](#3041)) ([86ed3cd](86ed3cd)) * download report assets upon package build such that reports become possible offline (cont. of [#2904](#2904)) ([#3026](#3026)) ([e8dad4b](e8dad4b)) ### Documentation * Add 'Editor integrations' section to Installation page ([#3045](#3045)) ([9a4006d](9a4006d)) * Fix typo (seesee to see) ([#3037](#3037)) ([de201fb](de201fb)) * various documentation fixes ([#3052](#3052)) ([b11460c](b11460c)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…me possible offline (cont. of snakemake#2904) (snakemake#3026) The original PR has been reverted in main because it does not seem to work will with developer installation mode (assets are not installed in the right place in that case). cc @fs82 ### QC <!-- Make sure that you can tick the boxes below. --> * [x] The PR contains a test case for the changes or the changes are already covered by an existing test case. * [x] The documentation (`docs/`) is updated to reflect the changes or this is not necessary (e.g. if the change does neither modify the language nor the behavior or functionalities of Snakemake). <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Summary by CodeRabbit - **New Features** - Introduced structured asset management within the Snakemake framework, allowing for better handling and deployment of external resources. - **Improvements** - Enhanced package metadata handling for improved maintainability and accessibility of license and source files. - Enabled the inclusion of additional package data during installation, ensuring necessary files are available. - **Bug Fixes** - Improved reliability by transitioning to local paths for resource referencing, enhancing accessibility and reducing dependency on external URLs. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
🤖 I have created a release *beep* *boop* --- ## [8.19.0](snakemake/snakemake@v8.18.2...v8.19.0) (2024-08-29) ### Features * check consistency of output file mtimes (must be newer than input files) ([snakemake#3050](snakemake#3050)) ([666cf62](snakemake@666cf62)) * print host name when executing workflow ([snakemake#3048](snakemake#3048)) ([b0ff787](snakemake@b0ff787)) ### Bug Fixes * `mem` and `disk` inference fixes ([snakemake#3040](snakemake#3040)) ([7530794](snakemake@7530794)) * avoid error accessing superclass in ioutils ([snakemake#3056](snakemake#3056)) ([a66a5f5](snakemake@a66a5f5)) * disable execute after print compilation ([snakemake#3041](snakemake#3041)) ([86ed3cd](snakemake@86ed3cd)) * download report assets upon package build such that reports become possible offline (cont. of [snakemake#2904](snakemake#2904)) ([snakemake#3026](snakemake#3026)) ([e8dad4b](snakemake@e8dad4b)) ### Documentation * Add 'Editor integrations' section to Installation page ([snakemake#3045](snakemake#3045)) ([9a4006d](snakemake@9a4006d)) * Fix typo (seesee to see) ([snakemake#3037](snakemake#3037)) ([de201fb](snakemake@de201fb)) * various documentation fixes ([snakemake#3052](snakemake#3052)) ([b11460c](snakemake@b11460c)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>



The original PR has been reverted in main because it does not seem to work will with developer installation mode (assets are not installed in the right place in that case).
cc @fs82
QC
docs/) is updated to reflect the changes or this is not necessary (e.g. if the change does neither modify the language nor the behavior or functionalities of Snakemake).Summary by CodeRabbit
Summary by CodeRabbit
New Features
Improvements
Bug Fixes