diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..34299c01 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,753 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.8.1] - 2026-02-18 + +Full changelog: https://github.com/crs4/rocrate-validator/compare/0.8.0...0.8.1 + +### 🔧 Changed + +- refactor(core): rename flag `disable_inherited_profiles_reporting` to `disable_inherited_profiles_issue_reporting` ([daebea1](https://github.com/crs4/rocrate-validator/commit/daebea1)) +- refactor(core): set `disable_inherited_profiles_issue_reporting` to disabled by default ([c8e7de7](https://github.com/crs4/rocrate-validator/commit/c8e7de7)) +- refactor(core): skip inherited profile event notifications when issue reporting is disabled ([c8ad7b9](https://github.com/crs4/rocrate-validator/commit/c8ad7b9)) +- build(poetry): allow using the latest PySHACL version ([fde97be](https://github.com/crs4/rocrate-validator/commit/fde97be)) + +### 🐛 Fixed + +- fix(cli): fix `rich` deprecation warning ([dbdfae5](https://github.com/crs4/rocrate-validator/commit/dbdfae5)) +- fix(core): ensure skipped checks are reported properly ([471745b](https://github.com/crs4/rocrate-validator/commit/471745b)) +- fix(cli): wrong param name ([38f22ff](https://github.com/crs4/rocrate-validator/commit/38f22ff)) +- fix(core): ensure skip_checks is defined before use ([04988b1](https://github.com/crs4/rocrate-validator/commit/04988b1)) +- fix(core): enable skipping of Python checks ([efcad8b](https://github.com/crs4/rocrate-validator/commit/efcad8b)) +- fix(core): enable skipping of SHACL checks ([9141a72](https://github.com/crs4/rocrate-validator/commit/9141a72)) +- fix(core): exclude skipped checks from stats ([4a27eb9](https://github.com/crs4/rocrate-validator/commit/4a27eb9)) +- fix(core): remove inherited checks from stats when `disable_inherited_profiles_issue_reporting` is set ([f6e15b7](https://github.com/crs4/rocrate-validator/commit/f6e15b7)) +- fix(cli): make the `disable_profile_inheritance` CLI flag affect only reporting (not loading) of inherited profiles ([d6f9192](https://github.com/crs4/rocrate-validator/commit/d6f9192)) + +### 🗑️ Removed + +- chore: filter `rdflib` JSON-LD deprecation warnings ([c6da40a](https://github.com/crs4/rocrate-validator/commit/c6da40a)) + +### 📚 Documentation + +- docs(core): clarify the proper usage of the `enable_profile_inheritance` flag ([cd3af57](https://github.com/crs4/rocrate-validator/commit/cd3af57)) +- docs(core): improve code documentation with additional comments ([cd03486](https://github.com/crs4/rocrate-validator/commit/cd03486)) + +## [0.8.0] - 2026-01-07 + +### ✨ Added + +- feat(cli): detect environment and properly handle Console initialization +- feat(profiles/ro-crate): check if the JSON-LD context can be loaded +- feat(profiles/ro-crate): check for the compacted JSON-LD format of the file descriptor +- feat(profiles/ro-crate): check recommended existence of absolute local data entities +- feat(profiles/ro-crate): update check to skip absolute paths +- feat(core): extend entity model to detect local and relative paths +- feat(profiles/ro-crate): check for the existence of data entities +- feat(cli): allow configuring the list of checks to skip via CLI +- feat(core): allow skipping a configurable list of checks +- feat(cli): display the full check identifier when verbose mode is enabled +- feat(core): fix and extend method to fetch entities by type +- feat(core): add utility method to retrieve all data entities +- feat(core): expose path/uri of rocrate entities +- feat(core): add class method to derive data entity path from identifier +- feat(cli): add support for relative root path option +- feat(model): allow instantiating metadata-only RO-Crates +- feat(services): add a service method to validate RO-Crate metadata from a dict +- feat(profiles/ro-crate): extend flat JSON-LD check to support value objects +- feat(core): add factory method to automatically instantiate RO-Crate with the correct subtype +- feat(model): add classes for handling BagIt-wrapped RO-Crates + +### 🔧 Changed + +- refactor(utils): reorganize the `utils` package structure +- refactor(utils): rename `rocv_io` to `io_helpers` +- refactor(utils): move rocv_io into the utils package +- refactor(core): convert utils module into a package +- refactor(io.output): restructure and simplify the formatter classes +- refactor(io.output): simplify Console class +- refactor(cli): restructure CLI output handling logic +- refactor(cli): move and extend the base class to handle console output +- refactor(io.output): move the Pager class to a dedicated module +- refactor(cli): move input methods to the `io.input` module +- refactor(model): move profile finder to the Profile class +- refactor(core): improve file and directory availability checks +- refactor(core): refactor entity availability check with generic ZIP support and path unquoting +- refactor(cli): remove CLI parameters from the global validation settings +- refactor(core): move the init logic to the `__post__init__` method +- refactor(profiles/ro-crate): move required properties to a dedicated shape +- refactor(core): declare the function as class level method +- refactor(core): simplify profiles parsing +- refactor(core): rewrite magic method to sort profiles +- refactor(cli): update the short option to skip checks +- refactor(core): use method to identify remote entities +- refactor(core): remove redundant code +- refactor(utils): refactor multiple delegator methods into one +- refactor(core): remove relative imports +- refactor(core): adopt the `HttpRequester` class +- refactor(shacl): only exclude fragment identifiers that refer to the root data entity +- refactor(core): refactor Python detection of local identifiers + +### 🐛 Fixed + +- fix(profiles/ro-crate): fix SHACL nodeKind constraint being too strict +- fix(cli): wrong param name +- fix(core): ensure skip_checks is defined before use +- fix(core): enable skipping of Python checks +- fix(core): enable skipping of SHACL checks +- fix(core): exclude skipped checks from stats +- fix(core): remove inherited checks from stats when `disable_inherited_profiles_issue_reporting` is set +- fix(cli): make the `disable_profile_inheritance` CLI flag affect only reporting +- fix(tests): fix unit test assertion +- fix(logging): fix typo +- fix(cli): missing object dump +- fix(core): fix the candidate profiles collection +- fix(io.output): fix import +- fix(io.output): allow initialization of the report layout without an initial state +- fix(cli): fix formatter parameter +- fix(cli): restructure logic to process CLI text output of validation result +- fix(io.output): fix missing padding +- fix(model): fix availability check of external resources +- fix(model): use the custom class for remote Bagit RO-Crate objects +- fix(model): fix initialisation of BagitROCrate objects +- fix(model): fix fallback value for root path +- fix(model): fix initialisation of Bagit objects +- fix(model): fix linter warnings +- fix(model): fix linter warning E999 +- fix(profiles/ro-crate): trailing slash for Data Entities is recommended not mandatory +- fix(profiles/ro-crate): fix `sh:message` for the required `datePublished` + +### 🗑️ Removed + +- chore: filter `rdflib` JSON-LD deprecation warnings +- chore(poetry): fix missing whitespaces +- chore: update copyright notice to 2026 +- chore(git): ignore IDE project files + +### 📚 Documentation + +- docs(api): update docs +- docs(profiles): add note about ontology graph support and formal definitions +- docs(io.output): add some note about output formatters +- docs(readme): specify python 3.9 or later +- docs(profiles/ro-crate): add notes on custom validation profiles +- docs(cli): rephrase `--skip-checks` option description +- docs(cli): improve description of the `skip-checks` option +- docs(cli): add notes about programmatic metadata-only validation +- docs(core): clarify the proper usage of the `enable_profile_inheritance` flag +- docs(core): improve code documentation with additional comments + +### ⚡ Performance + +- perf(io.output): remove padding when using using no color console +- perf(cache): optimize Redis connection pooling +- perf(shacl): skip redundant violation messages +- perf(core): compute overrides on the fly +- perf(core): add a method to find a profile by checking its name +- perf(core): add properties to get parents and siblings of a given profile +- perf(core): add getter for sibling profiles +- perf(core): automatically detect overrides during Profile initialization +- perf(core): add support for overrides to the `Profile` model + +## [0.7.3] - 2025-06-23 + +### 🐛 Fixed + +- Restore Python 3.13 compatibility + +## [0.7.2] - 2025-06-19 + +### 🔧 Changed + +- Allow pyshacl 0.30 +- Adjust dependency version ranges for better flexibility + +## [0.7.1] - 2025-05-20 + +### 🔧 Changed + +- Upgrade dependencies + +## [0.7.0] - 2025-05-16 + +### ✨ Added + +- feat(profiles/ro-crate): exclude from the definition of Dataset Data Entities any dataset with a local identifier +- feat(profiles/ro-crate): exclude from the definition of File Data Entities any file with a local identifier +- feat(profiles/ro-crate): including files with local identifiers in the crate is not mandatory + +### 🔧 Changed + +- refactor(shacl): only exclude fragment identifiers that refer to the root data entity +- refactor(core): refactor Python detection of local identifiers + +## [0.6.5] - 2025-04-30 + +### ✨ Added + +- feat(core): allow avoiding duplicated events + +### 🔧 Changed + +- refactor(shacl): fix issue notifications +- chore(core): update log and comment messages + +### 🐛 Fixed + +- fix(shacl): fix return value of SHACL requirement check +- fix(core): do not skip overridden checks of the target profile +- fix(shacl): keep track of the checks that have been notified + +## [0.6.4] - 2025-04-24 + +### ✨ Added + +- feat(utils): add multithreading support +- feat(utils): add a singleton class to handle HTTP requests + +### 🔧 Changed + +- refactor(utils): refactor multiple delegator methods into one +- refactor(core): remove relative imports +- refactor(core): adopt the `HttpRequester` class + +## [0.6.3] - 2025-03-25 + +### 🐛 Fixed + +- fix(cli): don't skip overridden checks of the target profile + +### 🔧 Changed + +- chore: update copyright notice + +## [0.6.2] - 2025-03-12 + +### ✨ Added + +- feat(core): add method to list the entries of a ZIP archive +- feat(core): add getter for archive entry info + +### 🔧 Changed + +- refactor(core): allow empty files and directories within a ZIP file +- Acknowledge CN HPC + +### 🐛 Fixed + +- fix(core): update logic to check the availability of archive folders +- fix(cli): fix typo + +## [0.6.1] - 2025-02-20 + +### 🐛 Fixed + +- fix(core): fix the candidate profiles collection + +### 🔧 Changed + +- chore: update github action version + +## [0.6.0] - 2025-02-06 + +### ✨ Added + +- feat(profiles/ro-crate): check if the JSON-LD context can be loaded +- feat(profiles/ro-crate): check for the compacted JSON-LD format of the file descriptor +- feat(profiles/ro-crate): check recommended existence of absolute local data entities +- feat(profiles/ro-crate): update check to skip absolute paths +- feat(core): extend entity model to detect local and relative paths +- feat(profiles/ro-crate): check for the existence of data entities +- feat(cli): allow configuring the list of checks to skip via CLI +- feat(core): allow skipping a configurable list of checks +- feat(cli): display the full check identifier when verbose mode is enabled +- feat(core): fix and extend method to fetch entities by type +- feat(core): add utility method to retrieve all data entities +- feat(core): expose path/uri of rocrate entities +- feat(core): add class method to derive data entity path from identifier +- feat(cli): check the minimum required Python version +- feat(utils): add utility functions to read and check the minimum required Python version + +### 🔧 Changed + +- refactor(cli): remove CLI parameters from the global validation settings +- refactor(core): move the init logic to the `__post__init__` method +- refactor(profiles/ro-crate): move required properties to a dedicated shape +- refactor(core): declare the function as class level method +- refactor(core): simplify profiles parsing +- refactor(core): rewrite magic method to sort profiles +- refactor(cli): update the short option to skip checks +- refactor(core): use method to identify remote entities +- refactor(core): remove redundant code +- refactor(core): rename method arguments +- refactor(core): rename method +- refactor(core): remove redundant method +- refactor(core): remove cache timeout from validation settings +- refactor(core): remove unused `ontology_path` setting +- refactor(core): rename the flag to disable downloading a remote crate +- refactor(core): rename flag to disable reporting of inherited checks +- refactor(core): rename property to enable profile inheritance +- refactor(core): link the context with the settings as an object +- refactor(core): init and validate URI on settings object +- refactor(core): remove unused imports +- refactor(core): rename input parameter for the ro-crate uri +- refactor(core): remove internal settings from the `ValidationSettings` interface + +### 🐛 Fixed + +- fix(profiles/ro-crate): fix SHACL nodeKind constraint being too strict +- fix(cli): wrong param name +- fix(core): ensure skip_checks is defined before use +- fix(core): enable skipping of Python checks +- fix(core): enable skipping of SHACL checks +- fix(core): exclude skipped checks from stats +- fix(core): remove inherited checks from stats when `disable_inherited_profiles_issue_reporting` is set +- fix(cli): make the `disable_profile_inheritance` CLI flag affect only reporting +- fix(profiles/ro-crate): trailing slash for Data Entities is recommended not mandatory + +### 📚 Documentation + +- docs(readthedocs): add copyright +- docs(readthedocs): mention the fallback profile +- docs(readthedocs): restructure toc +- docs(readthedocs): fix typos +- docs(readthedocs): rewrite note +- docs(readthedocs): reformat +- docs(readthedocs): update toc +- docs(readthedocs): rename api docs file +- docs(readthedocs): more details on profile detection and versioning +- docs(readthedocs): add an initial "How it works" section +- docs(readthedocs): add link to Github repository +- docs(readthedocs): dynamically set the version +- docs(readthedocs): fix copyright +- docs(diagrams): extend diagrams by adding captions +- docs(diagrams): fix svg width +- docs(diagrams): fix missing `by` +- docs(readthedocs): update flag description +- docs(core): don't expose an internal validate method +- docs(core): extend param description +- docs(diagrams): update diagrams +- docs(diagrams): fix missing link +- docs(diagrams): fix blanks +- docs(diagrams): add missing params +- docs: add diagram for the `profiles` service +- docs: add diagram for the `validate` service +- docs: fix link +- docs: move the diagram files +- docs: refine "Core Model" diagram +- docs(core): update docstring +- docs(core): add docstring of `ValidationSettings` class +- docs(readme): reformat note +- docs(readme): extend the list of features +- docs(core): improve code documentation +- docs(core): add docstrings to the `ValidationResult` class +- docs(readme): add a comment on `profile_identifier` +- docs(readme): simplify path to crate in the programmatic validation example +- docs(readme): update list of supported profiles +- docs: add minimal example of programmatic usage +- docs: reformat +- docs(readme): extend example +- docs(core): add a docstring for the `violatingPropertyValue` +- docs(readme): add badge to the readthedocs documentation +- docs(core): bootstrap sphinx documentation + +### ⚡ Performance + +- perf(shacl): skip redundant violation messages +- perf(core): compute overrides on the fly +- perf(core): add a method to find a profile by checking its name +- perf(core): add properties to get parents and siblings of a given profile +- perf(core): add getter for sibling profiles +- perf(core): automatically detect overrides during Profile initialization +- perf(core): add support for overrides to the `Profile` model + +## [0.5.0] - 2024-12-17 + +### ✨ Added + +- feat(cli): swap default behaviour for fail fast +- feat(core): swap default behaviour `fail fast` option in API settings +- feat: add provenance run crate profile +- feat(profiles/provenance-run-crate): check `connection` property on `HowToStep` instances +- feat(profiles/provenance-run-crate): check `connection` property on computational workflow instances +- feat(profiles/provenance-run-crate): check if ParameterConnection instances are referenced through connections +- feat(core): add property to denote the format of the JSON output + +### 🔧 Changed + +- refactor(core): rename the property to indicate the validator version in the JSON output +- refactor(shacl): avoid code repetition +- refactor(core): reorder method args +- refactor(core): rename method arguments +- refactor(core): rename method +- refactor(core): remove redundant method +- refactor(core): remove cache timeout from validation settings +- refactor(core): remove unused `ontology_path` setting +- refactor(core): rename the flag to disable downloading a remote crate +- refactor(core): rename flag to disable reporting of inherited checks +- refactor(core): rename property to enable profile inheritance +- refactor(core): link the context with the settings as an object +- refactor(core): init and validate URI on settings object +- refactor(core): remove unused imports +- refactor(core): rename input parameter for the ro-crate uri +- refactor(core): remove internal settings from the `ValidationSettings` interface +- refactor(core): rename some properties of the `ValidationResult` class +- refactor(services): the `profile_identifier` should be a positional argument +- refactor(core): update the representation of the `ValidationResult` object +- refactor(shacl): mark internal methods +- refactor(core): rename link property between result and RO-Crate URI +- refactor(core): rename some CheckIssue properties +- refactor(services): remove unused function argument +- refactor(core): rename the parameter for ROCrate instantiation +- refactor(core): use more descriptive names for `resultPath` and `focusNode` +- refactor(core): update `CheckIssue` representation +- refactor(core): improve the readability of the identifier +- refactor(core): add a docstring to the main validation classes +- refactor(cli): always include the `profile_identifiers` property in the json output format +- refactor(cli): move test data to the appropriate path +- refactor(profiles): move test data to the appropriate path +- refactor(profiles/provenance-run-crate): use validator prefixes to denote shapes + +### 🐛 Fixed + +- fix(shacl): preserve issues with identical messages for different entities +- fix(profiles/provenance-run-crate): allow the position property of steps to accept integer values +- fix(readthedocs): minor changes +- fix(docs): raw html object to include the diagram +- fix(readthedocs): fix missing dependency +- fix(shacl): typo +- fix(core): typo +- fix(shacl): avoid repeating errors +- fix(core): fix severity detection of Python checks +- fix(core): determine the issue level and severity based on the check +- fix(profiles/workflow-run-crate): fix missing f-string formatting + +### 📚 Documentation + +- docs(profiles/provenance-run-crate): add copyright notice + +### ⚡ Performance + +- perf(core): compute overrides on the fly +- perf(core): add a method to find a profile by checking its name +- perf(core): add properties to get parents and siblings of a given profile +- perf(core): add getter for sibling profiles +- perf(core): automatically detect overrides during Profile initialization +- perf(core): add support for overrides to the `Profile` model + +## [0.4.6] - 2024-11-13 + +### 🐛 Fixed + +- fix: RO-Crate validation should work for nested properties without id + +## [0.4.5] - 2024-11-08 + +### ✨ Added + +- feat: allow to exit cli from pager on unix +- feat: allow to exit cli during interactive input on unix + +## [0.4.4] - 2024-11-07 + +### ✨ Added + +- feat(core): add the ability to hide Python requirements +- feat(profile/ro-crate): validate ro-crate metadata is flattened +- feat(core): always validate the ROCrate URI before instantiating the corresponding object +- feat(utils): add function to validate a RO-Crate URI parameter + +### 🔧 Changed + +- refactor(utils): update the error message for resource unavailability +- refactor(cli): delegate URI validation from the CLI to the utility function +- refactor(utils): use the updated `ROCrateInvalidURIError` class +- refactor(utils): set a default error message in the `ROCrateInvalidURIError` class + +### 🐛 Fixed + +- fix(utils): fix string format of error message +- fix(core): allow to exit cli from pager on unix +- fix(core): allow to exit cli during interactive input on unix + +## [0.4.3] - 2024-11-06 + +### ✨ Added + +- feat(cli): check the minimum required Python version +- feat(utils): add utility functions to read and check the minimum required Python version +- feat(profile/ro-crate): more comprehensive pattern to detect valid ISO 8601 dates +- feat(profile/ro-crate): add check for recommended values of the `RootDataEntity` `datePublished` property +- feat(shacl): add root requirement check +- feat(shacl): extend SHACL check initialisation +- feat(shacl): extend model to mark root requirement checks +- feat(core): extend model to include hidden requirement checks + +### 🔧 Changed + +- build(python): update the minimum python version to 3.9.20 +- refactor(shacl): restructure the initialisation of shack checks +- refactor(shacl): restructure the logic to set and retrieve the requirement level in SHACL checks +- refactor(cli): update `profiles list` to show the number of checks by severity +- refactor(cli): restructure fn to generate checks stats +- refactor(core): update `get_requirements` method +- refactor(core): remove `level` property from the `Requirement` model +- refactor(core): update `Requirement` identifier +- refactor(core): update the requirements loading process +- refactor(shacl): clean up + +### 🐛 Fixed + +- fix(cli): skip counting overridden checks +- fix(cli): do not skip overridden checks when they belong to the target profile +- fix(shacl): fix property getter +- fix(profiles/ro-crate): fix severity of WebDataEntity shapes +- fix(shacl): fix the override of the base method +- fix(shacl): always parse the result graph +- fix(profiles/ro-crate): fix mismatch in the requirement level +- fix(core): fix LevelCollection getter +- fix(core): wrong property name +- fix(core): properly initialize `PyRequirement` instances +- fix(shacl): use the shape description +- fix(shacl): fix condition to print the mismatch warning +- fix(core): fix in progress for detecting overrides +- fix(profiles/ro-crate): fix inconsistent severity level + +## [0.4.2] - 2024-10-30 + +### ✨ Added + +- feat(core): add property to denote the format of the JSON output + +### 🔧 Changed + +- refactor(core): rename the property to indicate the validator version in the JSON output + +## [0.4.1] - 2024-10-30 + +### ✨ Added + +- feat(core): add `to_dict` serializer methods +- feat(core): extend check info on JSON output +- feat(core): add minimal dict serializers for the Profile and RequirementCheck models + +### 🔧 Changed + +- refactor(core): add rocrate-validator version to the JSON output +- refactor(core): remove `rocrate` path property from JSON output +- refactor(core): remove `data_path` and `profiles_path` from JSON output +- refactor(core): remove `resultPath` from issue serialisation +- refactor(shacl): expose `node_name` getter + +### 🐛 Fixed + +- fix(core): fix severity detection of Python checks +- fix(core): determine the issue level and severity based on the check associated with the issue +- fix(profiles/workflow-run-crate): fix missing f-string formatting + +### 📚 Documentation + +- docs(profiles/workflow-run-crate): add copyright notice + +## [0.4.0] - 2024-10-24 + +### ✨ Added + +- feat(profiles/provenance-run-crate): check `connection` property on `HowToStep` instances +- feat(profiles/provenance-run-crate): check `connection` property on computational workflow instances +- feat(profiles/provenance-run-crate): check if ParameterConnection instances are referenced through connections +- feat(profiles/provenance-run-crate): add provenance run crate profile + +### 🔧 Changed + +- refactor(profiles/provenance-run-crate): use validator prefixes to denote shapes + +## [0.3.0] - 2024-10-11 + +### ✨ Added + +- feat(core): declare package version +- feat(utils): enhance version detection: take Git repository state into account +- feat(profiles/workflow-run-crate): add workflow run crate profile + +### 🔧 Changed + +- build: rename package to `roc-validator` +- build: update package version number +- refactor(ci): restructure testing pipeline +- refactor(ci): restructure release pipeline +- refactor(core): use the `severity` property to denote the severity level of a Python requirement +- refactor(cli): remove short option for `profiles_path` +- refactor(profiles/ro-crate): move WebDataEntity shapes +- refactor(shacl): restructure the logic to set/get requirement level on SHACL checks +- refactor(core): update `Requirement.level` definition +- refactor(core): update the requirements loading process +- refactor(shacl): set the conforms property to be computed based on the presence of issues +- refactor(core): fix the sorting criteria of the requirements +- refactor(core): safer way to add candidate profiles +- refactor(cli): fix output of `profiles describe` command +- refactor(cli): disable ontologies parameter +- refactor(utils): generic function to load graphs from paths +- refactor: move code to the rocrate-validator folder +- refactor: move ttl file +- refactor: move code to the src folder + +### 🐛 Fixed + +- fix(profiles/ro-crate): change severity of the `RootDataEntity` properties +- fix(profiles/ro-crate): fix `sh:message` for the required `datePublished` +- fix(cli): disable pagination on Windows systems +- fix(logging): update logging configuration +- fix(shacl): report a generic error when the metadata is invalid +- fix(core): fix the sorting criteria of the requirements +- fix(profiles/ro-crate): fix inconsistent severity level +- fix(ci): update error message +- fix(ci): fix the command to check the tool version +- fix(ci): add missing steps + +### 📚 Documentation + +- docs(readme): add `pip` as installation method +- docs(readme): reorder status badges +- docs(readme): add PyPI version badge +- docs(readme): add build status badge +- docs(readme): update testing status and license badges +- docs: enrich the package metadata +- docs(readme): add installation instructions +- docs(readme): add usage instructions +- docs(readme): add supported profiles section +- docs(readme): add features section +- docs(readme): add badges + +### ⚡ Performance + +- perf(shacl): filter shapes based on the requirement level +- perf(shacl): set the check severity based on the declared value, or infer it from the path +- perf(shacl): allow to get declared `severity` of a Shape Node + +## [0.2.1] - 2024-09-25 + +### 🐛 Fixed + +- fix: fix version parser + +## [0.2.0] - 2024-09-25 + +### ✨ Added + +- feat(ci): restructure testing pipeline +- feat(ci): restructure release pipeline +- feat(core): allow to specify the `level` of a Python requirement +- feat(shacl): filter shapes based on the requirement level +- feat(shacl): set the check severity based on the declared value, or infer it from the path +- feat(shacl): allow to get declared `severity` of a Shape Node +- feat(services): expose the severity property in the `get_profile` service +- feat(shacl): enable info and warning severity levels in PySHACL +- feat(core): add `{severity,requirement_level}_from_path` properties to the `Requirement` class +- feat(core): add properties to get parents and siblings of a given profile +- feat(core): add getter for sibling profiles +- feat(core): mark a requirement as overridden if all checks are overridden +- feat(core): do not notify events of overridden requirements +- feat(core): improve detection of check overrides +- feat(core): extend the check model to support multiple overrides +- feat(cli): support `profiles-path` override on `profiles` subcommand +- feat(cli): show multiple check overrides +- feat(cli): allow configuring the list of checks to skip via CLI + +### 🔧 Changed + +- build: rename package to `roc-validator` +- build: update package version number +- refactor(core): use the `severity` property to denote the severity level of a Python requirement +- refactor(cli): remove short option for `profiles_path` +- refactor(profiles/ro-crate): move WebDataEntity shapes +- refactor(shacl): restructure the logic to set/get requirement level on SHACL checks +- refactor(core): update `Requirement.level` definition +- refactor(core): update the requirements loading process +- refactor(shacl): set the conforms property to be computed based on the presence of issues +- refactor(core): fix the sorting criteria of the requirements +- refactor(core): safer way to add candidate profiles +- refactor(cli): fix output of `profiles describe` command + +### 🐛 Fixed + +- fix(shacl): fix property getter +- fix(profiles/ro-crate): fix severity of WebDataEntity shapes +- fix(shacl): fix the override of the base method +- fix(shacl): always parse the result graph +- fix(profiles/ro-crate): fix mismatch in the requirement level +- fix(core): fix LevelCollection getter +- fix(core): wrong property name +- fix(core): properly initialize `PyRequirement` instances +- fix(shacl): use the shape description +- fix(shacl): fix condition to print the mismatch warning +- fix(core): fix in progress for detecting overrides +- fix(profiles/ro-crate): fix inconsistent severity level +- fix(shacl): report a generic error when the metadata is invalid + +### 📚 Documentation + +- docs(core): add package description +- docs(readme): update testing status and license badges + +### ⚡ Performance + +- perf(shacl): filter shapes based on the requirement level +- perf(shacl): set the check severity based on the declared value, or infer it from the path +- perf(shacl): allow to get declared `severity` of a Shape Node + +## [0.1.2] - 2024-09-19 + +### ✨ Added + +- feat(core): declare package version +- feat(utils): enhance version detection: take Git repository state into account +- feat(ci): set up automatic release process +- feat: add minimal cli entrypoint +- feat(srv): add validation services +- feat: add models +- feat: add utils module +- feat: initial minimal shapes + +### 🔧 Changed + +- build: configure the `rocrate-validator` script +- build(core): update Python packages +- build(dep): add click dependency +- build(dep): add pyshacl dependency +- build(dep): add rdflib dependency +- build: init poetry project +- refactor: move code to the rocrate-validator folder +- refactor: move ttl file +- refactor: move code to the src folder +- refactor(cli): disable ontologies parameter +- refactor(utils): generic function to load graphs from paths + +## [0.1.1] - 2024-02-20 + +### ✨ Added + +- Initial release +- feat: add minimal cli entrypoint +- feat(srv): add validation services +- feat: add models +- feat: add utils module +- feat: initial minimal shapes + +### 🔧 Changed + +- build: configure the `rocrate-validator` script +- build(core): update Python packages +- build(dep): add click dependency +- build(dep): add pyshacl dependency +- build(dep): add rdflib dependency +- build: init poetry project +- refactor: move code to the rocrate-validator folder +- refactor: move ttl file +- refactor: move code to the src folder +- refactor(cli): disable ontologies parameter +- refactor(utils): generic function to load graphs from paths diff --git a/CITATION.cff b/CITATION.cff index 6ec8f8c3..3ead09ad 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -19,6 +19,12 @@ authors: - family-names: Bauer given-names: Daniel orcid: https://orcid.org/0000-0001-9447-460X + - family-names: "Wetzels" + given-names: "Florian" + orcid: https://orcid.org/0000-0002-5526-7138 + - family-names: "Weil" + given-names: "Heinrich Lukas" + orcid: https://orcid.org/0000-0003-1945-6342 repository-code: "https://github.com/crs4/rocrate-validator" url: "https://github.com/crs4/rocrate-validator" keywords: diff --git a/poetry.lock b/poetry.lock index c88d27cf..fd74bc93 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.3.2 and should not be changed by hand. [[package]] name = "alabaster" @@ -6,6 +6,7 @@ version = "1.0.0" description = "A light, configurable Sphinx theme" optional = false python-versions = ">=3.10" +groups = ["docs"] files = [ {file = "alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b"}, {file = "alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e"}, @@ -17,6 +18,7 @@ version = "1.4.1" description = "Handy tools for working with URLs and APIs." optional = false python-versions = ">=3.6.1" +groups = ["docs"] files = [ {file = "apeye-1.4.1-py3-none-any.whl", hash = "sha256:44e58a9104ec189bf42e76b3a7fe91e2b2879d96d48e9a77e5e32ff699c9204e"}, {file = "apeye-1.4.1.tar.gz", hash = "sha256:14ea542fad689e3bfdbda2189a354a4908e90aee4bf84c15ab75d68453d76a36"}, @@ -38,6 +40,7 @@ version = "1.1.5" description = "Core (offline) functionality for the apeye library." optional = false python-versions = ">=3.6.1" +groups = ["docs"] files = [ {file = "apeye_core-1.1.5-py3-none-any.whl", hash = "sha256:dc27a93f8c9e246b3b238c5ea51edf6115ab2618ef029b9f2d9a190ec8228fbf"}, {file = "apeye_core-1.1.5.tar.gz", hash = "sha256:5de72ed3d00cc9b20fea55e54b7ab8f5ef8500eb33a5368bc162a5585e238a55"}, @@ -53,6 +56,8 @@ version = "0.1.4" description = "Disable App Nap on macOS >= 10.9" optional = false python-versions = ">=3.6" +groups = ["dev"] +markers = "platform_system == \"Darwin\"" files = [ {file = "appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c"}, {file = "appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee"}, @@ -64,6 +69,7 @@ version = "3.3.11" description = "An abstract syntax tree for Python with inference support." optional = false python-versions = ">=3.9.0" +groups = ["dev"] files = [ {file = "astroid-3.3.11-py3-none-any.whl", hash = "sha256:54c760ae8322ece1abd213057c4b5bba7c49818853fc901ef09719a60dbf9dec"}, {file = "astroid-3.3.11.tar.gz", hash = "sha256:1e5a5011af2920c7c67a53f65d536d65bfa7116feeaf2354d8b94f29573bb0ce"}, @@ -78,6 +84,7 @@ version = "3.0.1" description = "Annotate AST trees with source code positions" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a"}, {file = "asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7"}, @@ -93,6 +100,7 @@ version = "25.4.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.9" +groups = ["main", "docs"] files = [ {file = "attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373"}, {file = "attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11"}, @@ -104,6 +112,7 @@ version = "0.2.14" description = "Extended sphinx autodoc including automatic autosummaries" optional = false python-versions = ">=3.7" +groups = ["docs"] files = [ {file = "autodocsumm-0.2.14-py3-none-any.whl", hash = "sha256:3bad8717fc5190802c60392a7ab04b9f3c97aa9efa8b3780b3d81d615bfe5dc0"}, {file = "autodocsumm-0.2.14.tar.gz", hash = "sha256:2839a9d4facc3c4eccd306c08695540911042b46eeafcdc3203e6d0bab40bc77"}, @@ -114,17 +123,18 @@ Sphinx = ">=4.0,<9.0" [[package]] name = "babel" -version = "2.17.0" +version = "2.18.0" description = "Internationalization utilities" optional = false python-versions = ">=3.8" +groups = ["docs"] files = [ - {file = "babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2"}, - {file = "babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d"}, + {file = "babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35"}, + {file = "babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d"}, ] [package.extras] -dev = ["backports.zoneinfo", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata"] +dev = ["backports.zoneinfo ; python_version < \"3.9\"", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata ; sys_platform == \"win32\""] [[package]] name = "beautifulsoup4" @@ -132,6 +142,7 @@ version = "4.14.3" description = "Screen-scraping library" optional = false python-versions = ">=3.7.0" +groups = ["docs"] files = [ {file = "beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb"}, {file = "beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86"}, @@ -154,6 +165,7 @@ version = "6.3.0" description = "An easy safelist-based HTML-sanitizing tool." optional = false python-versions = ">=3.10" +groups = ["docs"] files = [ {file = "bleach-6.3.0-py3-none-any.whl", hash = "sha256:fe10ec77c93ddf3d13a73b035abaac7a9f5e436513864ccdad516693213c65d6"}, {file = "bleach-6.3.0.tar.gz", hash = "sha256:6f3b91b1c0a02bb9a78b5a454c92506aa0fdf197e1d5e114d2e00c6f64306d22"}, @@ -172,6 +184,7 @@ version = "0.14.4" description = "httplib2 caching for requests" optional = false python-versions = ">=3.10" +groups = ["docs"] files = [ {file = "cachecontrol-0.14.4-py3-none-any.whl", hash = "sha256:b7ac014ff72ee199b5f8af1de29d60239954f223e948196fa3d84adaffc71d2b"}, {file = "cachecontrol-0.14.4.tar.gz", hash = "sha256:e6220afafa4c22a47dd0badb319f84475d79108100d04e26e8542ef7d3ab05a1"}, @@ -193,6 +206,7 @@ version = "25.3.0" description = "Composable complex class support for attrs and dataclasses." optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "cattrs-25.3.0-py3-none-any.whl", hash = "sha256:9896e84e0a5bf723bc7b4b68f4481785367ce07a8a02e7e9ee6eb2819bc306ff"}, {file = "cattrs-25.3.0.tar.gz", hash = "sha256:1ac88d9e5eda10436c4517e390a4142d88638fe682c436c93db7ce4a277b884a"}, @@ -207,8 +221,8 @@ typing-extensions = ">=4.14.0" bson = ["pymongo (>=4.4.0)"] cbor2 = ["cbor2 (>=5.4.6)"] msgpack = ["msgpack (>=1.0.5)"] -msgspec = ["msgspec (>=0.19.0)"] -orjson = ["orjson (>=3.11.3)"] +msgspec = ["msgspec (>=0.19.0) ; implementation_name == \"cpython\""] +orjson = ["orjson (>=3.11.3) ; implementation_name == \"cpython\""] pyyaml = ["pyyaml (>=6.0)"] tomlkit = ["tomlkit (>=0.11.8)"] ujson = ["ujson (>=5.10.0)"] @@ -219,6 +233,7 @@ version = "2026.1.4" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.7" +groups = ["main", "docs"] files = [ {file = "certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c"}, {file = "certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120"}, @@ -230,6 +245,8 @@ version = "2.0.0" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.9" +groups = ["dev", "docs"] +markers = "implementation_name == \"pypy\"" files = [ {file = "cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44"}, {file = "cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49"}, @@ -326,6 +343,7 @@ version = "3.4.4" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" +groups = ["main", "docs"] files = [ {file = "charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d"}, {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8"}, @@ -448,6 +466,7 @@ version = "8.3.1" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.10" +groups = ["main"] files = [ {file = "click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6"}, {file = "click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a"}, @@ -462,10 +481,12 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main", "dev", "docs", "test"] files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +markers = {main = "platform_system == \"Windows\" or sys_platform == \"win32\"", dev = "sys_platform == \"win32\"", docs = "sys_platform == \"win32\"", test = "sys_platform == \"win32\""} [[package]] name = "colorlog" @@ -473,6 +494,7 @@ version = "6.10.1" description = "Add colours to the output of Python's logging module." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "colorlog-6.10.1-py3-none-any.whl", hash = "sha256:2d7e8348291948af66122cff006c9f8da6255d224e7cf8e37d8de2df3bad8c9c"}, {file = "colorlog-6.10.1.tar.gz", hash = "sha256:eb4ae5cb65fe7fec7773c2306061a8e63e02efc2c72eba9d27b0fa23c94f1321"}, @@ -490,6 +512,7 @@ version = "0.2.3" description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417"}, {file = "comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971"}, @@ -500,110 +523,125 @@ test = ["pytest"] [[package]] name = "coverage" -version = "7.13.1" +version = "7.13.4" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.10" -files = [ - {file = "coverage-7.13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e1fa280b3ad78eea5be86f94f461c04943d942697e0dac889fa18fff8f5f9147"}, - {file = "coverage-7.13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c3d8c679607220979434f494b139dfb00131ebf70bb406553d69c1ff01a5c33d"}, - {file = "coverage-7.13.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:339dc63b3eba969067b00f41f15ad161bf2946613156fb131266d8debc8e44d0"}, - {file = "coverage-7.13.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:db622b999ffe49cb891f2fff3b340cdc2f9797d01a0a202a0973ba2562501d90"}, - {file = "coverage-7.13.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1443ba9acbb593fa7c1c29e011d7c9761545fe35e7652e85ce7f51a16f7e08d"}, - {file = "coverage-7.13.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c832ec92c4499ac463186af72f9ed4d8daec15499b16f0a879b0d1c8e5cf4a3b"}, - {file = "coverage-7.13.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:562ec27dfa3f311e0db1ba243ec6e5f6ab96b1edfcfc6cf86f28038bc4961ce6"}, - {file = "coverage-7.13.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4de84e71173d4dada2897e5a0e1b7877e5eefbfe0d6a44edee6ce31d9b8ec09e"}, - {file = "coverage-7.13.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:a5a68357f686f8c4d527a2dc04f52e669c2fc1cbde38f6f7eb6a0e58cbd17cae"}, - {file = "coverage-7.13.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:77cc258aeb29a3417062758975521eae60af6f79e930d6993555eeac6a8eac29"}, - {file = "coverage-7.13.1-cp310-cp310-win32.whl", hash = "sha256:bb4f8c3c9a9f34423dba193f241f617b08ffc63e27f67159f60ae6baf2dcfe0f"}, - {file = "coverage-7.13.1-cp310-cp310-win_amd64.whl", hash = "sha256:c8e2706ceb622bc63bac98ebb10ef5da80ed70fbd8a7999a5076de3afaef0fb1"}, - {file = "coverage-7.13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a55d509a1dc5a5b708b5dad3b5334e07a16ad4c2185e27b40e4dba796ab7f88"}, - {file = "coverage-7.13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4d010d080c4888371033baab27e47c9df7d6fb28d0b7b7adf85a4a49be9298b3"}, - {file = "coverage-7.13.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d938b4a840fb1523b9dfbbb454f652967f18e197569c32266d4d13f37244c3d9"}, - {file = "coverage-7.13.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bf100a3288f9bb7f919b87eb84f87101e197535b9bd0e2c2b5b3179633324fee"}, - {file = "coverage-7.13.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef6688db9bf91ba111ae734ba6ef1a063304a881749726e0d3575f5c10a9facf"}, - {file = "coverage-7.13.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0b609fc9cdbd1f02e51f67f51e5aee60a841ef58a68d00d5ee2c0faf357481a3"}, - {file = "coverage-7.13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c43257717611ff5e9a1d79dce8e47566235ebda63328718d9b65dd640bc832ef"}, - {file = "coverage-7.13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e09fbecc007f7b6afdfb3b07ce5bd9f8494b6856dd4f577d26c66c391b829851"}, - {file = "coverage-7.13.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:a03a4f3a19a189919c7055098790285cc5c5b0b3976f8d227aea39dbf9f8bfdb"}, - {file = "coverage-7.13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3820778ea1387c2b6a818caec01c63adc5b3750211af6447e8dcfb9b6f08dbba"}, - {file = "coverage-7.13.1-cp311-cp311-win32.whl", hash = "sha256:ff10896fa55167371960c5908150b434b71c876dfab97b69478f22c8b445ea19"}, - {file = "coverage-7.13.1-cp311-cp311-win_amd64.whl", hash = "sha256:a998cc0aeeea4c6d5622a3754da5a493055d2d95186bad877b0a34ea6e6dbe0a"}, - {file = "coverage-7.13.1-cp311-cp311-win_arm64.whl", hash = "sha256:fea07c1a39a22614acb762e3fbbb4011f65eedafcb2948feeef641ac78b4ee5c"}, - {file = "coverage-7.13.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6f34591000f06e62085b1865c9bc5f7858df748834662a51edadfd2c3bfe0dd3"}, - {file = "coverage-7.13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b67e47c5595b9224599016e333f5ec25392597a89d5744658f837d204e16c63e"}, - {file = "coverage-7.13.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3e7b8bd70c48ffb28461ebe092c2345536fb18bbbf19d287c8913699735f505c"}, - {file = "coverage-7.13.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c223d078112e90dc0e5c4e35b98b9584164bea9fbbd221c0b21c5241f6d51b62"}, - {file = "coverage-7.13.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:794f7c05af0763b1bbd1b9e6eff0e52ad068be3b12cd96c87de037b01390c968"}, - {file = "coverage-7.13.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0642eae483cc8c2902e4af7298bf886d605e80f26382124cddc3967c2a3df09e"}, - {file = "coverage-7.13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9f5e772ed5fef25b3de9f2008fe67b92d46831bd2bc5bdc5dd6bfd06b83b316f"}, - {file = "coverage-7.13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:45980ea19277dc0a579e432aef6a504fe098ef3a9032ead15e446eb0f1191aee"}, - {file = "coverage-7.13.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e4f18eca6028ffa62adbd185a8f1e1dd242f2e68164dba5c2b74a5204850b4cf"}, - {file = "coverage-7.13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f8dca5590fec7a89ed6826fce625595279e586ead52e9e958d3237821fbc750c"}, - {file = "coverage-7.13.1-cp312-cp312-win32.whl", hash = "sha256:ff86d4e85188bba72cfb876df3e11fa243439882c55957184af44a35bd5880b7"}, - {file = "coverage-7.13.1-cp312-cp312-win_amd64.whl", hash = "sha256:16cc1da46c04fb0fb128b4dc430b78fa2aba8a6c0c9f8eb391fd5103409a6ac6"}, - {file = "coverage-7.13.1-cp312-cp312-win_arm64.whl", hash = "sha256:8d9bc218650022a768f3775dd7fdac1886437325d8d295d923ebcfef4892ad5c"}, - {file = "coverage-7.13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:cb237bfd0ef4d5eb6a19e29f9e528ac67ac3be932ea6b44fb6cc09b9f3ecff78"}, - {file = "coverage-7.13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1dcb645d7e34dcbcc96cd7c132b1fc55c39263ca62eb961c064eb3928997363b"}, - {file = "coverage-7.13.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3d42df8201e00384736f0df9be2ced39324c3907607d17d50d50116c989d84cd"}, - {file = "coverage-7.13.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fa3edde1aa8807de1d05934982416cb3ec46d1d4d91e280bcce7cca01c507992"}, - {file = "coverage-7.13.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9edd0e01a343766add6817bc448408858ba6b489039eaaa2018474e4001651a4"}, - {file = "coverage-7.13.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:985b7836931d033570b94c94713c6dba5f9d3ff26045f72c3e5dbc5fe3361e5a"}, - {file = "coverage-7.13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ffed1e4980889765c84a5d1a566159e363b71d6b6fbaf0bebc9d3c30bc016766"}, - {file = "coverage-7.13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8842af7f175078456b8b17f1b73a0d16a65dcbdc653ecefeb00a56b3c8c298c4"}, - {file = "coverage-7.13.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:ccd7a6fca48ca9c131d9b0a2972a581e28b13416fc313fb98b6d24a03ce9a398"}, - {file = "coverage-7.13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0403f647055de2609be776965108447deb8e384fe4a553c119e3ff6bfbab4784"}, - {file = "coverage-7.13.1-cp313-cp313-win32.whl", hash = "sha256:549d195116a1ba1e1ae2f5ca143f9777800f6636eab917d4f02b5310d6d73461"}, - {file = "coverage-7.13.1-cp313-cp313-win_amd64.whl", hash = "sha256:5899d28b5276f536fcf840b18b61a9fce23cc3aec1d114c44c07fe94ebeaa500"}, - {file = "coverage-7.13.1-cp313-cp313-win_arm64.whl", hash = "sha256:868a2fae76dfb06e87291bcbd4dcbcc778a8500510b618d50496e520bd94d9b9"}, - {file = "coverage-7.13.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:67170979de0dacac3f3097d02b0ad188d8edcea44ccc44aaa0550af49150c7dc"}, - {file = "coverage-7.13.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f80e2bb21bfab56ed7405c2d79d34b5dc0bc96c2c1d2a067b643a09fb756c43a"}, - {file = "coverage-7.13.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f83351e0f7dcdb14d7326c3d8d8c4e915fa685cbfdc6281f9470d97a04e9dfe4"}, - {file = "coverage-7.13.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bb3f6562e89bad0110afbe64e485aac2462efdce6232cdec7862a095dc3412f6"}, - {file = "coverage-7.13.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77545b5dcda13b70f872c3b5974ac64c21d05e65b1590b441c8560115dc3a0d1"}, - {file = "coverage-7.13.1-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a4d240d260a1aed814790bbe1f10a5ff31ce6c21bc78f0da4a1e8268d6c80dbd"}, - {file = "coverage-7.13.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d2287ac9360dec3837bfdad969963a5d073a09a85d898bd86bea82aa8876ef3c"}, - {file = "coverage-7.13.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:0d2c11f3ea4db66b5cbded23b20185c35066892c67d80ec4be4bab257b9ad1e0"}, - {file = "coverage-7.13.1-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:3fc6a169517ca0d7ca6846c3c5392ef2b9e38896f61d615cb75b9e7134d4ee1e"}, - {file = "coverage-7.13.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d10a2ed46386e850bb3de503a54f9fe8192e5917fcbb143bfef653a9355e9a53"}, - {file = "coverage-7.13.1-cp313-cp313t-win32.whl", hash = "sha256:75a6f4aa904301dab8022397a22c0039edc1f51e90b83dbd4464b8a38dc87842"}, - {file = "coverage-7.13.1-cp313-cp313t-win_amd64.whl", hash = "sha256:309ef5706e95e62578cda256b97f5e097916a2c26247c287bbe74794e7150df2"}, - {file = "coverage-7.13.1-cp313-cp313t-win_arm64.whl", hash = "sha256:92f980729e79b5d16d221038dbf2e8f9a9136afa072f9d5d6ed4cb984b126a09"}, - {file = "coverage-7.13.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:97ab3647280d458a1f9adb85244e81587505a43c0c7cff851f5116cd2814b894"}, - {file = "coverage-7.13.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8f572d989142e0908e6acf57ad1b9b86989ff057c006d13b76c146ec6a20216a"}, - {file = "coverage-7.13.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d72140ccf8a147e94274024ff6fd8fb7811354cf7ef88b1f0a988ebaa5bc774f"}, - {file = "coverage-7.13.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d3c9f051b028810f5a87c88e5d6e9af3c0ff32ef62763bf15d29f740453ca909"}, - {file = "coverage-7.13.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f398ba4df52d30b1763f62eed9de5620dcde96e6f491f4c62686736b155aa6e4"}, - {file = "coverage-7.13.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:132718176cc723026d201e347f800cd1a9e4b62ccd3f82476950834dad501c75"}, - {file = "coverage-7.13.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9e549d642426e3579b3f4b92d0431543b012dcb6e825c91619d4e93b7363c3f9"}, - {file = "coverage-7.13.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:90480b2134999301eea795b3a9dbf606c6fbab1b489150c501da84a959442465"}, - {file = "coverage-7.13.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e825dbb7f84dfa24663dd75835e7257f8882629fc11f03ecf77d84a75134b864"}, - {file = "coverage-7.13.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:623dcc6d7a7ba450bbdbeedbaa0c42b329bdae16491af2282f12a7e809be7eb9"}, - {file = "coverage-7.13.1-cp314-cp314-win32.whl", hash = "sha256:6e73ebb44dca5f708dc871fe0b90cf4cff1a13f9956f747cc87b535a840386f5"}, - {file = "coverage-7.13.1-cp314-cp314-win_amd64.whl", hash = "sha256:be753b225d159feb397bd0bf91ae86f689bad0da09d3b301478cd39b878ab31a"}, - {file = "coverage-7.13.1-cp314-cp314-win_arm64.whl", hash = "sha256:228b90f613b25ba0019361e4ab81520b343b622fc657daf7e501c4ed6a2366c0"}, - {file = "coverage-7.13.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:60cfb538fe9ef86e5b2ab0ca8fc8d62524777f6c611dcaf76dc16fbe9b8e698a"}, - {file = "coverage-7.13.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:57dfc8048c72ba48a8c45e188d811e5efd7e49b387effc8fb17e97936dde5bf6"}, - {file = "coverage-7.13.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3f2f725aa3e909b3c5fdb8192490bdd8e1495e85906af74fe6e34a2a77ba0673"}, - {file = "coverage-7.13.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ee68b21909686eeb21dfcba2c3b81fee70dcf38b140dcd5aa70680995fa3aa5"}, - {file = "coverage-7.13.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:724b1b270cb13ea2e6503476e34541a0b1f62280bc997eab443f87790202033d"}, - {file = "coverage-7.13.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:916abf1ac5cf7eb16bc540a5bf75c71c43a676f5c52fcb9fe75a2bd75fb944e8"}, - {file = "coverage-7.13.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:776483fd35b58d8afe3acbd9988d5de592ab6da2d2a865edfdbc9fdb43e7c486"}, - {file = "coverage-7.13.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b6f3b96617e9852703f5b633ea01315ca45c77e879584f283c44127f0f1ec564"}, - {file = "coverage-7.13.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:bd63e7b74661fed317212fab774e2a648bc4bb09b35f25474f8e3325d2945cd7"}, - {file = "coverage-7.13.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:933082f161bbb3e9f90d00990dc956120f608cdbcaeea15c4d897f56ef4fe416"}, - {file = "coverage-7.13.1-cp314-cp314t-win32.whl", hash = "sha256:18be793c4c87de2965e1c0f060f03d9e5aff66cfeae8e1dbe6e5b88056ec153f"}, - {file = "coverage-7.13.1-cp314-cp314t-win_amd64.whl", hash = "sha256:0e42e0ec0cd3e0d851cb3c91f770c9301f48647cb2877cb78f74bdaa07639a79"}, - {file = "coverage-7.13.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eaecf47ef10c72ece9a2a92118257da87e460e113b83cc0d2905cbbe931792b4"}, - {file = "coverage-7.13.1-py3-none-any.whl", hash = "sha256:2016745cb3ba554469d02819d78958b571792bb68e31302610e898f80dd3a573"}, - {file = "coverage-7.13.1.tar.gz", hash = "sha256:b7593fe7eb5feaa3fbb461ac79aac9f9fc0387a5ca8080b0c6fe2ca27b091afd"}, +groups = ["test"] +files = [ + {file = "coverage-7.13.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0fc31c787a84f8cd6027eba44010517020e0d18487064cd3d8968941856d1415"}, + {file = "coverage-7.13.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a32ebc02a1805adf637fc8dec324b5cdacd2e493515424f70ee33799573d661b"}, + {file = "coverage-7.13.4-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e24f9156097ff9dc286f2f913df3a7f63c0e333dcafa3c196f2c18b4175ca09a"}, + {file = "coverage-7.13.4-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8041b6c5bfdc03257666e9881d33b1abc88daccaf73f7b6340fb7946655cd10f"}, + {file = "coverage-7.13.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a09cfa6a5862bc2fc6ca7c3def5b2926194a56b8ab78ffcf617d28911123012"}, + {file = "coverage-7.13.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:296f8b0af861d3970c2a4d8c91d48eb4dd4771bcef9baedec6a9b515d7de3def"}, + {file = "coverage-7.13.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e101609bcbbfb04605ea1027b10dc3735c094d12d40826a60f897b98b1c30256"}, + {file = "coverage-7.13.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aa3feb8db2e87ff5e6d00d7e1480ae241876286691265657b500886c98f38bda"}, + {file = "coverage-7.13.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4fc7fa81bbaf5a02801b65346c8b3e657f1d93763e58c0abdf7c992addd81a92"}, + {file = "coverage-7.13.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:33901f604424145c6e9c2398684b92e176c0b12df77d52db81c20abd48c3794c"}, + {file = "coverage-7.13.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:bb28c0f2cf2782508a40cec377935829d5fcc3ad9a3681375af4e84eb34b6b58"}, + {file = "coverage-7.13.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9d107aff57a83222ddbd8d9ee705ede2af2cc926608b57abed8ef96b50b7e8f9"}, + {file = "coverage-7.13.4-cp310-cp310-win32.whl", hash = "sha256:a6f94a7d00eb18f1b6d403c91a88fd58cfc92d4b16080dfdb774afc8294469bf"}, + {file = "coverage-7.13.4-cp310-cp310-win_amd64.whl", hash = "sha256:2cb0f1e000ebc419632bbe04366a8990b6e32c4e0b51543a6484ffe15eaeda95"}, + {file = "coverage-7.13.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d490ba50c3f35dd7c17953c68f3270e7ccd1c6642e2d2afe2d8e720b98f5a053"}, + {file = "coverage-7.13.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:19bc3c88078789f8ef36acb014d7241961dbf883fd2533d18cb1e7a5b4e28b11"}, + {file = "coverage-7.13.4-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3998e5a32e62fdf410c0dbd3115df86297995d6e3429af80b8798aad894ca7aa"}, + {file = "coverage-7.13.4-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8e264226ec98e01a8e1054314af91ee6cde0eacac4f465cc93b03dbe0bce2fd7"}, + {file = "coverage-7.13.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a3aa4e7b9e416774b21797365b358a6e827ffadaaca81b69ee02946852449f00"}, + {file = "coverage-7.13.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:71ca20079dd8f27fcf808817e281e90220475cd75115162218d0e27549f95fef"}, + {file = "coverage-7.13.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e2f25215f1a359ab17320b47bcdaca3e6e6356652e8256f2441e4ef972052903"}, + {file = "coverage-7.13.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d65b2d373032411e86960604dc4edac91fdfb5dca539461cf2cbe78327d1e64f"}, + {file = "coverage-7.13.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94eb63f9b363180aff17de3e7c8760c3ba94664ea2695c52f10111244d16a299"}, + {file = "coverage-7.13.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e856bf6616714c3a9fbc270ab54103f4e685ba236fa98c054e8f87f266c93505"}, + {file = "coverage-7.13.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:65dfcbe305c3dfe658492df2d85259e0d79ead4177f9ae724b6fb245198f55d6"}, + {file = "coverage-7.13.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b507778ae8a4c915436ed5c2e05b4a6cecfa70f734e19c22a005152a11c7b6a9"}, + {file = "coverage-7.13.4-cp311-cp311-win32.whl", hash = "sha256:784fc3cf8be001197b652d51d3fd259b1e2262888693a4636e18879f613a62a9"}, + {file = "coverage-7.13.4-cp311-cp311-win_amd64.whl", hash = "sha256:2421d591f8ca05b308cf0092807308b2facbefe54af7c02ac22548b88b95c98f"}, + {file = "coverage-7.13.4-cp311-cp311-win_arm64.whl", hash = "sha256:79e73a76b854d9c6088fe5d8b2ebe745f8681c55f7397c3c0a016192d681045f"}, + {file = "coverage-7.13.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:02231499b08dabbe2b96612993e5fc34217cdae907a51b906ac7fca8027a4459"}, + {file = "coverage-7.13.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40aa8808140e55dc022b15d8aa7f651b6b3d68b365ea0398f1441e0b04d859c3"}, + {file = "coverage-7.13.4-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5b856a8ccf749480024ff3bd7310adaef57bf31fd17e1bfc404b7940b6986634"}, + {file = "coverage-7.13.4-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2c048ea43875fbf8b45d476ad79f179809c590ec7b79e2035c662e7afa3192e3"}, + {file = "coverage-7.13.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b7b38448866e83176e28086674fe7368ab8590e4610fb662b44e345b86d63ffa"}, + {file = "coverage-7.13.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:de6defc1c9badbf8b9e67ae90fd00519186d6ab64e5cc5f3d21359c2a9b2c1d3"}, + {file = "coverage-7.13.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7eda778067ad7ffccd23ecffce537dface96212576a07924cbf0d8799d2ded5a"}, + {file = "coverage-7.13.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e87f6c587c3f34356c3759f0420693e35e7eb0e2e41e4c011cb6ec6ecbbf1db7"}, + {file = "coverage-7.13.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8248977c2e33aecb2ced42fef99f2d319e9904a36e55a8a68b69207fb7e43edc"}, + {file = "coverage-7.13.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:25381386e80ae727608e662474db537d4df1ecd42379b5ba33c84633a2b36d47"}, + {file = "coverage-7.13.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:ee756f00726693e5ba94d6df2bdfd64d4852d23b09bb0bc700e3b30e6f333985"}, + {file = "coverage-7.13.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fdfc1e28e7c7cdce44985b3043bc13bbd9c747520f94a4d7164af8260b3d91f0"}, + {file = "coverage-7.13.4-cp312-cp312-win32.whl", hash = "sha256:01d4cbc3c283a17fc1e42d614a119f7f438eabb593391283adca8dc86eff1246"}, + {file = "coverage-7.13.4-cp312-cp312-win_amd64.whl", hash = "sha256:9401ebc7ef522f01d01d45532c68c5ac40fb27113019b6b7d8b208f6e9baa126"}, + {file = "coverage-7.13.4-cp312-cp312-win_arm64.whl", hash = "sha256:b1ec7b6b6e93255f952e27ab58fbc68dcc468844b16ecbee881aeb29b6ab4d8d"}, + {file = "coverage-7.13.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b66a2da594b6068b48b2692f043f35d4d3693fb639d5ea8b39533c2ad9ac3ab9"}, + {file = "coverage-7.13.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3599eb3992d814d23b35c536c28df1a882caa950f8f507cef23d1cbf334995ac"}, + {file = "coverage-7.13.4-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:93550784d9281e374fb5a12bf1324cc8a963fd63b2d2f223503ef0fd4aa339ea"}, + {file = "coverage-7.13.4-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b720ce6a88a2755f7c697c23268ddc47a571b88052e6b155224347389fdf6a3b"}, + {file = "coverage-7.13.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7b322db1284a2ed3aa28ffd8ebe3db91c929b7a333c0820abec3d838ef5b3525"}, + {file = "coverage-7.13.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f4594c67d8a7c89cf922d9df0438c7c7bb022ad506eddb0fdb2863359ff78242"}, + {file = "coverage-7.13.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:53d133df809c743eb8bce33b24bcababb371f4441340578cd406e084d94a6148"}, + {file = "coverage-7.13.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:76451d1978b95ba6507a039090ba076105c87cc76fc3efd5d35d72093964d49a"}, + {file = "coverage-7.13.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7f57b33491e281e962021de110b451ab8a24182589be17e12a22c79047935e23"}, + {file = "coverage-7.13.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1731dc33dc276dafc410a885cbf5992f1ff171393e48a21453b78727d090de80"}, + {file = "coverage-7.13.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:bd60d4fe2f6fa7dff9223ca1bbc9f05d2b6697bc5961072e5d3b952d46e1b1ea"}, + {file = "coverage-7.13.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9181a3ccead280b828fae232df12b16652702b49d41e99d657f46cc7b1f6ec7a"}, + {file = "coverage-7.13.4-cp313-cp313-win32.whl", hash = "sha256:f53d492307962561ac7de4cd1de3e363589b000ab69617c6156a16ba7237998d"}, + {file = "coverage-7.13.4-cp313-cp313-win_amd64.whl", hash = "sha256:e6f70dec1cc557e52df5306d051ef56003f74d56e9c4dd7ddb07e07ef32a84dd"}, + {file = "coverage-7.13.4-cp313-cp313-win_arm64.whl", hash = "sha256:fb07dc5da7e849e2ad31a5d74e9bece81f30ecf5a42909d0a695f8bd1874d6af"}, + {file = "coverage-7.13.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:40d74da8e6c4b9ac18b15331c4b5ebc35a17069410cad462ad4f40dcd2d50c0d"}, + {file = "coverage-7.13.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4223b4230a376138939a9173f1bdd6521994f2aff8047fae100d6d94d50c5a12"}, + {file = "coverage-7.13.4-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1d4be36a5114c499f9f1f9195e95ebf979460dbe2d88e6816ea202010ba1c34b"}, + {file = "coverage-7.13.4-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:200dea7d1e8095cc6e98cdabe3fd1d21ab17d3cee6dab00cadbb2fe35d9c15b9"}, + {file = "coverage-7.13.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8eb931ee8e6d8243e253e5ed7336deea6904369d2fd8ae6e43f68abbf167092"}, + {file = "coverage-7.13.4-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:75eab1ebe4f2f64d9509b984f9314d4aa788540368218b858dad56dc8f3e5eb9"}, + {file = "coverage-7.13.4-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c35eb28c1d085eb7d8c9b3296567a1bebe03ce72962e932431b9a61f28facf26"}, + {file = "coverage-7.13.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb88b316ec33760714a4720feb2816a3a59180fd58c1985012054fa7aebee4c2"}, + {file = "coverage-7.13.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7d41eead3cc673cbd38a4417deb7fd0b4ca26954ff7dc6078e33f6ff97bed940"}, + {file = "coverage-7.13.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:fb26a934946a6afe0e326aebe0730cdff393a8bc0bbb65a2f41e30feddca399c"}, + {file = "coverage-7.13.4-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:dae88bc0fc77edaa65c14be099bd57ee140cf507e6bfdeea7938457ab387efb0"}, + {file = "coverage-7.13.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:845f352911777a8e722bfce168958214951e07e47e5d5d9744109fa5fe77f79b"}, + {file = "coverage-7.13.4-cp313-cp313t-win32.whl", hash = "sha256:2fa8d5f8de70688a28240de9e139fa16b153cc3cbb01c5f16d88d6505ebdadf9"}, + {file = "coverage-7.13.4-cp313-cp313t-win_amd64.whl", hash = "sha256:9351229c8c8407645840edcc277f4a2d44814d1bc34a2128c11c2a031d45a5dd"}, + {file = "coverage-7.13.4-cp313-cp313t-win_arm64.whl", hash = "sha256:30b8d0512f2dc8c8747557e8fb459d6176a2c9e5731e2b74d311c03b78451997"}, + {file = "coverage-7.13.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:300deaee342f90696ed186e3a00c71b5b3d27bffe9e827677954f4ee56969601"}, + {file = "coverage-7.13.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:29e3220258d682b6226a9b0925bc563ed9a1ebcff3cad30f043eceea7eaf2689"}, + {file = "coverage-7.13.4-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:391ee8f19bef69210978363ca930f7328081c6a0152f1166c91f0b5fdd2a773c"}, + {file = "coverage-7.13.4-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0dd7ab8278f0d58a0128ba2fca25824321f05d059c1441800e934ff2efa52129"}, + {file = "coverage-7.13.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78cdf0d578b15148b009ccf18c686aa4f719d887e76e6b40c38ffb61d264a552"}, + {file = "coverage-7.13.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:48685fee12c2eb3b27c62f2658e7ea21e9c3239cba5a8a242801a0a3f6a8c62a"}, + {file = "coverage-7.13.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4e83efc079eb39480e6346a15a1bcb3e9b04759c5202d157e1dd4303cd619356"}, + {file = "coverage-7.13.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ecae9737b72408d6a950f7e525f30aca12d4bd8dd95e37342e5beb3a2a8c4f71"}, + {file = "coverage-7.13.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ae4578f8528569d3cf303fef2ea569c7f4c4059a38c8667ccef15c6e1f118aa5"}, + {file = "coverage-7.13.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:6fdef321fdfbb30a197efa02d48fcd9981f0d8ad2ae8903ac318adc653f5df98"}, + {file = "coverage-7.13.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b0f6ccf3dbe577170bebfce1318707d0e8c3650003cb4b3a9dd744575daa8b5"}, + {file = "coverage-7.13.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75fcd519f2a5765db3f0e391eb3b7d150cce1a771bf4c9f861aeab86c767a3c0"}, + {file = "coverage-7.13.4-cp314-cp314-win32.whl", hash = "sha256:8e798c266c378da2bd819b0677df41ab46d78065fb2a399558f3f6cae78b2fbb"}, + {file = "coverage-7.13.4-cp314-cp314-win_amd64.whl", hash = "sha256:245e37f664d89861cf2329c9afa2c1fe9e6d4e1a09d872c947e70718aeeac505"}, + {file = "coverage-7.13.4-cp314-cp314-win_arm64.whl", hash = "sha256:ad27098a189e5838900ce4c2a99f2fe42a0bf0c2093c17c69b45a71579e8d4a2"}, + {file = "coverage-7.13.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:85480adfb35ffc32d40918aad81b89c69c9cc5661a9b8a81476d3e645321a056"}, + {file = "coverage-7.13.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:79be69cf7f3bf9b0deeeb062eab7ac7f36cd4cc4c4dd694bd28921ba4d8596cc"}, + {file = "coverage-7.13.4-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:caa421e2684e382c5d8973ac55e4f36bed6821a9bad5c953494de960c74595c9"}, + {file = "coverage-7.13.4-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:14375934243ee05f56c45393fe2ce81fe5cc503c07cee2bdf1725fb8bef3ffaf"}, + {file = "coverage-7.13.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25a41c3104d08edb094d9db0d905ca54d0cd41c928bb6be3c4c799a54753af55"}, + {file = "coverage-7.13.4-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f01afcff62bf9a08fb32b2c1d6e924236c0383c02c790732b6537269e466a72"}, + {file = "coverage-7.13.4-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eb9078108fbf0bcdde37c3f4779303673c2fa1fe8f7956e68d447d0dd426d38a"}, + {file = "coverage-7.13.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0e086334e8537ddd17e5f16a344777c1ab8194986ec533711cbe6c41cde841b6"}, + {file = "coverage-7.13.4-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:725d985c5ab621268b2edb8e50dfe57633dc69bda071abc470fed55a14935fd3"}, + {file = "coverage-7.13.4-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:3c06f0f1337c667b971ca2f975523347e63ec5e500b9aa5882d91931cd3ef750"}, + {file = "coverage-7.13.4-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:590c0ed4bf8e85f745e6b805b2e1c457b2e33d5255dd9729743165253bc9ad39"}, + {file = "coverage-7.13.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:eb30bf180de3f632cd043322dad5751390e5385108b2807368997d1a92a509d0"}, + {file = "coverage-7.13.4-cp314-cp314t-win32.whl", hash = "sha256:c4240e7eded42d131a2d2c4dec70374b781b043ddc79a9de4d55ca71f8e98aea"}, + {file = "coverage-7.13.4-cp314-cp314t-win_amd64.whl", hash = "sha256:4c7d3cc01e7350f2f0f6f7036caaf5673fb56b6998889ccfe9e1c1fe75a9c932"}, + {file = "coverage-7.13.4-cp314-cp314t-win_arm64.whl", hash = "sha256:23e3f687cf945070d1c90f85db66d11e3025665d8dafa831301a0e0038f3db9b"}, + {file = "coverage-7.13.4-py3-none-any.whl", hash = "sha256:1af1641e57cf7ba1bd67d677c9abdbcd6cc2ab7da3bca7fa1e2b7e50e65f2ad0"}, + {file = "coverage-7.13.4.tar.gz", hash = "sha256:e5c8f6ed1e61a8b2dcdf31eb0b9bbf0130750ca79c1c49eb898e2ad86f5ccc91"}, ] [package.dependencies] tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} [package.extras] -toml = ["tomli"] +toml = ["tomli ; python_full_version <= \"3.11.0a6\""] [[package]] name = "cssutils" @@ -611,6 +649,7 @@ version = "2.11.1" description = "A CSS Cascading Style Sheets library for Python" optional = false python-versions = ">=3.8" +groups = ["docs"] files = [ {file = "cssutils-2.11.1-py3-none-any.whl", hash = "sha256:a67bfdfdff4f3867fab43698ec4897c1a828eca5973f4073321b3bccaf1199b1"}, {file = "cssutils-2.11.1.tar.gz", hash = "sha256:0563a76513b6af6eebbe788c3bf3d01c920e46b3f90c8416738c5cfc773ff8e2"}, @@ -621,45 +660,46 @@ more-itertools = "*" [package.extras] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -test = ["cssselect", "importlib-resources", "jaraco.test (>=5.1)", "lxml", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] +test = ["cssselect", "importlib-resources ; python_version < \"3.9\"", "jaraco.test (>=5.1)", "lxml ; python_version < \"3.11\"", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [[package]] name = "debugpy" -version = "1.8.19" +version = "1.8.20" description = "An implementation of the Debug Adapter Protocol for Python" optional = false python-versions = ">=3.8" -files = [ - {file = "debugpy-1.8.19-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:fce6da15d73be5935b4438435c53adb512326a3e11e4f90793ea87cd9f018254"}, - {file = "debugpy-1.8.19-cp310-cp310-manylinux_2_34_x86_64.whl", hash = "sha256:e24b1652a1df1ab04d81e7ead446a91c226de704ff5dde6bd0a0dbaab07aa3f2"}, - {file = "debugpy-1.8.19-cp310-cp310-win32.whl", hash = "sha256:327cb28c3ad9e17bc925efc7f7018195fd4787c2fe4b7af1eec11f1d19bdec62"}, - {file = "debugpy-1.8.19-cp310-cp310-win_amd64.whl", hash = "sha256:b7dd275cf2c99e53adb9654f5ae015f70415bbe2bacbe24cfee30d54b6aa03c5"}, - {file = "debugpy-1.8.19-cp311-cp311-macosx_15_0_universal2.whl", hash = "sha256:c5dcfa21de1f735a4f7ced4556339a109aa0f618d366ede9da0a3600f2516d8b"}, - {file = "debugpy-1.8.19-cp311-cp311-manylinux_2_34_x86_64.whl", hash = "sha256:806d6800246244004625d5222d7765874ab2d22f3ba5f615416cf1342d61c488"}, - {file = "debugpy-1.8.19-cp311-cp311-win32.whl", hash = "sha256:783a519e6dfb1f3cd773a9bda592f4887a65040cb0c7bd38dde410f4e53c40d4"}, - {file = "debugpy-1.8.19-cp311-cp311-win_amd64.whl", hash = "sha256:14035cbdbb1fe4b642babcdcb5935c2da3b1067ac211c5c5a8fdc0bb31adbcaa"}, - {file = "debugpy-1.8.19-cp312-cp312-macosx_15_0_universal2.whl", hash = "sha256:bccb1540a49cde77edc7ce7d9d075c1dbeb2414751bc0048c7a11e1b597a4c2e"}, - {file = "debugpy-1.8.19-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:e9c68d9a382ec754dc05ed1d1b4ed5bd824b9f7c1a8cd1083adb84b3c93501de"}, - {file = "debugpy-1.8.19-cp312-cp312-win32.whl", hash = "sha256:6599cab8a783d1496ae9984c52cb13b7c4a3bd06a8e6c33446832a5d97ce0bee"}, - {file = "debugpy-1.8.19-cp312-cp312-win_amd64.whl", hash = "sha256:66e3d2fd8f2035a8f111eb127fa508469dfa40928a89b460b41fd988684dc83d"}, - {file = "debugpy-1.8.19-cp313-cp313-macosx_15_0_universal2.whl", hash = "sha256:91e35db2672a0abaf325f4868fcac9c1674a0d9ad9bb8a8c849c03a5ebba3e6d"}, - {file = "debugpy-1.8.19-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:85016a73ab84dea1c1f1dcd88ec692993bcbe4532d1b49ecb5f3c688ae50c606"}, - {file = "debugpy-1.8.19-cp313-cp313-win32.whl", hash = "sha256:b605f17e89ba0ecee994391194285fada89cee111cfcd29d6f2ee11cbdc40976"}, - {file = "debugpy-1.8.19-cp313-cp313-win_amd64.whl", hash = "sha256:c30639998a9f9cd9699b4b621942c0179a6527f083c72351f95c6ab1728d5b73"}, - {file = "debugpy-1.8.19-cp314-cp314-macosx_15_0_universal2.whl", hash = "sha256:1e8c4d1bd230067bf1bbcdbd6032e5a57068638eb28b9153d008ecde288152af"}, - {file = "debugpy-1.8.19-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:d40c016c1f538dbf1762936e3aeb43a89b965069d9f60f9e39d35d9d25e6b809"}, - {file = "debugpy-1.8.19-cp314-cp314-win32.whl", hash = "sha256:0601708223fe1cd0e27c6cce67a899d92c7d68e73690211e6788a4b0e1903f5b"}, - {file = "debugpy-1.8.19-cp314-cp314-win_amd64.whl", hash = "sha256:8e19a725f5d486f20e53a1dde2ab8bb2c9607c40c00a42ab646def962b41125f"}, - {file = "debugpy-1.8.19-cp38-cp38-macosx_15_0_x86_64.whl", hash = "sha256:d9b6f633fd2865af2afba2beb0c1819b6ecd4aed1c8f90f5d1bbca3272306b10"}, - {file = "debugpy-1.8.19-cp38-cp38-manylinux_2_34_x86_64.whl", hash = "sha256:a21bfdea088f713df05fa246ba0520f6ba44dd7eaec224742f51987a6979a648"}, - {file = "debugpy-1.8.19-cp38-cp38-win32.whl", hash = "sha256:b1cb98e5325da3059ca24445fca48314bfddfdf65ce1b59ff07055e723f06bd2"}, - {file = "debugpy-1.8.19-cp38-cp38-win_amd64.whl", hash = "sha256:c9b9bf440141a36836bdbe4320a2b126bb38aafa85e1aed05d7bfbb0e2a278bf"}, - {file = "debugpy-1.8.19-cp39-cp39-macosx_15_0_x86_64.whl", hash = "sha256:c047177ab2d286451f242b855b650d313198c4a987140d4b35218b2855a64a4a"}, - {file = "debugpy-1.8.19-cp39-cp39-manylinux_2_34_x86_64.whl", hash = "sha256:4468de0c30012d367944f0eab4ecb8371736e8ef9522a465f61214f344c11183"}, - {file = "debugpy-1.8.19-cp39-cp39-win32.whl", hash = "sha256:7b62c0f015120ede25e5124a5f9d8a424e1208e3d96a36c89958f046ee21fff6"}, - {file = "debugpy-1.8.19-cp39-cp39-win_amd64.whl", hash = "sha256:76f566baaf7f3e06adbe67ffedccd2ee911d1e486f55931939ce3f0fe1090774"}, - {file = "debugpy-1.8.19-py2.py3-none-any.whl", hash = "sha256:360ffd231a780abbc414ba0f005dad409e71c78637efe8f2bd75837132a41d38"}, - {file = "debugpy-1.8.19.tar.gz", hash = "sha256:eea7e5987445ab0b5ed258093722d5ecb8bb72217c5c9b1e21f64efe23ddebdb"}, +groups = ["dev"] +files = [ + {file = "debugpy-1.8.20-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:157e96ffb7f80b3ad36d808646198c90acb46fdcfd8bb1999838f0b6f2b59c64"}, + {file = "debugpy-1.8.20-cp310-cp310-manylinux_2_34_x86_64.whl", hash = "sha256:c1178ae571aff42e61801a38b007af504ec8e05fde1c5c12e5a7efef21009642"}, + {file = "debugpy-1.8.20-cp310-cp310-win32.whl", hash = "sha256:c29dd9d656c0fbd77906a6e6a82ae4881514aa3294b94c903ff99303e789b4a2"}, + {file = "debugpy-1.8.20-cp310-cp310-win_amd64.whl", hash = "sha256:3ca85463f63b5dd0aa7aaa933d97cbc47c174896dcae8431695872969f981893"}, + {file = "debugpy-1.8.20-cp311-cp311-macosx_15_0_universal2.whl", hash = "sha256:eada6042ad88fa1571b74bd5402ee8b86eded7a8f7b827849761700aff171f1b"}, + {file = "debugpy-1.8.20-cp311-cp311-manylinux_2_34_x86_64.whl", hash = "sha256:7de0b7dfeedc504421032afba845ae2a7bcc32ddfb07dae2c3ca5442f821c344"}, + {file = "debugpy-1.8.20-cp311-cp311-win32.whl", hash = "sha256:773e839380cf459caf73cc533ea45ec2737a5cc184cf1b3b796cd4fd98504fec"}, + {file = "debugpy-1.8.20-cp311-cp311-win_amd64.whl", hash = "sha256:1f7650546e0eded1902d0f6af28f787fa1f1dbdbc97ddabaf1cd963a405930cb"}, + {file = "debugpy-1.8.20-cp312-cp312-macosx_15_0_universal2.whl", hash = "sha256:4ae3135e2089905a916909ef31922b2d733d756f66d87345b3e5e52b7a55f13d"}, + {file = "debugpy-1.8.20-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:88f47850a4284b88bd2bfee1f26132147d5d504e4e86c22485dfa44b97e19b4b"}, + {file = "debugpy-1.8.20-cp312-cp312-win32.whl", hash = "sha256:4057ac68f892064e5f98209ab582abfee3b543fb55d2e87610ddc133a954d390"}, + {file = "debugpy-1.8.20-cp312-cp312-win_amd64.whl", hash = "sha256:a1a8f851e7cf171330679ef6997e9c579ef6dd33c9098458bd9986a0f4ca52e3"}, + {file = "debugpy-1.8.20-cp313-cp313-macosx_15_0_universal2.whl", hash = "sha256:5dff4bb27027821fdfcc9e8f87309a28988231165147c31730128b1c983e282a"}, + {file = "debugpy-1.8.20-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:84562982dd7cf5ebebfdea667ca20a064e096099997b175fe204e86817f64eaf"}, + {file = "debugpy-1.8.20-cp313-cp313-win32.whl", hash = "sha256:da11dea6447b2cadbf8ce2bec59ecea87cc18d2c574980f643f2d2dfe4862393"}, + {file = "debugpy-1.8.20-cp313-cp313-win_amd64.whl", hash = "sha256:eb506e45943cab2efb7c6eafdd65b842f3ae779f020c82221f55aca9de135ed7"}, + {file = "debugpy-1.8.20-cp314-cp314-macosx_15_0_universal2.whl", hash = "sha256:9c74df62fc064cd5e5eaca1353a3ef5a5d50da5eb8058fcef63106f7bebe6173"}, + {file = "debugpy-1.8.20-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:077a7447589ee9bc1ff0cdf443566d0ecf540ac8aa7333b775ebcb8ce9f4ecad"}, + {file = "debugpy-1.8.20-cp314-cp314-win32.whl", hash = "sha256:352036a99dd35053b37b7803f748efc456076f929c6a895556932eaf2d23b07f"}, + {file = "debugpy-1.8.20-cp314-cp314-win_amd64.whl", hash = "sha256:a98eec61135465b062846112e5ecf2eebb855305acc1dfbae43b72903b8ab5be"}, + {file = "debugpy-1.8.20-cp38-cp38-macosx_15_0_x86_64.whl", hash = "sha256:b773eb026a043e4d9c76265742bc846f2f347da7e27edf7fe97716ea19d6bfc5"}, + {file = "debugpy-1.8.20-cp38-cp38-manylinux_2_34_x86_64.whl", hash = "sha256:20d6e64ea177ab6732bffd3ce8fc6fb8879c60484ce14c3b3fe183b1761459ca"}, + {file = "debugpy-1.8.20-cp38-cp38-win32.whl", hash = "sha256:0dfd9adb4b3c7005e9c33df430bcdd4e4ebba70be533e0066e3a34d210041b66"}, + {file = "debugpy-1.8.20-cp38-cp38-win_amd64.whl", hash = "sha256:60f89411a6c6afb89f18e72e9091c3dfbcfe3edc1066b2043a1f80a3bbb3e11f"}, + {file = "debugpy-1.8.20-cp39-cp39-macosx_15_0_x86_64.whl", hash = "sha256:bff8990f040dacb4c314864da95f7168c5a58a30a66e0eea0fb85e2586a92cd6"}, + {file = "debugpy-1.8.20-cp39-cp39-manylinux_2_34_x86_64.whl", hash = "sha256:70ad9ae09b98ac307b82c16c151d27ee9d68ae007a2e7843ba621b5ce65333b5"}, + {file = "debugpy-1.8.20-cp39-cp39-win32.whl", hash = "sha256:9eeed9f953f9a23850c85d440bf51e3c56ed5d25f8560eeb29add815bd32f7ee"}, + {file = "debugpy-1.8.20-cp39-cp39-win_amd64.whl", hash = "sha256:760813b4fff517c75bfe7923033c107104e76acfef7bda011ffea8736e9a66f8"}, + {file = "debugpy-1.8.20-py2.py3-none-any.whl", hash = "sha256:5be9bed9ae3be00665a06acaa48f8329d2b9632f15fd09f6a9a8c8d9907e54d7"}, + {file = "debugpy-1.8.20.tar.gz", hash = "sha256:55bc8701714969f1ab89a6d5f2f3d40c36f91b2cbe2f65d98bf8196f6a6a2c33"}, ] [[package]] @@ -668,6 +708,7 @@ version = "5.2.1" description = "Decorators for Humans" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a"}, {file = "decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360"}, @@ -679,6 +720,7 @@ version = "0.7.1" description = "XML bomb protection for Python stdlib modules" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["docs"] files = [ {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, @@ -690,6 +732,7 @@ version = "0.3.0.post1" description = "A μ-library for constructing cascading style sheets from Python dictionaries." optional = false python-versions = ">=3.6" +groups = ["docs"] files = [ {file = "dict2css-0.3.0.post1-py3-none-any.whl", hash = "sha256:f006a6b774c3e31869015122ae82c491fd25e7de4a75607a62aa3e798f837e0d"}, {file = "dict2css-0.3.0.post1.tar.gz", hash = "sha256:89c544c21c4ca7472c3fffb9d37d3d926f606329afdb751dc1de67a411b70719"}, @@ -701,13 +744,14 @@ domdf-python-tools = ">=2.2.0" [[package]] name = "dill" -version = "0.4.0" +version = "0.4.1" description = "serialize all of Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" +groups = ["dev"] files = [ - {file = "dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049"}, - {file = "dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0"}, + {file = "dill-0.4.1-py3-none-any.whl", hash = "sha256:1e1ce33e978ae97fcfcff5638477032b801c46c7c65cf717f95fbc2248f79a9d"}, + {file = "dill-0.4.1.tar.gz", hash = "sha256:423092df4182177d4d8ba8290c8a5b640c66ab35ec7da59ccfa00f6fa3eea5fa"}, ] [package.extras] @@ -720,6 +764,7 @@ version = "0.21.2" description = "Docutils -- Python Documentation Utilities" optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"}, {file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"}, @@ -731,6 +776,7 @@ version = "3.10.0" description = "Helpful functions for Python 🐍 🛠️" optional = false python-versions = ">=3.6" +groups = ["docs"] files = [ {file = "domdf_python_tools-3.10.0-py3-none-any.whl", hash = "sha256:5e71c1be71bbcc1f881d690c8984b60e64298ec256903b3147f068bc33090c36"}, {file = "domdf_python_tools-3.10.0.tar.gz", hash = "sha256:2ae308d2f4f1e9145f5f4ba57f840fbfd1c2983ee26e4824347789649d3ae298"}, @@ -750,6 +796,7 @@ version = "0.12.0" description = "Tools to expand Python's enum module." optional = false python-versions = ">=3.6" +groups = ["main", "docs"] files = [ {file = "enum_tools-0.12.0-py3-none-any.whl", hash = "sha256:d69b019f193c7b850b17d9ce18440db7ed62381571409af80ccc08c5218b340a"}, {file = "enum_tools-0.12.0.tar.gz", hash = "sha256:13ceb9376a4c5f574a1e7c5f9c8eb7f3d3fbfbb361cc18a738df1a58dfefd460"}, @@ -769,6 +816,8 @@ version = "1.3.1" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" +groups = ["main", "dev", "test"] +markers = "python_version == \"3.10\"" files = [ {file = "exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598"}, {file = "exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219"}, @@ -786,6 +835,7 @@ version = "2.1.2" description = "execnet: rapid multi-Python deployment" optional = false python-versions = ">=3.8" +groups = ["test"] files = [ {file = "execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec"}, {file = "execnet-2.1.2.tar.gz", hash = "sha256:63d83bfdd9a23e35b9c6a3261412324f964c2ec8dcd8d3c6916ee9373e0befcd"}, @@ -800,13 +850,14 @@ version = "2.2.1" description = "Get the currently executing AST node of a frame, and other information" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017"}, {file = "executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4"}, ] [package.extras] -tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] +tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich ; python_version >= \"3.11\""] [[package]] name = "fastjsonschema" @@ -814,6 +865,7 @@ version = "2.21.2" description = "Fastest Python implementation of JSON schema" optional = false python-versions = "*" +groups = ["docs"] files = [ {file = "fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463"}, {file = "fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de"}, @@ -824,13 +876,14 @@ devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benc [[package]] name = "filelock" -version = "3.20.2" +version = "3.24.2" description = "A platform independent file lock." optional = false python-versions = ">=3.10" +groups = ["docs"] files = [ - {file = "filelock-3.20.2-py3-none-any.whl", hash = "sha256:fbba7237d6ea277175a32c54bb71ef814a8546d8601269e1bfc388de333974e8"}, - {file = "filelock-3.20.2.tar.gz", hash = "sha256:a2241ff4ddde2a7cebddf78e39832509cb045d18ec1a09d7248d6bfc6bfbbe64"}, + {file = "filelock-3.24.2-py3-none-any.whl", hash = "sha256:667d7dc0b7d1e1064dd5f8f8e80bdac157a6482e8d2e02cd16fd3b6b33bd6556"}, + {file = "filelock-3.24.2.tar.gz", hash = "sha256:c22803117490f156e59fafce621f0550a7a853e2bbf4f87f112b11d469b6c81b"}, ] [[package]] @@ -839,6 +892,7 @@ version = "6.1.0" description = "the modular source code checker: pep8 pyflakes and co" optional = false python-versions = ">=3.8.1" +groups = ["dev"] files = [ {file = "flake8-6.1.0-py2.py3-none-any.whl", hash = "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5"}, {file = "flake8-6.1.0.tar.gz", hash = "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23"}, @@ -855,6 +909,7 @@ version = "1.1" description = "HTML parser based on the WHATWG HTML specification" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["docs"] files = [ {file = "html5lib-1.1-py2.py3-none-any.whl", hash = "sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d"}, {file = "html5lib-1.1.tar.gz", hash = "sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f"}, @@ -865,10 +920,10 @@ six = ">=1.9" webencodings = "*" [package.extras] -all = ["chardet (>=2.2)", "genshi", "lxml"] +all = ["chardet (>=2.2)", "genshi", "lxml ; platform_python_implementation == \"CPython\""] chardet = ["chardet (>=2.2)"] genshi = ["genshi"] -lxml = ["lxml"] +lxml = ["lxml ; platform_python_implementation == \"CPython\""] [[package]] name = "html5rdf" @@ -876,6 +931,7 @@ version = "1.2.1" description = "HTML parser based on the WHATWG HTML specification" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "html5rdf-1.2.1-py2.py3-none-any.whl", hash = "sha256:1f519121bc366af3e485310dc8041d2e86e5173c1a320fac3dc9d2604069b83e"}, {file = "html5rdf-1.2.1.tar.gz", hash = "sha256:ace9b420ce52995bb4f05e7425eedf19e433c981dfe7a831ab391e2fa2e1a195"}, @@ -887,6 +943,7 @@ version = "3.11" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.8" +groups = ["main", "docs"] files = [ {file = "idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea"}, {file = "idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902"}, @@ -901,6 +958,7 @@ version = "1.4.1" description = "Getting image size from png/jpeg/jpeg2000/gif file" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["docs"] files = [ {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, @@ -912,6 +970,8 @@ version = "8.7.1" description = "Read metadata from Python packages" optional = false python-versions = ">=3.9" +groups = ["main"] +markers = "python_version < \"3.12\"" files = [ {file = "importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151"}, {file = "importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb"}, @@ -921,13 +981,13 @@ files = [ zipp = ">=3.20" [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] enabler = ["pytest-enabler (>=3.4)"] perf = ["ipython"] test = ["flufl.flake8", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] -type = ["mypy (<1.19)", "pytest-mypy (>=1.0.1)"] +type = ["mypy (<1.19) ; platform_python_implementation == \"PyPy\"", "pytest-mypy (>=1.0.1)"] [[package]] name = "iniconfig" @@ -935,6 +995,7 @@ version = "2.3.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.10" +groups = ["test"] files = [ {file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"}, {file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"}, @@ -946,6 +1007,7 @@ version = "0.3.4" description = "Python port of Inquirer.js (A collection of common interactive command-line user interfaces)" optional = false python-versions = ">=3.7,<4.0" +groups = ["main"] files = [ {file = "InquirerPy-0.3.4-py3-none-any.whl", hash = "sha256:c65fdfbac1fa00e3ee4fb10679f4d3ed7a012abf4833910e63c295827fe2a7d4"}, {file = "InquirerPy-0.3.4.tar.gz", hash = "sha256:89d2ada0111f337483cb41ae31073108b2ec1e618a49d7110b0d7ade89fc197e"}, @@ -956,7 +1018,7 @@ pfzy = ">=0.3.1,<0.4.0" prompt-toolkit = ">=3.0.1,<4.0.0" [package.extras] -docs = ["Sphinx (>=4.1.2,<5.0.0)", "furo (>=2021.8.17-beta.43,<2022.0.0)", "myst-parser (>=0.15.1,<0.16.0)", "sphinx-autobuild (>=2021.3.14,<2022.0.0)", "sphinx-copybutton (>=0.4.0,<0.5.0)"] +docs = ["Sphinx (>=4.1.2,<5.0.0)", "furo (>=2021.8.17b43,<2022.0.0)", "myst-parser (>=0.15.1,<0.16.0)", "sphinx-autobuild (>=2021.3.14,<2022.0.0)", "sphinx-copybutton (>=0.4.0,<0.5.0)"] [[package]] name = "ipykernel" @@ -964,6 +1026,7 @@ version = "6.31.0" description = "IPython Kernel for Jupyter" optional = false python-versions = ">=3.9" +groups = ["dev"] files = [ {file = "ipykernel-6.31.0-py3-none-any.whl", hash = "sha256:abe5386f6ced727a70e0eb0cf1da801fa7c5fa6ff82147747d5a0406cd8c94af"}, {file = "ipykernel-6.31.0.tar.gz", hash = "sha256:2372ce8bc1ff4f34e58cafed3a0feb2194b91fc7cad0fc72e79e47b45ee9e8f6"}, @@ -997,6 +1060,8 @@ version = "8.38.0" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.10" +groups = ["dev"] +markers = "python_version == \"3.10\"" files = [ {file = "ipython-8.38.0-py3-none-any.whl", hash = "sha256:750162629d800ac65bb3b543a14e7a74b0e88063eac9b92124d4b2aa3f6d8e86"}, {file = "ipython-8.38.0.tar.gz", hash = "sha256:9cfea8c903ce0867cc2f23199ed8545eb741f3a69420bfcf3743ad1cec856d39"}, @@ -1018,7 +1083,7 @@ typing_extensions = {version = ">=4.6", markers = "python_version < \"3.12\""} [package.extras] all = ["ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole]", "ipython[test,test-extra]"] black = ["black"] -doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "tomli", "typing_extensions"] +doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "tomli ; python_version < \"3.11\"", "typing_extensions"] kernel = ["ipykernel"] matplotlib = ["matplotlib"] nbconvert = ["nbconvert"] @@ -1029,12 +1094,64 @@ qtconsole = ["qtconsole"] test = ["packaging", "pickleshare", "pytest", "pytest-asyncio (<0.22)", "testpath"] test-extra = ["curio", "ipython[test]", "jupyter_ai", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "trio"] +[[package]] +name = "ipython" +version = "9.10.0" +description = "IPython: Productive Interactive Computing" +optional = false +python-versions = ">=3.11" +groups = ["dev"] +markers = "python_version >= \"3.11\"" +files = [ + {file = "ipython-9.10.0-py3-none-any.whl", hash = "sha256:c6ab68cc23bba8c7e18e9b932797014cc61ea7fd6f19de180ab9ba73e65ee58d"}, + {file = "ipython-9.10.0.tar.gz", hash = "sha256:cd9e656be97618a0676d058134cd44e6dc7012c0e5cb36a9ce96a8c904adaf77"}, +] + +[package.dependencies] +colorama = {version = ">=0.4.4", markers = "sys_platform == \"win32\""} +decorator = ">=4.3.2" +ipython-pygments-lexers = ">=1.0.0" +jedi = ">=0.18.1" +matplotlib-inline = ">=0.1.5" +pexpect = {version = ">4.3", markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""} +prompt_toolkit = ">=3.0.41,<3.1.0" +pygments = ">=2.11.0" +stack_data = ">=0.6.0" +traitlets = ">=5.13.0" +typing_extensions = {version = ">=4.6", markers = "python_version < \"3.12\""} + +[package.extras] +all = ["argcomplete (>=3.0)", "ipython[doc,matplotlib,terminal,test,test-extra]"] +black = ["black"] +doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[matplotlib,test]", "setuptools (>=70.0)", "sphinx (>=8.0)", "sphinx-rtd-theme (>=0.1.8)", "sphinx_toml (==0.0.4)", "typing_extensions"] +matplotlib = ["matplotlib (>3.9)"] +test = ["packaging (>=20.1.0)", "pytest (>=7.0.0)", "pytest-asyncio (>=1.0.0)", "setuptools (>=61.2)", "testpath (>=0.2)"] +test-extra = ["curio", "ipykernel (>6.30)", "ipython[matplotlib]", "ipython[test]", "jupyter_ai", "nbclient", "nbformat", "numpy (>=1.27)", "pandas (>2.1)", "trio (>=0.1.0)"] + +[[package]] +name = "ipython-pygments-lexers" +version = "1.1.1" +description = "Defines a variety of Pygments lexers for highlighting IPython code." +optional = false +python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version >= \"3.11\"" +files = [ + {file = "ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c"}, + {file = "ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81"}, +] + +[package.dependencies] +pygments = "*" + [[package]] name = "isodate" version = "0.7.2" description = "An ISO 8601 date/time/duration parser and formatter" optional = false python-versions = ">=3.7" +groups = ["main"] +markers = "python_version == \"3.10\"" files = [ {file = "isodate-0.7.2-py3-none-any.whl", hash = "sha256:28009937d8031054830160fce6d409ed342816b543597cece116d966c6d99e15"}, {file = "isodate-0.7.2.tar.gz", hash = "sha256:4cd1aa0f43ca76f4a6c6c0292a85f40b35ec2e43e315b59f06e6d32171a953e6"}, @@ -1046,6 +1163,7 @@ version = "6.1.0" description = "A Python utility / library to sort Python imports." optional = false python-versions = ">=3.9.0" +groups = ["dev"] files = [ {file = "isort-6.1.0-py3-none-any.whl", hash = "sha256:58d8927ecce74e5087aef019f778d4081a3b6c98f15a80ba35782ca8a2097784"}, {file = "isort-6.1.0.tar.gz", hash = "sha256:9b8f96a14cfee0677e78e941ff62f03769a06d412aabb9e2a90487b3b7e8d481"}, @@ -1061,6 +1179,7 @@ version = "0.19.2" description = "An autocompletion tool for Python that can be used for text editors." optional = false python-versions = ">=3.6" +groups = ["dev"] files = [ {file = "jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9"}, {file = "jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0"}, @@ -1080,6 +1199,7 @@ version = "3.1.6" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" +groups = ["docs"] files = [ {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, @@ -1093,20 +1213,21 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "jsonschema" -version = "4.25.1" +version = "4.26.0" description = "An implementation of JSON Schema validation for Python" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" +groups = ["docs"] files = [ - {file = "jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63"}, - {file = "jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85"}, + {file = "jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce"}, + {file = "jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326"}, ] [package.dependencies] attrs = ">=22.2.0" -jsonschema-specifications = ">=2023.03.6" +jsonschema-specifications = ">=2023.3.6" referencing = ">=0.28.4" -rpds-py = ">=0.7.1" +rpds-py = ">=0.25.0" [package.extras] format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] @@ -1118,6 +1239,7 @@ version = "2025.9.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe"}, {file = "jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d"}, @@ -1128,13 +1250,14 @@ referencing = ">=0.31.0" [[package]] name = "jupyter-client" -version = "8.7.0" +version = "8.8.0" description = "Jupyter protocol implementation and client libraries" optional = false python-versions = ">=3.10" +groups = ["dev", "docs"] files = [ - {file = "jupyter_client-8.7.0-py3-none-any.whl", hash = "sha256:3671a94fd25e62f5f2f554f5e95389c2294d89822378a5f2dd24353e1494a9e0"}, - {file = "jupyter_client-8.7.0.tar.gz", hash = "sha256:3357212d9cbe01209e59190f67a3a7e1f387a4f4e88d1e0433ad84d7b262531d"}, + {file = "jupyter_client-8.8.0-py3-none-any.whl", hash = "sha256:f93a5b99c5e23a507b773d3a1136bd6e16c67883ccdbd9a829b0bbdb98cd7d7a"}, + {file = "jupyter_client-8.8.0.tar.gz", hash = "sha256:d556811419a4f2d96c869af34e854e3f059b7cc2d6d01a9cd9c85c267691be3e"}, ] [package.dependencies] @@ -1146,7 +1269,8 @@ traitlets = ">=5.3" [package.extras] docs = ["ipykernel", "myst-parser", "pydata-sphinx-theme", "sphinx (>=4)", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] -test = ["anyio", "coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pytest", "pytest-cov", "pytest-jupyter[client] (>=0.6.2)", "pytest-timeout"] +orjson = ["orjson"] +test = ["anyio", "coverage", "ipykernel (>=6.14)", "msgpack", "mypy ; platform_python_implementation != \"PyPy\"", "paramiko ; sys_platform == \"win32\"", "pre-commit", "pytest", "pytest-cov", "pytest-jupyter[client] (>=0.6.2)", "pytest-timeout"] [[package]] name = "jupyter-core" @@ -1154,6 +1278,7 @@ version = "5.9.1" description = "Jupyter core package. A base package on which Jupyter projects rely." optional = false python-versions = ">=3.10" +groups = ["dev", "docs"] files = [ {file = "jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407"}, {file = "jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508"}, @@ -1173,6 +1298,7 @@ version = "0.3.0" description = "Pygments theme using JupyterLab CSS variables" optional = false python-versions = ">=3.8" +groups = ["docs"] files = [ {file = "jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780"}, {file = "jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d"}, @@ -1184,6 +1310,7 @@ version = "3.0.0" description = "Python port of markdown-it. Markdown parsing, done right!" optional = false python-versions = ">=3.8" +groups = ["main", "docs"] files = [ {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, @@ -1208,6 +1335,7 @@ version = "3.0.3" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559"}, {file = "markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419"}, @@ -1306,6 +1434,7 @@ version = "0.2.1" description = "Inline Matplotlib backend for Jupyter" optional = false python-versions = ">=3.9" +groups = ["dev"] files = [ {file = "matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76"}, {file = "matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe"}, @@ -1323,6 +1452,7 @@ version = "0.7.0" description = "McCabe checker, plugin for flake8" optional = false python-versions = ">=3.6" +groups = ["dev"] files = [ {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, @@ -1334,6 +1464,7 @@ version = "0.5.0" description = "Collection of plugins for markdown-it-py" optional = false python-versions = ">=3.10" +groups = ["docs"] files = [ {file = "mdit_py_plugins-0.5.0-py3-none-any.whl", hash = "sha256:07a08422fc1936a5d26d146759e9155ea466e842f5ab2f7d2266dd084c8dab1f"}, {file = "mdit_py_plugins-0.5.0.tar.gz", hash = "sha256:f4918cb50119f50446560513a8e311d574ff6aaed72606ddae6d35716fe809c6"}, @@ -1353,6 +1484,7 @@ version = "0.1.2" description = "Markdown URL utilities" optional = false python-versions = ">=3.7" +groups = ["main", "docs"] files = [ {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, @@ -1364,6 +1496,7 @@ version = "3.2.0" description = "A sane and fast Markdown parser with useful plugins and renderers" optional = false python-versions = ">=3.8" +groups = ["docs"] files = [ {file = "mistune-3.2.0-py3-none-any.whl", hash = "sha256:febdc629a3c78616b94393c6580551e0e34cc289987ec6c35ed3f4be42d0eee1"}, {file = "mistune-3.2.0.tar.gz", hash = "sha256:708487c8a8cdd99c9d90eb3ed4c3ed961246ff78ac82f03418f5183ab70e398a"}, @@ -1378,6 +1511,7 @@ version = "10.8.0" description = "More routines for operating on iterables, beyond itertools" optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b"}, {file = "more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd"}, @@ -1389,6 +1523,7 @@ version = "1.1.2" description = "MessagePack serializer" optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "msgpack-1.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0051fffef5a37ca2cd16978ae4f0aef92f164df86823871b5162812bebecd8e2"}, {file = "msgpack-1.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a605409040f2da88676e9c9e5853b3449ba8011973616189ea5ee55ddbc5bc87"}, @@ -1460,6 +1595,7 @@ version = "4.0.1" description = "An extended [CommonMark](https://spec.commonmark.org/) compliant parser," optional = false python-versions = ">=3.10" +groups = ["docs"] files = [ {file = "myst_parser-4.0.1-py3-none-any.whl", hash = "sha256:9134e88959ec3b5780aedf8a99680ea242869d012e8821db3126d427edc9c95d"}, {file = "myst_parser-4.0.1.tar.gz", hash = "sha256:5cfea715e4f3574138aecbf7d54132296bfd72bb614d31168f48c477a830a7c4"}, @@ -1486,6 +1622,7 @@ version = "8.4.0" description = "Simple yet flexible natural sorting in Python." optional = false python-versions = ">=3.7" +groups = ["docs"] files = [ {file = "natsort-8.4.0-py3-none-any.whl", hash = "sha256:4732914fb471f56b5cce04d7bae6f164a592c7712e1c85f9ef585e197299521c"}, {file = "natsort-8.4.0.tar.gz", hash = "sha256:45312c4a0e5507593da193dedd04abb1469253b601ecaf63445ad80f0a1ea581"}, @@ -1501,6 +1638,7 @@ version = "0.10.4" description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." optional = false python-versions = ">=3.10.0" +groups = ["docs"] files = [ {file = "nbclient-0.10.4-py3-none-any.whl", hash = "sha256:9162df5a7373d70d606527300a95a975a47c137776cd942e52d9c7e29ff83440"}, {file = "nbclient-0.10.4.tar.gz", hash = "sha256:1e54091b16e6da39e297b0ece3e10f6f29f4ac4e8ee515d29f8a7099bd6553c9"}, @@ -1519,13 +1657,14 @@ test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>= [[package]] name = "nbconvert" -version = "7.16.6" -description = "Converting Jupyter Notebooks (.ipynb files) to other formats. Output formats include asciidoc, html, latex, markdown, pdf, py, rst, script. nbconvert can be used both as a Python library (`import nbconvert`) or as a command line tool (invoked as `jupyter nbconvert ...`)." +version = "7.17.0" +description = "Convert Jupyter Notebooks (.ipynb files) to other formats." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" +groups = ["docs"] files = [ - {file = "nbconvert-7.16.6-py3-none-any.whl", hash = "sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b"}, - {file = "nbconvert-7.16.6.tar.gz", hash = "sha256:576a7e37c6480da7b8465eefa66c17844243816ce1ccc372633c6b71c3c0f582"}, + {file = "nbconvert-7.17.0-py3-none-any.whl", hash = "sha256:4f99a63b337b9a23504347afdab24a11faa7d86b405e5c8f9881cd313336d518"}, + {file = "nbconvert-7.17.0.tar.gz", hash = "sha256:1b2696f1b5be12309f6c7d707c24af604b87dfaf6d950794c7b07acab96dda78"}, ] [package.dependencies] @@ -1545,8 +1684,8 @@ pygments = ">=2.4.1" traitlets = ">=5.1" [package.extras] -all = ["flaky", "ipykernel", "ipython", "ipywidgets (>=7.5)", "myst-parser", "nbsphinx (>=0.2.12)", "playwright", "pydata-sphinx-theme", "pyqtwebengine (>=5.15)", "pytest (>=7)", "sphinx (==5.0.2)", "sphinxcontrib-spelling", "tornado (>=6.1)"] -docs = ["ipykernel", "ipython", "myst-parser", "nbsphinx (>=0.2.12)", "pydata-sphinx-theme", "sphinx (==5.0.2)", "sphinxcontrib-spelling"] +all = ["flaky", "intersphinx-registry", "ipykernel", "ipython", "ipywidgets (>=7.5)", "myst-parser", "nbsphinx (>=0.2.12)", "playwright", "pydata-sphinx-theme", "pyqtwebengine (>=5.15)", "pytest (>=7)", "sphinx (>=5.0.2)", "sphinxcontrib-spelling", "tornado (>=6.1)"] +docs = ["intersphinx-registry", "ipykernel", "ipython", "myst-parser", "nbsphinx (>=0.2.12)", "pydata-sphinx-theme", "sphinx (>=5.0.2)", "sphinxcontrib-spelling"] qtpdf = ["pyqtwebengine (>=5.15)"] qtpng = ["pyqtwebengine (>=5.15)"] serve = ["tornado (>=6.1)"] @@ -1559,6 +1698,7 @@ version = "5.10.4" description = "The Jupyter Notebook format" optional = false python-versions = ">=3.8" +groups = ["docs"] files = [ {file = "nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b"}, {file = "nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a"}, @@ -1580,6 +1720,7 @@ version = "0.9.8" description = "Jupyter Notebook Tools for Sphinx" optional = false python-versions = ">=3.8" +groups = ["docs"] files = [ {file = "nbsphinx-0.9.8-py3-none-any.whl", hash = "sha256:92d95ee91784e56bc633b60b767a6b6f23a0445f891e24641ce3c3f004759ccf"}, {file = "nbsphinx-0.9.8.tar.gz", hash = "sha256:d0765908399a8ee2b57be7ae881cf2ea58d66db3af7bbf33e6eb48f83bea5495"}, @@ -1599,6 +1740,7 @@ version = "1.6.0" description = "Patch asyncio to allow nested event loops" optional = false python-versions = ">=3.5" +groups = ["dev"] files = [ {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, @@ -1610,6 +1752,7 @@ version = "7.1.4" description = "A simple implementation of the OWL2 RL Profile, as well as a basic RDFS inference, on top of RDFLib. Based mechanical forward chaining." optional = false python-versions = "<4.0,>=3.9" +groups = ["main"] files = [ {file = "owlrl-7.1.4-py3-none-any.whl", hash = "sha256:e78b46020169783345636da93a467d318f18700c483184dd15e885850cf64775"}, {file = "owlrl-7.1.4.tar.gz", hash = "sha256:60bd4067e346b9111f0a2924565afe97ac6595b98b2bbe953928b5113971daf7"}, @@ -1620,13 +1763,14 @@ rdflib = ">=7.1.4" [[package]] name = "packaging" -version = "25.0" +version = "26.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" +groups = ["main", "dev", "docs", "test"] files = [ - {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, - {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, + {file = "packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529"}, + {file = "packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4"}, ] [[package]] @@ -1635,6 +1779,7 @@ version = "1.5.1" description = "Utilities for writing pandoc filters in python" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["docs"] files = [ {file = "pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc"}, {file = "pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e"}, @@ -1642,17 +1787,18 @@ files = [ [[package]] name = "parso" -version = "0.8.5" +version = "0.8.6" description = "A Python Parser" optional = false python-versions = ">=3.6" +groups = ["dev"] files = [ - {file = "parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887"}, - {file = "parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a"}, + {file = "parso-0.8.6-py2.py3-none-any.whl", hash = "sha256:2c549f800b70a5c4952197248825584cb00f033b29c692671d3bf08bf380baff"}, + {file = "parso-0.8.6.tar.gz", hash = "sha256:2b9a0332696df97d454fa67b81618fd69c35a7b90327cbe6ba5c92d2c68a7bfd"}, ] [package.extras] -qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +qa = ["flake8 (==5.0.4)", "types-setuptools (==67.2.0.1)", "zuban (==0.5.1)"] testing = ["docopt", "pytest"] [[package]] @@ -1661,6 +1807,8 @@ version = "4.9.0" description = "Pexpect allows easy control of interactive console applications." optional = false python-versions = "*" +groups = ["dev"] +markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\"" files = [ {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, @@ -1675,36 +1823,34 @@ version = "0.3.4" description = "Python port of the fzy fuzzy string matching algorithm" optional = false python-versions = ">=3.7,<4.0" +groups = ["main"] files = [ {file = "pfzy-0.3.4-py3-none-any.whl", hash = "sha256:5f50d5b2b3207fa72e7ec0ef08372ef652685470974a107d0d4999fc5a903a96"}, {file = "pfzy-0.3.4.tar.gz", hash = "sha256:717ea765dd10b63618e7298b2d98efd819e0b30cd5905c9707223dceeb94b3f1"}, ] [package.extras] -docs = ["Sphinx (>=4.1.2,<5.0.0)", "furo (>=2021.8.17-beta.43,<2022.0.0)", "myst-parser (>=0.15.1,<0.16.0)", "sphinx-autobuild (>=2021.3.14,<2022.0.0)", "sphinx-copybutton (>=0.4.0,<0.5.0)"] +docs = ["Sphinx (>=4.1.2,<5.0.0)", "furo (>=2021.8.17b43,<2022.0.0)", "myst-parser (>=0.15.1,<0.16.0)", "sphinx-autobuild (>=2021.3.14,<2022.0.0)", "sphinx-copybutton (>=0.4.0,<0.5.0)"] [[package]] name = "platformdirs" -version = "4.5.1" +version = "4.9.2" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.10" +groups = ["main", "dev", "docs"] files = [ - {file = "platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31"}, - {file = "platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda"}, + {file = "platformdirs-4.9.2-py3-none-any.whl", hash = "sha256:9170634f126f8efdae22fb58ae8a0eaa86f38365bc57897a6c4f781d1f5875bd"}, + {file = "platformdirs-4.9.2.tar.gz", hash = "sha256:9a33809944b9db043ad67ca0db94b14bf452cc6aeaac46a88ea55b26e2e9d291"}, ] -[package.extras] -docs = ["furo (>=2025.9.25)", "proselint (>=0.14)", "sphinx (>=8.2.3)", "sphinx-autodoc-typehints (>=3.2)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.4.2)", "pytest-cov (>=7)", "pytest-mock (>=3.15.1)"] -type = ["mypy (>=1.18.2)"] - [[package]] name = "pluggy" version = "1.6.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.9" +groups = ["test"] files = [ {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, @@ -1720,6 +1866,7 @@ version = "3.17.0" description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format" optional = false python-versions = ">=3.10" +groups = ["main"] files = [ {file = "prettytable-3.17.0-py3-none-any.whl", hash = "sha256:aad69b294ddbe3e1f95ef8886a060ed1666a0b83018bbf56295f6f226c43d287"}, {file = "prettytable-3.17.0.tar.gz", hash = "sha256:59f2590776527f3c9e8cf9fe7b66dd215837cca96a9c39567414cbc632e8ddb0"}, @@ -1737,6 +1884,7 @@ version = "3.0.52" description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955"}, {file = "prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855"}, @@ -1747,37 +1895,38 @@ wcwidth = "*" [[package]] name = "psutil" -version = "7.2.1" +version = "7.2.2" description = "Cross-platform lib for process and system monitoring." optional = false python-versions = ">=3.6" -files = [ - {file = "psutil-7.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ba9f33bb525b14c3ea563b2fd521a84d2fa214ec59e3e6a2858f78d0844dd60d"}, - {file = "psutil-7.2.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:81442dac7abfc2f4f4385ea9e12ddf5a796721c0f6133260687fec5c3780fa49"}, - {file = "psutil-7.2.1-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ea46c0d060491051d39f0d2cff4f98d5c72b288289f57a21556cc7d504db37fc"}, - {file = "psutil-7.2.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:35630d5af80d5d0d49cfc4d64c1c13838baf6717a13effb35869a5919b854cdf"}, - {file = "psutil-7.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:923f8653416604e356073e6e0bccbe7c09990acef442def2f5640dd0faa9689f"}, - {file = "psutil-7.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:cfbe6b40ca48019a51827f20d830887b3107a74a79b01ceb8cc8de4ccb17b672"}, - {file = "psutil-7.2.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:494c513ccc53225ae23eec7fe6e1482f1b8a44674241b54561f755a898650679"}, - {file = "psutil-7.2.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3fce5f92c22b00cdefd1645aa58ab4877a01679e901555067b1bd77039aa589f"}, - {file = "psutil-7.2.1-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93f3f7b0bb07711b49626e7940d6fe52aa9940ad86e8f7e74842e73189712129"}, - {file = "psutil-7.2.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d34d2ca888208eea2b5c68186841336a7f5e0b990edec929be909353a202768a"}, - {file = "psutil-7.2.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2ceae842a78d1603753561132d5ad1b2f8a7979cb0c283f5b52fb4e6e14b1a79"}, - {file = "psutil-7.2.1-cp314-cp314t-win_arm64.whl", hash = "sha256:08a2f175e48a898c8eb8eace45ce01777f4785bc744c90aa2cc7f2fa5462a266"}, - {file = "psutil-7.2.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b2e953fcfaedcfbc952b44744f22d16575d3aa78eb4f51ae74165b4e96e55f42"}, - {file = "psutil-7.2.1-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:05cc68dbb8c174828624062e73078e7e35406f4ca2d0866c272c2410d8ef06d1"}, - {file = "psutil-7.2.1-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e38404ca2bb30ed7267a46c02f06ff842e92da3bb8c5bfdadbd35a5722314d8"}, - {file = "psutil-7.2.1-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab2b98c9fc19f13f59628d94df5cc4cc4844bc572467d113a8b517d634e362c6"}, - {file = "psutil-7.2.1-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f78baafb38436d5a128f837fab2d92c276dfb48af01a240b861ae02b2413ada8"}, - {file = "psutil-7.2.1-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:99a4cd17a5fdd1f3d014396502daa70b5ec21bf4ffe38393e152f8e449757d67"}, - {file = "psutil-7.2.1-cp37-abi3-win_amd64.whl", hash = "sha256:b1b0671619343aa71c20ff9767eced0483e4fc9e1f489d50923738caf6a03c17"}, - {file = "psutil-7.2.1-cp37-abi3-win_arm64.whl", hash = "sha256:0d67c1822c355aa6f7314d92018fb4268a76668a536f133599b91edd48759442"}, - {file = "psutil-7.2.1.tar.gz", hash = "sha256:f7583aec590485b43ca601dd9cea0dcd65bd7bb21d30ef4ddbf4ea6b5ed1bdd3"}, -] - -[package.extras] -dev = ["abi3audit", "black", "check-manifest", "coverage", "packaging", "psleak", "pylint", "pyperf", "pypinfo", "pytest", "pytest-cov", "pytest-instafail", "pytest-xdist", "requests", "rstcheck", "ruff", "setuptools", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "validate-pyproject[all]", "virtualenv", "vulture", "wheel"] -test = ["psleak", "pytest", "pytest-instafail", "pytest-xdist", "setuptools"] +groups = ["dev"] +files = [ + {file = "psutil-7.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2edccc433cbfa046b980b0df0171cd25bcaeb3a68fe9022db0979e7aa74a826b"}, + {file = "psutil-7.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e78c8603dcd9a04c7364f1a3e670cea95d51ee865e4efb3556a3a63adef958ea"}, + {file = "psutil-7.2.2-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a571f2330c966c62aeda00dd24620425d4b0cc86881c89861fbc04549e5dc63"}, + {file = "psutil-7.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:917e891983ca3c1887b4ef36447b1e0873e70c933afc831c6b6da078ba474312"}, + {file = "psutil-7.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:ab486563df44c17f5173621c7b198955bd6b613fb87c71c161f827d3fb149a9b"}, + {file = "psutil-7.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:ae0aefdd8796a7737eccea863f80f81e468a1e4cf14d926bd9b6f5f2d5f90ca9"}, + {file = "psutil-7.2.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:eed63d3b4d62449571547b60578c5b2c4bcccc5387148db46e0c2313dad0ee00"}, + {file = "psutil-7.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7b6d09433a10592ce39b13d7be5a54fbac1d1228ed29abc880fb23df7cb694c9"}, + {file = "psutil-7.2.2-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fa4ecf83bcdf6e6c8f4449aff98eefb5d0604bf88cb883d7da3d8d2d909546a"}, + {file = "psutil-7.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e452c464a02e7dc7822a05d25db4cde564444a67e58539a00f929c51eddda0cf"}, + {file = "psutil-7.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c7663d4e37f13e884d13994247449e9f8f574bc4655d509c3b95e9ec9e2b9dc1"}, + {file = "psutil-7.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:11fe5a4f613759764e79c65cf11ebdf26e33d6dd34336f8a337aa2996d71c841"}, + {file = "psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486"}, + {file = "psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979"}, + {file = "psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9"}, + {file = "psutil-7.2.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e"}, + {file = "psutil-7.2.2-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8"}, + {file = "psutil-7.2.2-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc"}, + {file = "psutil-7.2.2-cp37-abi3-win_amd64.whl", hash = "sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988"}, + {file = "psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee"}, + {file = "psutil-7.2.2.tar.gz", hash = "sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372"}, +] + +[package.extras] +dev = ["abi3audit", "black", "check-manifest", "colorama ; os_name == \"nt\"", "coverage", "packaging", "psleak", "pylint", "pyperf", "pypinfo", "pyreadline3 ; os_name == \"nt\"", "pytest", "pytest-cov", "pytest-instafail", "pytest-xdist", "pywin32 ; os_name == \"nt\" and implementation_name != \"pypy\"", "requests", "rstcheck", "ruff", "setuptools", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "validate-pyproject[all]", "virtualenv", "vulture", "wheel", "wheel ; os_name == \"nt\" and implementation_name != \"pypy\"", "wmi ; os_name == \"nt\" and implementation_name != \"pypy\""] +test = ["psleak", "pytest", "pytest-instafail", "pytest-xdist", "pywin32 ; os_name == \"nt\" and implementation_name != \"pypy\"", "setuptools", "wheel ; os_name == \"nt\" and implementation_name != \"pypy\"", "wmi ; os_name == \"nt\" and implementation_name != \"pypy\""] [[package]] name = "ptyprocess" @@ -1785,6 +1934,8 @@ version = "0.7.0" description = "Run a subprocess in a pseudo terminal" optional = false python-versions = "*" +groups = ["dev"] +markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\"" files = [ {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, @@ -1796,6 +1947,7 @@ version = "0.2.3" description = "Safely evaluate AST nodes without side effects" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0"}, {file = "pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42"}, @@ -1810,6 +1962,7 @@ version = "2.11.1" description = "Python style guide checker" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"}, {file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"}, @@ -1817,13 +1970,15 @@ files = [ [[package]] name = "pycparser" -version = "2.23" +version = "3.0" description = "C parser in Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" +groups = ["dev", "docs"] +markers = "implementation_name == \"pypy\"" files = [ - {file = "pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934"}, - {file = "pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2"}, + {file = "pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992"}, + {file = "pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29"}, ] [[package]] @@ -1832,6 +1987,7 @@ version = "3.1.0" description = "passive checker of Python programs" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774"}, {file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"}, @@ -1843,6 +1999,7 @@ version = "2.19.2" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" +groups = ["main", "dev", "docs", "test"] files = [ {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, @@ -1857,6 +2014,7 @@ version = "3.3.9" description = "python code static checker" optional = false python-versions = ">=3.9.0" +groups = ["dev"] files = [ {file = "pylint-3.3.9-py3-none-any.whl", hash = "sha256:01f9b0462c7730f94786c283f3e52a1fbdf0494bbe0971a78d7277ef46a751e7"}, {file = "pylint-3.3.9.tar.gz", hash = "sha256:d312737d7b25ccf6b01cc4ac629b5dcd14a0fcf3ec392735ac70f137a9d5f83a"}, @@ -1868,7 +2026,7 @@ colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} dill = [ {version = ">=0.2", markers = "python_version < \"3.11\""}, {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, - {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, + {version = ">=0.3.6", markers = "python_version == \"3.11\""}, ] isort = ">=4.2.5,<5.13 || >5.13,<7" mccabe = ">=0.6,<0.8" @@ -1882,13 +2040,14 @@ testutils = ["gitpython (>3)"] [[package]] name = "pyparsing" -version = "3.3.1" +version = "3.3.2" description = "pyparsing - Classes and methods to define and execute parsing grammars" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ - {file = "pyparsing-3.3.1-py3-none-any.whl", hash = "sha256:023b5e7e5520ad96642e2c6db4cb683d3970bd640cdf7115049a6e9c3682df82"}, - {file = "pyparsing-3.3.1.tar.gz", hash = "sha256:47fad0f17ac1e2cad3de3b458570fbc9b03560aa029ed5e16ee5554da9a2251c"}, + {file = "pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d"}, + {file = "pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc"}, ] [package.extras] @@ -1900,6 +2059,7 @@ version = "6.1.0" description = "pyproject-flake8 (`pflake8`), a monkey patching wrapper to connect flake8 with pyproject.toml configuration" optional = false python-versions = ">=3.8.1" +groups = ["dev"] files = [ {file = "pyproject_flake8-6.1.0-py3-none-any.whl", hash = "sha256:86ea5559263c098e1aa4f866776aa2cf45362fd91a576b9fd8fbbbb55db12c4e"}, {file = "pyproject_flake8-6.1.0.tar.gz", hash = "sha256:6da8e5a264395e0148bc11844c6fb50546f1fac83ac9210f7328664135f9e70f"}, @@ -1911,13 +2071,14 @@ tomli = {version = "*", markers = "python_version < \"3.11\""} [[package]] name = "pyshacl" -version = "0.30.1" +version = "0.31.0" description = "Python SHACL Validator" optional = false python-versions = "<4,>=3.9" +groups = ["main"] files = [ - {file = "pyshacl-0.30.1-py3-none-any.whl", hash = "sha256:d7e0c21b25e948bb643dbc5db6258da64a90a8ac89055c1fe562b469031072aa"}, - {file = "pyshacl-0.30.1.tar.gz", hash = "sha256:df712ac961b1ee7bcf0b27fa71ecab7785a135b2af69783ce30cb05fe41bcaf5"}, + {file = "pyshacl-0.31.0-py3-none-any.whl", hash = "sha256:5cae2184401d956b67deebb00e3c78ab7052784741a730e52e309e33c8a0b9a5"}, + {file = "pyshacl-0.31.0.tar.gz", hash = "sha256:327950875a5bb0d1a15c246a8a272b2dbf6bc9b96e28cfa8fdbfa4d73aadc0ba"}, ] [package.dependencies] @@ -1943,6 +2104,7 @@ version = "9.0.2" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.10" +groups = ["test"] files = [ {file = "pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b"}, {file = "pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11"}, @@ -1966,6 +2128,7 @@ version = "5.0.0" description = "Pytest plugin for measuring coverage." optional = false python-versions = ">=3.8" +groups = ["test"] files = [ {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, @@ -1984,6 +2147,7 @@ version = "3.8.0" description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" optional = false python-versions = ">=3.9" +groups = ["test"] files = [ {file = "pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88"}, {file = "pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1"}, @@ -2004,6 +2168,7 @@ version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["dev", "docs"] files = [ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, @@ -2018,6 +2183,7 @@ version = "6.0.3" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.8" +groups = ["docs"] files = [ {file = "PyYAML-6.0.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f"}, {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4"}, @@ -2100,6 +2266,7 @@ version = "27.1.0" description = "Python bindings for 0MQ" optional = false python-versions = ">=3.8" +groups = ["dev", "docs"] files = [ {file = "pyzmq-27.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:508e23ec9bc44c0005c4946ea013d9317ae00ac67778bd47519fdf5a0e930ff4"}, {file = "pyzmq-27.1.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:507b6f430bdcf0ee48c0d30e734ea89ce5567fd7b8a0f0044a369c176aa44556"}, @@ -2200,13 +2367,14 @@ cffi = {version = "*", markers = "implementation_name == \"pypy\""} [[package]] name = "rdflib" -version = "7.5.0" +version = "7.6.0" description = "RDFLib is a Python library for working with RDF, a simple yet powerful language for representing information." optional = false python-versions = ">=3.8.1" +groups = ["main"] files = [ - {file = "rdflib-7.5.0-py3-none-any.whl", hash = "sha256:b011dfc40d0fc8a44252e906dcd8fc806a7859bc231be190c37e9568a31ac572"}, - {file = "rdflib-7.5.0.tar.gz", hash = "sha256:663083443908b1830e567350d72e74d9948b310f827966358d76eebdc92bf592"}, + {file = "rdflib-7.6.0-py3-none-any.whl", hash = "sha256:30c0a3ebf4c0e09215f066be7246794b6492e054e782d7ac2a34c9f70a15e0dd"}, + {file = "rdflib-7.6.0.tar.gz", hash = "sha256:6c831288d5e4a5a7ece85d0ccde9877d512a3d0f02d7c06455d00d6d0ea379df"}, ] [package.dependencies] @@ -2216,6 +2384,7 @@ pyparsing = ">=2.1.0,<4" [package.extras] berkeleydb = ["berkeleydb (>=18.1.0,<19.0.0)"] +graphdb = ["httpx (>=0.28.1,<0.29.0)"] html = ["html5rdf (>=1.2,<2)"] lxml = ["lxml (>=4.3,<6.0)"] networkx = ["networkx (>=2,<4)"] @@ -2228,6 +2397,7 @@ version = "0.37.0" description = "JSON Referencing + Python" optional = false python-versions = ">=3.10" +groups = ["docs"] files = [ {file = "referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231"}, {file = "referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8"}, @@ -2244,6 +2414,7 @@ version = "2.32.5" description = "Python HTTP for Humans." optional = false python-versions = ">=3.9" +groups = ["main", "docs"] files = [ {file = "requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6"}, {file = "requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf"}, @@ -2261,13 +2432,14 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "requests-cache" -version = "1.2.1" +version = "1.3.0" description = "A persistent cache for python requests" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "requests_cache-1.2.1-py3-none-any.whl", hash = "sha256:1285151cddf5331067baa82598afe2d47c7495a1334bfe7a7d329b43e9fd3603"}, - {file = "requests_cache-1.2.1.tar.gz", hash = "sha256:68abc986fdc5b8d0911318fbb5f7c80eebcd4d01bfacc6685ecf8876052511d1"}, + {file = "requests_cache-1.3.0-py3-none-any.whl", hash = "sha256:f09f27bbf100c250886acf13a9db35b53cf2852fddd71977b47c71ea7d90dbba"}, + {file = "requests_cache-1.3.0.tar.gz", hash = "sha256:070e357ccef11a300ccef4294a85de1ab265833c5d9c9538b26cd7ba4085d54a"}, ] [package.dependencies] @@ -2275,15 +2447,12 @@ attrs = ">=21.2" cattrs = ">=22.2" platformdirs = ">=2.5" requests = ">=2.22" -url-normalize = ">=1.4" +url-normalize = ">=2.0" urllib3 = ">=1.25.5" [package.extras] -all = ["boto3 (>=1.15)", "botocore (>=1.18)", "itsdangerous (>=2.0)", "pymongo (>=3)", "pyyaml (>=6.0.1)", "redis (>=3)", "ujson (>=5.4)"] -bson = ["bson (>=0.5)"] -docs = ["furo (>=2023.3,<2024.0)", "linkify-it-py (>=2.0,<3.0)", "myst-parser (>=1.0,<2.0)", "sphinx (>=5.0.2,<6.0.0)", "sphinx-autodoc-typehints (>=1.19)", "sphinx-automodapi (>=0.14)", "sphinx-copybutton (>=0.5)", "sphinx-design (>=0.2)", "sphinx-notfound-page (>=0.8)", "sphinxcontrib-apidoc (>=0.3)", "sphinxext-opengraph (>=0.9)"] +all = ["boto3 (>=1.15)", "botocore (>=1.18)", "itsdangerous (>=2.0)", "orjson (>=3.0)", "pymongo (>=3)", "pyyaml (>=6.0.1)", "redis (>=3)", "ujson (>=5.4)"] dynamodb = ["boto3 (>=1.15)", "botocore (>=1.18)"] -json = ["ujson (>=5.4)"] mongodb = ["pymongo (>=3)"] redis = ["redis (>=3)"] security = ["itsdangerous (>=2.0)"] @@ -2295,6 +2464,7 @@ version = "13.9.4" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.8.0" +groups = ["main"] files = [ {file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"}, {file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"}, @@ -2310,13 +2480,14 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "rich-click" -version = "1.9.5" +version = "1.9.7" description = "Format click help output nicely with rich" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "rich_click-1.9.5-py3-none-any.whl", hash = "sha256:9b195721a773b1acf0e16ff9ec68cef1e7d237e53471e6e3f7ade462f86c403a"}, - {file = "rich_click-1.9.5.tar.gz", hash = "sha256:48120531493f1533828da80e13e839d471979ec8d7d0ca7b35f86a1379cc74b6"}, + {file = "rich_click-1.9.7-py3-none-any.whl", hash = "sha256:2f99120fca78f536e07b114d3b60333bc4bb2a0969053b1250869bcdc1b5351b"}, + {file = "rich_click-1.9.7.tar.gz", hash = "sha256:022997c1e30731995bdbc8ec2f82819340d42543237f033a003c7b1f843fc5dc"}, ] [package.dependencies] @@ -2327,7 +2498,36 @@ typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""} [package.extras] dev = ["inline-snapshot (>=0.24)", "jsonschema (>=4)", "mypy (>=1.14.1)", "nodeenv (>=1.9.1)", "packaging (>=25)", "pre-commit (>=3.5)", "pytest (>=8.3.5)", "pytest-cov (>=5)", "rich-codex (>=1.2.11)", "ruff (>=0.12.4)", "typer (>=0.15)", "types-setuptools (>=75.8.0.20250110)"] -docs = ["markdown-include (>=0.8.1)", "mike (>=2.1.3)", "mkdocs-github-admonitions-plugin (>=0.1.1)", "mkdocs-glightbox (>=0.4)", "mkdocs-include-markdown-plugin (>=7.1.7)", "mkdocs-material-extensions (>=1.3.1)", "mkdocs-material[imaging] (>=9.5.18,<9.6.0)", "mkdocs-redirects (>=1.2.2)", "mkdocs-rss-plugin (>=1.15)", "mkdocs[docs] (>=1.6.1)", "mkdocstrings[python] (>=0.26.1)", "rich-codex (>=1.2.11)", "typer (>=0.15)"] +docs = ["markdown-include (>=0.8.1)", "mike (>=2.1.3)", "mkdocs-github-admonitions-plugin (>=0.1.1)", "mkdocs-glightbox (>=0.4)", "mkdocs-include-markdown-plugin (>=7.1.7) ; python_version >= \"3.9\"", "mkdocs-material-extensions (>=1.3.1)", "mkdocs-material[imaging] (>=9.5.18,<9.6.0)", "mkdocs-redirects (>=1.2.2)", "mkdocs-rss-plugin (>=1.15)", "mkdocs[docs] (>=1.6.1)", "mkdocstrings[python] (>=0.26.1)", "rich-codex (>=1.2.11)", "typer (>=0.15)"] + +[[package]] +name = "roman-numerals" +version = "4.1.0" +description = "Manipulate well-formed Roman numerals" +optional = false +python-versions = ">=3.10" +groups = ["docs"] +markers = "python_version >= \"3.11\"" +files = [ + {file = "roman_numerals-4.1.0-py3-none-any.whl", hash = "sha256:647ba99caddc2cc1e55a51e4360689115551bf4476d90e8162cf8c345fe233c7"}, + {file = "roman_numerals-4.1.0.tar.gz", hash = "sha256:1af8b147eb1405d5839e78aeb93131690495fe9da5c91856cb33ad55a7f1e5b2"}, +] + +[[package]] +name = "roman-numerals-py" +version = "4.1.0" +description = "This package is deprecated, switch to roman-numerals." +optional = false +python-versions = ">=3.10" +groups = ["docs"] +markers = "python_version >= \"3.11\"" +files = [ + {file = "roman_numerals_py-4.1.0-py3-none-any.whl", hash = "sha256:553114c1167141c1283a51743759723ecd05604a1b6b507225e91dc1a6df0780"}, + {file = "roman_numerals_py-4.1.0.tar.gz", hash = "sha256:f5d7b2b4ca52dd855ef7ab8eb3590f428c0b1ea480736ce32b01fef2a5f8daf9"}, +] + +[package.dependencies] +roman-numerals = "4.1.0" [[package]] name = "rpds-py" @@ -2335,6 +2535,7 @@ version = "0.30.0" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.10" +groups = ["docs"] files = [ {file = "rpds_py-0.30.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:679ae98e00c0e8d68a7fda324e16b90fd5260945b45d3b824c892cec9eea3288"}, {file = "rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cc2206b76b4f576934f0ed374b10d7ca5f457858b157ca52064bdfc26b9fc00"}, @@ -2459,6 +2660,7 @@ version = "0.19.1" description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "ruamel_yaml-0.19.1-py3-none-any.whl", hash = "sha256:27592957fedf6e0b62f281e96effd28043345e0e66001f97683aa9a40c667c93"}, {file = "ruamel_yaml-0.19.1.tar.gz", hash = "sha256:53eb66cd27849eff968ebf8f0bf61f46cdac2da1d1f3576dd4ccee9b25c31993"}, @@ -2467,8 +2669,8 @@ files = [ [package.extras] docs = ["mercurial (>5.7)", "ryd"] jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] -libyaml = ["ruamel.yaml.clibz (>=0.3.7)"] -oldlibyaml = ["ruamel.yaml.clib"] +libyaml = ["ruamel.yaml.clibz (>=0.3.7) ; platform_python_implementation == \"CPython\""] +oldlibyaml = ["ruamel.yaml.clib ; platform_python_implementation == \"CPython\""] [[package]] name = "six" @@ -2476,6 +2678,7 @@ version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["dev", "docs"] files = [ {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, @@ -2487,6 +2690,7 @@ version = "3.0.1" description = "This package provides 32 stemmers for 30 languages generated from Snowball algorithms." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*" +groups = ["docs"] files = [ {file = "snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064"}, {file = "snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895"}, @@ -2494,13 +2698,14 @@ files = [ [[package]] name = "soupsieve" -version = "2.8.1" +version = "2.8.3" description = "A modern CSS selector implementation for Beautiful Soup." optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ - {file = "soupsieve-2.8.1-py3-none-any.whl", hash = "sha256:a11fe2a6f3d76ab3cf2de04eb339c1be5b506a8a47f2ceb6d139803177f85434"}, - {file = "soupsieve-2.8.1.tar.gz", hash = "sha256:4cf733bc50fa805f5df4b8ef4740fc0e0fa6218cf3006269afd3f9d6d80fd350"}, + {file = "soupsieve-2.8.3-py3-none-any.whl", hash = "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95"}, + {file = "soupsieve-2.8.3.tar.gz", hash = "sha256:3267f1eeea4251fb42728b6dfb746edc9acaffc4a45b27e19450b676586e8349"}, ] [[package]] @@ -2509,6 +2714,8 @@ version = "8.1.3" description = "Python documentation generator" optional = false python-versions = ">=3.10" +groups = ["docs"] +markers = "python_version == \"3.10\"" files = [ {file = "sphinx-8.1.3-py3-none-any.whl", hash = "sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2"}, {file = "sphinx-8.1.3.tar.gz", hash = "sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927"}, @@ -2538,12 +2745,51 @@ docs = ["sphinxcontrib-websupport"] lint = ["flake8 (>=6.0)", "mypy (==1.11.1)", "pyright (==1.1.384)", "pytest (>=6.0)", "ruff (==0.6.9)", "sphinx-lint (>=0.9)", "tomli (>=2)", "types-Pillow (==10.2.0.20240822)", "types-Pygments (==2.18.0.20240506)", "types-colorama (==0.4.15.20240311)", "types-defusedxml (==0.7.0.20240218)", "types-docutils (==0.21.0.20241005)", "types-requests (==2.32.0.20240914)", "types-urllib3 (==1.26.25.14)"] test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=8.0)", "setuptools (>=70.0)", "typing_extensions (>=4.9)"] +[[package]] +name = "sphinx" +version = "8.2.3" +description = "Python documentation generator" +optional = false +python-versions = ">=3.11" +groups = ["docs"] +markers = "python_version >= \"3.11\"" +files = [ + {file = "sphinx-8.2.3-py3-none-any.whl", hash = "sha256:4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3"}, + {file = "sphinx-8.2.3.tar.gz", hash = "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348"}, +] + +[package.dependencies] +alabaster = ">=0.7.14" +babel = ">=2.13" +colorama = {version = ">=0.4.6", markers = "sys_platform == \"win32\""} +docutils = ">=0.20,<0.22" +imagesize = ">=1.3" +Jinja2 = ">=3.1" +packaging = ">=23.0" +Pygments = ">=2.17" +requests = ">=2.30.0" +roman-numerals-py = ">=1.0.0" +snowballstemmer = ">=2.2" +sphinxcontrib-applehelp = ">=1.0.7" +sphinxcontrib-devhelp = ">=1.0.6" +sphinxcontrib-htmlhelp = ">=2.0.6" +sphinxcontrib-jsmath = ">=1.0.1" +sphinxcontrib-qthelp = ">=1.0.6" +sphinxcontrib-serializinghtml = ">=1.1.9" + +[package.extras] +docs = ["sphinxcontrib-websupport"] +lint = ["betterproto (==2.0.0b6)", "mypy (==1.15.0)", "pypi-attestations (==0.0.21)", "pyright (==1.1.395)", "pytest (>=8.0)", "ruff (==0.9.9)", "sphinx-lint (>=0.9)", "types-Pillow (==10.2.0.20240822)", "types-Pygments (==2.19.0.20250219)", "types-colorama (==0.4.15.20240311)", "types-defusedxml (==0.7.0.20240218)", "types-docutils (==0.21.0.20241128)", "types-requests (==2.32.0.20241016)", "types-urllib3 (==1.26.25.14)"] +test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=8.0)", "pytest-xdist[psutil] (>=3.4)", "setuptools (>=70.0)", "typing_extensions (>=4.9)"] + [[package]] name = "sphinx-autodoc-typehints" version = "3.0.1" description = "Type hints (PEP 484) support for the Sphinx autodoc extension" optional = false python-versions = ">=3.10" +groups = ["docs"] +markers = "python_version == \"3.10\"" files = [ {file = "sphinx_autodoc_typehints-3.0.1-py3-none-any.whl", hash = "sha256:4b64b676a14b5b79cefb6628a6dc8070e320d4963e8ff640a2f3e9390ae9045a"}, {file = "sphinx_autodoc_typehints-3.0.1.tar.gz", hash = "sha256:b9b40dd15dee54f6f810c924f863f9cf1c54f9f3265c495140ea01be7f44fa55"}, @@ -2556,12 +2802,33 @@ sphinx = ">=8.1.3" docs = ["furo (>=2024.8.6)"] testing = ["covdefaults (>=2.3)", "coverage (>=7.6.10)", "defusedxml (>=0.7.1)", "diff-cover (>=9.2.1)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "sphobjinv (>=2.3.1.2)", "typing-extensions (>=4.12.2)"] +[[package]] +name = "sphinx-autodoc-typehints" +version = "3.5.2" +description = "Type hints (PEP 484) support for the Sphinx autodoc extension" +optional = false +python-versions = ">=3.11" +groups = ["docs"] +markers = "python_version >= \"3.11\"" +files = [ + {file = "sphinx_autodoc_typehints-3.5.2-py3-none-any.whl", hash = "sha256:0accd043619f53c86705958e323b419e41667917045ac9215d7be1b493648d8c"}, + {file = "sphinx_autodoc_typehints-3.5.2.tar.gz", hash = "sha256:5fcd4a3eb7aa89424c1e2e32bedca66edc38367569c9169a80f4b3e934171fdb"}, +] + +[package.dependencies] +sphinx = ">=8.2.3" + +[package.extras] +docs = ["furo (>=2025.9.25)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.10.7)", "defusedxml (>=0.7.1)", "diff-cover (>=9.7.1)", "pytest (>=8.4.2)", "pytest-cov (>=7)", "sphobjinv (>=2.3.1.3)", "typing-extensions (>=4.15)"] + [[package]] name = "sphinx-copybutton" version = "0.5.2" description = "Add a copy button to each of your code cells." optional = false python-versions = ">=3.7" +groups = ["docs"] files = [ {file = "sphinx-copybutton-0.5.2.tar.gz", hash = "sha256:4cf17c82fb9646d1bc9ca92ac280813a3b605d8c421225fd9913154103ee1fbd"}, {file = "sphinx_copybutton-0.5.2-py3-none-any.whl", hash = "sha256:fb543fd386d917746c9a2c50360c7905b605726b9355cd26e9974857afeae06e"}, @@ -2580,6 +2847,7 @@ version = "0.4.1" description = "Patches Jinja2 v3 to restore compatibility with earlier Sphinx versions." optional = false python-versions = ">=3.6" +groups = ["docs"] files = [ {file = "sphinx_jinja2_compat-0.4.1-py3-none-any.whl", hash = "sha256:64ca0d46f0d8029fbe69ea612793a55e6ef0113e1bba4a85d402158c09f17a14"}, {file = "sphinx_jinja2_compat-0.4.1.tar.gz", hash = "sha256:0188f0802d42c3da72997533b55a00815659a78d3f81d4b4747b1fb15a5728e6"}, @@ -2596,6 +2864,8 @@ version = "1.9.0" description = "Sphinx directive to add unselectable prompt" optional = false python-versions = ">=3.10" +groups = ["docs"] +markers = "python_version == \"3.10\"" files = [ {file = "sphinx_prompt-1.9.0-py3-none-any.whl", hash = "sha256:fd731446c03f043d1ff6df9f22414495b23067c67011cc21658ea8d36b3575fc"}, {file = "sphinx_prompt-1.9.0.tar.gz", hash = "sha256:471b3c6d466dce780a9b167d9541865fd4e9a80ed46e31b06a52a0529ae995a1"}, @@ -2609,20 +2879,44 @@ pygments = "*" Sphinx = ">=8.0.0,<9.0.0" urllib3 = "*" +[[package]] +name = "sphinx-prompt" +version = "1.10.2" +description = "Sphinx directive to add unselectable prompt" +optional = false +python-versions = ">=3.11" +groups = ["docs"] +markers = "python_version >= \"3.11\"" +files = [ + {file = "sphinx_prompt-1.10.2-py3-none-any.whl", hash = "sha256:6594337962c4b1498602e6984634bed4a0dc7955852e3cfc255eb0af766ed859"}, + {file = "sphinx_prompt-1.10.2.tar.gz", hash = "sha256:47b592ba75caebd044b0eddf7a5a1b6e0aef6df587b034377cd101a999b686ba"}, +] + +[package.dependencies] +certifi = "*" +docutils = "*" +idna = "*" +jinja2 = "*" +pygments = "*" +requests = ">=2.32.4" +Sphinx = "*" +urllib3 = "*" + [[package]] name = "sphinx-rtd-theme" -version = "3.0.2" +version = "3.1.0" description = "Read the Docs theme for Sphinx" optional = false python-versions = ">=3.8" +groups = ["docs"] files = [ - {file = "sphinx_rtd_theme-3.0.2-py2.py3-none-any.whl", hash = "sha256:422ccc750c3a3a311de4ae327e82affdaf59eb695ba4936538552f3b00f4ee13"}, - {file = "sphinx_rtd_theme-3.0.2.tar.gz", hash = "sha256:b7457bc25dda723b20b086a670b9953c859eab60a2a03ee8eb2bb23e176e5f85"}, + {file = "sphinx_rtd_theme-3.1.0-py2.py3-none-any.whl", hash = "sha256:1785824ae8e6632060490f67cf3a72d404a85d2d9fc26bce3619944de5682b89"}, + {file = "sphinx_rtd_theme-3.1.0.tar.gz", hash = "sha256:b44276f2c276e909239a4f6c955aa667aaafeb78597923b1c60babc76db78e4c"}, ] [package.dependencies] -docutils = ">0.18,<0.22" -sphinx = ">=6,<9" +docutils = ">0.18,<0.23" +sphinx = ">=6,<10" sphinxcontrib-jquery = ">=4,<5" [package.extras] @@ -2634,6 +2928,7 @@ version = "3.4.5" description = "Tabbed views for Sphinx" optional = false python-versions = "~=3.7" +groups = ["docs"] files = [ {file = "sphinx-tabs-3.4.5.tar.gz", hash = "sha256:ba9d0c1e3e37aaadd4b5678449eb08176770e0fc227e769b6ce747df3ceea531"}, {file = "sphinx_tabs-3.4.5-py3-none-any.whl", hash = "sha256:92cc9473e2ecf1828ca3f6617d0efc0aa8acb06b08c56ba29d1413f2f0f6cf09"}, @@ -2654,6 +2949,7 @@ version = "3.10.0" description = "Box of handy tools for Sphinx 🧰 📔" optional = false python-versions = ">=3.7" +groups = ["docs"] files = [ {file = "sphinx_toolbox-3.10.0-py3-none-any.whl", hash = "sha256:675e5978eaee31adf21701054fa75bacf820459d56e93ac30ad01eaee047a6ef"}, {file = "sphinx_toolbox-3.10.0.tar.gz", hash = "sha256:6afea9ac9afabe76bd5bd4d2b01edfdad81d653a1a34768e776e6a56d5a6f572"}, @@ -2688,6 +2984,7 @@ version = "2.0.0" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5"}, {file = "sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1"}, @@ -2704,6 +3001,7 @@ version = "2.0.0" description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2"}, {file = "sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad"}, @@ -2720,6 +3018,7 @@ version = "2.1.0" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8"}, {file = "sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9"}, @@ -2736,6 +3035,7 @@ version = "4.1" description = "Extension to include jQuery on newer Sphinx releases" optional = false python-versions = ">=2.7" +groups = ["docs"] files = [ {file = "sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a"}, {file = "sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae"}, @@ -2750,6 +3050,7 @@ version = "1.0.1" description = "A sphinx extension which renders display math in HTML via JavaScript" optional = false python-versions = ">=3.5" +groups = ["docs"] files = [ {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, @@ -2764,6 +3065,7 @@ version = "2.0.0" description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb"}, {file = "sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab"}, @@ -2780,6 +3082,7 @@ version = "2.0.0" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331"}, {file = "sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d"}, @@ -2796,6 +3099,7 @@ version = "0.6.3" description = "Extract data from python stack frames and tracebacks for informative displays" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, @@ -2815,6 +3119,8 @@ version = "3.10.14" description = "Standard library imghdr redistribution. \"dead battery\"." optional = false python-versions = "*" +groups = ["docs"] +markers = "python_version >= \"3.13\"" files = [ {file = "standard_imghdr-3.10.14-py3-none-any.whl", hash = "sha256:cdf6883163349624dee9a81d2853a20260337c4cd41c04e99c082e01833a08e2"}, {file = "standard_imghdr-3.10.14.tar.gz", hash = "sha256:2598fe2e7c540dbda34b233295e10957ab8dc8ac6f3bd9eaa8d38be167232e52"}, @@ -2826,6 +3132,7 @@ version = "0.9.0" description = "Pretty-print tabular data" optional = false python-versions = ">=3.7" +groups = ["docs"] files = [ {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, @@ -2840,6 +3147,7 @@ version = "1.4.0" description = "A tiny CSS parser" optional = false python-versions = ">=3.8" +groups = ["docs"] files = [ {file = "tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289"}, {file = "tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7"}, @@ -2858,6 +3166,7 @@ version = "0.10.2" description = "Python Library for Tom's Obvious, Minimal Language" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +groups = ["main"] files = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, @@ -2865,64 +3174,72 @@ files = [ [[package]] name = "tomli" -version = "2.3.0" +version = "2.4.0" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" -files = [ - {file = "tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45"}, - {file = "tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba"}, - {file = "tomli-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf"}, - {file = "tomli-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441"}, - {file = "tomli-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845"}, - {file = "tomli-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c"}, - {file = "tomli-2.3.0-cp311-cp311-win32.whl", hash = "sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456"}, - {file = "tomli-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be"}, - {file = "tomli-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac"}, - {file = "tomli-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22"}, - {file = "tomli-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f"}, - {file = "tomli-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52"}, - {file = "tomli-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8"}, - {file = "tomli-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6"}, - {file = "tomli-2.3.0-cp312-cp312-win32.whl", hash = "sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876"}, - {file = "tomli-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878"}, - {file = "tomli-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b"}, - {file = "tomli-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae"}, - {file = "tomli-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b"}, - {file = "tomli-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf"}, - {file = "tomli-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f"}, - {file = "tomli-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05"}, - {file = "tomli-2.3.0-cp313-cp313-win32.whl", hash = "sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606"}, - {file = "tomli-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999"}, - {file = "tomli-2.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e"}, - {file = "tomli-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3"}, - {file = "tomli-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc"}, - {file = "tomli-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0"}, - {file = "tomli-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879"}, - {file = "tomli-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005"}, - {file = "tomli-2.3.0-cp314-cp314-win32.whl", hash = "sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463"}, - {file = "tomli-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8"}, - {file = "tomli-2.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77"}, - {file = "tomli-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf"}, - {file = "tomli-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530"}, - {file = "tomli-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b"}, - {file = "tomli-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67"}, - {file = "tomli-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f"}, - {file = "tomli-2.3.0-cp314-cp314t-win32.whl", hash = "sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0"}, - {file = "tomli-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba"}, - {file = "tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b"}, - {file = "tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549"}, +groups = ["dev", "docs", "test"] +markers = "python_version == \"3.10\"" +files = [ + {file = "tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867"}, + {file = "tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9"}, + {file = "tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95"}, + {file = "tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76"}, + {file = "tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d"}, + {file = "tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576"}, + {file = "tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a"}, + {file = "tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa"}, + {file = "tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614"}, + {file = "tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1"}, + {file = "tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8"}, + {file = "tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a"}, + {file = "tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1"}, + {file = "tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b"}, + {file = "tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51"}, + {file = "tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729"}, + {file = "tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da"}, + {file = "tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3"}, + {file = "tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0"}, + {file = "tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e"}, + {file = "tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4"}, + {file = "tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e"}, + {file = "tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c"}, + {file = "tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f"}, + {file = "tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86"}, + {file = "tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87"}, + {file = "tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132"}, + {file = "tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6"}, + {file = "tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc"}, + {file = "tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66"}, + {file = "tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d"}, + {file = "tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702"}, + {file = "tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8"}, + {file = "tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776"}, + {file = "tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475"}, + {file = "tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2"}, + {file = "tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9"}, + {file = "tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0"}, + {file = "tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df"}, + {file = "tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d"}, + {file = "tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f"}, + {file = "tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b"}, + {file = "tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087"}, + {file = "tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd"}, + {file = "tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4"}, + {file = "tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a"}, + {file = "tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c"}, ] [[package]] name = "tomlkit" -version = "0.13.3" +version = "0.14.0" description = "Style preserving TOML library" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" +groups = ["dev"] files = [ - {file = "tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0"}, - {file = "tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1"}, + {file = "tomlkit-0.14.0-py3-none-any.whl", hash = "sha256:592064ed85b40fa213469f81ac584f67a4f2992509a7c3ea2d632208623a3680"}, + {file = "tomlkit-0.14.0.tar.gz", hash = "sha256:cf00efca415dbd57575befb1f6634c4f42d2d87dbba376128adb42c121b87064"}, ] [[package]] @@ -2931,6 +3248,7 @@ version = "6.5.4" description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." optional = false python-versions = ">=3.9" +groups = ["dev", "docs"] files = [ {file = "tornado-6.5.4-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d6241c1a16b1c9e4cc28148b1cda97dd1c6cb4fb7068ac1bedc610768dff0ba9"}, {file = "tornado-6.5.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2d50f63dda1d2cac3ae1fa23d254e16b5e38153758470e9956cbc3d813d40843"}, @@ -2952,6 +3270,7 @@ version = "5.14.3" description = "Traitlets Python configuration system" optional = false python-versions = ">=3.8" +groups = ["dev", "docs"] files = [ {file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"}, {file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"}, @@ -2967,28 +3286,31 @@ version = "4.15.0" description = "Backported and Experimental Type Hints for Python 3.9+" optional = false python-versions = ">=3.9" +groups = ["main", "dev", "docs", "test"] files = [ {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, ] +markers = {dev = "python_version < \"3.12\"", test = "python_version == \"3.10\""} [[package]] name = "typos" -version = "1.41.0" +version = "1.43.5" description = "Source Code Spelling Correction" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "typos-1.41.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a8cd95a79ea62c88245ffb93cf299e0ce2bb7c11752128817e94bd0e2cdbca4d"}, - {file = "typos-1.41.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:027c6b40e2240a948f5dc7ae9d24314290242c4deece68e5f93ed3653c811b22"}, - {file = "typos-1.41.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce42b79d949a7cc5bf428835b0cf7f9ff1f2c3cf995bfc16a257a586ab38b7b2"}, - {file = "typos-1.41.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6699920644bae8f4fd048bb4b3787f24fc9f2a4cec624ef1f89e29a0c3fe9cc1"}, - {file = "typos-1.41.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb46a5f39264c5df3d6db3e2d03df115121543f6479c0909fff6eedb3a6f9036"}, - {file = "typos-1.41.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:db893e3bfb960a0b148e59fa23764a8ecb9e3efcb39c7d96136bb0540d9331f9"}, - {file = "typos-1.41.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:bf576832c53017db5ccddf5ede64e4cc0aea516a7fe618970f6eaaf5d81230ea"}, - {file = "typos-1.41.0-py3-none-win32.whl", hash = "sha256:21c38ab788a8731c7df630497acaafcf8d83b16a540094728d7c30800b610c7e"}, - {file = "typos-1.41.0-py3-none-win_amd64.whl", hash = "sha256:186b0e3bc3f87f8be352df9834d887c16b763f27eb15149f1c9633413459b1f0"}, - {file = "typos-1.41.0.tar.gz", hash = "sha256:771087bd8c145f197f9d7edd320b5cb3dc9a957e15e5d679563f346aa0503396"}, + {file = "typos-1.43.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:733221c09d6914c001d2ac16f630773dc36ff384df9ab128c9e93b019eeedf2f"}, + {file = "typos-1.43.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b1d2f86b458917fdc91b89f47101498adc7338361e1ed0bed6e4325d0e674aca"}, + {file = "typos-1.43.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d75091c9519224f2f74964b6ca5133abfba9be44ce49f12a981e27c29bcef97"}, + {file = "typos-1.43.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:839dfa2bc802b02460097b21f7d93d0fa87d5f76adb83049072211a7279f5ebe"}, + {file = "typos-1.43.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0825a4d77d66726e86fac03c6cf2efc11b0a5c112b2156dcaeb61a24a807166"}, + {file = "typos-1.43.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7ee0a71ac21820868686ad52cb26a3e08197b09ceedf04d1736cb8472061665b"}, + {file = "typos-1.43.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:09615c8f64e656940533aa025a9e8dc5c93e5cf6bfbedb059cdcafde75cb6d72"}, + {file = "typos-1.43.5-py3-none-win32.whl", hash = "sha256:4c865b1b6149acbdaed9d548282ccfad526e1380de19d189e7ac675cd4869156"}, + {file = "typos-1.43.5-py3-none-win_amd64.whl", hash = "sha256:10009e9a3702da037803b075efc94fa5328bd93af357fb6a2f284c0dbcc77f30"}, + {file = "typos-1.43.5.tar.gz", hash = "sha256:aa445c5eaf0e32095c3183dda96e0fa8ffcabbfd796721c75d7a8a68e9cd0d75"}, ] [[package]] @@ -2997,6 +3319,7 @@ version = "2.2.1" description = "URL normalization for Python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "url_normalize-2.2.1-py3-none-any.whl", hash = "sha256:3deb687587dc91f7b25c9ae5162ffc0f057ae85d22b1e15cf5698311247f567b"}, {file = "url_normalize-2.2.1.tar.gz", hash = "sha256:74a540a3b6eba1d95bdc610c24f2c0141639f3ba903501e61a52a8730247ff37"}, @@ -3010,30 +3333,32 @@ dev = ["mypy", "pre-commit", "pytest", "pytest-cov", "pytest-socket", "ruff"] [[package]] name = "urllib3" -version = "2.6.2" +version = "2.6.3" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" +groups = ["main", "docs"] files = [ - {file = "urllib3-2.6.2-py3-none-any.whl", hash = "sha256:ec21cddfe7724fc7cb4ba4bea7aa8e2ef36f607a4bab81aa6ce42a13dc3f03dd"}, - {file = "urllib3-2.6.2.tar.gz", hash = "sha256:016f9c98bb7e98085cb2b4b17b87d2c702975664e4f060c6532e64d1c1a5e797"}, + {file = "urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4"}, + {file = "urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed"}, ] [package.extras] -brotli = ["brotli (>=1.2.0)", "brotlicffi (>=1.2.0.0)"] +brotli = ["brotli (>=1.2.0) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=1.2.0.0) ; platform_python_implementation != \"CPython\""] h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["backports-zstd (>=1.0.0)"] +zstd = ["backports-zstd (>=1.0.0) ; python_version < \"3.14\""] [[package]] name = "wcwidth" -version = "0.2.14" +version = "0.6.0" description = "Measures the displayed width of unicode strings in a terminal" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" +groups = ["main", "dev"] files = [ - {file = "wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1"}, - {file = "wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605"}, + {file = "wcwidth-0.6.0-py3-none-any.whl", hash = "sha256:1a3a1e510b553315f8e146c54764f4fb6264ffad731b3d78088cdb1478ffbdad"}, + {file = "wcwidth-0.6.0.tar.gz", hash = "sha256:cdc4e4262d6ef9a1a57e018384cbeb1208d8abbc64176027e2c2455c81313159"}, ] [[package]] @@ -3042,6 +3367,7 @@ version = "0.5.1" description = "Character encoding aliases for legacy web content" optional = false python-versions = "*" +groups = ["docs"] files = [ {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, @@ -3053,13 +3379,15 @@ version = "3.23.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.9" +groups = ["main"] +markers = "python_version < \"3.12\"" files = [ {file = "zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e"}, {file = "zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166"}, ] [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] enabler = ["pytest-enabler (>=2.2)"] @@ -3067,6 +3395,6 @@ test = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more_it type = ["pytest-mypy"] [metadata] -lock-version = "2.0" +lock-version = "2.1" python-versions = ">=3.10,<4.0" -content-hash = "46fce423df46d196b232ddd18b8fec414fd797b9bd4d9bf7aae6a3505d0354b3" +content-hash = "8bc0729ff37fdf976143c55e5be984ea8db53fc34d80c7cbacb4a2cb154dd67a" diff --git a/pyproject.toml b/pyproject.toml index 7ef29168..e41b35a9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "roc-validator" -version = "0.8.0" +version = "0.8.1" description = "A Python package to validate RO-Crates" authors = [ "Marco Enrico Piras ", @@ -60,7 +60,7 @@ include = [ [tool.poetry.dependencies] python = ">=3.10,<4.0" rdflib = ">=7.1,<8.0" -pyshacl = ">=0.26,<0.31" +pyshacl = ">=0.26" click = ">=8.2,<9.0" rich = ">=13.9,<14.0" toml = ">=0.10.2,<1.0" @@ -106,9 +106,17 @@ skip_dirs = [".git", ".github", ".vscode"] [tool.pytest.ini_options] testpaths = ["tests"] +filterwarnings = [ + # Ignore deprecation warnings from rdflib's JSON-LD parser, + # used internally by pyshacl. These warnings are unrelated to + # our code and currently noisy. + # See: https://github.com/RDFLib/rdflib/issues/3064 + # Fix in progress: https://github.com/RDFLib/rdflib/issues/3302 + "ignore::DeprecationWarning:rdflib.plugins.parsers.jsonld", +] [tool.typos.files] -extend-exclude = ["tests/data","docs/diagrams","*.json","*.html","*__init__.py"] +extend-exclude = ["tests/data", "docs/diagrams", "*.json", "*.html", "*__init__.py"] [tool.typos.default.extend-words] TRE = "TRE" diff --git a/pytest.ini b/pytest.ini index fc982742..4aff318a 100644 --- a/pytest.ini +++ b/pytest.ini @@ -17,4 +17,10 @@ ; log_cli=true ; log_level=DEBUG addopts = -n auto -; filterwarnings = +filterwarnings = + # Ignore deprecation warnings from rdflib's JSON-LD parser, + # used internally by pyshacl. These warnings are unrelated to + # our code and currently noisy. + # See: https://github.com/RDFLib/rdflib/issues/3064 + # Fix in progress: https://github.com/RDFLib/rdflib/issues/3302 + ignore::DeprecationWarning:rdflib.plugins.parsers.jsonld diff --git a/rocrate_validator/cli/commands/validate.py b/rocrate_validator/cli/commands/validate.py index 46a55008..fac40d47 100644 --- a/rocrate_validator/cli/commands/validate.py +++ b/rocrate_validator/cli/commands/validate.py @@ -16,6 +16,7 @@ import os import sys +from contextlib import nullcontext from pathlib import Path from typing import Optional @@ -276,7 +277,7 @@ def validate(ctx, "profile_identifier": profile_identifier, "requirement_severity": requirement_severity, "requirement_severity_only": requirement_severity_only, - "enable_profile_inheritance": not disable_profile_inheritance, + "disable_inherited_profiles_issue_reporting": disable_profile_inheritance, "rocrate_uri": rocrate_uri, "rocrate_relative_root_path": relative_root_path, "abort_on_first": fail_fast, @@ -472,7 +473,7 @@ def validate(ctx, console.print(f"\n{' '*2}📋 [bold]The validation report in JSON format: [/bold]\n") # Generate the JSON output and write it to the specified output file or to stdout - with open(output_file, "w", encoding="utf-8") if output_file else sys.stdout as f: + with open(output_file, "w", encoding="utf-8") if output_file else nullcontext(sys.stdout) as f: out = Console(width=output_line_width, file=f) out.register_formatter(JSONOutputFormatter()) out.print(results) diff --git a/rocrate_validator/cli/main.py b/rocrate_validator/cli/main.py index f6ef16c9..e42097f9 100644 --- a/rocrate_validator/cli/main.py +++ b/rocrate_validator/cli/main.py @@ -29,7 +29,7 @@ @click.group(invoke_without_command=True) -@click.rich_config(help_config=click.RichHelpConfiguration(use_rich_markup=True)) +@click.rich_config(help_config=click.RichHelpConfiguration(text_markup="rich")) @click.option( '--debug', is_flag=True, diff --git a/rocrate_validator/models.py b/rocrate_validator/models.py index 82d77b8e..6fbd446c 100644 --- a/rocrate_validator/models.py +++ b/rocrate_validator/models.py @@ -1007,26 +1007,43 @@ def _do_validate_(self, context: ValidationContext) -> bool: logger.debug("Running %s checks for Requirement '%s'", len(self._checks), self.name) all_passed = True - for check in [_ for _ in self._checks - if not context.settings.skip_checks - or _.identifier not in context.settings.skip_checks]: - + checks_to_perform = [ + _ for _ in self._checks + if not context.settings.skip_checks + or _.identifier not in context.settings.skip_checks + ] + for check in checks_to_perform: try: if check.overridden and not check.requirement.profile.identifier == context.profile_identifier: logger.debug("Skipping check '%s' because overridden by '%r'", check.identifier, [_.identifier for _ in check.overridden_by]) continue - context.validator.notify(RequirementCheckValidationEvent( - EventType.REQUIREMENT_CHECK_VALIDATION_START, check)) + # Determine whether to skip event notification for inherited profiles + skip_event_notify = False + if check.requirement.profile.identifier != context.profile_identifier and \ + context.settings.disable_inherited_profiles_issue_reporting: + logger.debug("Inherited profiles reporting disabled. " + "Skipping requirement %s as it belongs to an inherited profile %s", + check.requirement.identifier, check.requirement.profile.identifier) + skip_event_notify = True + # Notify the start of the check execution if not skip_event_notify is set to True + if not skip_event_notify: + context.validator.notify(RequirementCheckValidationEvent( + EventType.REQUIREMENT_CHECK_VALIDATION_START, check)) + # Execute the check check_result = check.execute_check(context) logger.debug("Result of check %s: %s", check.identifier, check_result) context.result._add_executed_check(check, check_result) - context.validator.notify(RequirementCheckValidationEvent( - EventType.REQUIREMENT_CHECK_VALIDATION_END, check, validation_result=check_result)) + # Notify the end of the check execution if not skip_event_notify is set to True + if not skip_event_notify: + context.validator.notify(RequirementCheckValidationEvent( + EventType.REQUIREMENT_CHECK_VALIDATION_END, check, validation_result=check_result)) logger.debug("Ran check '%s'. Got result %s", check.identifier, check_result) + # Ensure the check result is a boolean if not isinstance(check_result, bool): logger.warning("Ignoring the check %s as it returned the value %r instead of a boolean", check.name) raise RuntimeError(f"Ignoring invalid result from check {check.name}") + # Aggregate the check result all_passed = all_passed and check_result if not all_passed and context.fail_fast: break @@ -1040,7 +1057,8 @@ def _do_validate_(self, context: ValidationContext) -> bool: logger.warning("Consider reporting this as a bug.") if logger.isEnabledFor(logging.DEBUG): logger.exception(e) - + skipped_checks = set(self._checks) - set(checks_to_perform) + context.result.skipped_checks.update(skipped_checks) logger.debug("Checks for Requirement '%s' completed. Checks passed? %s", self.name, all_passed) return all_passed @@ -1625,7 +1643,7 @@ def __initialise__(cls, validation_settings: ValidationSettings): profiles = [profile] # add inherited profiles if enabled - if validation_settings.enable_profile_inheritance: + if not validation_settings.disable_inherited_profiles_issue_reporting: profiles.extend(profile.inherited_profiles) logger.debug("Inherited profiles: %r", profile.inherited_profiles) @@ -1656,9 +1674,20 @@ def __initialise__(cls, validation_settings: ValidationSettings): if severity < severity_validation: continue # count the checks - requirement_checks = [_ for _ in requirement.get_checks_by_level(LevelCollection.get(severity.name)) - if not _.overridden or - _.requirement.profile.identifier == target_profile_identifier] + requirement_checks = [ + _ + for _ in requirement.get_checks_by_level( + LevelCollection.get(severity.name) + ) + if ( + not validation_settings.skip_checks + or _.identifier not in validation_settings.skip_checks + ) + and ( + not _.overridden + or _.requirement.profile.identifier == target_profile_identifier + ) + ] num_checks = len(requirement_checks) requirement_checks_count += num_checks if num_checks > 0: @@ -2325,12 +2354,20 @@ class ValidationSettings: #: The profile identifier to validate against profile_identifier: str = DEFAULT_PROFILE_IDENTIFIER #: Flag to enable profile inheritance + # Use the `enable_profile_inheritance` flag with caution: disable inheritance only if the + # target validation profile is fully self-contained and does not rely on definitions + # from inherited profiles (e.g., entities defined upstream). For modularization + # purposes, some base entities and properties are defined in the base RO-Crate + # profile and are intentionally not redefined in specialized profiles; they are + # required for validations targeting those specializations and therefore cannot be skipped. + # Nevertheless, the validator can still suppress issue reporting for checks defined + # in inherited profiles by setting disable_inherited_profiles_issue_reporting to `True`. enable_profile_inheritance: bool = True # Validation settings #: Flag to abort on first error abort_on_first: Optional[bool] = False - #: Flag to disable inherited profiles reporting - disable_inherited_profiles_reporting: bool = False + #: Flag to disable reporting of issues related to inherited profiles + disable_inherited_profiles_issue_reporting: bool = False #: Flag to disable remote crate download disable_remote_crate_download: bool = True # Requirement settings diff --git a/rocrate_validator/profiles/isa-ro-crate/0_investigation.ttl b/rocrate_validator/profiles/isa-ro-crate/0_investigation.ttl new file mode 100644 index 00000000..54b9f1f7 --- /dev/null +++ b/rocrate_validator/profiles/isa-ro-crate/0_investigation.ttl @@ -0,0 +1,136 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +@prefix ro: <./> . +@prefix ro-crate: . +@prefix isa-ro-crate: . +@prefix bioschemas: . +@prefix rdf: . +@prefix schema: . +@prefix sh: . +@prefix validator: . +@prefix xsd: . + +isa-ro-crate:RootDataEntityMustBeInvestigation a sh:NodeShape ; + sh:name "Root Data Entity must be Investigation" ; + sh:description "The root data entity must follow the investigation profile" ; + sh:targetClass ro-crate:RootDataEntity ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:additionalType ; + sh:minCount 1 ; + sh:hasValue "Investigation"; + sh:description "Check if the root data entity is specified as an investigation through additionalType" ; + sh:message "The root data entity must have additionalType of `Investigation`" ; + sh:severity sh:Violation ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:identifier ; + sh:minCount 1 ; + sh:datatype xsd:string ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check if the root data entity (investigation) has an identifier" ; + sh:message "The root data entity must have a non-empty identifier" ; + sh:severity sh:Violation ; + ] ; + # sh:property [ + # a sh:PropertyShape ; + # sh:path schema:name ; + # sh:minCount 1 ; + # sh:not [ + # sh:hasValue "" + # ] ; + # sh:description "Check if the root data entity (investigation) has a name" ; + # sh:message "The root data entity must have a non-empty name" ; + # sh:severity sh:Violation ; + # ] ; + # sh:property [ + # a sh:PropertyShape ; + # sh:path schema:description ; + # sh:minCount 1 ; + # sh:not [ + # sh:hasValue "" + # ] ; + # sh:description "Check if the root data entity (investigation) has a description" ; + # sh:message "The root data entity must have a non-empty description" ; + # sh:severity sh:Violation ; + # ] ; + # sh:property [ + # a sh:PropertyShape ; + # sh:path schema:license ; + # sh:minCount 1 ; + # sh:description "Check if the root data entity (investigation) specifies a license" ; + # sh:message "The root data entity must specify a license" ; + # sh:severity sh:Violation ; + # ] ; + # sh:property [ + # a sh:PropertyShape ; + # sh:path schema:datePublished ; + # sh:minCount 1 ; + # sh:nodeKind sh:Literal ; + # sh:pattern "^([\\+-]?\\d{4})((-?)((0[1-9]|1[0-2])(\\3([12]\\d|0[1-9]|3[01]))|W([0-4]\\d|5[0-2])(-?[1-7])|(00[1-9]|0[1-9]\\d|[12]\\d{2}|3([0-5]\\d|6[1-6])))([T\\s]((([01]\\d|2[0-3])((:?)?[0-5]\\d)?|24:?00)([\\.,]\\d+(?!:))?)?(\\17[0-5]\\d([\\.,]\\d+)?)?([zZ]|([\\+-])([01]\\d|2[0-3]):?([0-5]\\d)?)?)?)$" ; + # sh:description "Check if the root data entity (investigation) has a datePublished" ; + # sh:message "The root data entity must have a datePublished" ; + # sh:severity sh:Violation ; + # ] ; +. + +isa-ro-crate:InvestigationShouldHaveCreator a sh:NodeShape ; + sh:name "Investigation SHOULD have creator" ; + sh:description "An Investigation SHOULD have a creator" ; + sh:targetClass ro-crate:RootDataEntity ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:creator ; + sh:minCount 1 ; + sh:description "Check that investigation does have at least one creator" ; + sh:message "Investigation entity SHOULD have a creator" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:creator ; + sh:class schema:Person ; + sh:description "Check that if investigation does have at least one creator, it MUST be of type Person" ; + sh:message "Investigation creator MUST be of type Person" ; + sh:severity sh:Violation ; + ] +. + +isa-ro-crate:InvestigationShouldHaveDateCreated a sh:NodeShape ; + sh:name "Investigation SHOULD have dateCreated" ; + sh:description "An Investigation SHOULD have a dateCreated" ; + sh:targetClass ro-crate:RootDataEntity ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:dateCreated ; + sh:minCount 1 ; + sh:description "Check that investigation does have at least one dateCreated" ; + sh:message "Investigation entity SHOULD have a dateCreated" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:dateCreated ; + sh:nodeKind sh:Literal ; + sh:pattern "^([\\+-]?\\d{4})((-?)((0[1-9]|1[0-2])(\\3([12]\\d|0[1-9]|3[01]))|W([0-4]\\d|5[0-2])(-?[1-7])|(00[1-9]|0[1-9]\\d|[12]\\d{2}|3([0-5]\\d|6[1-6])))([T\\s]((([01]\\d|2[0-3])((:?)?[0-5]\\d)?|24:?00)([\\.,]\\d+(?!:))?)?(\\17[0-5]\\d([\\.,]\\d+)?)?([zZ]|([\\+-])([01]\\d|2[0-3]):?([0-5]\\d)?)?)?)$" ; + sh:description "Check that if investigation does have at least one dateCreated, it MUST be a valid ISO 8601 date." ; + sh:message "Investigation dateCreated MUST be a valid ISO 8601 date" ; + sh:severity sh:Violation ; + ] +. \ No newline at end of file diff --git a/rocrate_validator/profiles/isa-ro-crate/10_definedterm.ttl b/rocrate_validator/profiles/isa-ro-crate/10_definedterm.ttl new file mode 100644 index 00000000..e481ade1 --- /dev/null +++ b/rocrate_validator/profiles/isa-ro-crate/10_definedterm.ttl @@ -0,0 +1,70 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +@prefix ro: <./> . +@prefix ro-crate: . +@prefix isa-ro-crate: . +@prefix bioschemas: . +@prefix bioschemas-prop: . +@prefix rdf: . +@prefix schema: . +@prefix sh: . +@prefix validator: . +@prefix xsd: . + + +isa-ro-crate:DefinedTermMustHaveName a sh:NodeShape ; + sh:name "DefinedTerm MUST have a name" ; + sh:description "A DefinedTerm MUST have a name" ; + sh:targetClass schema:DefinedTerm ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:name ; + sh:datatype xsd:string ; + sh:minCount 1 ; + sh:maxCount 1 ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check that DefinedTerm does have non-empty name and it's a string" ; + sh:message "DefinedTerm entity MUST have a non-empty name of type string" ; + sh:severity sh:Violation ; + ] +. + +isa-ro-crate:DefinedTermShouldHaveTermCodeOfCorrectType a sh:NodeShape ; + sh:name "DefinedTerm SHOULD have termCode of correct type" ; + sh:description "A DefinedTerm SHOULD have at least one termCode of correct type" ; + sh:targetClass schema:DefinedTerm ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:termCode ; + sh:minCount 1 ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check that DefinedTerm does have at least one termCode" ; + sh:message "DefinedTerm entity SHOULD have at least one termCode" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:termCode ; + sh:datatype xsd:string ; + sh:description "The termCode of a DefinedTerm MUST be of type string" ; + sh:message "DefinedTerm termCode MUST be of type string" ; + sh:severity sh:Violation ; + ] +. \ No newline at end of file diff --git a/rocrate_validator/profiles/isa-ro-crate/11_propertyvalue.ttl b/rocrate_validator/profiles/isa-ro-crate/11_propertyvalue.ttl new file mode 100644 index 00000000..b0c8c990 --- /dev/null +++ b/rocrate_validator/profiles/isa-ro-crate/11_propertyvalue.ttl @@ -0,0 +1,133 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +@prefix ro: <./> . +@prefix ro-crate: . +@prefix isa-ro-crate: . +@prefix bioschemas: . +@prefix bioschemas-prop: . +@prefix rdf: . +@prefix schema: . +@prefix sh: . +@prefix validator: . +@prefix xsd: . + + +ro-crate:FindPropertyValueSubtypes a sh:NodeShape, validator:HiddenShape; + sh:name "Identify PropertyValue subtypes within the RO-Crate" ; + sh:description "A PropertyValue has type Parameter, Characteristic, Factor or Component if additionalType is set accordingly." ; + sh:targetClass schema:PropertyValue ; + # Expand data graph with triples from the file data entity + sh:rule [ + a sh:TripleRule ; + sh:subject sh:this ; + sh:predicate rdf:type ; + sh:object isa-ro-crate:Parameter ; + # The condition: additionalType == "Parameter" + sh:condition [ + sh:property [ + sh:path schema:additionalType ; + sh:hasValue "Parameter" ; + ] ; + ] ; + ] ; + sh:rule [ + a sh:TripleRule ; + sh:subject sh:this ; + sh:predicate rdf:type ; + sh:object isa-ro-crate:Characteristic ; + # The condition: additionalType == "Characteristic" + sh:condition [ + sh:property [ + sh:path schema:additionalType ; + sh:hasValue "Characteristic" ; + ] ; + ] ; + ] ; + sh:rule [ + a sh:TripleRule ; + sh:subject sh:this ; + sh:predicate rdf:type ; + sh:object isa-ro-crate:Factor ; + # The condition: additionalType == "Factor" + sh:condition [ + sh:property [ + sh:path schema:additionalType ; + sh:hasValue "Factor" ; + ] ; + ] ; + ] ; + sh:rule [ + a sh:TripleRule ; + sh:subject sh:this ; + sh:predicate rdf:type ; + sh:object isa-ro-crate:Component ; + # The condition: additionalType == "Component" + sh:condition [ + sh:property [ + sh:path schema:additionalType ; + sh:hasValue "Component" ; + ] ; + ] ; + ] +. + +isa-ro-crate:PropertyValueMustHaveName a sh:NodeShape ; + sh:name "PropertyValue MUST have a name" ; + sh:description "A PropertyValue MUST have a name" ; + sh:targetClass schema:PropertyValue ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:name ; + sh:datatype xsd:string ; + sh:minCount 1 ; + sh:maxCount 1 ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check that PropertyValue does have non-empty name and it's a string" ; + sh:message "PropertyValue entity MUST have a non-empty name of type string" ; + sh:severity sh:Violation ; + ] +. + +isa-ro-crate:PropertyValueShouldHaveValueOfCorrectType a sh:NodeShape ; + sh:name "PropertyValue SHOULD have value of correct type" ; + sh:description "A PropertyValue SHOULD have at least one value of correct type" ; + sh:targetClass schema:PropertyValue ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:value ; + sh:minCount 1 ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check that PropertyValue does have at least one value" ; + sh:message "PropertyValue entity SHOULD have at least one value" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:value ; + sh:or( + [ sh:datatype xsd:string ] + [ sh:datatype xsd:float ] + [ sh:datatype xsd:integer ] + ) ; + sh:description "The value of a PropertyValue MUST be of type string or a number" ; + sh:message "PropertyValue value MUST be of type string, float, or integer" ; + sh:severity sh:Violation ; + ] +. \ No newline at end of file diff --git a/rocrate_validator/profiles/isa-ro-crate/1_study.ttl b/rocrate_validator/profiles/isa-ro-crate/1_study.ttl new file mode 100644 index 00000000..dc5ab239 --- /dev/null +++ b/rocrate_validator/profiles/isa-ro-crate/1_study.ttl @@ -0,0 +1,246 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +@prefix ro: <./> . +@prefix ro-crate: . +@prefix isa-ro-crate: . +@prefix bioschemas: . +@prefix rdf: . +@prefix schema: . +@prefix sh: . +@prefix validator: . +@prefix xsd: . + +# class:study +# isTypeDataset +# isAdditionalType"Study + + +# check study must have identifier +# check study must have name +# check study must have description +# check study should have about + +# check study must be pointed to by investigation through hasPart + +# # Find studies and add isa-ro-crate:Study type to them, for easier retrieval for checks +# ro-crate:FindStudies a sh:NodeShape, validator:HiddenShape; +# sh:name "Identify Studies within the RO-Crate" ; +# sh:description "A Study has type Dataset and additionalType 'Study'." ; +# sh:target [ +# a sh:SPARQLTarget ; +# sh:prefixes ro-crate:sparqlPrefixes ; +# sh:select """ +# SELECT ?this +# WHERE { +# ?this a schema:Dataset . +# ?this schema:additionalType "Study" . +# } +# """ +# ] ; + +# # Expand data graph with triples from the file data entity +# sh:rule [ +# a sh:TripleRule ; +# sh:subject sh:this ; +# sh:predicate rdf:type ; +# sh:object isa-ro-crate:Study ; +# ] . + +# Find studies and add isa-ro-crate:Study type to them, for easier retrieval for checks +ro-crate:FindStudies a sh:NodeShape, validator:HiddenShape; + sh:name "Identify Studies within the RO-Crate" ; + sh:description "A Study has type Dataset and additionalType 'Study'." ; + sh:targetClass schema:Dataset ; + # Expand data graph with triples from the file data entity + sh:rule [ + a sh:TripleRule ; + sh:subject sh:this ; + sh:predicate rdf:type ; + sh:object isa-ro-crate:Study ; + # The condition: additionalType == "Study" + sh:condition [ + sh:property [ + sh:path schema:additionalType ; + sh:hasValue "Study" ; + ] ; + ] ; + ] +. + +# WIP +isa-ro-crate:StudyMustHaveBaseDescriptors a sh:NodeShape ; + sh:name "Study MUST have base properties" ; + sh:description "A Study MUST have identifier, name and description" ; + sh:targetClass isa-ro-crate:Study ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:identifier ; + sh:datatype xsd:string ; + sh:minCount 1 ; + sh:maxCount 1 ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check that study does have non-empty identifier and it's a string" ; + sh:message "Study entity MUST have a non-empty identifier of type string" ; + sh:severity sh:Violation ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:name ; + sh:datatype xsd:string ; + sh:minCount 1 ; + sh:maxCount 1 ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check that study does have non-empty name and it's a string" ; + sh:message "Study entity MUST have a non-empty name of type string" ; + sh:severity sh:Violation ; + ] ; +. + + +isa-ro-crate:StudyMustBeReferencedFromInvestigation a sh:NodeShape ; + sh:name "Study MUST be directly referenced from Investigation (Root Data Entity)" ; + sh:targetClass isa-ro-crate:Study ; + sh:property [ + a sh:PropertyShape ; + sh:path [ sh:inversePath schema:hasPart ] ; + sh:qualifiedValueShape [ sh:class ro-crate:RootDataEntity ] ; + sh:qualifiedMinCount 1 ; + sh:name "Study MUST be directly referenced from Investigation (Root Data Entity)" ; + sh:description """Check if the Study is directly linked to the Investigation (which is the Root Data Entity) using the `hasPart` (as defined in `schema.org`) property" """ ; + sh:message "Study MUST be directly referenced in hasPart on the Investigation (Root Data Entity)" + ] +. + +isa-ro-crate:StudyRecommendedProperties a sh:NodeShape ; + sh:name "Study SHOULD have dateCreated, datePublished, hasPart, description, creator, and about" ; + sh:description "A Study SHOULD have a dateCreated" ; + sh:targetClass isa-ro-crate:Study ; + + sh:property [ + a sh:PropertyShape ; + sh:path schema:dateCreated ; + sh:minCount 1 ; + sh:description "Check that study does have at least one dateCreated" ; + sh:message "Study entity SHOULD have a dateCreated" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:dateCreated ; + sh:nodeKind sh:Literal ; + sh:pattern "^([\\+-]?\\d{4})((-?)((0[1-9]|1[0-2])(\\3([12]\\d|0[1-9]|3[01]))|W([0-4]\\d|5[0-2])(-?[1-7])|(00[1-9]|0[1-9]\\d|[12]\\d{2}|3([0-5]\\d|6[1-6])))([T\\s]((([01]\\d|2[0-3])((:?)?[0-5]\\d)?|24:?00)([\\.,]\\d+(?!:))?)?(\\17[0-5]\\d([\\.,]\\d+)?)?([zZ]|([\\+-])([01]\\d|2[0-3]):?([0-5]\\d)?)?)?)$" ; + sh:description "Check that if investigation does have at least one dateCreated, it MUST be of type Literal matching the date pattern" ; + sh:message "Study dateCreated MUST be a valid date literal" ; + sh:severity sh:Violation ; + ] ; + + sh:property [ + a sh:PropertyShape ; + sh:path schema:datePublished ; + sh:minCount 1 ; + sh:description "Check that study does have at least one datePublished" ; + sh:message "Study entity SHOULD have a datePublished" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:datePublished ; + sh:nodeKind sh:Literal ; + sh:pattern "^([\\+-]?\\d{4})((-?)((0[1-9]|1[0-2])(\\3([12]\\d|0[1-9]|3[01]))|W([0-4]\\d|5[0-2])(-?[1-7])|(00[1-9]|0[1-9]\\d|[12]\\d{2}|3([0-5]\\d|6[1-6])))([T\\s]((([01]\\d|2[0-3])((:?)?[0-5]\\d)?|24:?00)([\\.,]\\d+(?!:))?)?(\\17[0-5]\\d([\\.,]\\d+)?)?([zZ]|([\\+-])([01]\\d|2[0-3]):?([0-5]\\d)?)?)?)$" ; + sh:description "Check that if investigation does have at least one dateCreated, it MUST be of type Literal matching the date pattern" ; + sh:message "Study datePublished MUST be a valid date literal" ; + sh:severity sh:Violation ; + ] ; + + sh:property [ + a sh:PropertyShape ; + sh:path schema:description ; + sh:minCount 1 ; + sh:maxCount 1 ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check that study does have non-empty description and it's a string" ; + sh:message "Study entity SHOULD have a non-empty description of type string" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:description ; + sh:datatype xsd:string ; + sh:description "The description of a study MUST be a string" ; + sh:message "Study description MUST be of type string" ; + sh:severity sh:Violation ; + ] ; + + sh:property [ + a sh:PropertyShape ; + sh:path schema:creator ; + sh:minCount 1 ; + sh:description "Check that study does have at least one creator" ; + sh:message "Study entity SHOULD have a creator" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:creator ; + sh:class schema:Person ; + sh:description "Check that if study does have at least one creator, it MUST be of type Person" ; + sh:message "Study creator MUST be of type Person" ; + sh:severity sh:Violation ; + ] ; + + sh:property [ + a sh:PropertyShape ; + sh:path schema:hasPart ; + sh:minCount 1 ; + sh:description "Check that study does have at least one object in hasPart" ; + sh:message "Study entity SHOULD have hasPart" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:hasPart ; + sh:or ( + [sh:class schema:MediaObject] + [sh:class schema:Dataset] + ); + sh:description "Check that if study does have at least one object in hasPart, it MUST be of type Dataset or File" ; + sh:message "Study hasPart MUST be of type Dataset or File" ; + sh:severity sh:Violation ; + ] ; + + sh:property [ + a sh:PropertyShape ; + sh:path schema:about ; + sh:minCount 1 ; + sh:description "Check that study does have at least one object in about" ; + sh:message "Study entity SHOULD have about" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:about ; + sh:class bioschemas:LabProcess ; + sh:description "Check that if study does have at least one object in about, it MUST be of type LabProcess" ; + sh:message "Study about MUST be of type LabProcess" ; + sh:severity sh:Violation ; + ] +. diff --git a/rocrate_validator/profiles/isa-ro-crate/2_assay.ttl b/rocrate_validator/profiles/isa-ro-crate/2_assay.ttl new file mode 100644 index 00000000..8158498d --- /dev/null +++ b/rocrate_validator/profiles/isa-ro-crate/2_assay.ttl @@ -0,0 +1,255 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +@prefix ro: <./> . +@prefix ro-crate: . +@prefix isa-ro-crate: . +@prefix bioschemas: . +@prefix rdf: . +@prefix schema: . +@prefix sh: . +@prefix validator: . +@prefix xsd: . + + +# check assay must have name + +# check assay must be pointed to by investigation through hasPart + +# Find assays and add isa-ro-crate:Assay type to them, for easier retrieval for checks +# ro-crate:FindAssays a sh:NodeShape, validator:HiddenShape; +# sh:name "Identify Assays within the RO-Crate" ; +# sh:description "An Assay has type Dataset and additionalType 'Assay'." ; +# sh:target [ +# a sh:SPARQLTarget ; +# sh:prefixes ro-crate:sparqlPrefixes ; +# sh:select """ +# SELECT ?this +# WHERE { +# ?this a schema:Dataset . +# ?this schema:additionalType "Assay" . +# } +# """ +# ] ; + +# # Expand data graph with triples from the file data entity +# sh:rule [ +# a sh:TripleRule ; +# sh:subject sh:this ; +# sh:predicate rdf:type ; +# sh:object isa-ro-crate:Assay ; +# ] . + +ro-crate:FindAssays a sh:NodeShape, validator:HiddenShape; + sh:name "Identify Assays within the RO-Crate" ; + sh:description "An Assay has type Dataset and additionalType 'Assay'." ; + sh:targetClass schema:Dataset ; + # Expand data graph with triples from the file data entity + sh:rule [ + a sh:TripleRule ; + sh:subject sh:this ; + sh:predicate rdf:type ; + sh:object isa-ro-crate:Assay ; + # The condition: additionalType == "Assay" + sh:condition [ + sh:property [ + sh:path schema:additionalType ; + sh:hasValue "Assay" ; + ] ; + ] ; + ] +. + +# WIP +isa-ro-crate:AssayMustHaveBaseDescriptors a sh:NodeShape ; + sh:name "Assay MUST have base properties" ; + sh:description "An Assay MUST have identifier" ; + sh:targetClass isa-ro-crate:Assay ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:identifier ; + sh:datatype xsd:string ; + sh:minCount 1 ; + sh:maxCount 1 ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check that assay does have non-empty identifier and it's a string" ; + sh:message "Assay entity MUST have a non-empty identifier of type string" ; + sh:severity sh:Violation ; + ] ; +. + + +isa-ro-crate:AssayMustBeReferencedFromInvestigation a sh:NodeShape ; + sh:name "Assay MUST be directly referenced from Investigation (Root Data Entity) or Study" ; + sh:targetClass isa-ro-crate:Assay ; + sh:property[ + a sh:PropertyShape ; + sh:path [ sh:inversePath schema:hasPart ] ; + sh:qualifiedValueShape [ + sh:or ( + [ sh:class ro-crate:RootDataEntity ] + [ sh:class isa-ro-crate:Study ] + ) ; + ] ; + sh:qualifiedMinCount 1 ; + sh:name "Assay MUST be directly referenced from Investigation (Root Data Entity) or Study" ; + sh:description """Check if the Assay is directly linked to the Investigation (which is the Root Data Entity) or a Study using the `hasPart` (as defined in `schema.org`) property" """ ; + sh:message "Assay MUST be directly referenced in hasPart on the Investigation (Root Data Entity) or a Study" + ] +. + +isa-ro-crate:AssayRecommendedProperties a sh:NodeShape ; + sh:name "Assay SHOULD have hasPart, name, description, creator, measurementMethod, measurementTechnique, and about" ; + sh:description "An Assay SHOULD have recommended fields" ; + sh:targetClass isa-ro-crate:Assay ; + + sh:property [ + a sh:PropertyShape ; + sh:path schema:name ; + sh:minCount 1 ; + sh:maxCount 1 ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check that assay does have non-empty name and it's a string" ; + sh:message "Assay entity SHOULD have a non-empty name of type string" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:name ; + sh:datatype xsd:string ; + sh:description "The name of an assay MUST be a string" ; + sh:message "Assay name MUST be of type string" ; + sh:severity sh:Violation ; + ] ; + + sh:property [ + a sh:PropertyShape ; + sh:path schema:description ; + sh:minCount 1 ; + sh:maxCount 1 ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check that assay does have non-empty description and it's a string" ; + sh:message "Assay entity SHOULD have a non-empty description of type string" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:description ; + sh:datatype xsd:string ; + sh:description "The description of an assay MUST be a string" ; + sh:message "Assay description MUST be of type string" ; + sh:severity sh:Violation ; + ] ; + + sh:property [ + a sh:PropertyShape ; + sh:path schema:creator ; + sh:minCount 1 ; + sh:description "Check that assay does have at least one creator" ; + sh:message "Assay entity SHOULD have a creator" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:creator ; + sh:class schema:Person ; + sh:description "Check that if assay does have at least one creator, it MUST be of type Person" ; + sh:message "Assay creator MUST be of type Person" ; + sh:severity sh:Violation ; + ] ; + + sh:property [ + a sh:PropertyShape ; + sh:path schema:hasPart ; + sh:minCount 1 ; + sh:description "Check that assay does have at least one object in hasPart" ; + sh:message "Assay entity SHOULD have hasPart" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:hasPart ; + sh:or ( + [sh:class schema:Dataset] + [sh:class schema:MediaObject] + ); + sh:description "Check that if assay does have at least one object in hasPart, it MUST be of type Dataset or File" ; + sh:message "Assay hasPart MUST be of type Dataset or File" ; + sh:severity sh:Violation ; + ] ; + + sh:property [ + a sh:PropertyShape ; + sh:path schema:measurementMethod ; + sh:minCount 1 ; + sh:description "Check that assay does have at least one measurement method" ; + sh:message "Assay entity SHOULD have a measurement method" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:measurementMethod ; + sh:or ( + [sh:datatype xsd:string] + [sh:class schema:DefinedTerm] + ); + sh:description "Check that if assay does have a measurement method, it MUST be of type string or DefinedTerm" ; + sh:message "Assay measurement method MUST be of type string or DefinedTerm" ; + sh:severity sh:Violation ; + ] ; + + sh:property [ + a sh:PropertyShape ; + sh:path schema:measurementTechnique ; + sh:minCount 1 ; + sh:description "Check that assay does have at least one measurement technique" ; + sh:message "Assay entity SHOULD have a measurement technique" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:measurementTechnique ; + sh:or ( + [sh:datatype xsd:string] + [sh:class schema:DefinedTerm] + ); + sh:description "Check that if assay does have a measurement technique, it MUST be of type string or DefinedTerm" ; + sh:message "Assay measurement technique MUST be of type string or DefinedTerm" ; + sh:severity sh:Violation ; + ] ; + + sh:property [ + a sh:PropertyShape ; + sh:path schema:about ; + sh:minCount 1 ; + sh:description "Check that assay does have at least one object in about" ; + sh:message "Assay entity SHOULD have about" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:about ; + sh:class bioschemas:LabProcess ; + sh:description "Check that if assay does have at least one object in about, it MUST be of type LabProcess" ; + sh:message "Assay about MUST be of type LabProcess" ; + sh:severity sh:Violation ; + ] +. \ No newline at end of file diff --git a/rocrate_validator/profiles/isa-ro-crate/3_process.ttl b/rocrate_validator/profiles/isa-ro-crate/3_process.ttl new file mode 100644 index 00000000..40b6fdc7 --- /dev/null +++ b/rocrate_validator/profiles/isa-ro-crate/3_process.ttl @@ -0,0 +1,161 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +@prefix ro: <./> . +@prefix ro-crate: . +@prefix isa-ro-crate: . +@prefix bioschemas: . +@prefix bioschemas-prop: . +@prefix rdf: . +@prefix schema: . +@prefix sh: . +@prefix validator: . +@prefix xsd: . + + + +# check process must have name +# check process should have object +# check process should have result + +isa-ro-crate:ProcessMustHaveName a sh:NodeShape ; + sh:name "Process MUST have name" ; + sh:description "A Process MUST have a name" ; + sh:targetClass bioschemas:LabProcess ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:name ; + sh:datatype xsd:string ; + sh:minCount 1 ; + sh:maxCount 1 ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check that process does have non-empty name and it's a string" ; + sh:message "Process entity MUST have a non-empty name of type string" ; + sh:severity sh:Violation ; + ] ; +. + +isa-ro-crate:ProcessMustBeReferencedFromDataset a sh:NodeShape ; + sh:name "Process MUST be directly referenced from a dataset" ; + sh:targetClass bioschemas:LabProcess ; + sh:property + [ + a sh:PropertyShape ; + sh:path [ sh:inversePath schema:about ] ; + sh:node schema:Dataset ; + sh:minCount 1 ; + sh:name "Process MUST be directly referenced from a dataset" ; + sh:description """Check if the Process is directly linked to a Dataset using the `about` (as defined in `schema.org`) property" """ ; + sh:message "Process MUST be directly referenced in about on a Dataset" ; + sh:severity sh:Violation ; + ] . + +isa-ro-crate:ProcessShouldHaveObject a sh:NodeShape ; + sh:name "Process SHOULD have an object" ; + sh:description "A Process SHOULD have an object" ; + sh:targetClass bioschemas:LabProcess ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:object ; + sh:minCount 1 ; + sh:description "Check that process does have at least one object" ; + sh:message "Process entity SHOULD have an object" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:object ; + sh:or ( + [sh:class schema:MediaObject] + [sh:class bioschemas:Sample] + [sh:class bioschemas:BioSample] + ); + sh:description "Check that if process does have at least one object, it MUST be of type File, Sample or BioSample" ; + sh:message "Process objects MUST be of type File, Sample or BioSample" ; + sh:severity sh:Violation ; + ] +. + +isa-ro-crate:ProcessShouldHaveResult a sh:NodeShape ; + sh:name "Process SHOULD have a result" ; + sh:description "A Process SHOULD have a result" ; + sh:targetClass bioschemas:LabProcess ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:result ; + sh:minCount 1 ; + sh:description "Check that process does have at least one result" ; + sh:message "Process entity SHOULD have a result" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:result ; + sh:or ( + [sh:class schema:MediaObject] + [sh:class bioschemas:Sample] + [sh:class bioschemas:BioSample] + ); + sh:description "Check that if process does have at least one result, it MUST be of type File, Sample or BioSample" ; + sh:message "Process results MUST be of type File, Sample or BioSample" ; + sh:severity sh:Violation ; + ] +. + +isa-ro-crate:ProcessShouldHaveProtocol a sh:NodeShape ; + sh:name "Process SHOULD have a protocol" ; + sh:description "A Process SHOULD have a protocol" ; + sh:targetClass bioschemas:LabProcess ; + sh:property [ + a sh:PropertyShape ; + sh:path bioschemas-prop:executesLabProtocol ; + sh:minCount 1 ; + sh:description "Check that process does have at least one protocol" ; + sh:message "Process entity SHOULD have a protocol" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path bioschemas-prop:executesLabProtocol ; + sh:class bioschemas:LabProtocol; + sh:description "Check that if process does have at least one protocol, it MUST be of type LabProtocol" ; + sh:message "Process protocols MUST be of type LabProtocol" ; + sh:severity sh:Violation ; + ] +. + +isa-ro-crate:ProcessShouldHaveParamValue a sh:NodeShape ; + sh:name "Process SHOULD have a parameter value" ; + sh:description "A Process SHOULD have a parameter value" ; + sh:targetClass bioschemas:LabProcess ; + sh:property [ + a sh:PropertyShape ; + sh:path bioschemas-prop:parameterValue ; + sh:minCount 1 ; + sh:description "Check that process does have at least one parameter value" ; + sh:message "Process entity SHOULD have a parameter value" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path bioschemas-prop:parameterValue ; + sh:class schema:PropertyValue; + sh:description "Check that if process does have at least one parameter value, it MUST be of type PropertyValue" ; + sh:message "Process parameter values MUST be of type PropertyValue" ; + sh:severity sh:Violation ; + ] +. \ No newline at end of file diff --git a/rocrate_validator/profiles/isa-ro-crate/4_protocol.ttl b/rocrate_validator/profiles/isa-ro-crate/4_protocol.ttl new file mode 100644 index 00000000..6f5ef82e --- /dev/null +++ b/rocrate_validator/profiles/isa-ro-crate/4_protocol.ttl @@ -0,0 +1,106 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +@prefix ro: <./> . +@prefix ro-crate: . +@prefix isa-ro-crate: . +@prefix bioschemas: . +@prefix bioschemas-prop: . +@prefix rdf: . +@prefix schema: . +@prefix sh: . +@prefix validator: . +@prefix xsd: . + + + +# check protocol attributes must have correct types + +isa-ro-crate:ProtocolShouldHaveNameOfCorrectType a sh:NodeShape ; + sh:name "Protocol SHOULD have name" ; + sh:description "A Protocol SHOULD have a name" ; + sh:targetClass bioschemas:LabProtocol ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:name ; + sh:minCount 1 ; + sh:maxCount 1 ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check that protocol does have non-empty name and it's a string" ; + sh:message "Protocol entity SHOULD have a non-empty name of type string" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:name ; + sh:datatype xsd:string ; + sh:description "The name of a protocol MUST be a string" ; + sh:message "Protocol name MUST be of type string" ; + sh:severity sh:Violation ; + ] +. + +isa-ro-crate:ProtocolShouldHaveDescriptionOfCorrectType a sh:NodeShape ; + sh:name "Protocol SHOULD have description" ; + sh:description "A Protocol SHOULD have a description" ; + sh:targetClass bioschemas:LabProtocol ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:description ; + sh:minCount 1 ; + sh:maxCount 1 ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check that protocol does have non-empty description and it's a string" ; + sh:message "Protocol entity SHOULD have a non-empty description of type string" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:description ; + sh:datatype xsd:string ; + sh:description "The description of a protocol MUST be a string" ; + sh:message "Protocol description MUST be of type string" ; + sh:severity sh:Violation ; + ] +. + +isa-ro-crate:ProtocolShouldHaveIntendedUse a sh:NodeShape ; + sh:name "Protocol SHOULD have intended use" ; + sh:description "A Protocol SHOULD have an intended use" ; + sh:targetClass bioschemas:LabProtocol ; + sh:property [ + a sh:PropertyShape ; + sh:path bioschemas-prop:intendedUse ; + sh:minCount 1 ; + sh:description "Check that protocol does have at least one intended use" ; + sh:message "Protocol entity SHOULD have an intended use" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path bioschemas-prop:intendedUse ; + sh:or ( + [sh:datatype xsd:string] + [sh:class schema:DefinedTerm] + ) ; + sh:description "Check that if protocol does have at least one intended use, it MUST be of type string or DefinedTerm" ; + sh:message "Protocol intended use MUST be of type string or DefinedTerm" ; + sh:severity sh:Violation ; + ] +. \ No newline at end of file diff --git a/rocrate_validator/profiles/isa-ro-crate/5_sample.ttl b/rocrate_validator/profiles/isa-ro-crate/5_sample.ttl new file mode 100644 index 00000000..5b6bf2f5 --- /dev/null +++ b/rocrate_validator/profiles/isa-ro-crate/5_sample.ttl @@ -0,0 +1,70 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +@prefix ro: <./> . +@prefix ro-crate: . +@prefix isa-ro-crate: . +@prefix bioschemas: . +@prefix bioschemas-prop: . +@prefix rdf: . +@prefix schema: . +@prefix sh: . +@prefix validator: . +@prefix xsd: . + + + +# check Sample attributes must have correct types + +isa-ro-crate:SampledMustHaveName a sh:NodeShape ; + sh:name "Sample MUST have name" ; + sh:description "A Sample MUST have a name" ; + sh:targetClass bioschemas:Sample ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:name ; + sh:datatype xsd:string ; + sh:minCount 1 ; + sh:maxCount 1 ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check that sample does have non-empty name and it's a string" ; + sh:message "Sample entity MUST have a non-empty name of type string" ; + sh:severity sh:Violation ; + ] +. + +isa-ro-crate:SampleShouldHaveAdditionalPropertyOfCorrectType a sh:NodeShape ; + sh:name "Sample SHOULD have additional properties" ; + sh:description "A Sample SHOULD have at least one additional property" ; + sh:targetClass bioschemas:Sample ; + sh:property [ + a sh:PropertyShape ; + sh:path bioschemas-prop:additionalProperty ; + sh:minCount 1 ; + sh:description "Check that sample does have at least one additional property" ; + sh:message "Sample entity SHOULD have at least one additional property" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path bioschemas-prop:additionalProperty ; + sh:class schema:PropertyValue ; + sh:description "The additional property of a sample MUST be a PropertyValue" ; + sh:message "Sample additional property MUST be of type PropertyValue" ; + sh:severity sh:Violation ; + ] +. \ No newline at end of file diff --git a/rocrate_validator/profiles/isa-ro-crate/6_data.ttl b/rocrate_validator/profiles/isa-ro-crate/6_data.ttl new file mode 100644 index 00000000..3bc9da6a --- /dev/null +++ b/rocrate_validator/profiles/isa-ro-crate/6_data.ttl @@ -0,0 +1,48 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +@prefix ro: <./> . +@prefix ro-crate: . +@prefix isa-ro-crate: . +@prefix bioschemas: . +@prefix bioschemas-prop: . +@prefix rdf: . +@prefix schema: . +@prefix sh: . +@prefix validator: . +@prefix xsd: . + + + +# check File attributes must have correct types + +isa-ro-crate:FileMustHaveName a sh:NodeShape ; + sh:name "File MUST have name" ; + sh:description "A File MUST have a name" ; + sh:targetClass schema:MediaObject ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:name ; + sh:datatype xsd:string ; + sh:minCount 1 ; + sh:maxCount 1 ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check that file does have non-empty name and it's a string" ; + sh:message "File entity MUST have a non-empty name of type string" ; + sh:severity sh:Violation ; + ] +. \ No newline at end of file diff --git a/rocrate_validator/profiles/isa-ro-crate/7_person.ttl b/rocrate_validator/profiles/isa-ro-crate/7_person.ttl new file mode 100644 index 00000000..fe9976f6 --- /dev/null +++ b/rocrate_validator/profiles/isa-ro-crate/7_person.ttl @@ -0,0 +1,170 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +@prefix ro: <./> . +@prefix ro-crate: . +@prefix isa-ro-crate: . +@prefix bioschemas: . +@prefix bioschemas-prop: . +@prefix rdf: . +@prefix schema: . +@prefix sh: . +@prefix validator: . +@prefix xsd: . + + + +# check Person attributes must have correct types + +isa-ro-crate:PersonMustHaveGivenName a sh:NodeShape ; + sh:name "Person MUST have a given name" ; + sh:description "A Person MUST have a given name" ; + sh:targetClass schema:Person ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:givenName ; + sh:datatype xsd:string ; + sh:minCount 1 ; + sh:maxCount 1 ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check that person does have non-empty given name and it's a string" ; + sh:message "Person entity MUST have a non-empty given name of type string" ; + sh:severity sh:Violation ; + ] +. + +isa-ro-crate:PersonShouldHaveAffiliationOfCorrectType a sh:NodeShape ; + sh:name "Person SHOULD have affiliation" ; + sh:description "A Person SHOULD have at least one affiliation" ; + sh:targetClass schema:Person ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:affiliation ; + sh:minCount 1 ; + sh:description "Check that person does have at least one affiliation" ; + sh:message "Person entity SHOULD have at least one affiliation" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:affiliation ; + sh:class schema:Organization ; + sh:description "The affiliation of a person MUST be an Organization" ; + sh:message "Person affiliation MUST be of type Organization" ; + sh:severity sh:Violation ; + ] +. + +isa-ro-crate:PersonShouldHaveJobTitleOfCorrectType a sh:NodeShape ; + sh:name "Person SHOULD have job title" ; + sh:description "A Person SHOULD have at least one job title" ; + sh:targetClass schema:Person ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:jobTitle ; + sh:minCount 1 ; + sh:description "Check that person does have at least one job title" ; + sh:message "Person entity SHOULD have at least one job title" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:jobTitle ; + sh:class schema:DefinedTerm ; + sh:description "The job title of a person MUST be a defined term" ; + sh:message "Person job title MUST be of type DefinedTerm" ; + sh:severity sh:Violation ; + ] +. + +isa-ro-crate:PersonShouldHaveEmailOfCorrectType a sh:NodeShape ; + sh:name "Person SHOULD have email" ; + sh:description "A Person SHOULD have at least one email" ; + sh:targetClass schema:Person ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:email ; + sh:minCount 1 ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check that person does have non-empty email and it's a string" ; + sh:message "Person entity SHOULD have a non-empty email of type string" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:email ; + sh:datatype xsd:string ; + sh:description "The email of a person MUST be a string" ; + sh:message "Person email MUST be of type string" ; + sh:severity sh:Violation ; + ] +. + +isa-ro-crate:PersonShouldHaveFamilyNameOfCorrectType a sh:NodeShape ; + sh:name "Person SHOULD have family name" ; + sh:description "A Person SHOULD have at least one family name" ; + sh:targetClass schema:Person ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:familyName ; + sh:minCount 1 ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check that person does have non-empty family name and it's a string" ; + sh:message "Person entity SHOULD have a non-empty family name of type string" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:familyName ; + sh:datatype xsd:string ; + sh:description "The family name of a person MUST be a string" ; + sh:message "Person family name MUST be of type string" ; + sh:severity sh:Violation ; + ] +. + +isa-ro-crate:PersonShouldHaveIdentifierOfCorrectType a sh:NodeShape ; + sh:name "Person SHOULD have identifier" ; + sh:description "A Person SHOULD have at least one identifier" ; + sh:targetClass schema:Person ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:identifier ; + sh:minCount 1 ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check that person does have non-empty identifier and it's a string" ; + sh:message "Person entity SHOULD have a non-empty identifier of type string" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:identifier ; + sh:or ( + [sh:datatype xsd:string] + [sh:class schema:PropertyValue] + ) ; + sh:description "The identifier of a person MUST be a string or a PropertyValue" ; + sh:message "Person identifier MUST be of type string or PropertyValue" ; + sh:severity sh:Violation ; + ] +. \ No newline at end of file diff --git a/rocrate_validator/profiles/isa-ro-crate/8_article.ttl b/rocrate_validator/profiles/isa-ro-crate/8_article.ttl new file mode 100644 index 00000000..17612249 --- /dev/null +++ b/rocrate_validator/profiles/isa-ro-crate/8_article.ttl @@ -0,0 +1,89 @@ +## Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +@prefix ro: <./> . +@prefix ro-crate: . +@prefix isa-ro-crate: . +@prefix bioschemas: . +@prefix bioschemas-prop: . +@prefix rdf: . +@prefix schema: . +@prefix sh: . +@prefix validator: . +@prefix xsd: . + + +isa-ro-crate:ArticleMustHaveHeadline a sh:NodeShape ; + sh:name "Article MUST have a headline" ; + sh:description "An Article MUST have a headline" ; + sh:targetClass schema:ScholarlyArticle ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:headline ; + sh:datatype xsd:string ; + sh:minCount 1 ; + sh:maxCount 1 ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check that article does have non-empty headline and it's a string" ; + sh:message "Article entity MUST have a non-empty headline of type string" ; + sh:severity sh:Violation ; + ] +. + +isa-ro-crate:ArticleMustHaveIdentifier a sh:NodeShape ; + sh:name "Article MUST have an identifier" ; + sh:description "An Article MUST have an identifier" ; + sh:targetClass schema:ScholarlyArticle ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:identifier ; + sh:or( + [ sh:datatype xsd:string ] + [ sh:class schema:PropertyValue ] + ) ; + sh:minCount 1 ; + sh:maxCount 1 ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check that article does have non-empty identifier and it's a string or PropertyValue" ; + sh:message "Article entity MUST have a non-empty identifier of type string or PropertyValue" ; + sh:severity sh:Violation ; + ] +. + +isa-ro-crate:ArticleShouldHaveAuthorOfCorrectType a sh:NodeShape ; + sh:name "Article SHOULD have author" ; + sh:description "An Article SHOULD have at least one author" ; + sh:targetClass schema:ScholarlyArticle ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:author ; + sh:minCount 1 ; + sh:description "Check that article does have at least one author" ; + sh:message "Article entity SHOULD have at least one author" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:author ; + sh:class schema:Person ; + sh:description "The author of an article MUST be a Person" ; + sh:message "Article author MUST be of type Person" ; + sh:severity sh:Violation ; + ] +. \ No newline at end of file diff --git a/rocrate_validator/profiles/isa-ro-crate/9_comment.ttl b/rocrate_validator/profiles/isa-ro-crate/9_comment.ttl new file mode 100644 index 00000000..4d64e119 --- /dev/null +++ b/rocrate_validator/profiles/isa-ro-crate/9_comment.ttl @@ -0,0 +1,76 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +@prefix ro: <./> . +@prefix ro-crate: . +@prefix isa-ro-crate: . +@prefix bioschemas: . +@prefix bioschemas-prop: . +@prefix rdf: . +@prefix schema: . +@prefix sh: . +@prefix validator: . +@prefix xsd: . + + +isa-ro-crate:CommentShouldHaveName a sh:NodeShape ; + sh:name "Comment SHOULD have name" ; + sh:description "A Comment SHOULD have at least one name" ; + sh:targetClass schema:Comment ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:name ; + sh:minCount 1 ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check that comment does have at least one name" ; + sh:message "Comment entity SHOULD have at least one name" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:name ; + sh:datatype xsd:string ; + sh:description "The name of a comment MUST be a string" ; + sh:message "Comment name MUST be of type string" ; + sh:severity sh:Violation ; + ] +. + +isa-ro-crate:CommentShouldHaveText a sh:NodeShape ; + sh:name "Comment SHOULD have text" ; + sh:description "A Comment SHOULD have at least one text" ; + sh:targetClass schema:Comment ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:text ; + sh:minCount 1 ; + sh:not [ + sh:hasValue "" + ] ; + sh:description "Check that comment does have at least one text" ; + sh:message "Comment entity SHOULD have at least one text" ; + sh:severity sh:Warning ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:path schema:text ; + sh:datatype xsd:string ; + sh:description "The text of a comment MUST be a string" ; + sh:message "Comment text MUST be of type string" ; + sh:severity sh:Violation ; + ] +. \ No newline at end of file diff --git a/rocrate_validator/profiles/isa-ro-crate/ontology.ttl b/rocrate_validator/profiles/isa-ro-crate/ontology.ttl new file mode 100644 index 00000000..8e48b75b --- /dev/null +++ b/rocrate_validator/profiles/isa-ro-crate/ontology.ttl @@ -0,0 +1,91 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +@prefix owl: . +@prefix rdf: . +@prefix rdfs: . +@prefix schema: . +@prefix bioschemas: . +@prefix sh: . +@prefix ro-crate: . +@prefix isa-ro-crate: . + +# # ################################################################# +# # # Classes +# # ################################################################# + +# Study +isa-ro-crate:Study rdf:type owl:Class ; + rdfs:subClassOf schema:Dataset ; + rdfs:label "Study"@en . + +# Assay +isa-ro-crate:Assay rdf:type owl:Class ; + rdfs:subClassOf schema:Dataset ; + rdfs:label "Assay"@en . + +isa-ro-crate:Parameter rdf:type owl:Class ; + rdfs:subClassOf schema:PropertyValue ; + rdfs:label "Parameter"@en . + +isa-ro-crate:Characteristic rdf:type owl:Class ; + rdfs:subClassOf schema:PropertyValue ; + rdfs:label "Characteristic"@en . + +isa-ro-crate:Factor rdf:type owl:Class ; + rdfs:subClassOf schema:PropertyValue ; + rdfs:label "Factor"@en . + +isa-ro-crate:Component rdf:type owl:Class ; + rdfs:subClassOf schema:PropertyValue ; + rdfs:label "Component"@en . + +### https://bioschemas.org/LabProcess +bioschemas:LabProcess rdf:type owl:Class ; + rdfs:subClassOf schema:Action ; + rdfs:label "LabProcess"@en . + +### https://bioschemas.org/LabProtocol +bioschemas:LabProtocol rdf:type owl:Class ; + rdfs:subClassOf schema:HowTo ; + rdfs:label "LabProtocol"@en . + + +### https://bioschemas.org/Sample +bioschemas:Sample rdf:type owl:Class ; + rdfs:subClassOf schema:Thing ; + rdfs:label "Sample"@en . + + +### Data Entity +### TODO: confirm if still needed? There is also ro-crate:DataEntity but that is the 1.1 interpretation +isa-ro-crate:Data rdf:type owl:Class ; + rdfs:subClassOf [ + sh:or ( + ro-crate:File + schema:MediaObject + ) + ] ; + rdfs:label "Data Entity"@en . + + +### https://schema.org/PropertyValue +schema:PropertyValue rdf:type owl:Class ; + rdfs:label "PropertyValue"@en . + + +### https://schema.org/ScholarlyArticle +schema:ScholarlyArticle rdf:type owl:Class ; + rdfs:label "ScholarlyArticle"@en . diff --git a/rocrate_validator/profiles/isa-ro-crate/profile.ttl b/rocrate_validator/profiles/isa-ro-crate/profile.ttl new file mode 100644 index 00000000..a52b28e4 --- /dev/null +++ b/rocrate_validator/profiles/isa-ro-crate/profile.ttl @@ -0,0 +1,84 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# Copyright (c) 2026 CRS4 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +@prefix dct: . +@prefix prof: . +@prefix role: . +@prefix rdfs: . + + + + + a prof:Profile ; + + # the Profile's label + rdfs:label "ISA RO-Crate Metadata Specification 1.0" ; + + # regular metadata, a basic description of the Profile + rdfs:comment """ISA RO-Crate Metadata Specification."""@en ; + + # URI of the publisher of the ISA RO-Crate Metadata Specification + dct:publisher ; + + # This profile is an extension of the RO-Crate Metadata Specification 1.1 profile + prof:isProfileOf ; + + # Explicitly state that this profile is a transitive profile of the RO-Crate Metadata Specification 1.1 profile + prof:isTransitiveProfileOf ; + + # this profile has a JSON-LD context resource + prof:hasResource [ + a prof:ResourceDescriptor ; + + # it's in JSON-LD format + dct:format ; + + # it conforms to JSON-LD, here referred to by its namespace URI as a Profile + dct:conformsTo ; + + # this profile resource plays the role of "Vocabulary" + # described in this ontology's accompanying Roles vocabulary + prof:hasRole role:Vocabulary ; + + # this profile resource's actual file + prof:hasArtifact ; + ] ; + + # this profile has a human-readable documentation resource + prof:hasResource [ + a prof:ResourceDescriptor ; + + # it's in HTML format + dct:format ; + + # it conforms to HTML, here referred to by its namespace URI as a Profile + dct:conformsTo ; + + # this profile resource plays the role of "Specification" + # described in this ontology's accompanying Roles vocabulary + prof:hasRole role:Specification ; + + # this profile resource's actual file + # TODO: update to a specific tag on release + prof:hasArtifact ; + + # this profile is inherited from the RO-Crate Metadata Specification 1.1 + prof:isInheritedFrom ; + ] ; + + # a short code to refer to the Profile with when a URI can't be used + prof:hasToken "isa-ro-crate" ; +. diff --git a/rocrate_validator/profiles/ro-crate/ontology.ttl b/rocrate_validator/profiles/ro-crate/ontology.ttl index 9af3a09b..3ccb4003 100644 --- a/rocrate_validator/profiles/ro-crate/ontology.ttl +++ b/rocrate_validator/profiles/ro-crate/ontology.ttl @@ -22,7 +22,7 @@ @prefix rocrate: . @prefix bioschemas: . @prefix ro-crate: . -# @base <./.> . +@prefix isa-ro-crate: . rdf:type owl:Ontology ; owl:versionIRI . diff --git a/rocrate_validator/requirements/python/__init__.py b/rocrate_validator/requirements/python/__init__.py index 65887c97..b23c4a9d 100644 --- a/rocrate_validator/requirements/python/__init__.py +++ b/rocrate_validator/requirements/python/__init__.py @@ -55,6 +55,11 @@ def __init__(self, self._check_function = check_function def execute_check(self, context: ValidationContext) -> bool: + if self.requirement.profile.identifier != context.profile_identifier and \ + context.settings.disable_inherited_profiles_issue_reporting: + logger.debug("Skipping requirement %s as it belongs to an inherited profile %s", + self.requirement.identifier, self.requirement.profile.identifier) + return True return self._check_function(self, context) diff --git a/rocrate_validator/requirements/shacl/checks.py b/rocrate_validator/requirements/shacl/checks.py index 5fa56337..62a625e0 100644 --- a/rocrate_validator/requirements/shacl/checks.py +++ b/rocrate_validator/requirements/shacl/checks.py @@ -200,11 +200,13 @@ def __do_execute_check__(self, shacl_context: SHACLValidationContext): assert shape is not None, "Unable to map the violation to a shape" requirementCheck = SHACLCheck.get_instance(shape) assert requirementCheck is not None, "The requirement check cannot be None" - failed_requirements_checks.add(requirementCheck) - violations = failed_requirements_checks_violations.get(requirementCheck.identifier, None) - if violations is None: - failed_requirements_checks_violations[requirementCheck.identifier] = violations = [] - violations.append(violation) + if (not shacl_context.settings.skip_checks or + requirementCheck.identifier not in shacl_context.settings.skip_checks): + failed_requirements_checks.add(requirementCheck) + violations = failed_requirements_checks_violations.get(requirementCheck.identifier, None) + if violations is None: + failed_requirements_checks_violations[requirementCheck.identifier] = (violations := []) + violations.append(violation) # sort the failed checks by identifier and severity # to ensure a consistent order of the issues # and to make the fail fast mode deterministic @@ -212,7 +214,7 @@ def __do_execute_check__(self, shacl_context: SHACLValidationContext): # if the check is not in the current profile # and the disable_inherited_profiles_reporting is enabled, skip it if requirementCheck.requirement.profile != shacl_context.current_validation_profile and \ - shacl_context.settings.disable_inherited_profiles_reporting: + shacl_context.settings.disable_inherited_profiles_issue_reporting: continue for violation in failed_requirements_checks_violations[requirementCheck.identifier]: violating_entity = make_uris_relative(violation.focusNode.toPython(), shacl_context.publicID) @@ -273,6 +275,9 @@ def __do_execute_check__(self, shacl_context: SHACLValidationContext): if requirementCheck.identifier not in failed_requirement_checks_notified: failed_requirement_checks_notified.append(requirementCheck.identifier) shacl_context.result._add_executed_check(requirementCheck, True) + if requirementCheck.requirement.profile != shacl_context.target_profile and \ + shacl_context.settings.disable_inherited_profiles_issue_reporting: + continue shacl_context.validator.notify(RequirementCheckValidationEvent( EventType.REQUIREMENT_CHECK_VALIDATION_END, requirementCheck, validation_result=True)) logger.debug("Added skipped check to the context: %s", requirementCheck.identifier) diff --git a/tests/data/crates/valid/minimal-isa-ro-crate/ro-crate-metadata.json b/tests/data/crates/valid/minimal-isa-ro-crate/ro-crate-metadata.json new file mode 100644 index 00000000..3a9578d1 --- /dev/null +++ b/tests/data/crates/valid/minimal-isa-ro-crate/ro-crate-metadata.json @@ -0,0 +1,212 @@ +{ + "@context": [ + "https://w3id.org/ro/crate/1.2/context", + { + "Sample": "https://bioschemas.org/Sample", + "LabProtocol": "https://bioschemas.org/LabProtocol", + "LabProcess": "https://bioschemas.org/LabProcess", + "computationalTool": "https://bioschemas.org/properties/computationalTool", + "labEquipment": "https://bioschemas.org/properties/labEquipment", + "reagent": "https://bioschemas.org/properties/reagent", + "intendedUse": "https://bioschemas.org/properties/intendedUse", + "executesLabProtocol": "https://bioschemas.org/properties/executesLabProtocol", + "parameterValue": "https://bioschemas.org/properties/parameterValue", + "additionalProperty": "https://bioschemas.org/properties/additionalProperty" + } + ], + "@graph": [ + { + "@id": "assays/MyAssay/", + "@type": "Dataset", + "additionalType": "Assay", + "identifier": "MyAssay", + "name": "My Assay is great", + "description": "This is an example study.", + "creator": { + "@id": "#Person_John_Doe" + }, + "about": { + "@id": "#Process_MyProcess" + }, + "measurementMethod": { + "@id": "#Term_MyTerm" + }, + "measurementTechnique":{ + "@id": "#Term_MyTerm" + }, + "hasPart": [ + { + "@id": "assays/MyAssay/datafile.txt" + } + ] + }, + { + "@id": "#Sample_MyInputSample", + "@type": "Sample", + "additionalType": "Sample", + "name": "MyInputSample", + "additionalProperty": { + "@id": "#PV_MyParameterValue" + } + }, + { + "@id": "#Sample_MyOutputSample", + "@type": "Sample", + "additionalType": "Sample", + "name": "MyOutputSample", + "additionalProperty": { + "@id": "#PV_MyParameterValue" + } + }, + { + "@id": "#Process_MyProcess", + "@type": "LabProcess", + "name": "MyProcess", + "object": { + "@id": "#Sample_MyInputSample" + }, + "result": { + "@id": "#Sample_MyOutputSample" + }, + "executesLabProtocol": { + "@id": "#Protocol_MyProtocol" + }, + "parameterValue": { + "@id": "#PV_MyParameterValue" + } + }, + { + "@id": "#PV_MyParameterValue", + "@type": "PropertyValue", + "name": "MyParameter", + "value": 7 + }, + { + "@id": "#Protocol_MyProtocol", + "@type": "LabProtocol", + "name": "MyProtocol", + "intendedUse": { + "@id": "#Term_MyTerm" + }, + "description": "This is a protocol" + }, + { + "@type": "DefinedTerm", + "@id": "#Term_MyTerm", + "name": "MyTerm", + "termCode": "MT001" + }, + { + "@id": "assays/MyAssay/datafile.txt", + "@type": "File", + "name": "datafile.txt" + }, + { + "@id": "studies/MyStudy/", + "@type": "Dataset", + "additionalType": "Study", + "identifier": "MyStudy", + "name": "My Study is great", + "datePublished": "2025-12-09T16:11:16.8899868", + "dateCreated": "2025-12-09T16:11:16.8899868", + "description": "This is an example study.", + "creator": { + "@id": "#Person_John_Doe" + }, + "about": { + "@id": "#Process_MyProcess" + }, + "citation": { + "@id": "https://doi.org/10.1000/mydoi" + }, + "hasPart": [ + { + "@id": "assays/MyAssay/" + } + ] + }, + { + "@id": "https://doi.org/10.1000/mydoi", + "@type": "ScholarlyArticle", + "headline": "My Example DOI Article", + "author": { + "@id": "#Person_John_Doe" + }, + "identifier": { + "@id": "#DOI_MyDOI" + }, + "comment": { + "@id": "#Comment_MyComment" + } + }, + { + "@id": "#Comment_MyComment", + "@type": "Comment", + "name": "This is a comment on the article.", + "text": "Great article!" + }, + { + "@id": "#DOI_MyDOI", + "@type": "PropertyValue", + "propertyID": "http://purl.obolibrary.org/obo/OBI_0002110", + "name": "DOI", + "value": "10.1000/mydoi" + }, + { + "@id": "LICENSE", + "@type": "CreativeWork", + "text": "MYLICENSE" + }, + { + "@id": "./", + "@type": "Dataset", + "additionalType": "Investigation", + "identifier": "MyInvestigation", + "hasPart":[ + { + "@id": "studies/MyStudy/" + }, + { + "@id": "assays/MyAssay/" + } + ], + "name": "My Investigation is great", + "datePublished": "2025-12-09T16:11:16.8899868", + "dateCreated": "2025-12-09T16:11:16.8899868", + "creator": { + "@id": "#Person_John_Doe" + }, + "description": "This is an example investigation.", + "license": { + "@id": "LICENSE" + } + }, + { + "@id": "#Person_John_Doe", + "@type": "Person", + "givenName": "John", + "familyName": "Doe", + "affiliation": { + "@id": "#Example_University" + }, + "email": "abc", + "jobTitle": { "@id": "#Term_MyTerm" }, + "identifier": "http://orcid.org/0000-0000-0000-0000" + }, + { + "@type": "Organization", + "@id": "#Example_University", + "name": "Example University" + }, + { + "@id": "ro-crate-metadata.json", + "@type": "CreativeWork", + "conformsTo": { + "@id": "https://w3id.org/ro/crate/1.1" + }, + "about": { + "@id": "./" + } + } + ] +} \ No newline at end of file diff --git a/tests/integration/profiles/five-safes-crate/test_valid_5src.py b/tests/integration/profiles/five-safes-crate/test_valid_5src.py index 994bb997..6a7b0ca0 100644 --- a/tests/integration/profiles/five-safes-crate/test_valid_5src.py +++ b/tests/integration/profiles/five-safes-crate/test_valid_5src.py @@ -70,7 +70,7 @@ def test_valid_five_safes_crate_request_recommended(): SKIP_LOCAL_DATA_ENTITY_EXISTENCE_CHECK_IDENTIFIER, SKIP_WEB_RESOURCE_AVAILABILITY_IDENTIFIER, ], - disable_inherited_profiles_reporting=True, + disable_inherited_profiles_issue_reporting=True, ) @@ -98,7 +98,7 @@ def test_valid_five_safes_crate_result_recommended(): SKIP_LOCAL_DATA_ENTITY_EXISTENCE_CHECK_IDENTIFIER, SKIP_WEB_RESOURCE_AVAILABILITY_IDENTIFIER, ], - disable_inherited_profiles_reporting=True, + disable_inherited_profiles_issue_reporting=True, ) diff --git a/tests/integration/profiles/isa-ro-crate/test_0_investigation.py b/tests/integration/profiles/isa-ro-crate/test_0_investigation.py new file mode 100644 index 00000000..e6830f8b --- /dev/null +++ b/tests/integration/profiles/isa-ro-crate/test_0_investigation.py @@ -0,0 +1,194 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +from rocrate_validator.models import Severity +from tests.ro_crates import ValidROC +from tests.shared import do_entity_test, SPARQL_PREFIXES + +# set up logging +logger = logging.getLogger(__name__) + + +# ----- MUST fails tests + + +def test_isa_additionaltype_not_investigation(): + """ + Test an ISA RO-Crate where no Dataset has `additionalType` of "Investigation". + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?dataset schema:additionalType "Investigation" . + } + WHERE { + ?dataset a schema:Dataset . + ?dataset schema:additionalType "Investigation" . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + expected_triggered_requirements=["Root Data Entity must be Investigation"], + expected_triggered_issues=[ + "The root data entity must have additionalType of `Investigation`" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_investigation_no_identifier(): + """ + Test an ISA RO-Crate where the investigation has no identifier. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?dataset schema:identifier ?id . + } + WHERE { + ?dataset a schema:Dataset . + ?dataset schema:additionalType "Investigation" . + ?dataset schema:identifier ?id . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Investigation MUST have base properties"], + expected_triggered_issues=[ + "The root data entity must have a non-empty identifier" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_investigation_identifier_not_string(): + """ + Test an ISA RO-Crate where the investigation has an identifier that is not a string. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?dataset schema:identifier ?id . + } + INSERT { + ?dataset schema:identifier 42 . + } + WHERE { + ?dataset a schema:Dataset . + ?dataset schema:additionalType "Investigation" . + ?dataset schema:identifier ?id . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Investigation MUST have base properties"], + expected_triggered_issues=[ + "The root data entity must have a non-empty identifier" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_investigation_no_shoulds(): + """ + Test an ISA RO-Crate where the investigation is missing should properties. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?dataset schema:dateCreated ?dc . + ?dataset schema:creator ?creator . + } + WHERE { + ?dataset a schema:Dataset . + ?dataset schema:additionalType "Investigation" . + ?creator a schema:Person . + ?creator schema:familyName "Doe" . + ?dataset schema:dateCreated ?dc . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + # expected_triggered_requirements=["Investigation MUST have base properties"], + expected_triggered_issues=[ + "Investigation entity SHOULD have a dateCreated", + "Investigation entity SHOULD have a creator", + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_investigation_shoulds_have_wrong_types(): + """ + Test an ISA RO-Crate where the investigation's should properties have wrong types. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?dataset schema:dateCreated ?dc . + ?dataset schema:creator ?creator . + } + INSERT { + ?dataset schema:dateCreated 42 . + ?dataset schema:creator 42 . + } + WHERE { + ?dataset a schema:Dataset . + ?dataset schema:additionalType "Investigation" . + ?dataset schema:dateCreated ?dc . + ?dataset schema:creator ?creator . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Investigation MUST have base properties"], + expected_triggered_issues=[ + "Investigation dateCreated MUST be a valid ISO 8601 date", + "Investigation creator MUST be of type Person", + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) diff --git a/tests/integration/profiles/isa-ro-crate/test_10_definedterm.py b/tests/integration/profiles/isa-ro-crate/test_10_definedterm.py new file mode 100644 index 00000000..9f129b2c --- /dev/null +++ b/tests/integration/profiles/isa-ro-crate/test_10_definedterm.py @@ -0,0 +1,148 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +from rocrate_validator.models import Severity +from tests.ro_crates import ValidROC +from tests.shared import do_entity_test, SPARQL_PREFIXES + +# set up logging +logger = logging.getLogger(__name__) + + +# ----- MUST fails tests +def test_isa_defined_term_name(): + """ + Test an ISA RO-Crate where a defined term has no name. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?defined_term schema:name ?name . + } + WHERE { + ?defined_term a schema:DefinedTerm . + ?defined_term schema:name ?name . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "DefinedTerm entity MUST have a non-empty name of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_defined_term_name_of_incorrect_type(): + """ + Test an ISA RO-Crate where a defined term name has wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?defined_term schema:name ?name . + } + INSERT { + ?defined_term schema:name 42 . + } + WHERE { + ?defined_term a schema:DefinedTerm . + ?defined_term schema:name ?name . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "DefinedTerm entity MUST have a non-empty name of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_defined_term_termCode(): + """ + Test an ISA RO-Crate where a defined term has no termCode. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?defined_term schema:termCode ?termCode . + } + WHERE { + ?defined_term a schema:DefinedTerm . + ?defined_term schema:termCode ?termCode . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "DefinedTerm entity SHOULD have at least one termCode" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_defined_term_termCode_of_incorrect_type(): + """ + Test an ISA RO-Crate where a defined term termCode has wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?defined_term schema:termCode ?termCode . + } + INSERT { + ?defined_term schema:termCode 42 . + } + WHERE { + ?defined_term a schema:DefinedTerm . + ?defined_term schema:termCode ?termCode . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=["DefinedTerm termCode MUST be of type string"], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) diff --git a/tests/integration/profiles/isa-ro-crate/test_11_propertyvalue.py b/tests/integration/profiles/isa-ro-crate/test_11_propertyvalue.py new file mode 100644 index 00000000..36459e53 --- /dev/null +++ b/tests/integration/profiles/isa-ro-crate/test_11_propertyvalue.py @@ -0,0 +1,156 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +from rocrate_validator.models import Severity +from tests.ro_crates import ValidROC +from tests.shared import do_entity_test, SPARQL_PREFIXES + +# set up logging +logger = logging.getLogger(__name__) + + +# ----- MUST fails tests +def test_isa_property_value_name(): + """ + Test an ISA RO-Crate where a property value has no name. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?property_value schema:name ?name . + } + WHERE { + ?property_value a schema:PropertyValue . + ?property_value schema:name "MyParameter" . + ?property_value schema:name ?name . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "PropertyValue entity MUST have a non-empty name of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_property_value_name_of_incorrect_type(): + """ + Test an ISA RO-Crate where a property value name has wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?property_value schema:name ?name . + } + INSERT { + ?property_value schema:name 42 . + } + WHERE { + ?property_value a schema:PropertyValue . + ?property_value schema:name "MyParameter" . + ?property_value schema:name ?name . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "PropertyValue entity MUST have a non-empty name of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_property_value_value(): + """ + Test an ISA RO-Crate where a property value has no value. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?property_value schema:value ?value . + } + WHERE { + ?property_value a schema:PropertyValue . + ?property_value schema:name "MyParameter" . + ?property_value schema:value ?value . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "PropertyValue entity SHOULD have at least one value" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_property_value_value_of_incorrect_type(): + """ + Test an ISA RO-Crate where a property value value has wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?property_value schema:value ?value . + } + INSERT { + ?property_value schema:value ?term . + } + WHERE { + ?property_value a schema:PropertyValue . + ?property_value schema:name "MyParameter" . + ?property_value schema:value ?value . + ?term a schema:DefinedTerm . + ?term schema:name "MyTerm" . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "PropertyValue value MUST be of type string, float, or integer" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) diff --git a/tests/integration/profiles/isa-ro-crate/test_1_study.py b/tests/integration/profiles/isa-ro-crate/test_1_study.py new file mode 100644 index 00000000..e1ba02a6 --- /dev/null +++ b/tests/integration/profiles/isa-ro-crate/test_1_study.py @@ -0,0 +1,327 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +from rocrate_validator.models import Severity +from tests.ro_crates import ValidROC +from tests.shared import do_entity_test, SPARQL_PREFIXES + +# set up logging +logger = logging.getLogger(__name__) + + +# ----- MUST fails tests + + +# WIP update these tests to actually do what the name/description say +def test_isa_study_no_identifier(): + """ + Test an ISA RO-Crate where a Study has no identifier. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?dataset schema:identifier ?id . + } + WHERE { + ?dataset a schema:Dataset . + ?dataset schema:additionalType "Study" . + ?dataset schema:identifier ?id . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "Study entity MUST have a non-empty identifier of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_study_identifier_not_string(): + """ + Test an ISA RO-Crate where a Study has an identifier that is not a string. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?dataset schema:identifier ?id . + } + INSERT { + ?dataset schema:identifier 42 . + } + WHERE { + ?dataset a schema:Dataset . + ?dataset schema:additionalType "Study" . + ?dataset schema:identifier ?id . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "Study entity MUST have a non-empty identifier of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_study_name(): + """ + Test an ISA RO-Crate where a Study does not have a name. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?dataset schema:name ?name . + } + WHERE { + ?dataset a schema:Dataset . + ?dataset schema:additionalType "Study" . + ?dataset schema:name ?name . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "Study entity MUST have a non-empty name of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_study_name_not_string(): + """ + Test an ISA RO-Crate where a Study has a name that is not a string. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?dataset schema:name ?id . + } + INSERT { + ?dataset schema:name 42 . + } + WHERE { + ?dataset a schema:Dataset . + ?dataset schema:additionalType "Study" . + ?dataset schema:identifier ?id . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "Study entity MUST have a non-empty name of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_study_correctly_referenced_from_investigation(): + """ + Test an ISA RO-Crate where a Study is referenced from the Investigation/Root Data Entity with wrong property. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?dataset1 schema:hasPart ?dataset2 . + } + INSERT { + ?dataset1 schema:mentions ?dataset2 . + } + WHERE { + ?dataset1 a schema:Dataset . + ?dataset2 a schema:Dataset . + ?dataset2 schema:additionalType "Study" . + ?dataset1 schema:hasPart ?dataset2 . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + expected_triggered_requirements=[ + "Study MUST be directly referenced from Investigation (Root Data Entity)" + ], + expected_triggered_issues=[ + "Study MUST be directly referenced in hasPart on the Investigation (Root Data Entity)" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_study_directly_referenced_from_investigation(): + """ + Test an ISA RO-Crate where a Study is not directly referenced from the Investigation/Root Data Entity. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?dataset1 schema:hasPart ?dataset2 . + } + WHERE { + ?dataset1 a schema:Dataset . + ?dataset2 a schema:Dataset . + ?dataset1 schema:additionalType "Investigation" . + ?dataset2 schema:additionalType "Study" . + ?dataset1 schema:hasPart ?dataset2 . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + expected_triggered_requirements=["Study MUST be directly referenced from Investigation (Root Data Entity)"], + expected_triggered_issues=[ + "Study MUST be directly referenced in hasPart on the Investigation (Root Data Entity)" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_study_no_shoulds(): + """ + Test an ISA RO-Crate where the study is missing should properties. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?dataset schema:dateCreated ?dc . + ?dataset schema:datePublished ?dp . + ?dataset schema:creator ?creator . + ?dataset schema:hasPart ?hasPart . + ?dataset schema:about ?about . + ?dataset schema:description ?description . + } + WHERE { + ?dataset a schema:Dataset . + ?dataset schema:additionalType "Study" . + ?dataset schema:dateCreated ?dc . + ?dataset schema:datePublished ?dp . + ?dataset schema:creator ?creator . + ?dataset schema:hasPart ?hasPart . + ?dataset schema:about ?about . + ?dataset schema:description ?description . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "Study entity SHOULD have a dateCreated", + "Study entity SHOULD have a datePublished", + "Study entity SHOULD have a creator", + "Study entity SHOULD have hasPart", + "Study entity SHOULD have about", + "Study entity SHOULD have a non-empty description of type string", + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_study_shoulds_have_wrong_types(): + """ + Test an ISA RO-Crate where the study has should properties with wrong types. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?dataset schema:dateCreated ?dc . + ?dataset schema:datePublished ?dp . + ?dataset schema:creator ?creator . + ?dataset schema:hasPart ?hasPart . + ?dataset schema:about ?about . + ?dataset schema:description ?description . + } + INSERT { + ?dataset schema:dateCreated 42 . + ?dataset schema:datePublished 42 . + ?dataset schema:creator 42 . + ?dataset schema:hasPart 42 . + ?dataset schema:about 42 . + ?dataset schema:description 42 . + } + WHERE { + ?dataset a schema:Dataset . + ?dataset schema:additionalType "Study" . + ?dataset schema:dateCreated ?dc . + ?dataset schema:datePublished ?dp . + ?dataset schema:creator ?creator . + ?dataset schema:hasPart ?hasPart . + ?dataset schema:about ?about . + ?dataset schema:description ?description . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "Study dateCreated MUST be a valid date literal", + "Study datePublished MUST be a valid date literal", + "Study creator MUST be of type Person", + "Study hasPart MUST be of type Dataset or File", + "Study about MUST be of type LabProcess", + "Study description MUST be of type string", + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) diff --git a/tests/integration/profiles/isa-ro-crate/test_2_assay.py b/tests/integration/profiles/isa-ro-crate/test_2_assay.py new file mode 100644 index 00000000..f0cc5076 --- /dev/null +++ b/tests/integration/profiles/isa-ro-crate/test_2_assay.py @@ -0,0 +1,274 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +from rocrate_validator.models import Severity +from tests.ro_crates import ValidROC +from tests.shared import do_entity_test, SPARQL_PREFIXES + +# set up logging +logger = logging.getLogger(__name__) + + +# WIP update these tests to actually do what the name/description say +def test_isa_assay_no_identifier(): + """ + Test an ISA RO-Crate where a Assay has no identifier. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?dataset schema:identifier ?id . + } + WHERE { + ?dataset a schema:Dataset . + ?dataset schema:additionalType "Assay" . + ?dataset schema:identifier ?id . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + expected_triggered_requirements=["Assay MUST have base properties"], + expected_triggered_issues=[ + "Assay entity MUST have a non-empty identifier of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_assay_identifier_not_string(): + """ + Test an ISA RO-Crate where a Assay has an identifier that is not a string. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?dataset schema:identifier ?id . + } + INSERT { + ?dataset schema:identifier 42 . + } + WHERE { + ?dataset a schema:Dataset . + ?dataset schema:additionalType "Assay" . + ?dataset schema:identifier ?id . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Root Data Entity must be Investigation"], + expected_triggered_issues=[ + "Assay entity MUST have a non-empty identifier of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_assay_correctly_referenced_from_investigation(): + """ + Test an ISA RO-Crate where a Assay is referenced from the Investigation/Root Data Entity with wrong property. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?dataset1 schema:hasPart ?dataset2 . + } + INSERT { + ?dataset1 schema:mentions ?dataset2 . + } + WHERE { + ?dataset1 a schema:Dataset . + ?dataset2 a schema:Dataset . + ?dataset2 schema:additionalType "Assay" . + ?dataset1 schema:hasPart ?dataset2 . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + expected_triggered_issues=[ + "Assay MUST be directly referenced in hasPart on the Investigation (Root Data Entity) or a Study" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_assay_directly_referenced_from_investigation(): + """ + Test an ISA RO-Crate where a Assay is not directly referenced from the Investigation/Root Data Entity. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?dataset1 schema:hasPart ?dataset3 . + ?dataset2 schema:hasPart ?dataset3 . + } + INSERT { + a schema:Dataset ; + schema:identifier "abc" ; + schema:name "A Dataset" ; + schema:hasPart ?dataset3 . + schema:hasPart ?dataset3 . + ?dataset1 schema:hasPart . + } + WHERE { + ?dataset1 a schema:Dataset . + ?dataset2 a schema:Dataset . + ?dataset3 a schema:Dataset . + ?dataset1 schema:additionalType "Investigation" . + ?dataset2 schema:additionalType "Study" . + ?dataset3 schema:additionalType "Assay" . + ?dataset1 schema:hasPart ?dataset2 . + ?dataset2 schema:hasPart ?dataset3 . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + expected_triggered_issues=[ + "Assay MUST be directly referenced in hasPart on the Investigation (Root Data Entity) or a Study" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_assay_no_shoulds(): + """ + Test an ISA RO-Crate where the assay is missing should properties. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?dataset schema:name ?name . + ?dataset schema:description ?description . + ?dataset schema:creator ?creator . + ?dataset schema:about ?about . + ?dataset schema:measurementMethod ?measurementMethod . + ?dataset schema:measurementTechnique ?measurementTechnique . + ?dataset schema:hasPart ?hasPart . + } + WHERE { + ?dataset a schema:Dataset . + ?dataset schema:identifier "MyAssay" . + ?dataset schema:name ?name . + ?dataset schema:description ?description . + ?dataset schema:creator ?creator . + ?dataset schema:about ?about . + ?dataset schema:measurementMethod ?measurementMethod . + ?dataset schema:measurementTechnique ?measurementTechnique . + ?dataset schema:hasPart ?hasPart . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "Assay entity SHOULD have a non-empty name of type string", + "Assay entity SHOULD have a non-empty description of type string", + "Assay entity SHOULD have a creator", + "Assay entity SHOULD have about", + "Assay entity SHOULD have a measurement method", + "Assay entity SHOULD have a measurement technique", + "Assay entity SHOULD have hasPart", + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_assay_shoulds_have_wrong_types(): + """ + Test an ISA RO-Crate where the assay has should properties with wrong types. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?dataset schema:name ?name . + ?dataset schema:description ?description . + ?dataset schema:creator ?creator . + ?dataset schema:about ?about . + ?dataset schema:measurementMethod ?measurementMethod . + ?dataset schema:measurementTechnique ?measurementTechnique . + ?dataset schema:hasPart ?hasPart . + } + INSERT { + ?dataset schema:name 42 . + ?dataset schema:description 42 . + ?dataset schema:creator 42 . + ?dataset schema:about 42 . + ?dataset schema:measurementMethod 42 . + ?dataset schema:measurementTechnique 42 . + ?dataset schema:hasPart 42 . + } + WHERE { + ?dataset a schema:Dataset . + ?dataset schema:identifier "MyAssay" . + ?dataset schema:name ?name . + ?dataset schema:description ?description . + ?dataset schema:creator ?creator . + ?dataset schema:about ?about . + ?dataset schema:measurementMethod ?measurementMethod . + ?dataset schema:measurementTechnique ?measurementTechnique . + ?dataset schema:hasPart ?hasPart . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "Assay name MUST be of type string", + "Assay description MUST be of type string", + "Assay creator MUST be of type Person", + "Assay about MUST be of type LabProcess", + "Assay measurement method MUST be of type string or DefinedTerm", + "Assay measurement technique MUST be of type string or DefinedTerm", + "Assay hasPart MUST be of type Dataset or File", + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) diff --git a/tests/integration/profiles/isa-ro-crate/test_3_process.py b/tests/integration/profiles/isa-ro-crate/test_3_process.py new file mode 100644 index 00000000..7c1234cd --- /dev/null +++ b/tests/integration/profiles/isa-ro-crate/test_3_process.py @@ -0,0 +1,345 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +from rocrate_validator.models import Severity +from tests.ro_crates import ValidROC +from tests.shared import do_entity_test, SPARQL_PREFIXES + +# set up logging +logger = logging.getLogger(__name__) + + +# ----- MUST fails tests +def test_isa_process_name(): + """ + Test an ISA RO-Crate where a Process does not have a name. + """ + sparql = ( + SPARQL_PREFIXES + + """ + PREFIX bioschemas: + DELETE { + ?process schema:name ?name . + } + WHERE { + ?process a bioschemas:LabProcess . + ?process schema:name ?name . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + expected_triggered_requirements=["Process MUST have name"], + expected_triggered_issues=[ + "Process entity MUST have a non-empty name of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_process_not_correctly_referenced_from_dataset(): + """ + Test an ISA RO-Crate where a Process is referenced from a Dataset with wrong property. + """ + sparql = ( + SPARQL_PREFIXES + + """ + PREFIX bioschemas: + DELETE { + ?dataset schema:about ?process . + } + INSERT { + ?dataset schema:mentions ?process . + } + WHERE { + ?dataset a schema:Dataset . + ?dataset schema:about ?process. + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + expected_triggered_requirements=[ + "Process MUST be directly referenced from a dataset" + ], + expected_triggered_issues=[ + "Process MUST be directly referenced in about on a Dataset" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_process_no_object(): + """ + Test an ISA RO-Crate where a Process does not have an object. + """ + sparql = ( + SPARQL_PREFIXES + + """ + PREFIX bioschemas: + DELETE { + ?process schema:object ?object . + } + WHERE { + ?process a bioschemas:LabProcess . + ?process schema:object ?object . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + expected_triggered_requirements=["Process SHOULD have an object"], + expected_triggered_issues=["Process entity SHOULD have an object"], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_process_object_incorrect_type(): + """ + Test an ISA RO-Crate where a Process has an object with the wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + PREFIX bioschemas: + DELETE { + ?process schema:object ?object . + } + INSERT { + ?process schema:object 42 . + } + WHERE { + ?process a bioschemas:LabProcess . + ?process schema:object ?object . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + expected_triggered_requirements=["Process SHOULD have an object"], + expected_triggered_issues=[ + "Process objects MUST be of type File, Sample or BioSample" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_process_no_result(): + """ + Test an ISA RO-Crate where a Process does not have a result. + """ + sparql = ( + SPARQL_PREFIXES + + """ + PREFIX bioschemas: + DELETE { + ?process schema:result ?result . + } + WHERE { + ?process a bioschemas:LabProcess . + ?process schema:result ?result . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + expected_triggered_requirements=["Process SHOULD have a result"], + expected_triggered_issues=["Process entity SHOULD have a result"], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_process_result_incorrect_type(): + """ + Test an ISA RO-Crate where a Process has a result with the wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + PREFIX bioschemas: + DELETE { + ?process schema:result ?result . + } + INSERT { + ?process schema:result 42 . + } + WHERE { + ?process a bioschemas:LabProcess . + ?process schema:result ?result . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + expected_triggered_requirements=["Process SHOULD have a result"], + expected_triggered_issues=[ + "Process results MUST be of type File, Sample or BioSample" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_process_no_value(): + """ + Test an ISA RO-Crate where a Process does not have a parameter value. + """ + sparql = ( + SPARQL_PREFIXES + + """ + PREFIX bioschemas: + PREFIX bioschemas-prop: + DELETE { + ?process bioschemas-prop:parameterValue ?pv . + } + WHERE { + ?process a bioschemas:LabProcess . + ?process bioschemas-prop:parameterValue ?pv . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + expected_triggered_requirements=["Process SHOULD have a parameter value"], + expected_triggered_issues=["Process entity SHOULD have a parameter value"], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_process_value_incorrect_type(): + """ + Test an ISA RO-Crate where a Process has a parameter value with the wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + PREFIX bioschemas: + PREFIX bioschemas-prop: + DELETE { + ?process bioschemas-prop:parameterValue ?pv . + } + INSERT { + ?process bioschemas-prop:parameterValue 42 . + } + WHERE { + ?process a bioschemas:LabProcess . + ?process bioschemas-prop:parameterValue ?pv . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + expected_triggered_requirements=["Process SHOULD have a parameter value"], + expected_triggered_issues=[ + "Process parameter values MUST be of type PropertyValue" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_process_no_protocol(): + """ + Test an ISA RO-Crate where a Process does not have a protocol. + """ + sparql = ( + SPARQL_PREFIXES + + """ + PREFIX bioschemas: + PREFIX bioschemas-prop: + DELETE { + ?process bioschemas-prop:executesLabProtocol ?prot . + } + WHERE { + ?process a bioschemas:LabProcess . + ?process bioschemas-prop:executesLabProtocol ?prot . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + expected_triggered_requirements=["Process SHOULD have a protocol"], + expected_triggered_issues=["Process entity SHOULD have a protocol"], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_process_protocol_incorrect_type(): + """ + Test an ISA RO-Crate where a Process has a protocol with the wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + PREFIX bioschemas: + PREFIX bioschemas-prop: + DELETE { + ?process bioschemas-prop:executesLabProtocol ?prot . + } + INSERT { + ?process bioschemas-prop:executesLabProtocol 42 . + } + WHERE { + ?process a bioschemas:LabProcess . + ?process bioschemas-prop:executesLabProtocol ?prot . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + expected_triggered_requirements=["Process SHOULD have a protocol"], + expected_triggered_issues=["Process protocols MUST be of type LabProtocol"], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) diff --git a/tests/integration/profiles/isa-ro-crate/test_4_protocol.py b/tests/integration/profiles/isa-ro-crate/test_4_protocol.py new file mode 100644 index 00000000..c48885b5 --- /dev/null +++ b/tests/integration/profiles/isa-ro-crate/test_4_protocol.py @@ -0,0 +1,216 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +from rocrate_validator.models import Severity +from tests.ro_crates import ValidROC +from tests.shared import do_entity_test, SPARQL_PREFIXES + +# set up logging +logger = logging.getLogger(__name__) + + +# ----- MUST fails tests +def test_isa_protocol_no_name(): + """ + Test an ISA RO-Crate where a Protocol does not have a name. + """ + sparql = ( + SPARQL_PREFIXES + + """ + PREFIX bioschemas: + PREFIX bioschemas-prop: + DELETE { + ?protocol schema:name ?name . + } + WHERE { + ?protocol a bioschemas:LabProtocol . + ?protocol schema:name ?name . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + # expected_triggered_requirements=["Protocol SHOULD have name"], + expected_triggered_issues=[ + "Protocol entity SHOULD have a non-empty name of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_protocol_name_incorrect_type(): + """ + Test an ISA RO-Crate where a Protocol has a name with the wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + PREFIX bioschemas: + PREFIX bioschemas-prop: + DELETE { + ?protocol schema:name ?name . + } + INSERT { + ?protocol schema:name 42 . + } + WHERE { + ?protocol a bioschemas:LabProtocol . + ?protocol schema:name ?name . + } + """ + ) + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Protocol SHOULD have name"], + expected_triggered_issues=["Protocol name MUST be of type string"], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_protocol_no_description(): + """ + Test an ISA RO-Crate where a Protocol does not have a description. + """ + sparql = ( + SPARQL_PREFIXES + + """ + PREFIX bioschemas: + PREFIX bioschemas-prop: + DELETE { + ?protocol schema:description ?description . + } + WHERE { + ?protocol a bioschemas:LabProtocol . + ?protocol schema:description ?description . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + # expected_triggered_requirements=["Protocol SHOULD have description"], + expected_triggered_issues=[ + "Protocol entity SHOULD have a non-empty description of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_protocol_description_incorrect_type(): + """ + Test an ISA RO-Crate where a Protocol has a description with the wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + PREFIX bioschemas: + PREFIX bioschemas-prop: + DELETE { + ?protocol schema:description ?description . + } + INSERT { + ?protocol schema:description 42 . + } + WHERE { + ?protocol a bioschemas:LabProtocol . + ?protocol schema:description ?description . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Protocol SHOULD have description"], + expected_triggered_issues=["Protocol description MUST be of type string"], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_protocol_no_intendedUse(): + """ + Test an ISA RO-Crate where a Protocol does not have an intended use. + """ + sparql = ( + SPARQL_PREFIXES + + """ + PREFIX bioschemas: + PREFIX bioschemas-prop: + DELETE { + ?protocol bioschemas-prop:intendedUse ?intendedUse . + } + WHERE { + ?protocol a bioschemas:LabProtocol . + ?protocol bioschemas-prop:intendedUse ?intendedUse . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + # expected_triggered_requirements=["Protocol SHOULD have intended use"], + expected_triggered_issues=["Protocol entity SHOULD have an intended use"], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_protocol_intendedUse_incorrect_type(): + """ + Test an ISA RO-Crate where a Protocol has an intended use with the wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + PREFIX bioschemas: + PREFIX bioschemas-prop: + DELETE { + ?protocol bioschemas-prop:intendedUse ?intendedUse . + } + INSERT { + ?protocol bioschemas-prop:intendedUse 42 . + } + WHERE { + ?protocol a bioschemas:LabProtocol . + ?protocol bioschemas-prop:intendedUse ?intendedUse . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Protocol SHOULD have intended use"], + expected_triggered_issues=["Protocol intended use MUST be of type string or DefinedTerm"], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) diff --git a/tests/integration/profiles/isa-ro-crate/test_5_sample.py b/tests/integration/profiles/isa-ro-crate/test_5_sample.py new file mode 100644 index 00000000..305ccca0 --- /dev/null +++ b/tests/integration/profiles/isa-ro-crate/test_5_sample.py @@ -0,0 +1,158 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +from rocrate_validator.models import Severity +from tests.ro_crates import ValidROC +from tests.shared import do_entity_test, SPARQL_PREFIXES + +# set up logging +logger = logging.getLogger(__name__) + + +# ----- MUST fails tests +def test_isa_sample_name(): + """ + Test an ISA RO-Crate where a sample has no name. + """ + sparql = ( + SPARQL_PREFIXES + + """ + PREFIX bioschemas: + DELETE { + ?sample schema:name "MyInputSample" . + } + WHERE { + ?sample a bioschemas:Sample . + ?sample schema:name "MyInputSample" . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "Sample entity MUST have a non-empty name of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_sample_name_of_incorrect_type(): + """ + Test an ISA RO-Crate where a sample name has wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + PREFIX bioschemas: + DELETE { + ?sample schema:name "MyInputSample" . + } + INSERT { + ?sample schema:name 42 . + } + WHERE { + ?sample a bioschemas:Sample . + ?sample schema:name "MyInputSample" . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "Sample entity MUST have a non-empty name of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_sample_no_additional_property(): + """ + Test an ISA RO-Crate where a sample has no additional properties. + """ + sparql = ( + SPARQL_PREFIXES + + """ + PREFIX bioschemas: + PREFIX bioschemas-prop: + DELETE { + ?sample bioschemas-prop:additionalProperty ?ap . + } + WHERE { + ?sample a bioschemas:Sample . + ?sample schema:name "MyInputSample" . + ?sample bioschemas-prop:additionalProperty ?ap . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "Sample entity SHOULD have at least one additional property" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_sample_additional_property_of_incorrect_type(): + """ + Test an ISA RO-Crate where a sample has additional property with wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + PREFIX bioschemas: + PREFIX bioschemas-prop: + DELETE { + ?sample bioschemas-prop:additionalProperty ?ap . + } + INSERT { + ?sample bioschemas-prop:additionalProperty 42 . + } + WHERE { + ?sample a bioschemas:Sample . + ?sample schema:name "MyInputSample" . + ?sample bioschemas-prop:additionalProperty ?ap . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "Sample additional property MUST be of type PropertyValue" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) diff --git a/tests/integration/profiles/isa-ro-crate/test_6_data.py b/tests/integration/profiles/isa-ro-crate/test_6_data.py new file mode 100644 index 00000000..1f19f0ec --- /dev/null +++ b/tests/integration/profiles/isa-ro-crate/test_6_data.py @@ -0,0 +1,87 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +from rocrate_validator.models import Severity +from tests.ro_crates import ValidROC +from tests.shared import do_entity_test, SPARQL_PREFIXES + +# set up logging +logger = logging.getLogger(__name__) + + +# ----- MUST fails tests +def test_isa_file_name(): + """ + Test an ISA RO-Crate where a file has no name. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?file schema:name "datafile.txt" . + } + WHERE { + ?file a schema:MediaObject . + ?file schema:name "datafile.txt" . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "File entity MUST have a non-empty name of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_file_name_of_incorrect_type(): + """ + Test an ISA RO-Crate where a file name has wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?file schema:name "datafile.txt" . + } + INSERT { + ?file schema:name 42 . + } + WHERE { + ?file a schema:MediaObject . + ?file schema:name "datafile.txt" . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "File entity MUST have a non-empty name of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) diff --git a/tests/integration/profiles/isa-ro-crate/test_7_person.py b/tests/integration/profiles/isa-ro-crate/test_7_person.py new file mode 100644 index 00000000..9135b633 --- /dev/null +++ b/tests/integration/profiles/isa-ro-crate/test_7_person.py @@ -0,0 +1,397 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +from rocrate_validator.models import Severity +from tests.ro_crates import ValidROC +from tests.shared import do_entity_test, SPARQL_PREFIXES + +# set up logging +logger = logging.getLogger(__name__) + + +# ----- MUST fails tests +def test_isa_person_given_name(): + """ + Test an ISA RO-Crate where a person has no given name. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?person schema:givenName "John" . + } + WHERE { + ?person a schema:Person . + ?person schema:givenName "John". + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "Person entity MUST have a non-empty given name of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_person_given_name_of_incorrect_type(): + """ + Test an ISA RO-Crate where a person given name has wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?person schema:givenName ?name . + } + INSERT { + ?person schema:givenName 42 . + } + WHERE { + ?person a schema:Person . + ?person schema:familyName "Doe" . + ?person schema:givenName ?name . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "Person entity MUST have a non-empty given name of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_person_family_name(): + """ + Test an ISA RO-Crate where a person has no family name. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?person schema:familyName "Doe" . + } + WHERE { + ?person a schema:Person . + ?person schema:familyName "Doe" . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "Person entity SHOULD have a non-empty family name of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_person_family_name_of_incorrect_type(): + """ + Test an ISA RO-Crate where a person family name has wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?person schema:familyName "Doe" . + } + INSERT { + ?person schema:familyName 42 . + } + WHERE { + ?person a schema:Person . + ?person schema:familyName "Doe" . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=["Person family name MUST be of type string"], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_person_email(): + """ + Test an ISA RO-Crate where a person has no email. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?person schema:email "abc" . + } + WHERE { + ?person a schema:Person . + ?person schema:email "abc" . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "Person entity SHOULD have a non-empty email of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_person_email_of_incorrect_type(): + """ + Test an ISA RO-Crate where a person email has wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?person schema:email "abc" . + } + INSERT { + ?person schema:email 42 . + } + WHERE { + ?person a schema:Person . + ?person schema:email "abc" . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=["Person email MUST be of type string"], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_person_identifier(): + """ + Test an ISA RO-Crate where a person has no identifier. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?person schema:identifier ?id . + } + WHERE { + ?person a schema:Person . + ?person schema:familyName "Doe" . + ?person schema:identifier ?id . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "Person entity SHOULD have a non-empty identifier of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_person_identifier_of_incorrect_type(): + """ + Test an ISA RO-Crate where a person identifier has wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?person schema:identifier ?id . + } + INSERT { + ?person schema:identifier 42 . + } + WHERE { + ?person a schema:Person . + ?person schema:familyName "Doe" . + ?person schema:identifier ?id . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=["Person identifier MUST be of type string"], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_person_affiliation(): + """ + Test an ISA RO-Crate where a person has no affiliation. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?person schema:affiliation ?a . + } + WHERE { + ?person a schema:Person . + ?person schema:familyName "Doe" . + ?person schema:affiliation ?a . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "Person entity SHOULD have at least one affiliation" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_person_affiliation_of_incorrect_type(): + """ + Test an ISA RO-Crate where a person affiliation has wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?person schema:affiliation ?a . + } + INSERT { + ?person schema:affiliation 42 . + } + WHERE { + ?person a schema:Person . + ?person schema:familyName "Doe" . + ?person schema:affiliation ?a . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=["Person affiliation MUST be of type Organization"], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_person_job_title(): + """ + Test an ISA RO-Crate where a person has no job title. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?person schema:jobTitle ?jt . + } + WHERE { + ?person a schema:Person . + ?person schema:familyName "Doe" . + ?person schema:jobTitle ?jt . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=["Person entity SHOULD have at least one job title"], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_person_job_title_of_incorrect_type(): + """ + Test an ISA RO-Crate where a person job title has wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?person schema:jobTitle ?jt . + } + INSERT { + ?person schema:jobTitle 42 . + } + WHERE { + ?person a schema:Person . + ?person schema:familyName "Doe" . + ?person schema:jobTitle ?jt . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=["Person job title MUST be of type DefinedTerm"], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) diff --git a/tests/integration/profiles/isa-ro-crate/test_8_article.py b/tests/integration/profiles/isa-ro-crate/test_8_article.py new file mode 100644 index 00000000..fac95cbb --- /dev/null +++ b/tests/integration/profiles/isa-ro-crate/test_8_article.py @@ -0,0 +1,209 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +from rocrate_validator.models import Severity +from tests.ro_crates import ValidROC +from tests.shared import do_entity_test, SPARQL_PREFIXES + +# set up logging +logger = logging.getLogger(__name__) + + +# ----- MUST fails tests +def test_isa_article_headline(): + """ + Test an ISA RO-Crate where an article has no headline. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?article schema:headline ?headline . + } + WHERE { + ?article a schema:ScholarlyArticle . + ?article schema:headline ?headline . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "Article entity MUST have a non-empty headline of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_article_headline_of_incorrect_type(): + """ + Test an ISA RO-Crate where an article headline has wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?article schema:headline ?headline . + } + INSERT { + ?article schema:headline 42 . + } + WHERE { + ?article a schema:ScholarlyArticle . + ?article schema:headline ?headline . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "Article entity MUST have a non-empty headline of type string" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_article_identifier(): + """ + Test an ISA RO-Crate where an article has no identifier. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?article schema:identifier ?identifier . + } + WHERE { + ?article a schema:ScholarlyArticle . + ?article schema:identifier ?identifier . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "Article entity MUST have a non-empty identifier of type string or PropertyValue" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_article_identifier_of_incorrect_type(): + """ + Test an ISA RO-Crate where an article identifier has wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?article schema:identifier ?identifier . + } + INSERT { + ?article schema:identifier 42 . + } + WHERE { + ?article a schema:ScholarlyArticle . + ?article schema:identifier ?identifier . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=[ + "Article entity MUST have a non-empty identifier of type string or PropertyValue" + ], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_article_author(): + """ + Test an ISA RO-Crate where an article has no author. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?article schema:author ?author . + } + WHERE { + ?article a schema:ScholarlyArticle . + ?article schema:author ?author . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=["Article entity SHOULD have at least one author"], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_article_author_of_incorrect_type(): + """ + Test an ISA RO-Crate where an article author has wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?article schema:author ?author . + } + INSERT { + ?article schema:author 42 . + } + WHERE { + ?article a schema:ScholarlyArticle . + ?article schema:author ?author . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=["Article author MUST be of type Person"], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) diff --git a/tests/integration/profiles/isa-ro-crate/test_9_comment.py b/tests/integration/profiles/isa-ro-crate/test_9_comment.py new file mode 100644 index 00000000..c2b7db4c --- /dev/null +++ b/tests/integration/profiles/isa-ro-crate/test_9_comment.py @@ -0,0 +1,83 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +from rocrate_validator.models import Severity +from tests.ro_crates import ValidROC +from tests.shared import do_entity_test, SPARQL_PREFIXES + +# set up logging +logger = logging.getLogger(__name__) + + +# ----- MUST fails tests +def test_isa_comment_text(): + """ + Test an ISA RO-Crate where a comment has no text. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?comment schema:text ?text . + } + WHERE { + ?comment a schema:Comment . + ?comment schema:text ?text . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=["Comment entity SHOULD have at least one text"], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_isa_comment_text_of_incorrect_type(): + """ + Test an ISA RO-Crate where a comment text has wrong type. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?comment schema:text ?text . + } + INSERT { + ?comment schema:text 42 . + } + WHERE { + ?comment a schema:Comment . + ?comment schema:text ?text . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().isa_ro_crate, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + # expected_triggered_requirements=["Study MUST have base properties"], + expected_triggered_issues=["Comment text MUST be of type string"], + profile_identifier="isa-ro-crate", + rocrate_entity_mod_sparql=sparql, + ) diff --git a/tests/integration/profiles/isa-ro-crate/test_valid_isa_crate.py b/tests/integration/profiles/isa-ro-crate/test_valid_isa_crate.py new file mode 100644 index 00000000..f5509c31 --- /dev/null +++ b/tests/integration/profiles/isa-ro-crate/test_valid_isa_crate.py @@ -0,0 +1,35 @@ +# Copyright (c) 2026 DataPLANT +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +from rocrate_validator.models import Severity +from tests.conftest import SKIP_LOCAL_DATA_ENTITY_EXISTENCE_CHECK_IDENTIFIER +from tests.ro_crates import ValidROC +from tests.shared import do_entity_test + +logger = logging.getLogger(__name__) +logger.setLevel(logging.DEBUG) + + +def test_valid_isa_ro_crate(): + """Test a valid ISA RO-Crate.""" + do_entity_test( + ValidROC().isa_ro_crate, + Severity.REQUIRED, + True, + profile_identifier="isa-ro-crate", + skip_checks=[SKIP_LOCAL_DATA_ENTITY_EXISTENCE_CHECK_IDENTIFIER], + ) diff --git a/tests/ro_crates.py b/tests/ro_crates.py index a3ac78d7..b30b1d57 100644 --- a/tests/ro_crates.py +++ b/tests/ro_crates.py @@ -110,6 +110,10 @@ def workflow_run_crate(self) -> Path: def provenance_run_crate(self) -> Path: return VALID_CRATES_DATA_PATH / "provenance-run-crate" + @property + def isa_ro_crate(self) -> Path: + return VALID_CRATES_DATA_PATH / "minimal-isa-ro-crate" + @property def multi_profile_crate(self) -> Path: return VALID_CRATES_DATA_PATH / "multi-profile-crate" diff --git a/tests/unit/test_services.py b/tests/unit/test_services.py index 1711c672..1aef7370 100644 --- a/tests/unit/test_services.py +++ b/tests/unit/test_services.py @@ -21,7 +21,7 @@ from rocrate_validator.models import ValidationSettings from rocrate_validator.rocrate import ROCrateMetadata from rocrate_validator.services import detect_profiles, get_profiles, validate -from tests.ro_crates import InvalidMultiProfileROC, ValidROC +from tests.ro_crates import InvalidMultiProfileROC, ValidROC, InvalidFileDescriptorEntity # set up logging logger = logging.getLogger(__name__) @@ -106,6 +106,64 @@ def test_valid_local_workflow_testing_ro_crate(): "Expected the 'workflow-testing-ro-crate-0.1' profile" +def test_disable_inherited_profiles_issue_reporting(): + # Set the rocrate_uri to the workflow testing RO-Crate + crate_path = ValidROC().workflow_testing_ro_crate + logger.debug("Validating a local RO-Crate: %s", crate_path) + + # First, validate with inherited profiles issue reporting enabled + settings = ValidationSettings( + rocrate_uri=crate_path, + disable_inherited_profiles_issue_reporting=False + ) + result = validate(settings) + total_issues_with_inheritance = len(result.get_issues()) + logger.debug("Total issues with inherited profiles issue reporting enabled: %d", total_issues_with_inheritance) + + # Now, validate with inherited profiles issue reporting disabled + settings.disable_inherited_profiles_issue_reporting = True + result = validate(settings) + total_issues_without_inheritance = len(result.get_issues()) + logger.debug("Total issues with inherited profiles issue reporting disabled: %d", total_issues_without_inheritance) + + # Check that disabling inherited profiles issue reporting reduces the number of reported issues + assert total_issues_without_inheritance <= total_issues_with_inheritance, \ + "Disabling inherited profiles issue reporting should not increase the number of reported issues" + + # Check that all reported issues are from the main profile + main_profile_identifier = "workflow-testing-ro-crate-0.1" + for issue in result.get_issues(): + assert issue.check.profile.identifier == main_profile_identifier, \ + "All reported issues should belong to the main profile when inherited profiles issue reporting is disabled" + + +def test_skip_pycheck_on_workflow_ro_crate(): + # Set the rocrate_uri to the workflow testing RO-Crate + crate_path = InvalidFileDescriptorEntity().invalid_conforms_to + logger.debug("Validating a local RO-Crate: %s", crate_path) + settings = ValidationSettings(rocrate_uri=crate_path) + result = validate(settings) + assert not result.passed(), \ + "The RO-Crate is expected to be invalid because of an incorrect conformsTo field and missing resources" + assert len(result.failed_checks) == 2, "No failed checks expected when skipping the problematic check" + assert any(check.identifier == "ro-crate-1.1_5.3" for check in result.failed_checks), \ + "Expected the check 'ro-crate-1.1_5.3' to fail" + assert any(check.identifier == "ro-crate-1.1_12.1" for check in result.failed_checks), \ + "Expected the check 'ro-crate-1.1_12.1' to fail" + + # Perform a new validation skipping specific checks + settings.skip_checks = ["ro-crate-1.1_5.3", "ro-crate-1.1_12.1"] + result = validate(settings) + assert result.passed(), \ + "The RO-Crate should be valid when skipping the checks related to the invalid file descriptor entity" + + # Ensure that the skipped checks are indeed skipped + skipped_check_ids = {check.identifier for check in result.skipped_checks} + # logger.error("Skipped checks: %s", result.skipped_checks) + assert "ro-crate-1.1_5.3" in skipped_check_ids, "Expected check 'ro-crate-1.1_5.3' to be skipped" + assert "ro-crate-1.1_12.1" in skipped_check_ids, "Expected check 'ro-crate-1.1_12.1' to be skipped" + + def test_valid_local_multi_profile_crate(): # Set the rocrate_uri to the multi-profile RO-Crate crate_path = InvalidMultiProfileROC().invalid_multi_profile_crate diff --git a/tests/unit/test_validation_settings.py b/tests/unit/test_validation_settings.py index f2b61a15..9dcd2b40 100644 --- a/tests/unit/test_validation_settings.py +++ b/tests/unit/test_validation_settings.py @@ -23,12 +23,16 @@ def test_validation_settings_parse_dict(): "profiles_path": "/path/to/profiles", "requirement_severity": "RECOMMENDED", "enable_profile_inheritance": False, + "disable_inherited_profiles_issue_reporting": True, + "skip_checks": ["check1", "check2"] } settings = ValidationSettings.parse(settings_dict) assert str(settings.rocrate_uri) == "/path/to/data" assert settings.profiles_path == "/path/to/profiles" assert settings.requirement_severity == Severity.RECOMMENDED assert settings.enable_profile_inheritance is False + assert settings.disable_inherited_profiles_issue_reporting is True + assert settings.skip_checks == ["check1", "check2"] def test_validation_settings_parse_object(): @@ -36,13 +40,17 @@ def test_validation_settings_parse_object(): rocrate_uri="/path/to/data", profiles_path="/path/to/profiles", requirement_severity=Severity.RECOMMENDED, - enable_profile_inheritance=False + enable_profile_inheritance=False, + disable_inherited_profiles_issue_reporting=True, + skip_checks=["check1", "check2"] ) settings = ValidationSettings.parse(existing_settings) assert str(settings.rocrate_uri) == "/path/to/data" assert settings.profiles_path == "/path/to/profiles" assert settings.requirement_severity == Severity.RECOMMENDED assert settings.enable_profile_inheritance is False + assert settings.disable_inherited_profiles_issue_reporting is True + assert settings.skip_checks == ["check1", "check2"] def test_validation_settings_parse_invalid_type(): @@ -72,6 +80,17 @@ def test_validation_settings_enable_profile_inheritance(): assert settings.enable_profile_inheritance is False +def test_validation_settings_disable_inherited_profiles_issue_reporting(): + settings = ValidationSettings() + assert settings.disable_inherited_profiles_issue_reporting is False + + settings = ValidationSettings(disable_inherited_profiles_issue_reporting=True) + assert settings.disable_inherited_profiles_issue_reporting is True + + settings = ValidationSettings(disable_inherited_profiles_issue_reporting=False) + assert settings.disable_inherited_profiles_issue_reporting is False + + def test_validation_settings_data_path(): settings = ValidationSettings(rocrate_uri="/path/to/data") assert str(settings.rocrate_uri) == "/path/to/data"