././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1650984 asdf-3.4.0/0000755000175100001770000000000014653725331012051 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0210958 asdf-3.4.0/.github/0000755000175100001770000000000014653725331013411 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/.github/CODEOWNERS0000644000175100001770000000014114653725311014776 0ustar00runnerdocker# Requests reviews automatically for different parts of ASDF * @asdf-format/asdf-maintainers ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/.github/codecov.yml0000644000175100001770000000010614653725311015551 0ustar00runnerdockercoverage: status: project: default: threshold: 1% ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/.github/dependabot.yml0000644000175100001770000000054014653725311016236 0ustar00runnerdockerversion: 2 updates: # Maintain dependencies for GitHub Actions (main) - package-ecosystem: "github-actions" directory: "/" target-branch: "main" schedule: interval: "weekly" # Maintain dependencies for pip (main) - package-ecosystem: "pip" directory: "/" target-branch: "main" schedule: interval: "weekly" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/.github/issue_template.md0000644000175100001770000000114314653725311016753 0ustar00runnerdocker # Description of the problem # Example of the problem # System information asdf version: python version: operating system: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/.github/pull_request_template.md0000644000175100001770000000213014653725311020344 0ustar00runnerdocker # Description # Checklist: - [ ] pre-commit checks ran successfully - [ ] tests ran successfully - [ ] for a public change, a changelog entry was added - [ ] for a public change, documentation was updated - [ ] for any new features, unit tests were added ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0210958 asdf-3.4.0/.github/workflows/0000755000175100001770000000000014653725331015446 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/.github/workflows/build.yml0000644000175100001770000000070214653725311017265 0ustar00runnerdockername: build on: pull_request: release: types: [released] workflow_dispatch: jobs: build: uses: OpenAstronomy/github-actions-workflows/.github/workflows/publish_pure_python.yml@v1 with: upload_to_pypi: ${{ (github.event_name == 'release') && (github.event.action == 'released') }} test_extras: tests test_command: pytest --pyargs asdf secrets: pypi_token: ${{ secrets.PYPI_PASSWORD_ASDF_MAINTAINER }} ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/.github/workflows/changelog.yml0000644000175100001770000000156214653725311020122 0ustar00runnerdockername: Changelog on: pull_request: types: [labeled, unlabeled, opened, synchronize, reopened] # Only cancel in-progress jobs or runs for the current workflow # This cancels the already triggered workflows for a specific PR without canceling # other instances of this workflow (other PRs, scheduled triggers, etc) when something # within that PR re-triggers this CI concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: changelog: name: Confirm changelog entry runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 - name: Grep for PR number in CHANGES.rst run: grep -P '\[[^\]]*#${{github.event.number}}[,\]]' CHANGES.rst if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-changelog-entry-needed') }} ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/.github/workflows/ci.yml0000644000175100001770000000731314653725311016566 0ustar00runnerdockername: CI on: workflow_dispatch: schedule: - cron: '0 6 * * 1' # Every Monday at 6am UTC push: branches: - main - stable - '*.x' tags: - '*' pull_request: # Only cancel in-progress jobs or runs for the current workflow # This cancels the already triggered workflows for a specific PR without canceling # other instances of this workflow (other PRs, scheduled triggers, etc) when something # within that PR re-triggers this CI concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: pre-commit: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 - uses: pre-commit/action@v3.0.1 core: needs: [pre-commit] uses: OpenAstronomy/github-actions-workflows/.github/workflows/tox.yml@v1 with: submodules: false # Any env name which does not start with `pyXY` will use this Python version. default_python: '3.10' envs: | - linux: coverage name: Python 3.12 coverage python-version: 3.12 - linux: coverage name: Python 3.11 coverage python-version: 3.11 - linux: coverage name: Python 3.10 coverage python-version: 3.10 - linux: coverage name: Python 3.9 coverage python-version: 3.9 coverage: codecov jsonschema: uses: OpenAstronomy/github-actions-workflows/.github/workflows/tox.yml@v1 if: (github.repository == 'asdf-format/asdf' && (github.event_name == 'schedule' || github.event_name == 'push' || github.event_name == 'workflow_dispatch' || contains(github.event.pull_request.labels.*.name, 'jsonschema'))) with: submodules: false # Any env name which does not start with `pyXY` will use this Python version. default_python: '3.10' envs: | - linux: jsonschema asdf-schemas: needs: [core] uses: OpenAstronomy/github-actions-workflows/.github/workflows/tox.yml@v1 with: submodules: false # Any env name which does not start with `pyXY` will use this Python version. default_python: '3.10' envs: | - linux: asdf-standard - linux: asdf-transform-schemas test: needs: [core] uses: OpenAstronomy/github-actions-workflows/.github/workflows/tox.yml@v1 with: submodules: false # Any env name which does not start with `pyXY` will use this Python version. default_python: '3.9' envs: | - macos: py39-parallel - windows: py39-parallel dev: needs: [core] uses: OpenAstronomy/github-actions-workflows/.github/workflows/tox.yml@v1 with: submodules: false # Any env name which does not start with `pyXY` will use this Python version. default_python: '3.9' envs: | - linux: py39-devdeps-parallel - linux: py310-devdeps-parallel - linux: py311-devdeps-parallel - linux: py312-devdeps-parallel - linux: py313-devdeps-parallel # separate pytest so a failure here doesn't cause the whole suite to fail - linux: py311-pytestdev-parallel oldest: needs: [core] uses: OpenAstronomy/github-actions-workflows/.github/workflows/tox.yml@v1 with: submodules: false # Any env name which does not start with `pyXY` will use this Python version. default_python: '3.9' envs: | - linux: py39-oldestdeps-parallel compatibility: needs: [core] uses: OpenAstronomy/github-actions-workflows/.github/workflows/tox.yml@v1 with: submodules: false # Any env name which does not start with `pyXY` will use this Python version. default_python: '3.9' envs: | - linux: compatibility ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/.github/workflows/downstream.yml0000644000175100001770000000574214653725311020362 0ustar00runnerdockername: Downstream on: workflow_dispatch: schedule: - cron: '0 7 * * 1' # Every Monday at 6am UTC pull_request: # We also want this workflow triggered if the `Downstream CI` label is # added or present when PR is updated types: - synchronize - labeled push: tags: - '*' # Only cancel in-progress jobs or runs for the current workflow # This cancels the already triggered workflows for a specific PR without canceling # other instances of this workflow (other PRs, scheduled triggers, etc) when something # within that PR re-triggers this CI concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: asdf: uses: OpenAstronomy/github-actions-workflows/.github/workflows/tox.yml@v1 if: (github.repository == 'asdf-format/asdf' && (github.event_name == 'schedule' || github.event_name == 'push' || github.event_name == 'workflow_dispatch' || contains(github.event.pull_request.labels.*.name, 'Downstream CI'))) with: submodules: false # Any env name which does not start with `pyXY` will use this Python version. default_python: '3.10' envs: | - linux: asdf-wcs-schemas - linux: asdf-coordinates-schemas - linux: asdf-zarr - linux: asdf-compression astropy: uses: OpenAstronomy/github-actions-workflows/.github/workflows/tox.yml@v1 if: (github.repository == 'asdf-format/asdf' && (github.event_name == 'schedule' || github.event_name == 'push' || github.event_name == 'workflow_dispatch' || contains(github.event.pull_request.labels.*.name, 'Downstream CI'))) with: submodules: false # Any env name which does not start with `pyXY` will use this Python version. default_python: '3.10' envs: | - linux: asdf-astropy - linux: specutils stsci: uses: OpenAstronomy/github-actions-workflows/.github/workflows/tox.yml@v1 if: (github.repository == 'asdf-format/asdf' && (github.event_name == 'schedule' || github.event_name == 'push' || github.event_name == 'workflow_dispatch' || contains(github.event.pull_request.labels.*.name, 'Downstream CI'))) with: submodules: false # Any env name which does not start with `pyXY` will use this Python version. default_python: '3.10' envs: | - linux: astrocut - linux: gwcs - linux: jwst - linux: stdatamodels - linux: stpipe - linux: roman_datamodels third-party: uses: OpenAstronomy/github-actions-workflows/.github/workflows/tox.yml@v1 if: (github.repository == 'asdf-format/asdf' && (github.event_name == 'schedule' || github.event_name == 'push' || github.event_name == 'workflow_dispatch' || contains(github.event.pull_request.labels.*.name, 'Downstream CI'))) with: submodules: false # Any env name which does not start with `pyXY` will use this Python version. default_python: '3.10' envs: | - linux: weldx - linux: sunpy - linux: dkist ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/.github/workflows/s390x.yml0000644000175100001770000000433214653725311017057 0ustar00runnerdockername: s390x on: workflow_dispatch: schedule: - cron: '0 8 * * 1' # Every Monday at 6am UTC pull_request: # We also want this workflow triggered if the `s390x` label is # added or present when PR is updated types: - synchronize - labeled push: tags: - '*' # Only cancel in-progress jobs or runs for the current workflow # This cancels the already triggered workflows for a specific PR without canceling # other instances of this workflow (other PRs, scheduled triggers, etc) when something # within that PR re-triggers this CI concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: exotic_architechtures: runs-on: ubuntu-20.04 name: Python 3.9 if: (github.repository == 'asdf-format/asdf' && (github.event_name == 'schedule' || github.event_name == 'push' || github.event_name == 'workflow_dispatch' || contains(github.event.pull_request.labels.*.name, 's390x'))) env: ARCH_ON_CI: ${{ matrix.arch }} strategy: fail-fast: false matrix: include: - arch: aarch64 - arch: s390x steps: - uses: actions/checkout@v4 with: fetch-depth: 0 submodules: true - uses: uraimo/run-on-arch-action@v2 name: Run tests id: build with: arch: ${{ matrix.arch }} distro: ubuntu_rolling shell: /bin/bash install: | apt-get update -q -y apt-get install -q -y git \ g++ \ pkg-config \ python3 \ python3-astropy \ python3-lz4 \ python3-numpy \ python3-scipy \ python3-venv \ python3-wheel run: | python3 -m venv --system-site-packages tests source tests/bin/activate pip3 install --upgrade pip setuptools pytest pytest-remotedata pip3 install -e .[all,tests] pip3 list python3 -m pytest --remote-data ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/CHANGES.rst0000644000175100001770000011022414653725311013651 0ustar00runnerdocker3.5.0 (unreleased) ------------------ - 3.4.0 (2024-08-04) ------------------ - Fix issue where roundtripping a masked array with no masked values removes the mask [#1803] - Use a custom exception ``AsdfSerializationError`` to indicate when an object in the tree fails to be serialized by asdf (and by yaml). This exception currently inherits from ``yaml.representer.RepresenterError`` to provide backwards compatibility. However this inheritance may be dropped in a future asdf version. Please migrate to the new ``AsdfSerializationError``. [#1809] - Drop ``importlib_metadata`` as a dependency on Python 3.12 and newer [#1810] - Bumped minimal requirement on ``attrs`` from ``20.1.0`` to ``22.2.0`` [#1815] 3.3.0 (2024-07-12) ------------------ - Fix ``__asdf_traverse__`` for non-tagged objects [#1739] - Deprecate ``asdf.testing.helpers.format_tag`` [#1774] - Deprecate ``asdf.versioning.AsdfSpec`` [#1774] - Deprecate ``asdf.util.filepath_to_url`` use ``pathlib.Path.to_uri`` [#1735] - Record package providing manifest for extensions used to write a file and ``AsdfPackageVersionWarning`` when installed extension/manifest package does not match that used to write the file [#1758] - Fix bug where a dictionary containing a key ``id`` caused any contained references to fail to resolve [#1716] - Issue a ``AsdfManifestURIMismatchWarning`` during write if a used extension was created from a manifest registered with a uri that does not match the id in the manifest [#1785] - Allow converters to provide types as strings that can resolve to public classes (even if the class is implemented in a private module). [#1654] - Add options to control saving the base array when saving array views controlled via ``AsdfConfig.default_array_save_base``, ``AsdfFile.set_array_save_base`` and ``SerializationContext.set_array_save_base`` [#1753] - Deprecate ``ignore_implicit_conversion`` and "implicit conversion" [#1724] - Add ``lazy_tree`` option to ``asdf.open`` and ``asdf.config`` to allow lazy deserialization of ASDF tagged tree nodes to custom objects. [#1733] 3.2.0 (2024-04-05) ------------------ - Deprecate ``AsdfFile.version_map`` [#1745] - Fix ``numpy.ma.MaskedArray`` saving for numpy 2.x [#1769] - Add ``float16`` support [#1692] - Removed unused ``asdf-unit-schemas`` dependency [#1767] 3.1.0 (2024-02-27) ------------------ The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Cleanup ``asdf.util`` including deprecating: ``human_list`` ``resolve_name`` ``minversion`` and ``iter_subclasses`` [#1688] - Deprecate validation on ``AsdfFile.tree`` assignment. Please use ``AsdfFile.validate`` to validate the tree [#1691] - Deprecate validation during ``AsdfFile.resolve_references``. Please use ``AsdfFile.validate`` to validate the tree [#1691] - Deprecate ``asdf.asdf`` and ``AsdfFile.resolve_and_inline`` [#1690] - Deprecate automatic calling of ``AsdfFile.find_references`` during ``AsdfFile.__init__`` and ``asdf.open`` [#1708] - Allow views of memmapped arrays to keep the backing mmap open to avoid segfaults [#1668] - Introduce ``memmap`` argument to ``asdf.open`` that overrides ``copy_arrays`` with documentation that describes that the default for ``memmap`` when ``copy_arrays`` is removed in an upcoming asdf release will be ``False`` and asdf will no longer by-default memory map arrays. [#1667] - Introduce ``asdf.util.load_yaml`` to load just the YAML contents of an ASDF file (with the option ``tagged`` to load the contents as a tree of ``asdf.tagged.Tagged`` instances to preserve tags) [#1700] - Require pytest 7+ and update asdf pytest plugin to be compatible with the current development version of pytest (8.1) [#1731] - Eliminate the use of the legacy ``tmpdir`` fixture in favor of the new ``tmp_path`` fixture for temporary directory creation. [#1759] - Remove conversion of warnings to errors in asdf pytest plugin. This prevented other warning filters (like those provided with ``-W``) from working. If you want these warnings to produce errors you can now add your own warning filter [#1757] - Only show ``str`` representation during ``info`` and ``search`` if it contains a single line (and does not fail) [#1748] 3.0.1 (2023-10-30) ------------------ The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fix bug in ``asdftool diff`` for arrays within a list [#1672] - For ``info`` and ``search`` show ``str`` representation of childless (leaf) nodes if ``show_values`` is enabled [#1687] - Deprecate ``asdf.util.is_primitive`` [#1687] 3.0.0 (2023-10-16) ------------------ The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Drop support for ASDF-in-FITS. [#1288] - Add ``all_array_storage``, ``all_array_compression`` and ``all_array_compression_kwargs`` to ``asdf.config.AsdfConfig`` [#1468] - Move built-in tags to converters (except ndarray and integer). [#1474] - Add block storage support to Converter [#1508] - Remove deprecated legacy extension API [#1464] - Fix issue opening files that don't support ``fileno`` [#1557] - Allow Converters to defer conversion to other Converters by returning ``None`` in ``Converter.select_tag`` [#1561] - Remove deprecated tests.helpers [#1597] - Remove deprecated load_custom_schema [#1596] - Remove deprecated TagDefinition.schema_uri [#1595] - Removed deprecated AsdfFile.open and deprecated asdf.open AsdfFile.write_to and AsdfFile.update kwargs [#1592] - Fix ``AsdfFile.info`` loading all array data [#1572] - Blank out AsdfFile.tree on close [#1575] - Move ndarray to a converter, add ``convert_unknown_ndarray_subclasses`` to ``asdf.config.AsdfConfig``, move ``asdf.Stream`` to ``asdf.tags.core.Stream``, update block storage support for Converter and update internal block API [#1537] - Remove deprecated resolve_local_refs argument to load_schema [#1623] - Move IntegerType to converter and drop cache of converted values. [#1527] - Remove legacy extension API [#1637] - Fix bug that left out the name of the arrays that differed for ``asdftool diff`` comparisons [#1652] 2.15.2 (2023-09-29) ------------------- The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Add support for python 3.12 [#1641] 2.15.1 (2023-08-07) ------------------- The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Drop Python 3.8 support [#1556] - Drop NumPy 1.20, 1.21 support [#1568] - Convert numpy scalars to python types during yaml encoding to handle NEP51 changes for numpy 2.0 [#1605] - Vendorize jsonschema 4.17.3 [#1591] - Drop jsonschema as a dependency [#1614] 2.15.0 (2023-03-28) ------------------- The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Require numpy<1.25 for python 3.8 [#1327] - Add AsdfProvisionalAPIWarning to warn developers of new features that may undergo breaking changes but are likely to be included as stable features (without this warning) in a future version of ASDF [#1295] - Add AsdfDeprecationWarning to AsdfFile.blocks [#1336] - Document policy for ASDF release cycle including when support for ASDF versions end. Also document dependency support policy. [#1323] - Update lower pins on ``numpy`` (per release policy), ``packaging``, and ``pyyaml`` to ones that we can successfully build and test against. [#1360] - Provide more informative filename when failing to open a file [#1357] - Add new plugin type for custom schema validators. [#1328] - Add AsdfDeprecationWarning to ``asdf.types.CustomType`` [#1359] - Throw more useful error when provided with a path containing an extra leading slash [#1356] - Add AsdfDeprecationWarning to AsdfInFits. Support for reading and writing ASDF in fits files is being moved to `stdatamodels `_. [#1337] - Add AsdfDeprecationWarning to asdf.resolver [#1362] - Add AsdfDeprecationWarning to asdf.tests.helpers.assert_extension_correctness [#1388] - Add AsdfDeprecationWarning to asdf.type_index [#1403] - Add warning to use of asdftool extract and remove-hdu about deprecation and impending removal [#1411] - Deprecate AsdfFile attributes that use the legacy extension api [#1417] - Add AsdfDeprecationWarning to asdf.types [#1401] - deprecate default_extensions, get_default_resolver and get_cached_asdf_extension_list in asdf.extension [#1409] - move asdf.types.format_tag to asdf.testing.helpers.format_tag [#1433] - Deprecate AsdfExtenion, AsdfExtensionList, BuiltinExtension [#1429] - Add AsdfDeprecationWarning to asdf_extensions entry point [#1361] - Deprecate asdf.tests.helpers [#1440] - respect umask when determining file permissions for written files [#1451] - rename master branch to main [#1479] 2.14.4 (2022-03-17) ------------------- The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - require jsonschema<4.18 [#1487] 2.14.3 (2022-12-15) ------------------- The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Use importlib_metadata for all python versions [#1260] - Fix issue #1268, where update could fail to clear memmaps for some files [#1269] - Bump asdf-transform-schemas version [#1278] 2.14.2 (2022-12-05) ------------------- The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fix issue #1256, where ``enum`` could not be used on tagged objects. [#1257] 2.14.1 (2022-11-23) ------------------- The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fix issue #1239, close memmap with asdf file context [#1241] - Add ndarray-1.1.0 and integer-1.1.0 support [#1250] 2.14.0 (2022-11-22) ------------------- The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Update citation. [#1184] - Add search support to `~asdf.AsdfFile.schema_info`. [#1187] - Add `asdf.search.AsdfSearchResult` support for `~asdf.AsdfFile.schema_info` and `~asdf.search.AsdfSearchResult.schema_info` method. [#1197] - Use forc ndarray flag to correctly test for fortran array contiguity [#1206] - Unpin ``jsonschema`` version and fix ``jsonschema`` deprecation warnings. [#1185] - Replace ``pkg_resources`` with ``importlib.metadata``. [#1199] - Fix default validation for jsonschema 4.10+ [#1203] - Add ``asdf-unit-schemas`` as a dependency, for backwards compatibility. [#1210] - Remove stray toplevel packages ``docker`` ``docs`` and ``compatibility_tests`` from wheel [#1214] - Close files opened during a failed call to asdf.open [#1221] - Modify generic_file for fsspec compatibility [#1226] - Add fsspec http filesystem support [#1228] - Memmap whole file instead of each array [#1230] - Fix issue #1232 where array data was duplicated during resaving of a fits file [#1234] 2.13.0 (2022-08-19) ------------------- The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Add ability to pull information from schema about asdf file data, using `~asdf.AsdfFile.schema_info` method. [#1167] 2.12.1 (2022-08-17) ------------------- The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Overhaul of the ASDF documentation to make it more consistent and readable. [#1142, #1152] - Update deprecated instances of ``abstractproperty`` to ``abstractmethod`` [#1148] - Move build configuration into ``pyproject.toml`` [#1149, #1155] - Pin ``jsonschema`` to below ``4.10.0``. [#1171] 2.12.0 (2022-06-06) ------------------- The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Added ability to display title as a comment in using the ``info()`` functionality. [#1138] - Add ability to set asdf-standard version for schema example items. [#1143] 2.11.2 (2022-08-17) ------------------- - Backport ``jsonschema`` pin to strictly less than 4.10.1. [#1175] 2.11.1 (2022-04-15) ------------------- The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Update minimum astropy version to 5.0.4. [#1133] 2.11.0 (2022-03-15) ------------------- The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Update minimum jsonschema version to 4.0.1. [#1105] 2.10.1 (2022-03-02) ------------------- The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Bugfix for circular build dependency for asdf. [#1094] - Fix small bug with handling multiple schema uris per tag. [#1095] 2.10.0 (2022-02-17) ------------------- The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Replace asdf-standard submodule with pypi package. [#1079] 2.9.2 (2022-02-07) ------------------ The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fix deprecation warnings stemming from the release of pytest 7.0.0. [#1075] - Fix bug in pytest plugin when schemas are not in a directory named "schemas". [#1076] 2.9.1 (2022-02-03) ------------------ The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fix typo in testing module ``__init__.py`` name. [#1071] 2.9.0 (2022-02-02) ------------------ The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Added the capability for tag classes to provide an interface to asdf info functionality to obtain information about the class attributes rather than appear as an opaque class object. [#1052 #1055] - Fix tag listing when extension is not fully implemented. [#1034] - Drop support for Python 3.6. [#1054] - Adjustments to compression plugin tests and documentation. [#1053] - Update setup.py to raise error if "git submodule update --init" has not been run. [#1057] - Add ability for tags to correspond to multiple schema_uri, with an implied allOf among the schema_uris. [#1058, #1069] - Add the URL of the file being parsed to ``SerializationContext``. [#1065] - Add ``asdf.testing.helpers`` module with simplified versions of test helpers previously available in ``asdf.tests.helpers``. [#1067] 2.8.3 (2021-12-13) ------------------ The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fix more use of 'python' where 'python3' is intended. [#1033] 2.8.2 (2021-12-06) ------------------ The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Update documentation to reflect new 2.8 features. [#998] - Fix array compression for non-native byte order [#1010] - Fix use of 'python' where 'python3' is intended. [#1026] - Fix schema URI resolving when the URI prefix is also claimed by a legacy extension. [#1029] - Remove 'name' and 'version' attributes from NDArrayType instances. [#1031] 2.8.1 (2021-06-09) ------------------ - Fix bug in block manager when a new block is added to an existing file without a block index. [#1000] 2.8.0 (2021-05-12) ------------------ The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Add ``yaml_tag_handles`` property to allow definition of custom yaml ``%TAG`` handles in the asdf file header. [#963] - Add new resource mapping API for extending asdf with additional schemas. [#819, #828, #843, #846] - Add global configuration mechanism. [#819, #839, #844, #847] - Drop support for automatic serialization of subclass attributes. [#825] - Support asdf:// as a URI scheme. [#854, #855] - Include only extensions used during serialization in a file's metadata. [#848, #864] - Drop support for Python 3.5. [#856] - Add new extension API to support versioned extensions. [#850, #851, #853, #857, #874] - Permit wildcard in tag validator URIs. [#858, #865] - Implement support for ASDF Standard 1.6.0. This version of the standard limits mapping keys to string, integer, or boolean. [#866] - Stop removing schema defaults for all ASDF Standard versions, and automatically fill defaults only for versions <= 1.5.0. [#860] - Stop removing keys with ``None`` values from the tree on write. This fixes a long-standing issue where the tree structure is not preserved on write, but will break ``ExtensionType`` subclasses that depend on this behavior. Extension developers will need to modify their ``to_tree`` methods to check for ``None`` before adding a key to the tree (or modify the schema to permit nulls, if that is the intention). [#863] - Deprecated the ``auto_inline`` argument to ``AsdfFile.write_to`` and ``AsdfFile.update`` and added ``AsdfConfig.array_inline_threshold``. [#882, #991] - Add ``edit`` subcommand to asdftool for efficient editing of the YAML portion of an ASDF file. [#873, #922] - Increase limit on integer literals to signed 64-bit. [#894] - Remove the ``asdf.test`` method and ``asdf.__githash__`` attribute. [#943] - Add support for custom compression via extensions. [#931] - Remove unnecessary ``.tree`` from search result paths. [#954] - Drop support for bugs in older operating systems and Python versions. [#955] - Add argument to ``asdftool diff`` that ignores tree nodes that match a JMESPath expression. [#956] - Fix behavior of ``exception`` argument to ``GenericFile.seek_until``. [#980] - Fix issues in file type detection to allow non-seekable input and filenames without recognizable extensions. Remove the ``asdf.asdf.is_asdf_file`` function. [#978] - Update ``asdftool extensions`` and ``asdftool tags`` to incorporate the new extension API. [#988] - Add ``AsdfSearchResult.replace`` method for assigning new values to search results. [#981] - Search for block index starting from end of file. Fixes rare bug when a data block contains a block index. [#990] - Update asdf-standard to 1.6.0 tag. [#993] 2.7.5 (2021-06-09) ------------------ The ASDF Standard is at v1.5.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fix bug in ``asdf.schema.check_schema`` causing relative references in metaschemas to be resolved incorrectly. [#987] - Fix bug in block manager when a new block is added to an existing file without a block index. [#1000] 2.7.4 (2021-04-30) ------------------ The ASDF Standard is at v1.5.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fix pytest plugin failure under older versions of pytest. [#934] - Copy array views when the base array is non-contiguous. [#949] - Prohibit views over FITS arrays that change dtype. [#952] - Add support for HTTPS URLs and following redirects. [#971] - Prevent astropy warnings in tests when opening known bad files. [#977] 2.7.3 (2021-02-25) ------------------ The ASDF Standard is at v1.5.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Add pytest plugin options to skip and xfail individual tests and xfail the unsupported ndarray-1.0.0 example. [#929] - Fix bug resulting in invalid strides values for views over FITS arrays. [#930] 2.7.2 (2021-01-15) ------------------ The ASDF Standard is at v1.5.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fix bug causing test collection failures in some environments. [#889] - Fix bug when decompressing arrays with numpy 1.20. [#901, #909] 2.7.1 (2020-08-18) ------------------ The ASDF Standard is at v1.5.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fix bug preventing access to copied array data after ``AsdfFile`` is closed. [#869] 2.7.0 (2020-07-23) ------------------ The ASDF Standard is at v1.5.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fix bug preventing diff of files containing ndarray-1.0.0 objects in simplified form. [#786] - Fix bug causing duplicate elements to appear when calling ``copy.deepcopy`` on a ``TaggedList``. [#788] - Improve validator performance by skipping unnecessary step of copying schema objects. [#784] - Fix bug with ``auto_inline`` option where inline blocks are not converted to internal when they exceed the threshold. [#802] - Fix misinterpretation of byte order of blocks stored in FITS files. [#810] - Improve read performance by skipping unnecessary rebuild of tagged tree. [#787] - Add option to ``asdf.open`` and ``fits_embed.AsdfInFits.open`` that disables validation on read. [#792] - Fix bugs and code style found by adding F and W ``flake8`` checks. [#797] - Eliminate warnings in pytest plugin by using ``from_parent`` when available. [#799] - Prevent validation of empty tree when ``AsdfFile`` is initialized. [#794] - All warnings now subclass ``asdf.exceptions.AsdfWarning``. [#804] - Improve warning message when falling back to an older schema, and note that fallback behavior will be removed in 3.0. [#806] - Drop support for jsonschema 2.x. [#807] - Stop traversing oneOf and anyOf combiners when filling or removing default values. [#811] - Fix bug in version map caching that caused incompatible tags to be written under ASDF Standard 1.0.0. [#821] - Fix bug that corrupted ndarrays when the underlying block array was converted to C order on write. [#827] - Fix bug that produced unreadable ASDF files when an ndarray in the tree was both offset and broadcasted. [#827] - Fix bug preventing validation of default values in ``schema.check_schema``. [#785] - Add option to disable validation of schema default values in the pytest plugin. [#831] - Prevent errors when extension metadata contains additional properties. [#832] 2.6.0 (2020-04-22) ------------------ The ASDF Standard is at v1.5.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - AsdfDeprecationWarning now subclasses DeprecationWarning. [#710] - Resolve external references in custom schemas, and deprecate asdf.schema.load_custom_schema. [#738] - Add ``asdf.info`` for displaying a summary of a tree, and ``AsdfFile.search`` for searching a tree. [#736] - Add pytest plugin option to skip warning when a tag is unrecognized. [#771] - Fix generic_io ``read_blocks()`` reading past the requested size [#773] - Add support for ASDF Standard 1.5.0, which includes several new transform schemas. [#776] - Enable validation and serialization of previously unhandled numpy scalar types. [#778] - Fix handling of trees containing implicit internal references and reference cycles. Eliminate need to call ``yamlutil.custom_tree_to_tagged_tree`` and ``yamlutil.tagged_tree_to_custom_tree`` from extension code, and allow ``ExtensionType`` subclasses to return generators. [#777] - Fix bug preventing history entries when a file was previously saved without them. [#779] - Update developer overview documentation to describe design of changes to handle internal references and reference cycles. [#781] 2.5.2 (2020-02-28) ------------------ The ASDF Standard is at v1.4.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Add a developer overview document to help understand how ASDF works internally. Still a work in progress. [#730] - Remove unnecessary dependency on six. [#739] - Add developer documentation on schema versioning, additional schema and extension-related tests, and fix a variety of issues in ``AsdfType`` subclasses. [#750] - Update asdf-standard to include schemas that were previously missing from 1.4.0 version maps. [#767] - Simplify example in README.rst [#763] 2.5.1 (2020-01-07) ------------------ The ASDF Standard is at v1.4.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fix bug in test causing failure when test suite is run against an installed asdf package. [#732] 2.5.0 (2019-12-23) ------------------ The ASDF Standard is at v1.4.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Added asdf-standard 1.4.0 to the list of supported versions. [#704] - Fix load_schema LRU cache memory usage issue [#682] - Add convenience method for fetching the default resolver [#682] - ``SpecItem`` and ``Spec`` were deprecated in ``semantic_version`` and were replaced with ``SimpleSpec``. [#715] - Pinned the minimum required ``semantic_version`` to 2.8. [#715] - Fix bug causing segfault after update of a memory-mapped file. [#716] 2.4.2 (2019-08-29) ------------------ The ASDF Standard is at v1.3.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Limit the version of ``semantic_version`` to <=2.6.0 to work around a Deprecation warning. [#700] 2.4.1 (2019-08-27) ------------------ The ASDF Standard is at v1.3.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Define the ``in`` operator for top-level ``AsdfFile`` objects. [#623] - Overhaul packaging infrastructure. Remove use of ``astropy_helpers``. [#670] - Automatically register schema tester plugin. Do not enable schema tests by default. Add configuration setting and command line option to enable schema tests. [#676] - Enable handling of subclasses of known custom types by using decorators for convenience. [#563] - Add support for jsonschema 3.x. [#684] - Fix bug in ``NDArrayType.__len__``. It must be a method, not a property. [#673] 2.3.3 (2019-04-02) ------------------ The ASDF Standard is at v1.3.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Pass ``ignore_unrecognized_tag`` setting through to ASDF-in-FITS. [#650] - Use ``$schema`` keyword if available to determine meta-schema to use when testing whether schemas themselves are valid. [#654] - Take into account resolvers from installed extensions when loading schemas for validation. [#655] - Fix compatibility issue with new release of ``pyyaml`` (version 5.1). [#662] - Allow use of ``pathlib.Path`` objects for ``custom_schema`` option. [#663] 2.3.2 (2019-02-19) ------------------ The ASDF Standard is at v1.3.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fix bug that occurs when comparing installed extension version with that found in file. [#641] 2.3.1 (2018-12-20) ------------------ The ASDF Standard is at v1.3.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Provide source information for ``AsdfDeprecationWarning`` that come from extensions from external packages. [#629] - Ensure that top-level accesses to the tree outside a closed context handler result in an ``OSError``. [#628] - Fix the way ``generic_io`` handles URIs and paths on Windows. [#632] - Fix bug in ``asdftool`` that prevented ``extract`` command from being visible. [#633] 2.3.0 (2018-11-28) ------------------ The ASDF Standard is at v1.3.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Storage of arbitrary precision integers is now provided by ``asdf.IntegerType``. Reading a file with integer literals that are too large now causes only a warning instead of a validation error. This is to provide backwards compatibility for files that were created with a buggy version of ASDF (see #553 below). [#566] - Remove WCS tags. These are now provided by the `gwcs package `_. [#593] - Deprecate the ``asdf.asdftypes`` module in favor of ``asdf.types``. [#611] - Support use of ``pathlib.Path`` with ``asdf.open`` and ``AsdfFile.write_to``. [#617] - Update ASDF Standard submodule to version 1.3.0. 2.2.1 (2018-11-15) ------------------ - Fix an issue with the README that caused sporadic installation failures and also prevented the long description from being rendered on pypi. [#607] 2.2.0 (2018-11-14) ------------------ - Add new parameter ``lazy_load`` to ``AsdfFile.open``. It is ``True`` by default and preserves the default behavior. ``False`` detaches the loaded tree from the underlying file: all blocks are fully read and numpy arrays are materialized. Thus it becomes safe to close the file and continue using ``AsdfFile.tree``. However, ``copy_arrays`` parameter is still effective and the active memory maps may still require the file to stay open in case ``copy_arrays`` is ``False``. [#573] - Add ``AsdfConversionWarning`` for failures to convert ASDF tree into custom types. This warning is converted to an error when using ``assert_roundtrip_tree`` for tests. [#583] - Deprecate ``asdf.AsdfFile.open`` in favor of ``asdf.open``. [#579] - Add readonly protection to memory mapped arrays when the underlying file handle is readonly. [#579] 2.1.2 (2018-11-13) ------------------ - Make sure that all types corresponding to core tags are added to the type index before any others. This fixes a bug that was related to the way that subclass tags were overwritten by external extensions. [#598] 2.1.1 (2018-11-01) ------------------ - Make sure extension metadata is written even when constructing the ASDF tree on-the-fly. [#549] - Fix large integer validation when storing `numpy` integer literals in the tree. [#553] - Fix bug that caused subclass of external type to be serialized by the wrong tag. [#560] - Fix bug that occurred when attempting to open invalid file but Astropy import fails while checking for ASDF-in-FITS. [#562] - Fix bug that caused tree creation to fail when unable to locate a schema file for an unknown tag. This now simply causes a warning, and the offending node is converted to basic Python data structures. [#571] 2.1.0 (2018-09-25) ------------------ - Add API function for retrieving history entries. [#501] - Store ASDF-in-FITS data inside a 1x1 BINTABLE HDU. [#519] - Allow implicit conversion of ``namedtuple`` into serializable types. [#534] - Fix bug that prevented use of ASDF-in-FITS with HDUs that have names with underscores. [#543] - Add option to ``generic_io.get_file`` to close underlying file handle. [#544] - Add top-level ``keys`` method to ``AsdfFile`` to access tree keys. [#545] 2.0.3 (2018-09-06) ------------------ - Update asdf-standard to reflect more stringent (and, consequently, more correct) requirements on the formatting of complex numbers. [#526] - Fix bug with dangling file handle when using ASDF-in-FITS. [#533] - Fix bug that prevented fortran-order arrays from being serialized properly. [#539] 2.0.2 (2018-07-27) ------------------ - Allow serialization of broadcasted ``numpy`` arrays. [#507] - Fix bug that caused result of ``set_array_compression`` to be overwritten by ``all_array_compression`` argument to ``write_to``. [#510] - Add workaround for Python OSX write limit bug (see https://bugs.python.org/issue24658). [#521] - Fix bug with custom schema validation when using out-of-line definitions in schema file. [#522] 2.0.1 (2018-05-08) ------------------ - Allow test suite to run even when package is not installed. [#502] 2.0.0 (2018-04-19) ------------------ - Astropy-specific tags have moved to Astropy core package. [#359] - ICRSCoord tag has moved to Astropy core package. [#401] - Remove support for Python 2. [#409] - Create ``pytest`` plugin to be used for testing schema files. [#425] - Add metadata about extensions used to create a file to the history section of the file itself. [#475] - Remove hard dependency on Astropy. It is still required for testing, and for processing ASDF-in-FITS files. [#476] - Add command for extracting ASDF extension from ASDF-in-FITS file and converting it to a pure ASDF file. [#477] - Add command for removing ASDF extension from ASDF-in-FITS file. [#480] - Add an ``ExternalArrayReference`` type for referencing arrays in external files. [#400] - Improve the way URIs are detected for ASDF-in-FITS files in order to fix bug with reading gzipped ASDF-in-FITS files. [#416] - Explicitly disallow access to entire tree for ASDF file objects that have been closed. [#407] - Install and load extensions using ``setuptools`` entry points. [#384] - Automatically initialize ``asdf-standard`` submodule in ``setup.py``. [#398] - Allow foreign tags to be resolved in schemas and files. Deprecate ``tag_to_schema_resolver`` property for ``AsdfFile`` and ``AsdfExtensionList``. [#399] - Fix bug that caused serialized FITS tables to be duplicated in embedded ASDF HDU. [#411] - Create and use a new non-standard FITS extension instead of ImageHDU for storing ASDF files embedded in FITS. Explicitly remove support for the ``.update`` method of ``AsdfInFits``, even though it didn't appear to be working previously. [#412] - Allow package to be imported and used from source directory and builds in development mode. [#420] - Add command to ``asdftool`` for querying installed extensions. [#418] - Implement optional top-level validation pass using custom schema. This can be used to ensure that particular ASDF files follow custom conventions beyond those enforced by the standard. [#442] - Remove restrictions affecting top-level attributes ``data``, ``wcs``, and ``fits``. Bump top-level ASDF schema version to v1.1.0. [#444] 1.3.3 (2018-03-01) ------------------ - Update test infrastructure to rely on new Astropy v3.0 plugins. [#461] - Disable use of 2to3. This was causing test failures on Debian builds. [#463] 1.3.2 (2018-02-22) ------------------ - Updates to allow this version of ASDF to be compatible with Astropy v3.0. [#450] - Remove tests that are no longer relevant due to latest updates to Astropy's testing infrastructure. [#458] 1.3.1 (2017-11-02) ------------------ - Relax requirement on ``semantic_version`` version to 2.3.1. [#361] - Fix bug when retrieving file format version from new ASDF file. [#365] - Fix bug when duplicating inline arrays. [#370] - Allow tag references using the tag URI scheme to be resolved in schema files. [#371] 1.3.0 (2017-10-24) ------------------ - Fixed a bug in reading data from an "http:" url. [#231] - Implements v 1.1.0 of the asdf schemas. [#233] - Added a function ``is_asdf_file`` which inspects the input and returns ``True`` or ``False``. [#239] - The ``open`` method of ``AsdfInFits`` now accepts URIs and open file handles in addition to HDULists. The ``open`` method of ``AsdfFile`` will now try to parse the given URI or file handle as ``AsdfInFits`` if it is not obviously a regular ASDF file. [#241] - Updated WCS frame fields ``obsgeoloc`` and ``obsgeovel`` to reflect recent updates in ``astropy`` that changed representation from ``Quantity`` to ``CartesianRepresentation``. Updated to reflect ``astropy`` change that combines ``galcen_ra`` and ``galcen_dec`` into ``galcen_coord``. Added support for new field ``galcen_v_sun``. Added support for required module versions for tag classes. [#244] - Added support for ``lz4`` compression algorithm [#258]. Also added support for using a different compression algorithm for writing out a file than the one that was used for reading the file (e.g. to convert blocks to use a different compression algorithm) [#257] - Tag classes may now use an optional ``supported_versions`` attribute to declare exclusive support for particular versions of the corresponding schema. If this attribute is omitted (as it is for most existing tag classes), the tag is assumed to be compatible with all versions of the corresponding schema. If ``supported_versions`` is provided, the tag class implementation can include code that is conditioned on the schema version. If an incompatible schema is encountered, or if deserialization of the tagged object fails with an exception, a raw Python data structure will be returned. [#272] - Added option to ``AsdfFile.open`` to allow suppression of warning messages when mismatched schema versions are encountered. [#294] - Added a diff tool to ``asdftool`` to allow for visual comparison of pairs of ASDF files. [#286] - Added command to ``asdftool`` to display available tags. [#303] - When possible, display name of ASDF file that caused version mismatch warning. [#306] - Issue a warning when an unrecognized tag is encountered. [#295] This warning is silenced by default, but can be enabled with a parameter to the ``AsdfFile`` constructor, or to ``AsdfFile.open``. Also added an option for ignoring warnings from unrecognized schema tags. [#319] - Fix bug with loading JSON schemas in Python 3.5. [#317] - Remove all remnants of support for Python 2.6. [#333] - Fix issues with the type index used for writing out ASDF files. This ensures that items in the type index are not inadvertently overwritten by later versions of the same type. It also makes sure that schema example tests run against the correct version of the ASDF standard. [#350] - Update time schema to reflect changes in astropy. This fixes an outstanding bug. [#343] - Add ``copy_arrays`` option to ``asdf.open`` to control whether or not underlying array data should be memory mapped, if possible. [#355] - Allow the tree to be accessed using top-level ``__getitem__`` and ``__setitem__``. [#352] 1.2.1 (2016-11-07) ------------------ - Make asdf conditionally dependent on the version of astropy to allow running it with older versions of astropy. [#228] 1.2.0 (2016-10-04) ------------------ - Added Tabular model. [#214] - Forced new blocks to be contiguous [#221] - Rewrote code which tags complex objects [#223] - Fixed version error message [#224] 1.0.5 (2016-06-28) ------------------ - Fixed a memory leak when reading wcs that grew memory to over 10 Gb. [#200] 1.0.4 (2016-05-25) ------------------ - Added wrapper class for astropy.core.Time, TaggedTime. [#198] 1.0.2 (2016-02-29) ------------------ - Renamed package to ASDF. [#190] - Stopped support for Python 2.6 [#191] 1.0.1 (2016-01-08) ------------------ - Fixed installation from the source tarball on Python 3. [#187] - Fixed error handling when opening ASDF files not supported by the current version of asdf. [#178] - Fixed parse error that could occur sometimes when YAML data was read from a stream. [#183] 1.0.0 (2015-09-18) ------------------ - Initial release. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/CITATION.rst0000644000175100001770000000502714653725311014017 0ustar00runnerdockerIf you use ASDF for work/research presented in a publication (whether directly, as a dependency to another package), please cite the Zenodo DOI for the appropriate version of ASDF. The versions (and their BibTeX entries) can be found at: .. only:: html .. include:: ../../README.rst :start-after: begin-zenodo: :end-before: end-zenodo: .. only:: latex .. admonition:: Zenodo DOI https://zenodo.org/badge/latestdoi/18112754 We also recommend and encourage you to cite the general ASDF paper and/or its update: .. code:: bibtex @article{GREENFIELD2015240, title = {ASDF: A new data format for astronomy}, journal = {Astronomy and Computing}, volume = {12}, pages = {240-251}, year = {2015}, issn = {2213-1337}, doi = {https://doi.org/10.1016/j.ascom.2015.06.004}, url = {https://www.sciencedirect.com/science/article/pii/S2213133715000645}, author = {P. Greenfield and M. Droettboom and E. Bray}, keywords = {FITS, File formats, Standards, World coordinate system}, abstract = {We present the case for developing a successor format for the immensely successful FITS format. We first review existing alternative formats and discuss why we do not believe they provide an adequate solution. The proposed format is called the Advanced Scientific Data Format (ASDF) and is based on an existing text format, YAML, that we believe removes most of the current problems with the FITS format. An overview of the capabilities of the new format is given along with specific examples. This format has the advantage that it does not limit the size of attribute names (akin to FITS keyword names) nor place restrictions on the size or type of values attributes have. Hierarchical relationships are explicit in the syntax and require no special conventions. Finally, it is capable of storing binary data within the file in its binary form. At its basic level, the format proposed has much greater applicability than for just astronomical data.} } @InProceedings{ 00_greenfield-proc-scipy-2022, author = { {P}erry {G}reenfield and {E}dward {S}lavich and {W}illiam {J}amieson and {N}adia {D}encheva }, title = { {T}he {A}dvanced {S}cientific {D}ata {F}ormat ({A}{S}{D}{F}): {A}n {U}pdate }, booktitle = { {P}roceedings of the 21st {P}ython in {S}cience {C}onference }, pages = { 1 - 6 }, year = { 2022 }, editor = { {M}eghann {A}garwal and {C}hris {C}alloway and {D}illon {N}iederhut and {D}avid {S}hupe }, doi = { 10.25080/majora-212e5952-000 } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/CONTRIBUTING.rst0000644000175100001770000000541314653725311014513 0ustar00runnerdockerWe welcome feedback and contributions of all kinds. Contributions of code, documentation, or general feedback are all appreciated. This package follows the ASDF-format :ref:`Code Of Conduct ` and strives to provide a welcoming community to all of our users and contributors. New to GitHub or open source projects? If you are unsure about where to start or haven't used GitHub before, please feel free to contact the package maintainers. .. note:: The ASDF Standard itself also has a repository on github. Suggestions for improvements to the ASDF Standard can be reported `here `_. Feedback, Feature Requests, and Bug Reports ------------------------------------------- Feedback, feature requests, and bug reports for the ASDF Python implementation can be posted via `ASDF's github page `_. Please open a new issue any questions, bugs, feedback, or new features you would like to see. If there is an issue you would like to work on, please leave a comment and we will be happy to assist. New contributions and contributors are very welcome! Contributing Code and Bug Fixes ------------------------------- To contribute code to ASDF please fork ASDF first and then open a pull request from your fork to ASDF. Typically, the main development work is done on the "main" branch. The rest of the branches are for release maintenance and should not be used normally. Unless otherwise told by a maintainer, pull request should be made and submitted to the "main" branch. .. note:: The "stable" branch is protected and used for official releases. We ask that all contributions include unit tests to verify that the code works as intended. These tests are run automatically by GitHub when pull requests are open. If you have difficulties with tests failing or writing new tests please reach out to the maintainers, who are glad to assist you. .. note:: ASDF uses both ``black`` and ``ruff`` to format your code, so we ask that you run these tools regularly on your code to ensure that it is formatted correctly. To make this easier, we have included `pre-commit `__ support for ASDF. We suggest that you install ``pre-commit``, so that your code is automatically formatted before you commit. For those who do not run these tools regularly, the ``pre-commit-ci`` bot will attempt to fix the issues with your pull request when you submit it. .. note:: Backporting changes is done automatically using ``meeseeksdev``. If you are a maintainer, you can comment ``@meeseeksdev backport to `` on a pull request to manually trigger a backport. Moreover, when merging a "backport" pull request, please use the "Rebase and merge" option. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/LICENSE0000644000175100001770000000303114653725311013051 0ustar00runnerdockerBSD 3-Clause License Copyright (c) 2021 Association of Universities for Research in Astronomy. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/MANIFEST.in0000644000175100001770000000013414653725311013603 0ustar00runnerdockerrecursive-include docs * prune docs/_build prune docs/api global-exclude *.pyc exclude .* ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1650984 asdf-3.4.0/PKG-INFO0000644000175100001770000003433414653725331013155 0ustar00runnerdockerMetadata-Version: 2.1 Name: asdf Version: 3.4.0 Summary: Python implementation of the ASDF Standard Author-email: The ASDF Developers License: BSD 3-Clause License Copyright (c) 2021 Association of Universities for Research in Astronomy. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Project-URL: documentation, https://asdf.readthedocs.io/en/stable Project-URL: repository, https://github.com/asdf-format/asdf Project-URL: tracker, https://github.com/asdf-format/asdf/issues Classifier: Development Status :: 5 - Production/Stable Classifier: License :: OSI Approved :: BSD License Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Requires-Python: >=3.9 Description-Content-Type: text/x-rst License-File: LICENSE Requires-Dist: asdf-standard>=1.1.0 Requires-Dist: asdf-transform-schemas>=0.3 Requires-Dist: importlib-metadata>=4.11.4; python_version <= "3.11" Requires-Dist: jmespath>=0.6.2 Requires-Dist: numpy>=1.22 Requires-Dist: packaging>=19 Requires-Dist: pyyaml>=5.4.1 Requires-Dist: semantic_version>=2.8 Requires-Dist: attrs>=22.2.0 Provides-Extra: all Requires-Dist: lz4>=0.10; extra == "all" Provides-Extra: docs Requires-Dist: sphinx-asdf>=0.2.2; extra == "docs" Requires-Dist: graphviz; extra == "docs" Requires-Dist: sphinx-inline-tabs; extra == "docs" Requires-Dist: tomli; python_version < "3.11" and extra == "docs" Provides-Extra: tests Requires-Dist: fsspec[http]>=2022.8.2; extra == "tests" Requires-Dist: lz4>=0.10; extra == "tests" Requires-Dist: psutil; extra == "tests" Requires-Dist: pytest>=8; extra == "tests" Requires-Dist: pytest-remotedata; extra == "tests" ASDF - Advanced Scientific Data Format ====================================== .. _begin-badges: .. image:: https://github.com/asdf-format/asdf/workflows/CI/badge.svg :target: https://github.com/asdf-format/asdf/actions :alt: CI Status .. image:: https://github.com/asdf-format/asdf/workflows/s390x/badge.svg :target: https://github.com/asdf-format/asdf/actions :alt: s390x Status .. image:: https://github.com/asdf-format/asdf/workflows/Downstream/badge.svg :target: https://github.com/asdf-format/asdf/actions :alt: Downstream CI Status .. image:: https://readthedocs.org/projects/asdf/badge/?version=latest :target: https://asdf.readthedocs.io/en/latest/ .. image:: https://codecov.io/gh/asdf-format/asdf/branch/main/graphs/badge.svg :target: https://codecov.io/gh/asdf-format/asdf .. _begin-zenodo: .. image:: https://zenodo.org/badge/18112754.svg :target: https://zenodo.org/badge/latestdoi/18112754 .. _end-zenodo: .. image:: https://img.shields.io/pypi/l/asdf.svg :target: https://img.shields.io/pypi/l/asdf.svg .. image:: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white :target: https://github.com/pre-commit/pre-commit :alt: pre-commit .. image:: https://img.shields.io/badge/code%20style-black-000000.svg :target: https://github.com/psf/black .. _end-badges: .. _begin-summary-text: The **A**\ dvanced **S**\ cientific **D**\ ata **F**\ ormat (ASDF) is a next-generation interchange format for scientific data. This package contains the Python implementation of the ASDF Standard. More information on the ASDF Standard itself can be found `here `__. The ASDF format has the following features: * A hierarchical, human-readable metadata format (implemented using `YAML `__) * Numerical arrays are stored as binary data blocks which can be memory mapped. Data blocks can optionally be compressed. * The structure of the data can be automatically validated using schemas (implemented using `JSON Schema `__) * Native Python data types (numerical types, strings, dicts, lists) are serialized automatically * ASDF can be extended to serialize custom data types .. _end-summary-text: ASDF is under active development `on github `__. More information on contributing can be found `below <#contributing>`__. Overview -------- This section outlines basic use cases of the ASDF package for creating and reading ASDF files. Creating a file ~~~~~~~~~~~~~~~ .. _begin-create-file-text: We're going to store several `numpy` arrays and other data to an ASDF file. We do this by creating a "tree", which is simply a `dict`, and we provide it as input to the constructor of `AsdfFile`: .. code:: python import asdf import numpy as np # Create some data sequence = np.arange(100) squares = sequence**2 random = np.random.random(100) # Store the data in an arbitrarily nested dictionary tree = { "foo": 42, "name": "Monty", "sequence": sequence, "powers": {"squares": squares}, "random": random, } # Create the ASDF file object from our data tree af = asdf.AsdfFile(tree) # Write the data to a new file af.write_to("example.asdf") If we open the newly created file's metadata section, we can see some of the key features of ASDF on display: .. _begin-example-asdf-metadata: .. code:: yaml #ASDF 1.0.0 #ASDF_STANDARD 1.2.0 %YAML 1.1 %TAG ! tag:stsci.edu:asdf/ --- !core/asdf-1.1.0 asdf_library: !core/software-1.0.0 {author: The ASDF Developers, homepage: 'http://github.com/asdf-format/asdf', name: asdf, version: 2.0.0} history: extensions: - !core/extension_metadata-1.0.0 extension_class: asdf.extension.BuiltinExtension software: {name: asdf, version: 2.0.0} foo: 42 name: Monty powers: squares: !core/ndarray-1.0.0 source: 1 datatype: int64 byteorder: little shape: [100] random: !core/ndarray-1.0.0 source: 2 datatype: float64 byteorder: little shape: [100] sequence: !core/ndarray-1.0.0 source: 0 datatype: int64 byteorder: little shape: [100] ... .. _end-example-asdf-metadata: The metadata in the file mirrors the structure of the tree that was stored. It is hierarchical and human-readable. Notice that metadata has been added to the tree that was not explicitly given by the user. Notice also that the numerical array data is not stored in the metadata tree itself. Instead, it is stored as binary data blocks below the metadata section (not shown above). .. _end-create-file-text: .. _begin-compress-file: It is possible to compress the array data when writing the file: .. code:: python af.write_to("compressed.asdf", all_array_compression="zlib") The built-in compression algorithms are ``'zlib'``, and ``'bzp2'``. The ``'lz4'`` algorithm becomes available when the `lz4 `__ package is installed. Other compression algorithms may be available via extensions. .. _end-compress-file: Reading a file ~~~~~~~~~~~~~~ .. _begin-read-file-text: To read an existing ASDF file, we simply use the top-level `open` function of the `asdf` package: .. code:: python import asdf af = asdf.open("example.asdf") The `open` function also works as a context handler: .. code:: python with asdf.open("example.asdf") as af: ... To get a quick overview of the data stored in the file, use the top-level `AsdfFile.info()` method: .. code:: pycon >>> import asdf >>> af = asdf.open("example.asdf") >>> af.info() root (AsdfObject) ├─asdf_library (Software) │ ├─author (str): The ASDF Developers │ ├─homepage (str): http://github.com/asdf-format/asdf │ ├─name (str): asdf │ └─version (str): 2.8.0 ├─history (dict) │ └─extensions (list) │ └─[0] (ExtensionMetadata) │ ├─extension_class (str): asdf.extension.BuiltinExtension │ └─software (Software) │ ├─name (str): asdf │ └─version (str): 2.8.0 ├─foo (int): 42 ├─name (str): Monty ├─powers (dict) │ └─squares (NDArrayType): shape=(100,), dtype=int64 ├─random (NDArrayType): shape=(100,), dtype=float64 └─sequence (NDArrayType): shape=(100,), dtype=int64 The `AsdfFile` behaves like a Python `dict`, and nodes are accessed like any other dictionary entry: .. code:: pycon >>> af["name"] 'Monty' >>> af["powers"] {'squares': } Array data remains unloaded until it is explicitly accessed: .. code:: pycon >>> af["powers"]["squares"] array([ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400, 441, 484, 529, 576, 625, 676, 729, 784, 841, 900, 961, 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849, 1936, 2025, 2116, 2209, 2304, 2401, 2500, 2601, 2704, 2809, 2916, 3025, 3136, 3249, 3364, 3481, 3600, 3721, 3844, 3969, 4096, 4225, 4356, 4489, 4624, 4761, 4900, 5041, 5184, 5329, 5476, 5625, 5776, 5929, 6084, 6241, 6400, 6561, 6724, 6889, 7056, 7225, 7396, 7569, 7744, 7921, 8100, 8281, 8464, 8649, 8836, 9025, 9216, 9409, 9604, 9801]) >>> import numpy as np >>> expected = [x**2 for x in range(100)] >>> np.equal(af["powers"]["squares"], expected).all() True By default, uncompressed data blocks are memory mapped for efficient access. Memory mapping can be disabled by using the ``copy_arrays`` option of `open` when reading: .. code:: python af = asdf.open("example.asdf", copy_arrays=True) .. _end-read-file-text: For more information and for advanced usage examples, see the `documentation <#documentation>`__. Extending ASDF ~~~~~~~~~~~~~~ Out of the box, the ``asdf`` package automatically serializes and deserializes native Python types. It is possible to extend ``asdf`` by implementing custom tags that correspond to custom user types. More information on extending ASDF can be found in the `official documentation `__. Installation ------------ .. _begin-pip-install-text: Stable releases of the ASDF Python package are registered `at PyPi `__. The latest stable version can be installed using ``pip``: :: $ pip install asdf .. _begin-source-install-text: The latest development version of ASDF is available from the ``main`` branch `on github `__. To clone the project: :: $ git clone https://github.com/asdf-format/asdf To install: :: $ cd asdf $ pip install . To install in `development mode `__:: $ pip install -e . .. _end-source-install-text: Testing ------- .. _begin-testing-text: To install the test dependencies from a source checkout of the repository: :: $ pip install -e ".[tests]" To run the unit tests from a source checkout of the repository: :: $ pytest It is also possible to run the test suite from an installed version of the package. :: $ pip install "asdf[tests]" $ pytest --pyargs asdf It is also possible to run the tests using `tox `__. :: $ pip install tox To list all available environments: :: $ tox -va To run a specific environment: :: $ tox -e .. _end-testing-text: Documentation ------------- More detailed documentation on this software package can be found `here `__. More information on the ASDF Standard itself can be found `here `__. There are two mailing lists for ASDF: * `asdf-users `_ * `asdf-developers `_ If you are looking for the **A**\ daptable **S**\ eismic **D**\ ata **F**\ ormat, information can be found `here `__. License ------- ASDF is licensed under a BSD 3-clause style license. See `LICENSE.rst `_ for the `licenses folder `_ for licenses for any included software. Contributing ------------ We welcome feedback and contributions to the project. Contributions of code, documentation, or general feedback are all appreciated. Please follow the `contributing guidelines `__ to submit an issue or a pull request. We strive to provide a welcoming community to all of our users by abiding to the `Code of Conduct `__. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/README.rst0000644000175100001770000002545314653725311013547 0ustar00runnerdockerASDF - Advanced Scientific Data Format ====================================== .. _begin-badges: .. image:: https://github.com/asdf-format/asdf/workflows/CI/badge.svg :target: https://github.com/asdf-format/asdf/actions :alt: CI Status .. image:: https://github.com/asdf-format/asdf/workflows/s390x/badge.svg :target: https://github.com/asdf-format/asdf/actions :alt: s390x Status .. image:: https://github.com/asdf-format/asdf/workflows/Downstream/badge.svg :target: https://github.com/asdf-format/asdf/actions :alt: Downstream CI Status .. image:: https://readthedocs.org/projects/asdf/badge/?version=latest :target: https://asdf.readthedocs.io/en/latest/ .. image:: https://codecov.io/gh/asdf-format/asdf/branch/main/graphs/badge.svg :target: https://codecov.io/gh/asdf-format/asdf .. _begin-zenodo: .. image:: https://zenodo.org/badge/18112754.svg :target: https://zenodo.org/badge/latestdoi/18112754 .. _end-zenodo: .. image:: https://img.shields.io/pypi/l/asdf.svg :target: https://img.shields.io/pypi/l/asdf.svg .. image:: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white :target: https://github.com/pre-commit/pre-commit :alt: pre-commit .. image:: https://img.shields.io/badge/code%20style-black-000000.svg :target: https://github.com/psf/black .. _end-badges: .. _begin-summary-text: The **A**\ dvanced **S**\ cientific **D**\ ata **F**\ ormat (ASDF) is a next-generation interchange format for scientific data. This package contains the Python implementation of the ASDF Standard. More information on the ASDF Standard itself can be found `here `__. The ASDF format has the following features: * A hierarchical, human-readable metadata format (implemented using `YAML `__) * Numerical arrays are stored as binary data blocks which can be memory mapped. Data blocks can optionally be compressed. * The structure of the data can be automatically validated using schemas (implemented using `JSON Schema `__) * Native Python data types (numerical types, strings, dicts, lists) are serialized automatically * ASDF can be extended to serialize custom data types .. _end-summary-text: ASDF is under active development `on github `__. More information on contributing can be found `below <#contributing>`__. Overview -------- This section outlines basic use cases of the ASDF package for creating and reading ASDF files. Creating a file ~~~~~~~~~~~~~~~ .. _begin-create-file-text: We're going to store several `numpy` arrays and other data to an ASDF file. We do this by creating a "tree", which is simply a `dict`, and we provide it as input to the constructor of `AsdfFile`: .. code:: python import asdf import numpy as np # Create some data sequence = np.arange(100) squares = sequence**2 random = np.random.random(100) # Store the data in an arbitrarily nested dictionary tree = { "foo": 42, "name": "Monty", "sequence": sequence, "powers": {"squares": squares}, "random": random, } # Create the ASDF file object from our data tree af = asdf.AsdfFile(tree) # Write the data to a new file af.write_to("example.asdf") If we open the newly created file's metadata section, we can see some of the key features of ASDF on display: .. _begin-example-asdf-metadata: .. code:: yaml #ASDF 1.0.0 #ASDF_STANDARD 1.2.0 %YAML 1.1 %TAG ! tag:stsci.edu:asdf/ --- !core/asdf-1.1.0 asdf_library: !core/software-1.0.0 {author: The ASDF Developers, homepage: 'http://github.com/asdf-format/asdf', name: asdf, version: 2.0.0} history: extensions: - !core/extension_metadata-1.0.0 extension_class: asdf.extension.BuiltinExtension software: {name: asdf, version: 2.0.0} foo: 42 name: Monty powers: squares: !core/ndarray-1.0.0 source: 1 datatype: int64 byteorder: little shape: [100] random: !core/ndarray-1.0.0 source: 2 datatype: float64 byteorder: little shape: [100] sequence: !core/ndarray-1.0.0 source: 0 datatype: int64 byteorder: little shape: [100] ... .. _end-example-asdf-metadata: The metadata in the file mirrors the structure of the tree that was stored. It is hierarchical and human-readable. Notice that metadata has been added to the tree that was not explicitly given by the user. Notice also that the numerical array data is not stored in the metadata tree itself. Instead, it is stored as binary data blocks below the metadata section (not shown above). .. _end-create-file-text: .. _begin-compress-file: It is possible to compress the array data when writing the file: .. code:: python af.write_to("compressed.asdf", all_array_compression="zlib") The built-in compression algorithms are ``'zlib'``, and ``'bzp2'``. The ``'lz4'`` algorithm becomes available when the `lz4 `__ package is installed. Other compression algorithms may be available via extensions. .. _end-compress-file: Reading a file ~~~~~~~~~~~~~~ .. _begin-read-file-text: To read an existing ASDF file, we simply use the top-level `open` function of the `asdf` package: .. code:: python import asdf af = asdf.open("example.asdf") The `open` function also works as a context handler: .. code:: python with asdf.open("example.asdf") as af: ... To get a quick overview of the data stored in the file, use the top-level `AsdfFile.info()` method: .. code:: pycon >>> import asdf >>> af = asdf.open("example.asdf") >>> af.info() root (AsdfObject) ├─asdf_library (Software) │ ├─author (str): The ASDF Developers │ ├─homepage (str): http://github.com/asdf-format/asdf │ ├─name (str): asdf │ └─version (str): 2.8.0 ├─history (dict) │ └─extensions (list) │ └─[0] (ExtensionMetadata) │ ├─extension_class (str): asdf.extension.BuiltinExtension │ └─software (Software) │ ├─name (str): asdf │ └─version (str): 2.8.0 ├─foo (int): 42 ├─name (str): Monty ├─powers (dict) │ └─squares (NDArrayType): shape=(100,), dtype=int64 ├─random (NDArrayType): shape=(100,), dtype=float64 └─sequence (NDArrayType): shape=(100,), dtype=int64 The `AsdfFile` behaves like a Python `dict`, and nodes are accessed like any other dictionary entry: .. code:: pycon >>> af["name"] 'Monty' >>> af["powers"] {'squares': } Array data remains unloaded until it is explicitly accessed: .. code:: pycon >>> af["powers"]["squares"] array([ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400, 441, 484, 529, 576, 625, 676, 729, 784, 841, 900, 961, 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849, 1936, 2025, 2116, 2209, 2304, 2401, 2500, 2601, 2704, 2809, 2916, 3025, 3136, 3249, 3364, 3481, 3600, 3721, 3844, 3969, 4096, 4225, 4356, 4489, 4624, 4761, 4900, 5041, 5184, 5329, 5476, 5625, 5776, 5929, 6084, 6241, 6400, 6561, 6724, 6889, 7056, 7225, 7396, 7569, 7744, 7921, 8100, 8281, 8464, 8649, 8836, 9025, 9216, 9409, 9604, 9801]) >>> import numpy as np >>> expected = [x**2 for x in range(100)] >>> np.equal(af["powers"]["squares"], expected).all() True By default, uncompressed data blocks are memory mapped for efficient access. Memory mapping can be disabled by using the ``copy_arrays`` option of `open` when reading: .. code:: python af = asdf.open("example.asdf", copy_arrays=True) .. _end-read-file-text: For more information and for advanced usage examples, see the `documentation <#documentation>`__. Extending ASDF ~~~~~~~~~~~~~~ Out of the box, the ``asdf`` package automatically serializes and deserializes native Python types. It is possible to extend ``asdf`` by implementing custom tags that correspond to custom user types. More information on extending ASDF can be found in the `official documentation `__. Installation ------------ .. _begin-pip-install-text: Stable releases of the ASDF Python package are registered `at PyPi `__. The latest stable version can be installed using ``pip``: :: $ pip install asdf .. _begin-source-install-text: The latest development version of ASDF is available from the ``main`` branch `on github `__. To clone the project: :: $ git clone https://github.com/asdf-format/asdf To install: :: $ cd asdf $ pip install . To install in `development mode `__:: $ pip install -e . .. _end-source-install-text: Testing ------- .. _begin-testing-text: To install the test dependencies from a source checkout of the repository: :: $ pip install -e ".[tests]" To run the unit tests from a source checkout of the repository: :: $ pytest It is also possible to run the test suite from an installed version of the package. :: $ pip install "asdf[tests]" $ pytest --pyargs asdf It is also possible to run the tests using `tox `__. :: $ pip install tox To list all available environments: :: $ tox -va To run a specific environment: :: $ tox -e .. _end-testing-text: Documentation ------------- More detailed documentation on this software package can be found `here `__. More information on the ASDF Standard itself can be found `here `__. There are two mailing lists for ASDF: * `asdf-users `_ * `asdf-developers `_ If you are looking for the **A**\ daptable **S**\ eismic **D**\ ata **F**\ ormat, information can be found `here `__. License ------- ASDF is licensed under a BSD 3-clause style license. See `LICENSE.rst `_ for the `licenses folder `_ for licenses for any included software. Contributing ------------ We welcome feedback and contributions to the project. Contributions of code, documentation, or general feedback are all appreciated. Please follow the `contributing guidelines `__ to submit an issue or a pull request. We strive to provide a welcoming community to all of our users by abiding to the `Code of Conduct `__. ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.025096 asdf-3.4.0/asdf/0000755000175100001770000000000014653725331012766 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/__init__.py0000644000175100001770000000117414653725311015100 0ustar00runnerdocker""" asdf: Python library for reading and writing Advanced Scientific Data Format (ASDF) files """ __all__ = [ "AsdfFile", "Stream", "open", "IntegerType", "ExternalArrayReference", "info", "__version__", "ValidationError", "get_config", "config_context", ] from ._asdf import AsdfFile from ._asdf import open_asdf as open from ._convenience import info from ._version import version as __version__ from .config import config_context, get_config from .exceptions import ValidationError from .tags.core import IntegerType, Stream from .tags.core.external_reference import ExternalArrayReference ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_asdf.py0000644000175100001770000017553514653725311014432 0ustar00runnerdockerimport copy import datetime import io import os import pathlib import time import warnings import weakref from packaging.version import Version from . import _compression as mcompression from . import _display as display from . import _node_info as node_info from . import _version as version from . import constants, generic_io, lazy_nodes, reference, schema, treeutil, util, versioning, yamlutil from ._block.manager import Manager as BlockManager from ._helpers import validate_version from .config import config_context, get_config from .exceptions import ( AsdfDeprecationWarning, AsdfManifestURIMismatchWarning, AsdfPackageVersionWarning, AsdfWarning, DelimiterNotFoundError, ValidationError, ) from .extension import Extension, ExtensionProxy, _serialization_context, get_cached_extension_manager from .search import AsdfSearchResult from .tags.core import AsdfObject, ExtensionMetadata, HistoryEntry, Software from .util import NotSet def __getattr__(name): if name == "SerializationContext": warnings.warn( "importing SerializationContext from asdf.asdf is deprecated. " "Please import SerializationContext from asdf.extension", AsdfDeprecationWarning, ) from .extension._serialization_context import SerializationContext return SerializationContext msg = f"module {__name__!r} has no attribute {name!r}" raise AttributeError(msg) def _get_asdf_library_info(): """ Get information about asdf to include in the asdf_library entry in the Tree. """ return Software( { "name": "asdf", "version": version.version, "homepage": "http://github.com/asdf-format/asdf", "author": "The ASDF Developers", }, ) class AsdfFile: """ The main class that represents an ASDF file object. """ def __init__( self, tree=None, uri=None, extensions=None, version=None, ignore_version_mismatch=True, ignore_unrecognized_tag=False, ignore_implicit_conversion=NotSet, copy_arrays=False, memmap=NotSet, lazy_load=True, custom_schema=None, ): """ Parameters ---------- tree : dict or AsdfFile, optional The main tree data in the ASDF file. Must conform to the ASDF schema. uri : str, optional The URI for this ASDF file. Used to resolve relative references against. If not provided, will be automatically determined from the associated file object, if possible and if created from `asdf.open`. extensions : object, optional Additional extensions to use when reading and writing the file. May be an `asdf.extension.Extension` or a `list` of extensions. version : str, optional The ASDF Standard version. If not provided, defaults to the configured default version. See `asdf.config.AsdfConfig.default_version`. ignore_version_mismatch : bool, optional When `True`, do not raise warnings for mismatched schema versions. Set to `True` by default. ignore_unrecognized_tag : bool, optional When `True`, do not raise warnings for unrecognized tags. Set to `False` by default. ignore_implicit_conversion : bool DEPRECATED When `True`, do not raise warnings when types in the tree are implicitly converted into a serializable object. The motivating case for this is currently ``namedtuple``, which cannot be serialized as-is. copy_arrays : bool, optional When `False`, when reading files, attempt to memmap underlying data arrays when possible. memmap : bool, optional When `True`, when reading files, attempt to memmap underlying data arrays when possible. When set, this argument will override ``copy_arrays``. When not set, the ``copy_arrays`` will determine if arrays are memory mapped or copied. ``copy_arrays`` will be deprecated and the default will change in an upcoming asdf version which by default will not memory map arrays. lazy_load : bool, optional When `True` and the underlying file handle is seekable, data arrays will only be loaded lazily: i.e. when they are accessed for the first time. In this case the underlying file must stay open during the lifetime of the tree. Setting to False causes all data arrays to be loaded up front, which means that they can be accessed even after the underlying file is closed. Note: even if ``lazy_load`` is `False`, ``copy_arrays`` is still taken into account. custom_schema : str, optional Path to a custom schema file that will be used for a secondary validation pass. This can be used to ensure that particular ASDF files follow custom conventions beyond those enforced by the standard. """ self._fname = "" # make a new AsdfVersion instance here so files don't share the same instance self._file_format_version = versioning.AsdfVersion(versioning._FILE_FORMAT_VERSION) # Don't use the version setter here; it tries to access # the extensions, which haven't been assigned yet. if version is None: self._version = versioning.AsdfVersion(get_config().default_version) else: self._version = versioning.AsdfVersion(validate_version(version)) self._user_extensions = self._process_user_extensions(extensions) self._plugin_extensions = self._process_plugin_extensions() self._extension_manager = None if custom_schema is not None: self._custom_schema = schema._load_schema_cached(custom_schema, None, True) else: self._custom_schema = None self._ignore_version_mismatch = ignore_version_mismatch self._ignore_unrecognized_tag = ignore_unrecognized_tag self._ignore_implicit_conversion = ignore_implicit_conversion # Context of a call to treeutil.walk_and_modify, needed in the AsdfFile # in case walk_and_modify is re-entered by extension code (via # custom_tree_to_tagged_tree or tagged_tree_to_custom_tree). self._tree_modification_context = treeutil._TreeModificationContext() # A cache of tagged objects and their converted custom objects used when # a file is read with "lazy_tree=True". Used by lazy_nodes. self._tagged_object_cache = lazy_nodes._TaggedObjectCache() self._fd = None self._closed = False self._external_asdf_by_uri = {} # if memmap is set, it overrides copy_arrays if memmap is not NotSet: copy_arrays = not memmap self._blocks = BlockManager(uri=uri, lazy_load=lazy_load, memmap=not copy_arrays) # this message is passed into find_references to only warn if # a reference was found find_ref_warning_msg = ( "find_references during AsdfFile.__init__ is deprecated. " "call AsdfFile.find_references after AsdfFile.__init__" ) if tree is None: # Bypassing the tree property here, to avoid validating # an empty tree. self._tree = AsdfObject() elif isinstance(tree, AsdfFile): if self.extensions != tree.extensions: # TODO(eslavich): Why not? What if that's the goal # of copying the file? msg = "Can not copy AsdfFile and change active extensions" raise ValueError(msg) self._blocks._uri = tree.uri # Set directly to self._tree (bypassing property), since # we can assume the other AsdfFile is already valid. self._tree = tree.tree self.find_references(_warning_msg=find_ref_warning_msg) else: self._tree = AsdfObject(tree) try: self.validate() except ValidationError: warnings.warn( "Validation during AsdfFile.__init__ is deprecated. " "Please use AsdfFile.validate to validate the tree", AsdfDeprecationWarning, ) raise self.find_references(_warning_msg=find_ref_warning_msg) self._comments = [] @property def version(self): """ Get this AsdfFile's ASDF Standard version. Returns ------- asdf.versioning.AsdfVersion """ return self._version @version.setter def version(self, value): """ Set this AsdfFile's ASDF Standard version. Parameters ---------- value : str or asdf.versioning.AsdfVersion """ self._version = versioning.AsdfVersion(validate_version(value)) # The new version may not be compatible with the previous # set of extensions, so we need to check them again: self._user_extensions = self._process_user_extensions(self._user_extensions) self._plugin_extensions = self._process_plugin_extensions() self._extension_manager = None @property def version_string(self): """ Get this AsdfFile's ASDF Standard version as a string. Returns ------- str """ return str(self._version) @property def version_map(self): warnings.warn( "AsdfFile.version_map is deprecated. Please use the extension_manager", AsdfDeprecationWarning, ) return versioning._get_version_map(self.version_string) @property def extensions(self): """ Get the list of user extensions that are enabled for use with this AsdfFile. Returns ------- list of asdf.extension.ExtensionProxy """ return self._user_extensions @extensions.setter def extensions(self, value): """ Set the list of user extensions that are enabled for use with this AsdfFile. Parameters ---------- value : list of asdf.extension.Extension """ self._user_extensions = self._process_user_extensions(value) self._extension_manager = None @property def extension_manager(self): """ Get the ExtensionManager for this AsdfFile. Returns ------- asdf.extension.ExtensionManager """ if self._extension_manager is None: self._extension_manager = get_cached_extension_manager(self._user_extensions + self._plugin_extensions) return self._extension_manager def __enter__(self): return self def __exit__(self, type_, value, traceback): self.close() def _check_extensions(self, tree, strict=False): """ Compare the user's installed extensions to metadata in the tree and warn when a) an extension is missing or b) an extension is present but the file was written with a later version of the extension's package. Parameters ---------- tree : AsdfObject Fully converted tree of custom types. strict : bool, optional Set to `True` to convert warnings to exceptions. """ if "history" not in tree or not isinstance(tree["history"], dict) or "extensions" not in tree["history"]: return for extension in tree["history"]["extensions"]: installed = None for ext in self._user_extensions + self._plugin_extensions: if ( extension.extension_uri is not None and extension.extension_uri == ext.extension_uri or extension.extension_uri is None and extension.extension_class in ext.legacy_class_names ): installed = ext break filename = f"'{self._fname}' " if self._fname else "" if extension.extension_uri is not None: extension_description = f"URI '{extension.extension_uri}'" else: extension_description = f"class '{extension.extension_class}'" if extension.software is not None: extension_description += ( f" (from package {extension.software['name']}=={extension.software['version']})" ) if installed is None: msg = ( f"File {filename}was created with extension " f"{extension_description}, which is not currently installed" ) if strict: raise RuntimeError(msg) warnings.warn(msg, AsdfPackageVersionWarning) elif extension.software: # Local extensions may not have a real version. If the package name changed, # then the version sequence may have been reset. if installed.package_version is None or installed.package_name != extension.software["name"]: continue # Compare version in file metadata with installed version if Version(installed.package_version) < Version(extension.software["version"]): msg = ( f"File {filename}was created with extension {extension_description}, " f"but older package ({installed.package_name}=={installed.package_version}) is installed." ) if strict: raise RuntimeError(msg) warnings.warn(msg, AsdfPackageVersionWarning) # check version of manifest providing package (if one was recorded) if "manifest_software" in extension: package_name = extension["manifest_software"]["name"] package_version = Version(extension["manifest_software"]["version"]) package_description = f"{package_name}=={package_version}" installed_version = None for mapping in get_config().resource_manager._resource_mappings: if mapping.package_name == package_name: installed_version = Version(mapping.package_version) break msg = None if installed_version is None: msg = ( f"File {filename}was created with package {package_description}, " "which is currently not installed" ) elif installed_version < package_version: msg = ( f"File {filename}was created with package {package_description}, " f"but older package({package_name}=={installed_version}) is installed." ) if msg: if strict: raise RuntimeError(msg) warnings.warn(msg, AsdfPackageVersionWarning) def _process_plugin_extensions(self): """ Select installed extensions that are compatible with this file's ASDF Standard version. Returns ------- list of asdf.extension.ExtensionProxy """ return [e for e in get_config().extensions if self.version_string in e.asdf_standard_requirement] def _process_user_extensions(self, extensions): """ Validate a list of extensions requested by the user add missing extensions registered with the current `AsdfConfig`. Parameters ---------- extensions : object May be an `asdf.extension.Extension` or a `list` of extensions. Returns ------- list of asdf.extension.ExtensionProxy """ if extensions is None: extensions = [] elif isinstance(extensions, (Extension, ExtensionProxy)): extensions = [extensions] if not isinstance(extensions, list): msg = "The extensions parameter must be an extension or list of extensions" raise TypeError(msg) extensions = [ExtensionProxy.maybe_wrap(e) for e in extensions] result = [] for extension in extensions: if self.version_string not in extension.asdf_standard_requirement: warnings.warn( f"Extension {extension} does not support ASDF Standard {self.version_string}. " "It has been disabled.", AsdfWarning, ) else: result.append(extension) return result def _update_extension_history(self, tree, serialization_context): """ Update the extension metadata on this file's tree to reflect extensions used during serialization. Parameters ---------- serialization_context : asdf.extension.SerializationContext The context that was used to serialize the tree. """ if serialization_context.version < versioning.NEW_HISTORY_FORMAT_MIN_VERSION: return if "history" not in tree: tree["history"] = {"extensions": []} # Support clients who are still using the old history format elif isinstance(tree["history"], list): histlist = tree["history"] tree["history"] = {"entries": histlist, "extensions": []} warnings.warn( "The ASDF history format has changed in order to " "support metadata about extensions. History entries " "should now be stored under tree['history']['entries'].", AsdfWarning, ) elif "extensions" not in tree["history"]: tree["history"]["extensions"] = [] for extension in serialization_context._extensions_used: ext_name = extension.class_name ext_meta = ExtensionMetadata(extension_class=ext_name) if extension.package_name is not None: ext_meta["software"] = Software(name=extension.package_name, version=extension.package_version) if extension.extension_uri is not None: ext_meta["extension_uri"] = extension.extension_uri if extension.compressors: ext_meta["supported_compression"] = [comp.label.decode("ascii") for comp in extension.compressors] manifest = getattr(extension._delegate, "_manifest", None) if manifest is not None: # check if this extension was built from a manifest is a different package resource_mapping = get_config().resource_manager._mappings_by_uri.get(manifest["id"]) # if an extension was registered with a manifest uri that does not match the id the # resource_mapping lookup will fail (resource_mapping will be None) if resource_mapping is None: warnings.warn( f"Extension ({extension.extension_uri}) uses a manifest with a uri that " "does not match it's id. Please open an issue with the extension maintainer", AsdfManifestURIMismatchWarning, ) elif resource_mapping.package_name != extension.package_name: ext_meta["manifest_software"] = Software( name=resource_mapping.package_name, version=resource_mapping.package_version, ) for i, entry in enumerate(tree["history"]["extensions"]): # Update metadata about this extension if it already exists if ( entry.extension_uri is not None and entry.extension_uri == extension.extension_uri or entry.extension_class in extension.legacy_class_names ): tree["history"]["extensions"][i] = ext_meta break else: tree["history"]["extensions"].append(ext_meta) @property def file_format_version(self): return self._file_format_version def close(self): """ Close the file handles associated with the `asdf.AsdfFile`. """ if self._fd and not self._closed: # This is ok to always do because GenericFile knows # whether it "owns" the file and should close it. self._fd.close() self._fd = None self._closed = True # as we're closing the file, also empty out the # tree so that references to array data can be released self._tree = AsdfObject() self._tagged_object_cache.clear() for external in self._external_asdf_by_uri.values(): external.close() self._external_asdf_by_uri.clear() self._blocks.close() def copy(self): return self.__class__( copy.deepcopy(self._tree), self._blocks._uri, self._user_extensions, ) __copy__ = __deepcopy__ = copy @property def uri(self): """ Get the URI associated with the `AsdfFile`. In many cases, it is automatically determined from the file handle used to read or write the file. """ return self._blocks._uri def resolve_uri(self, uri): """ Resolve a (possibly relative) URI against the URI of this ASDF file. May be overridden by base classes to change how URIs are resolved. This does not apply any ``uri_mapping`` that was passed to the constructor. Parameters ---------- uri : str An absolute or relative URI to resolve against the URI of this ASDF file. Returns ------- uri : str The resolved URI. """ return generic_io.resolve_uri(self.uri, uri) def open_external(self, uri, **kwargs): """ Open an external ASDF file, from the given (possibly relative) URI. There is a cache (internal to this ASDF file) that ensures each external ASDF file is loaded only once. Parameters ---------- uri : str An absolute or relative URI to resolve against the URI of this ASDF file. Returns ------- asdffile : AsdfFile The external ASDF file. """ # For a cache key, we want to ignore the "fragment" part. base_uri = util.get_base_uri(uri) resolved_uri = self.resolve_uri(base_uri) # A uri like "#" should resolve back to ourself. In that case, # just return `self`. if resolved_uri == "" or resolved_uri == self.uri: return self asdffile = self._external_asdf_by_uri.get(resolved_uri) if asdffile is None: asdffile = open_asdf(resolved_uri, mode="r", **kwargs) self._external_asdf_by_uri[resolved_uri] = asdffile return asdffile @property def tree(self): """ Get/set the tree of data in the ASDF file. When set, the tree will be validated against the ASDF schema. """ if self._closed: msg = "Cannot access data from closed ASDF file" raise OSError(msg) return self._tree @tree.setter def tree(self, tree): asdf_object = AsdfObject(tree) # Only perform custom validation if the tree is not empty try: self._validate(asdf_object, custom=bool(tree)) except ValidationError: warnings.warn( "Validation on tree assignment is deprecated. Please use AsdfFile.validate", AsdfDeprecationWarning ) raise self._tree = asdf_object def keys(self): return self.tree.keys() def __getitem__(self, key): return self.tree[key] def __setitem__(self, key, value): self.tree[key] = value def __contains__(self, item): return item in self.tree @property def comments(self): """ Get the comments after the header, before the tree. """ return self._comments def _validate(self, tree, custom=True, reading=False): with self._blocks.options_context(): # If we're validating on read then the tree # is already guaranteed to be in tagged form. tagged_tree = tree if reading else yamlutil.custom_tree_to_tagged_tree(tree, self) schema.validate(tagged_tree, self, reading=reading) # Perform secondary validation pass if requested if custom and self._custom_schema: schema.validate(tagged_tree, self, self._custom_schema, reading=reading) def validate(self): """ Validate the current state of the tree against the ASDF schema. """ self._validate(self._tree) def make_reference(self, path=None): """ Make a new reference to a part of this file's tree, that can be assigned as a reference to another tree. Parameters ---------- path : list of str and int, optional The parts of the path pointing to an item in this tree. If omitted, points to the root of the tree. Returns ------- reference : A reference object. Examples -------- For the given AsdfFile ``ff``, add an external reference to the data in an external file:: >>> import asdf >>> flat = asdf.open("http://stsci.edu/reference_files/flat.asdf") # doctest: +SKIP >>> ff.tree['flat_field'] = flat.make_reference(['data']) # doctest: +SKIP """ return reference.make_reference(self, [] if path is None else path) def set_array_storage(self, arr, array_storage): """ Set the block type to use for the given array data. Parameters ---------- arr : numpy.ndarray The array to set. If multiple views of the array are in the tree, only the most recent block type setting will be used, since all views share a single block. array_storage : str Must be one of: - ``internal``: The default. The array data will be stored in a binary block in the same ASDF file. - ``external``: Store the data in a binary block in a separate ASDF file. - ``inline``: Store the data as YAML inline in the tree. """ self._blocks._set_array_storage(arr, array_storage) def get_array_storage(self, arr): """ Get the block type for the given array data. Parameters ---------- arr : numpy.ndarray """ return self._blocks._get_array_storage(arr) def set_array_compression(self, arr, compression, **compression_kwargs): """ Set the compression to use for the given array data. Parameters ---------- arr : numpy.ndarray The array to set. If multiple views of the array are in the tree, only the most recent compression setting will be used, since all views share a single block. compression : str or None Must be one of: - ``''`` or `None`: no compression - ``zlib``: Use zlib compression - ``bzp2``: Use bzip2 compression - ``lz4``: Use lz4 compression - ``input``: Use the same compression as in the file read. If there is no prior file, acts as None. """ self._blocks._set_array_compression(arr, compression, **compression_kwargs) def get_array_compression(self, arr): """ Get the compression type for the given array data. Parameters ---------- arr : numpy.ndarray Returns ------- compression : str or None """ return self._blocks._get_array_compression(arr) def get_array_compression_kwargs(self, arr): """ """ return self._blocks._get_array_compression_kwargs(arr) def set_array_save_base(self, arr, save_base): """ Set the ``save_base`` option for ``arr``. When ``arr`` is written to a file, if ``save_base`` is ``True`` the base array for ``arr`` will be saved. Note that similar to other array options this setting is linked to the base array if ``arr`` is a view. Parameters ---------- arr : numpy.ndarray save_base : bool or None if ``None`` the ``default_array_save_base`` value from asdf config will be used """ self._blocks._set_array_save_base(arr, save_base) def get_array_save_base(self, arr): """ Returns the ``save_base`` option for ``arr``. When ``arr`` is written to a file, if ``save_base`` is ``True`` the base array for ``arr`` will be saved. Parameters ---------- arr : numpy.ndarray Returns ------- save_base : bool or None """ return self._blocks._get_array_save_base(arr) @classmethod def _parse_header_line(cls, line): """ Parses the header line in a ASDF file to obtain the ASDF version. """ parts = line.split() if len(parts) != 2 or parts[0] != constants.ASDF_MAGIC: msg = "Does not appear to be a ASDF file." raise ValueError(msg) try: version = versioning.AsdfVersion(parts[1].decode("ascii")) except ValueError as err: msg = f"Unparsable version in ASDF file: {parts[1]}" raise ValueError(msg) from err if version != versioning._FILE_FORMAT_VERSION: msg = f"Unsupported ASDF file format version {version}" raise ValueError(msg) return version @classmethod def _read_comment_section(cls, fd): """ Reads the comment section, between the header line and the Tree or first block. """ content = fd.read_until( b"(%YAML)|(" + constants.BLOCK_MAGIC + b")", 5, "start of content", include=False, exception=False, ) comments = [] lines = content.splitlines() for line in lines: if not line.startswith(b"#"): msg = "Invalid content between header and tree" raise ValueError(msg) comments.append(line[1:].strip()) return comments @classmethod def _find_asdf_version_in_comments(cls, comments): for comment in comments: parts = comment.split() if len(parts) == 2 and parts[0] == constants.ASDF_STANDARD_COMMENT: try: version = versioning.AsdfVersion(parts[1].decode("ascii")) except ValueError: pass else: return version return None @classmethod def _open_asdf( cls, self, fd, validate_checksums=False, extensions=None, lazy_tree=NotSet, _get_yaml_content=False, _force_raw_types=False, strict_extension_check=False, ignore_missing_extensions=False, ): """Attempt to populate AsdfFile data from file-like object""" if strict_extension_check and ignore_missing_extensions: msg = "'strict_extension_check' and 'ignore_missing_extensions' are incompatible options" raise ValueError(msg) with config_context() as cfg: # validate_checksums (unlike memmap and lazy_load) is provided # here instead of in __init__ self._blocks._validate_checksums = validate_checksums self._mode = fd.mode self._fd = fd if self._fd._uri: self._blocks._uri = self._fd._uri # The filename is currently only used for tracing warning information self._fname = self._fd._uri if self._fd._uri else "" try: header_line = fd.read_until(b"\r?\n", 2, "newline", include=True) except DelimiterNotFoundError as e: msg = "Does not appear to be a ASDF file." raise ValueError(msg) from e self._file_format_version = cls._parse_header_line(header_line) self._comments = cls._read_comment_section(fd) version = cls._find_asdf_version_in_comments(self._comments) if version is not None: self.version = version else: # If no ASDF_STANDARD comment is found... self.version = versioning.AsdfVersion("1.0.0") # Now that version is set for good, we can add any additional # extensions, which may have narrow ASDF Standard version # requirements. if extensions: self.extensions = extensions yaml_token = fd.read(4) tree = None if yaml_token == b"%YAM": reader = fd.reader_until( constants.YAML_END_MARKER_REGEX, 7, "End of YAML marker", include=True, initial_content=yaml_token, ) # For testing: just return the raw YAML content if _get_yaml_content: yaml_content = reader.read() fd.close() return yaml_content # We parse the YAML content into basic data structures # now, but we don't do anything special with it until # after the blocks have been read tree = yamlutil.load_tree(reader) self._blocks.read(fd) elif yaml_token == constants.BLOCK_MAGIC: # this file has only blocks and we're already read the first block magic self._blocks.read(fd, after_magic=True) elif yaml_token != b"": msg = "ASDF file appears to contain garbage after header." raise OSError(msg) if tree is None: # At this point the tree should be tagged, but we want it to be # tagged with the core/asdf version appropriate to this file's # ASDF Standard version. We're using custom_tree_to_tagged_tree # to select the correct tag for us. tree = yamlutil.custom_tree_to_tagged_tree(AsdfObject(), self) find_ref_warning_msg = "find_references during open is deprecated. call AsdfFile.find_references after open" tree = reference.find_references(tree, self, _warning_msg=find_ref_warning_msg) if self.version <= versioning.FILL_DEFAULTS_MAX_VERSION and get_config().legacy_fill_schema_defaults: schema.fill_defaults(tree, self, reading=True) if get_config().validate_on_read: try: self._validate(tree, reading=True) except ValidationError: self.close() raise if lazy_tree is NotSet: lazy_tree = cfg.lazy_tree if lazy_tree and not _force_raw_types: obj = AsdfObject() obj.data = lazy_nodes.AsdfDictNode(tree, weakref.ref(self)) tree = obj else: tree = yamlutil.tagged_tree_to_custom_tree(tree, self, _force_raw_types) if not (ignore_missing_extensions or _force_raw_types): self._check_extensions(tree, strict=strict_extension_check) self._tree = tree return self @classmethod def _open_impl( cls, self, fd, uri=None, mode="r", validate_checksums=False, extensions=None, lazy_tree=NotSet, _get_yaml_content=False, _force_raw_types=False, strict_extension_check=False, ignore_missing_extensions=False, ): """Attempt to open file-like object as an AsdfFile""" close_on_fail = isinstance(fd, (str, pathlib.Path)) generic_file = generic_io.get_file(fd, mode=mode, uri=uri) try: return cls._open_asdf( self, generic_file, validate_checksums=validate_checksums, extensions=extensions, lazy_tree=lazy_tree, _get_yaml_content=_get_yaml_content, _force_raw_types=_force_raw_types, strict_extension_check=strict_extension_check, ignore_missing_extensions=ignore_missing_extensions, ) except Exception: if close_on_fail: generic_file.close() raise def _write_tree(self, tree, fd, pad_blocks): fd.write(constants.ASDF_MAGIC) fd.write(b" ") fd.write(f"{self.file_format_version}".encode("ascii")) fd.write(b"\n") fd.write(b"#") fd.write(constants.ASDF_STANDARD_COMMENT) fd.write(b" ") fd.write(self.version_string.encode("ascii")) fd.write(b"\n") if len(tree): serialization_context = self._create_serialization_context(_serialization_context.BlockAccess.WRITE) for compression in self._blocks.get_output_compressions(): # lookup extension compressor = mcompression._get_compressor_from_extensions(compression, return_extension=True) if compressor is not None: # mark it as used serialization_context._mark_extension_used(compressor[1]) def _tree_finalizer(tagged_tree): """ The list of extensions used is not known until after serialization, so we're using a hook provided by yamlutil.dump_tree to update extension metadata after the tree has been converted to tagged objects. """ self._update_extension_history(tree, serialization_context) if "history" in tree: tagged_tree["history"] = yamlutil.custom_tree_to_tagged_tree( tree["history"], self, _serialization_context=serialization_context, ) else: tagged_tree.pop("history", None) yamlutil.dump_tree( tree, fd, self, tree_finalizer=_tree_finalizer, _serialization_context=serialization_context, ) if pad_blocks: padding = util.calculate_padding(fd.tell(), pad_blocks, fd.block_size) fd.fast_forward(padding) def _pre_write(self, fd): pass def _post_write(self, fd): pass def _serial_write(self, fd, pad_blocks, include_block_index): with self._blocks.write_context(fd): self._pre_write(fd) try: # prep a tree for a writing tree = copy.copy(self._tree) tree["asdf_library"] = _get_asdf_library_info() if "history" in self._tree: tree["history"] = copy.deepcopy(self._tree["history"]) self._write_tree(tree, fd, pad_blocks) self._blocks.write(pad_blocks, include_block_index) finally: self._post_write(fd) def update( self, all_array_storage=NotSet, all_array_compression=NotSet, compression_kwargs=NotSet, pad_blocks=False, include_block_index=True, version=None, ): """ Update the file on disk in place. Parameters ---------- all_array_storage : string, optional If provided, override the array storage type of all blocks in the file immediately before writing. Must be one of: - ``internal``: The default. The array data will be stored in a binary block in the same ASDF file. - ``external``: Store the data in a binary block in a separate ASDF file. - ``inline``: Store the data as YAML inline in the tree. all_array_compression : string, optional If provided, set the compression type on all binary blocks in the file. Must be one of: - ``''`` or `None`: No compression. - ``zlib``: Use zlib compression. - ``bzp2``: Use bzip2 compression. - ``lz4``: Use lz4 compression. - ``input``: Use the same compression as in the file read. If there is no prior file, acts as None compression_kwargs : dict, optional If provided, set this as the compression keyword arguments for all binary blocks in the file. pad_blocks : float or bool, optional Add extra space between blocks to allow for updating of the file. If `False` (default), add no padding (always return 0). If `True`, add a default amount of padding of 10% If a float, it is a factor to multiple content_size by to get the new total size. include_block_index : bool, optional If `False`, don't include a block index at the end of the file. (Default: `True`) A block index is never written if the file has a streamed block. version : str, optional Update the ASDF Standard version of this AsdfFile before writing. """ with config_context() as config: if all_array_storage is not NotSet: config.all_array_storage = all_array_storage if all_array_compression is not NotSet: config.all_array_compression = all_array_compression if compression_kwargs is not NotSet: config.all_array_compression_kwargs = compression_kwargs fd = self._fd if fd is None: msg = "Can not update, since there is no associated file" raise ValueError(msg) if not fd.writable(): msg = ( "Can not update, since associated file is read-only. Make " "sure that the AsdfFile was opened with mode='rw' and the " "underlying file handle is writable." ) raise OSError(msg) if not fd.seekable(): msg = "Can not update, since associated file is not seekable" raise OSError(msg) if version is not None: self.version = version # flush all pending memmap writes if fd.can_memmap(): fd.flush_memmap() def rewrite(): self._fd.seek(0) self._serial_write(self._fd, pad_blocks, include_block_index) self._fd.truncate() if self._fd.can_memmap(): self._fd.close_memmap() # if we have no read blocks, we can just call write_to as no internal blocks are reused if len(self._blocks.blocks) == 0: rewrite() return # if we have all external blocks, we can just call write_to as no internal blocks are reused if config.all_array_storage == "external": rewrite() return self._pre_write(fd) try: self._tree["asdf_library"] = _get_asdf_library_info() # prepare block manager for writing with self._blocks.write_context(self._fd, copy_options=False): # write out tree to temporary buffer tree_fd = generic_io.get_file(io.BytesIO(), mode="rw") self._write_tree(self._tree, tree_fd, False) new_tree_size = tree_fd.tell() # update blocks self._blocks.update(new_tree_size, pad_blocks, include_block_index) end_of_file = self._fd.tell() # now write the tree self._fd.seek(0) tree_fd.seek(0) self._fd.write(tree_fd.read()) self._fd.flush() # close memmap to trigger arrays to reload themselves self._fd.seek(end_of_file) self._fd.truncate() if self._fd.can_memmap(): self._fd.close_memmap() finally: self._post_write(fd) def write_to( self, fd, all_array_storage=NotSet, all_array_compression=NotSet, compression_kwargs=NotSet, pad_blocks=False, include_block_index=True, version=None, ): """ Write the ASDF file to the given file-like object. `write_to` does not change the underlying file descriptor in the `asdf.AsdfFile` object, but merely copies the content to a new file. Parameters ---------- fd : string or file-like object May be a string path to a file, or a Python file-like object. If a string path, the file is automatically closed after writing. If not a string path, it is the caller's responsibility to close the object. all_array_storage : string, optional If provided, override the array storage type of all blocks in the file immediately before writing. Must be one of: - ``internal``: The default. The array data will be stored in a binary block in the same ASDF file. - ``external``: Store the data in a binary block in a separate ASDF file. - ``inline``: Store the data as YAML inline in the tree. all_array_compression : string, optional If provided, set the compression type on all binary blocks in the file. Must be one of: - ``''`` or `None`: No compression. - ``zlib``: Use zlib compression. - ``bzp2``: Use bzip2 compression. - ``lz4``: Use lz4 compression. - ``input``: Use the same compression as in the file read. If there is no prior file, acts as None. compression_kwargs : dict, optional If provided, set this as the compression keyword arguments for all binary blocks in the file. pad_blocks : float or bool, optional Add extra space between blocks to allow for updating of the file. If `False` (default), add no padding (always return 0). If `True`, add a default amount of padding of 10% If a float, it is a factor to multiple content_size by to get the new total size. include_block_index : bool, optional If `False`, don't include a block index at the end of the file. (Default: `True`) A block index is never written if the file has a streamed block. version : str, optional Update the ASDF Standard version of this AsdfFile before writing. """ with config_context() as config: if all_array_storage is not NotSet: config.all_array_storage = all_array_storage if all_array_compression is not NotSet: config.all_array_compression = all_array_compression if compression_kwargs is not NotSet: config.all_array_compression_kwargs = compression_kwargs if version is not None: previous_version = self.version self.version = version try: with generic_io.get_file(fd, mode="w") as fd: self._serial_write(fd, pad_blocks, include_block_index) finally: if version is not None: self.version = previous_version def find_references(self, _warning_msg=False): """ Finds all external "JSON References" in the tree and converts them to ``reference.Reference`` objects. """ # Set directly to self._tree, since it doesn't need to be re-validated. self._tree = reference.find_references(self._tree, self, _warning_msg=_warning_msg) def resolve_references(self, **kwargs): """ Finds all external "JSON References" in the tree, loads the external content, and places it directly in the tree. Saving a ASDF file after this operation means it will have no external references, and will be completely self-contained. """ if len(kwargs): warnings.warn("Passing kwargs to resolve_references is deprecated and does nothing", AsdfDeprecationWarning) self._tree = reference.resolve_references(self._tree, self) try: self.validate() except ValidationError: warnings.warn( "Validation during resolve_references is deprecated. " "Please use AsdfFile.validate after resolve_references to validate the resolved tree", AsdfDeprecationWarning, ) raise def resolve_and_inline(self): """ Resolves all external references and inlines all data. This produces something that, when saved, is a 100% valid YAML file. """ warnings.warn( "resolve_and_inline is deprecated. " "Use AsdfFile.resolve_references and all_array_storage=inline " "during AsdfFile.write_to", AsdfDeprecationWarning, ) self.resolve_references() for b in self._blocks.blocks: self.set_array_storage(b.data, "inline") def fill_defaults(self): """ Fill in any values that are missing in the tree using default values from the schema. """ tree = yamlutil.custom_tree_to_tagged_tree(self._tree, self) schema.fill_defaults(tree, self) self._tree = yamlutil.tagged_tree_to_custom_tree(tree, self) def remove_defaults(self): """ Remove any values in the tree that are the same as the default values in the schema """ tree = yamlutil.custom_tree_to_tagged_tree(self._tree, self) schema.remove_defaults(tree, self) self._tree = yamlutil.tagged_tree_to_custom_tree(tree, self) def add_history_entry(self, description, software=None): """ Add an entry to the history list. Parameters ---------- description : str A description of the change. software : dict or list of dict A description of the software used. It should not include asdf itself, as that is automatically notated in the ``asdf_library`` entry. Each dict must have the following keys: - ``name``: The name of the software - ``author``: The author or institution that produced the software - ``homepage``: A URI to the homepage of the software - ``version``: The version of the software """ if isinstance(software, list): software = [Software(x) for x in software] elif software is not None: software = Software(software) time_ = datetime.datetime.fromtimestamp( int(os.environ.get("SOURCE_DATE_EPOCH", time.time())), datetime.timezone.utc ) entry = HistoryEntry( { "description": description, "time": time_, }, ) if software is not None: entry["software"] = software if self.version >= versioning.NEW_HISTORY_FORMAT_MIN_VERSION: if "history" not in self.tree: self.tree["history"] = {"entries": []} elif "entries" not in self.tree["history"]: self.tree["history"]["entries"] = [] self.tree["history"]["entries"].append(entry) try: self.validate() except Exception: self.tree["history"]["entries"].pop() raise else: if "history" not in self.tree: self.tree["history"] = [] self.tree["history"].append(entry) try: self.validate() except Exception: self.tree["history"].pop() raise def get_history_entries(self): """ Get a list of history entries from the file object. Returns ------- entries : list A list of history entries. """ if "history" not in self.tree: return [] if isinstance(self.tree["history"], list): return self.tree["history"] if "entries" in self.tree["history"]: return self.tree["history"]["entries"] return [] def schema_info(self, key="description", path=None, preserve_list=True, refresh_extension_manager=False): """ Get a nested dictionary of the schema information for a given key, relative to the path. Parameters ---------- key : str The key to look up. Default: "description" path : str or asdf.search.AsdfSearchResult A dot-separated path to the parameter to find the key information on or an `asdf.search.AsdfSearchResult` object. Default = None (full dictionary). preserve_list : bool If True, then lists are preserved. Otherwise, they are turned into dicts. refresh_extension_manager : bool If `True`, refresh the extension manager before looking up the key. This is useful if you want to make sure that the schema data for a given key is up to date. """ if isinstance(path, AsdfSearchResult): return path.schema_info( key, preserve_list=preserve_list, refresh_extension_manager=refresh_extension_manager, ) return node_info.collect_schema_info( key, path, self.tree, preserve_list=preserve_list, refresh_extension_manager=refresh_extension_manager, ) def info( self, max_rows=display.DEFAULT_MAX_ROWS, max_cols=display.DEFAULT_MAX_COLS, show_values=display.DEFAULT_SHOW_VALUES, refresh_extension_manager=False, ): """ Print a rendering of this file's tree to stdout. Parameters ---------- max_rows : int, tuple, or None, optional Maximum number of lines to print. Nodes that cannot be displayed will be elided with a message. If int, constrain total number of displayed lines. If tuple, constrain lines per node at the depth corresponding \ to the tuple index. If None, display all lines. max_cols : int or None, optional Maximum length of line to print. Nodes that cannot be fully displayed will be truncated with a message. If int, constrain length of displayed lines. If None, line length is unconstrained. show_values : bool, optional Set to False to disable display of primitive values in the rendered tree. """ lines = display.render_tree( self.tree, max_rows=max_rows, max_cols=max_cols, show_values=show_values, identifier="root", refresh_extension_manager=refresh_extension_manager, ) print("\n".join(lines)) def search(self, key=NotSet, type_=NotSet, value=NotSet, filter_=None): """ Search this file's tree. Parameters ---------- key : NotSet, str, or any other object Search query that selects nodes by dict key or list index. If NotSet, the node key is unconstrained. If str, the input is searched among keys/indexes as a regular expression pattern. If any other object, node's key or index must equal the queried key. type_ : NotSet, str, or builtins.type Search query that selects nodes by type. If NotSet, the node type is unconstrained. If str, the input is searched among (fully qualified) node type names as a regular expression pattern. If builtins.type, the node must be an instance of the input. value : NotSet, str, or any other object Search query that selects nodes by value. If NotSet, the node value is unconstrained. If str, the input is searched among values as a regular expression pattern. If any other object, node's value must equal the queried value. filter_ : callable Callable that filters nodes by arbitrary criteria. The callable accepts one or two arguments: - the node - the node's list index or dict key (optional) and returns True to retain the node, or False to remove it from the search results. Returns ------- asdf.search.AsdfSearchResult the result of the search """ result = AsdfSearchResult(["root"], self.tree) return result.search(key=key, type_=type_, value=value, filter_=filter_) # This function is called from within yamlutil methods to create # a context when one isn't explicitly passed in. def _create_serialization_context(self, operation=_serialization_context.BlockAccess.NONE): return _serialization_context.create(self, operation) def open_asdf( fd, uri=None, mode=None, validate_checksums=False, extensions=None, ignore_version_mismatch=True, ignore_unrecognized_tag=False, _force_raw_types=False, copy_arrays=False, memmap=NotSet, lazy_tree=NotSet, lazy_load=True, custom_schema=None, strict_extension_check=False, ignore_missing_extensions=False, _get_yaml_content=False, ): """ Open an existing ASDF file. Parameters ---------- fd : string or file-like object May be a string ``file`` or ``http`` URI, or a Python file-like object. uri : string, optional The URI of the file. Only required if the URI can not be automatically determined from ``fd``. mode : string, optional The mode to open the file in. Must be ``r`` (default) or ``rw``. validate_checksums : bool, optional If `True`, validate the blocks against their checksums. Requires reading the entire file, so disabled by default. extensions : object, optional Additional extensions to use when reading and writing the file. May be an `asdf.extension.Extension` or a `list` of extensions. ignore_version_mismatch : bool, optional When `True`, do not raise warnings for mismatched schema versions. Set to `True` by default. ignore_unrecognized_tag : bool, optional When `True`, do not raise warnings for unrecognized tags. Set to `False` by default. copy_arrays : bool, optional When `False`, when reading files, attempt to memmap underlying data arrays when possible. memmap : bool, optional When `True`, when reading files, attempt to memmap underlying data arrays when possible. When set, this argument will override ``copy_arrays``. When not set, the ``copy_arrays`` will determine if arrays are memory mapped or copied. ``copy_arrays`` will be deprecated and the default will change in an upcoming asdf version which by default will not memory map arrays. lazy_load : bool, optional When `True` and the underlying file handle is seekable, data arrays will only be loaded lazily: i.e. when they are accessed for the first time. In this case the underlying file must stay open during the lifetime of the tree. Setting to False causes all data arrays to be loaded up front, which means that they can be accessed even after the underlying file is closed. Note: even if ``lazy_load`` is `False`, ``memmap`` is still taken into account. lazy_tree : bool, optional When `True` the ASDF tree will not be converted to custom objects when the file is loaded. Instead, objects will be "lazily" converted only when they are accessed. Note that the tree will not contain dict and list instances for containers and instead return instances of classes defined in `asdf.lazy_nodes`. Since objects are converted when they are accessed, traversing the tree (like is done during `AsdfFile.info` and `AsdfFile.search`) will result in nodes being converted. custom_schema : str, optional Path to a custom schema file that will be used for a secondary validation pass. This can be used to ensure that particular ASDF files follow custom conventions beyond those enforced by the standard. strict_extension_check : bool, optional When `True`, if the given ASDF file contains metadata about the extensions used to create it, and if those extensions are not installed, opening the file will fail. When `False`, opening a file under such conditions will cause only a warning. Defaults to `False`. ignore_missing_extensions : bool, optional When `True`, do not raise warnings when a file is read that contains metadata about extensions that are not available. Defaults to `False`. Returns ------- asdffile : AsdfFile The new AsdfFile object. """ if mode is not None and mode not in ["r", "rw"]: msg = f"Unrecognized asdf mode '{mode}'. Must be either 'r' or 'rw'" raise ValueError(msg) if mode is None: if isinstance(fd, io.IOBase): mode = "rw" if fd.writable() else "r" elif isinstance(fd, generic_io.GenericFile): mode = fd.mode else: # This is the safest assumption for the default fallback mode = "r" instance = AsdfFile( ignore_version_mismatch=ignore_version_mismatch, ignore_unrecognized_tag=ignore_unrecognized_tag, copy_arrays=copy_arrays, memmap=memmap, lazy_load=lazy_load, custom_schema=custom_schema, ) return AsdfFile._open_impl( instance, fd, uri=uri, mode=mode, validate_checksums=validate_checksums, extensions=extensions, lazy_tree=lazy_tree, _get_yaml_content=_get_yaml_content, _force_raw_types=_force_raw_types, strict_extension_check=strict_extension_check, ignore_missing_extensions=ignore_missing_extensions, ) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.025096 asdf-3.4.0/asdf/_block/0000755000175100001770000000000014653725331014217 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_block/__init__.py0000644000175100001770000000556014653725311016334 0ustar00runnerdocker""" Submodule for reading and writing ASDF blocks. The primary interface to this submodule is ``_block.manager.Manager`` that in some ways mimics the older ``BlockManager``. An instance of ``Manager`` will be created by each `asdf.AsdfFile` instance. Internally, this submodule is broken up into: - low-level: - ``io``: functions for reading and writing blocks - ``key``: ``Key`` used to implement ``Store`` (see below) - ``store``: ``Store`` special key-value store for indexing blocks - medium-level: - ``reader``: ``ReadBlock`` and ``read_blocks`` - ``writer``: ``WriteBlock`` and ``write_blocks`` - ``callback``: ``DataCallback`` for reading block data - ``external``: ``ExternalBlockCache`` for reading external blocks - ``options``: ``Options`` controlling block storage - high-level: - ``manager``: ``Manager`` and associated classes The low-level ``io`` functions are responsible for reading and writing bytes compatible with the block format defined in the ASDF standard. These should be compatible with as wide a variety of file formats as possible including files that are: - seekable and non-seekable - memory mappable - accessed from a remote server - stored in memory - etc To help organize ASDF block data the ``key`` and ``store`` submodules provide a special key-value store, ``Store``. ``Store`` uses ``Key`` instances to tie the lifetime of values to the lifetime of objects in the ASDF tree (without keeping references to the objects) and allows non-hashable objects to be used as keys. See the ``key`` submodule docstring for more details. One usage of ``Store`` is for managing ASDF block ``Options``. ``Options`` determine where and how array data will be written and a single ``Options`` instance might be associated with several arrays within the ASDF tree (if the arrays share the same base array). By using a ``Key`` generated with the base array the block ``Options`` can be stored in a ``Store`` without keeping a reference to the base array and these ``Options`` will be made unavailable if the base array is garbage collected (so they are not inapproriately assigned to a new array). The medium-level submodules ``reader`` and ``writer`` each define a helper class and function for reading or writing blocks: - ``ReadBlock`` and ``WriteBlock`` - ``read_blocks`` and ``write_blocks`` These abstract some of the complexity of reading and writing blocks using the low-level API and are the primary means by which the ``Manager`` reads and writes ASDF blocks. Reading of external blocks by the ``Manager`` requires some special handling which is contained in the ``external`` submodule. To allow for lazy-loading of ASDF block data, ``callback`` defines ``DataCallback`` which allows reading block data even after the blocks have been rearranged following an update-in-place. """ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_block/callback.py0000644000175100001770000000262314653725311016326 0ustar00runnerdocker""" A `DataCallback` class is implemented here to allow for reassignment of the index of an ASDF block corresponding to a callback. This is needed so that extension code can generate a callback during deserialization of an ASDF file that will continue to be valid even after an `AsdfFile.update` which might reorder blocks. To allow for 'low-level' block access needed for ndarray `DataCallback` can be called with an optional ``_attr`` argument to cache data, access the block header and other operations that we generally do not want to expose to extension code. """ import weakref class DataCallback: """ A callable object used to read data from an ASDF block read from an ASDF file. """ def __init__(self, index, read_blocks): self._reassign(index, read_blocks) def __call__(self, _attr=None): read_blocks = self._read_blocks_ref() if read_blocks is None: msg = "Attempt to read block data from missing block" raise OSError(msg) if _attr is None: return read_blocks[self._index].data else: # _attr allows NDArrayType to have low level block access for things # like reading the header and cached_data return getattr(read_blocks[self._index], _attr) def _reassign(self, index, read_blocks): self._index = index self._read_blocks_ref = weakref.ref(read_blocks) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_block/exceptions.py0000644000175100001770000000016514653725311016752 0ustar00runnerdockerclass BlockIndexError(Exception): """ An error occurred while reading or parsing an ASDF block index """ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_block/external.py0000644000175100001770000000414514653725311016415 0ustar00runnerdocker""" For external blocks, the previous block management would cache data opened from external files (to return the same underlying ndarray if the same external block was referenced more than once). `ExternalBlockCache` is used here to allow for the same behavior without requiring the block manager to have a reference to the `AsdfFile` (that references the block manager). """ import os import urllib import numpy as np from asdf import generic_io, util class UseInternalType: pass UseInternal = UseInternalType() class ExternalBlockCache: def __init__(self): self.clear() def load(self, base_uri, uri, memmap=False, validate_checksums=False): key = util.get_base_uri(uri) if key not in self._cache: resolved_uri = generic_io.resolve_uri(base_uri, uri) if resolved_uri == "" or resolved_uri == base_uri: return UseInternal from asdf import open as asdf_open with asdf_open( resolved_uri, "r", lazy_load=False, memmap=False, validate_checksums=validate_checksums ) as af: blk = af._blocks.blocks[0] if memmap and blk.header["compression"] == b"\0\0\0\0": parsed_url = util._patched_urllib_parse.urlparse(resolved_uri) if parsed_url.scheme == "file": # deal with leading slash for windows file:// filename = urllib.request.url2pathname(parsed_url.path) arr = np.memmap(filename, np.uint8, "r", blk.data_offset, blk.cached_data.nbytes) else: arr = blk.cached_data else: arr = blk.cached_data self._cache[key] = arr return self._cache[key] def clear(self): self._cache = {} def relative_uri_for_index(uri, index): # get the os-native separated path for this uri path = util._patched_urllib_parse.urlparse(uri).path dirname, filename = os.path.split(path) filename = os.path.splitext(filename)[0] + f"{index:04d}.asdf" return filename ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_block/io.py0000644000175100001770000004015514653725311015203 0ustar00runnerdocker""" Low-level functions for reading and writing ASDF blocks and other block related file contents (like the block index). """ import hashlib import io import os import struct import weakref import yaml from asdf import _compression as mcompression from asdf import constants, util from .exceptions import BlockIndexError BLOCK_HEADER = util._BinaryStruct( [ ("flags", "I"), ("compression", "4s"), ("allocated_size", "Q"), ("used_size", "Q"), ("data_size", "Q"), ("checksum", "16s"), ], ) def calculate_block_checksum(data): if data.ndim > 1: data = data.ravel(order="K") # The following line is safe because we're only using # the MD5 as a checksum. m = hashlib.new("md5") # noqa: S324 m.update(data) return m.digest() def validate_block_header(header): """ Check that they key value pairs in header contain consistent information about the ASDF block ``compression``, ``flags``, ``used_size`` and ``data_size`` (otherwise raise an exception). Parameters ---------- header : dict ASDF block header information. Raises ------ ValueError If the key value pairs in header contain inconsistent information """ compression = mcompression.validate(header["compression"]) if header["flags"] & constants.BLOCK_FLAG_STREAMED: if compression is not None: msg = "Compression set on a streamed block." raise ValueError(msg) else: if compression is None and header["used_size"] != header["data_size"]: msg = "used_size and data_size must be equal when no compression is used." raise ValueError(msg) return header def read_block_header(fd, offset=None): """ Read an ASDF block header Parameters ---------- fd : file or generic_io.GenericIO File to read. offset : int, optional Offset within the file where the start of the ASDF block header is located. If provided, the file will be seeked prior to reading. Returns ------- header : dict Dictionary containing the read ASDF header as parsed by the `BLOCK_HEADER` `asdf.util._BinaryStruct`. Raises ------ ValueError If the read header is inconsistent (see `validate_block_header`). """ if offset is not None: fd.seek(offset) # read the header size buff = fd.read(2) header_size = struct.unpack(b">H", buff)[0] if header_size < BLOCK_HEADER.size: msg = f"Header size must be >= {BLOCK_HEADER.size}" raise ValueError(msg) header = BLOCK_HEADER.unpack(fd.read(header_size)) return validate_block_header(header) def read_block_data(fd, header, offset=None, memmap=False): """ Read (or memory map) data for an ASDF block. Parameters ---------- fd : file or generic_io.GenericIO File to read. header : dict ASDF block header dictionary (as read from `read_block_header`). offset : int, optional Offset within the file where the start of the ASDF block data is located. If provided, the file will be seeked prior to reading. memmap : bool, optional, default False Memory map the block data using `generic_io.GenericIO.memmap_array`. A compressed block will never be memmapped and if the file ``fd`` does not support memmapping the data will not be memmapped (and no error will be raised). Returns ------- data : ndarray or memmap A one-dimensional ndarray of dtype uint8 """ if fd.seekable(): if offset is not None: fd.seek(offset) else: offset = fd.tell() if header["flags"] & constants.BLOCK_FLAG_STREAMED: used_size = -1 else: used_size = header["used_size"] # if no compression, just read data compression = mcompression.validate(header["compression"]) if compression: # compressed data will not be memmapped data = mcompression.decompress(fd, used_size, header["data_size"], compression) fd.fast_forward(header["allocated_size"] - header["used_size"]) else: if memmap and fd.can_memmap(): data = fd.memmap_array(offset, used_size) ff_bytes = header["allocated_size"] else: data = fd.read_into_array(used_size) ff_bytes = header["allocated_size"] - header["used_size"] if (header["flags"] & constants.BLOCK_FLAG_STREAMED) and fd.seekable(): fd.seek(0, os.SEEK_END) else: fd.fast_forward(ff_bytes) return data def read_block(fd, offset=None, memmap=False, lazy_load=False): """ Read a block (header and data) from an ASDF file. Parameters ---------- fd : file or generic_io.GenericIO File to read. offset : int, optional Offset within the file where the start of the ASDF block header is located. If provided, the file will be seeked prior to reading. Note this is the start of the block header not the start of the block magic. memmap : bool, optional, default False Memory map the block data see `read_block_data` for more details. lazy_load : bool, optional, default False Return a callable that when called will read the block data. This option is ignored for a non-seekable file. Returns ------- offset : int The offset within the file where the block was read (equal to offset argument if it was provided). header : dict ASDF block header as read with `read_block_header`. data_offset : int The offset within the file where the block data begins. data : ndarray, memmap or callable ASDF block data (one-dimensional ndarray of dtype uint8). If lazy_load (and the file is seekable) data will be a callable that when executed will seek the file and read the block data. """ # expects the fd or offset is past the block magic if offset is None and fd.seekable(): offset = fd.tell() header = read_block_header(fd, offset) if fd.seekable(): data_offset = fd.tell() else: data_offset = None if lazy_load and fd.seekable(): # setup a callback to later load the data fd_ref = weakref.ref(fd) def callback(): fd = fd_ref() if fd is None or fd.is_closed(): msg = "ASDF file has already been closed. Can not get the data." raise OSError(msg) position = fd.tell() data = read_block_data(fd, header, offset=data_offset, memmap=memmap) fd.seek(position) return data data = callback if header["flags"] & constants.BLOCK_FLAG_STREAMED: fd.seek(0, os.SEEK_END) else: fd.fast_forward(header["allocated_size"]) else: data = read_block_data(fd, header, offset=None, memmap=memmap) return offset, header, data_offset, data def generate_write_header(data, stream=False, compression_kwargs=None, padding=False, fs_block_size=1, **header_kwargs): """ Generate a dict representation of a ASDF block header that can be used for writing a block. Note that if a compression key is provided in ``header_kwargs`` this function will compress ``data`` to determine the used_size (the compressed data will be returned via the ``buff`` result to avoid needing to re-compress the data before writing). Parameters ---------- data : ndarray A one-dimensional ndarray of dtype uint8. stream : bool, optional, default False If True, generate a header for a streamed block. compression_kwargs : dict, optional If provided, these will be passed on to `asdf.compression.compress` if the data is compressed (see header_kwargs). padding : bool or float, optional, default False If the block should contain additional padding bytes. See the `asdf.util.calculate_padding` argument ``pad_blocks`` for more details. fs_block_size : int, optional, default 1 The filesystem block size. See the `asdf.util.calculate_padding` ``block_size`` argument for more details. **header_kwargs : dict, optional Block header settings that will be read, updated, and used to generate the binary block header representation by packing with `BLOCK_HEADER`. Returns ------- header : dict Dictionary representation of an ASDF block header. buff : bytes or None If this block is compressed buff will contained the compressed representation of data or None if the data is uncompressed. padding_bytes: int The number of padding bytes that must be written after the block data. """ if data.ndim != 1 or data.dtype != "uint8": msg = "Data must be of ndim==1 and dtype==uint8" raise ValueError(msg) if stream: header_kwargs["flags"] = header_kwargs.get("flags", 0) | constants.BLOCK_FLAG_STREAMED header_kwargs["data_size"] = 0 header_kwargs["checksum"] = b"\0" * 16 else: header_kwargs["flags"] = 0 header_kwargs["data_size"] = data.nbytes header_kwargs["checksum"] = calculate_block_checksum(data) header_kwargs["compression"] = mcompression.to_compression_header(header_kwargs.get("compression", None)) if header_kwargs["compression"] == b"\0\0\0\0": used_size = header_kwargs["data_size"] buff = None else: buff = io.BytesIO() mcompression.compress(buff, data, header_kwargs["compression"], config=compression_kwargs) used_size = buff.tell() if stream: header_kwargs["used_size"] = 0 header_kwargs["allocated_size"] = 0 else: header_kwargs["used_size"] = used_size padding = util.calculate_padding(used_size, padding, fs_block_size) header_kwargs["allocated_size"] = header_kwargs.get("allocated_size", used_size + padding) if header_kwargs["allocated_size"] < header_kwargs["used_size"]: msg = ( f"Block used size {header_kwargs['used_size']} larger than " f"allocated size {header_kwargs['allocated_size']}", ) raise RuntimeError(msg) padding_bytes = header_kwargs["allocated_size"] - header_kwargs["used_size"] return header_kwargs, buff, padding_bytes def write_block(fd, data, offset=None, stream=False, compression_kwargs=None, padding=False, **header_kwargs): """ Write an ASDF block. Parameters ---------- fd : file or generic_io.GenericIO File to write to. offset : int, optional If provided, seek to this offset before writing. stream : bool, optional, default False If True, write this as a streamed block. compression_kwargs : dict, optional If block is compressed, use these additional arguments during compression. See `generate_write_header`. padding : bool, optional, default False Optionally pad the block data. See `generate_write_header`. **header_kwargs : dict Block header settings. See `generate_write_header`. Returns ------- header : dict The ASDF block header as unpacked from the `BLOCK_HEADER` used for writing. """ header_dict, buff, padding_bytes = generate_write_header( data, stream, compression_kwargs, padding, fd.block_size, **header_kwargs ) header_bytes = BLOCK_HEADER.pack(**header_dict) if offset is not None: if fd.seekable(): fd.seek(offset) else: msg = "write_block received offset for non-seekable file" raise ValueError(msg) fd.write(struct.pack(b">H", len(header_bytes))) fd.write(header_bytes) if buff is None: # data is uncompressed fd.write_array(data) else: fd.write(buff.getvalue()) fd.fast_forward(padding_bytes) return header_dict def _candidate_offsets(min_offset, max_offset, block_size): offset = (max_offset // block_size) * block_size if offset == max_offset: offset -= block_size while offset > min_offset: yield offset offset -= block_size if offset <= min_offset: yield min_offset def find_block_index(fd, min_offset=None, max_offset=None): """ Find the location of an ASDF block index within a seekable file. Searching will begin at the end of the file (or max_offset if it is provided). Parameters ---------- fd : file or generic_io.GenericIO A seekable file that will be searched to try and find the start of an ASDF block index within the file. min_offset : int, optional The minimum search offset. A block index will not be found before this point. max_offset : int, optional The maximum search offset. A block index will not be found after this point. Returns ------- offset : int or None Index of start of ASDF block index. This is the location of the ASDF block index header. """ if min_offset is None: min_offset = fd.tell() if max_offset is None: fd.seek(0, os.SEEK_END) max_offset = fd.tell() block_size = fd.block_size block_index_offset = None buff = b"" pattern = constants.INDEX_HEADER for offset in _candidate_offsets(min_offset, max_offset, block_size): fd.seek(offset) buff = fd.read(block_size) + buff index = buff.find(pattern) if index != -1: block_index_offset = offset + index if block_index_offset >= max_offset: return None break buff = buff[: len(pattern)] return block_index_offset def read_block_index(fd, offset=None): """ Read an ASDF block index from a file. Parameters ---------- fd : file or generic_io.GenericIO File to read the block index from. offset : int, optional Offset within the file where the block index starts (the start of the ASDF block index header). If not provided reading will start at the current position of the file pointer. See `find_block_index` to locate the block index prior to calling this function. Returns ------- block_index : list of ints A list of ASDF block offsets read and parsed from the block index. Raises ------ BlockIndexError The data read from the file did not contain a valid block index. """ if offset is not None: fd.seek(offset) buff = fd.read(len(constants.INDEX_HEADER)) if buff != constants.INDEX_HEADER: msg = "Failed to read block index header at offset {offset}" raise BlockIndexError(msg) try: block_index = yaml.load(fd.read(-1), yaml.SafeLoader) except yaml.error.YAMLError: raise BlockIndexError("Failed to parse block index as yaml") if ( not isinstance(block_index, list) or any(not isinstance(v, int) for v in block_index) or block_index != sorted(block_index) ): raise BlockIndexError("Invalid block index") return block_index def write_block_index(fd, offsets, offset=None, yaml_version=None): """ Write a list of ASDF block offsets to a file in the form of an ASDF block index. Parameters ---------- fd : file or generic_io.GenericIO File to write to. offsets : list of ints List of byte offsets (from the start of the file) where ASDF blocks are located. offset : int, optional If provided, seek to this offset before writing. yaml_version : tuple, optional, default (1, 1) YAML version to use when writing the block index. This will be passed to ``yaml.dump`` as the version argument. """ if yaml_version is None: yaml_version = (1, 1) if offset is not None: fd.seek(offset) fd.write(constants.INDEX_HEADER) fd.write(b"\n") yaml.dump( offsets, stream=fd, Dumper=yaml.SafeDumper, explicit_start=True, explicit_end=True, allow_unicode=True, encoding="utf-8", version=yaml_version, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_block/key.py0000644000175100001770000000443014653725311015360 0ustar00runnerdocker""" A hashable Key class that provides a means for tracking the lifetime of objects to associate objects with blocks, options and other parts of an asdf file. This Key is meant to replace uses of id(obj) which in previous code was used to store settings (like block array storage). The use of id was problematic as an object might be deallocated (if it is removed from the tree and all other references freed) and a new object of the same type might occupy the same location in memory and result in the same id. This could result in options originally associated with the first object being incorrectly assigned to the new object. At it's core, Key, uses a weak reference to the object which can be checked to see if the object is still in memory. Instances of this class will be provided to extension code (see ``SerializationContext.generate_block_key``) as Converters will need to resupply these keys on rewrites (updates) to allow asdf to reassociate objects and blocks. To discourage modifications of these Key instances all methods and attributes are private. """ import weakref class Key: _next = 0 @classmethod def _next_key(cls): key = cls._next cls._next += 1 return key def __init__(self, obj=None, _key=None): if _key is None: _key = Key._next_key() self._key = _key self._ref = None if obj is not None: self._assign_object(obj) def _is_valid(self): if self._ref is None: return False r = self._ref() if r is None: return False return True def __hash__(self): return self._key def _assign_object(self, obj): self._ref = weakref.ref(obj) def _matches_object(self, obj): if self._ref is None: return False r = self._ref() if r is None: return False return r is obj def __eq__(self, other): if not isinstance(other, Key): return NotImplemented if self._key != other._key: return False if not self._is_valid(): return False return other._matches_object(self._ref()) def __copy__(self): obj = self._ref if self._ref is None else self._ref() return type(self)(obj, self._key) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_block/manager.py0000644000175100001770000006247514653725311016217 0ustar00runnerdockerimport collections import contextlib import copy from asdf import config, constants, generic_io, util from . import external, reader, store, writer from . import io as bio from .callback import DataCallback from .key import Key as BlockKey from .options import Options class ReadBlocks(collections.UserList): """ A list of ReadBlock instances. A simple list can't be used as other code will need to generate a weakref to instances of this class (and it is not possible to generate a weakref to a list). """ pass class WriteBlocks(collections.abc.Sequence): """ A collection of ``WriteBlock`` instances that can be accessed by: - numerical index (see ``collections.abc.Sequence``) - the object or objects in the tree that created or are associated with this block - the block data Access by object and data is via a Store which generates Keys to allow use of non-hashable objects (and to not hold a reference to the block data). """ def __init__(self, blocks=None): if blocks is None: blocks = [] self._blocks = blocks # both stores contain values that are indices of # WriteBlock instances in _blocks self._data_store = store.Store() self._object_store = store.Store() def __getitem__(self, index): return self._blocks.__getitem__(index) def __len__(self): return self._blocks.__len__() def index_for_data(self, data): return self._data_store.lookup_by_object(data) def assign_object_to_index(self, obj, index): self._object_store.assign_object(obj, index) def object_keys_for_index(self, index): yield from self._object_store.keys_for_value(index) def append_block(self, blk, obj): """ Append a ``WriteBlock`` instance to this collection assign an object, obj, to the block and return the index of the block within the collection. """ index = len(self._blocks) self._blocks.append(blk) # assign the block data to this block to allow # fast lookup of blocks based on data self._data_store.assign_object(blk._data, index) # assign the object that created/uses this block self._object_store.assign_object(obj, index) return index class OptionsStore(store.Store): """ A ``Store`` of ``Options`` that can be accessed by the base array that corresponds to a block. A ``Store`` is used to avoid holding references to the array data (see ``asdf._block.store.Store``). When ``Options`` are not found within the ``Store``, the ``OptionsStore`` will look for any available matching ``ReadBlock`` to determine default Options. """ def __init__(self, read_blocks): super().__init__() # ReadBlocks are needed to look up default options self._read_blocks = read_blocks def has_options(self, array): """ Check of Options have been defined for this array without falling back to generating Options from a ReadBlock. Parameters ---------- array : ndarray The base of this array (see `asdf.util.get_array_base`) will be used to lookup any Options in the Store. Returns ------- has_options : bool True if Options were previously defined for this array. """ base = util.get_array_base(array) return self.lookup_by_object(base) is not None def get_options_from_block(self, array): """ Get Options for some array using only settings read from a corresponding ReadBlock (one that shares the same base array). Any Options defined using previous calls to set_options will be ignored (use ``get_options`` if you would like these previously set options to be considered). Parameters ---------- array : ndarray The base of this array (see `asdf.util.get_array_base`) will be used to lookup a corresponding ReadBlock. Returns ------- options : Options or None Options initialized from settings read from a ReadBlock or None if no corresponding block was found. """ base = util.get_array_base(array) # look up by block with matching _data for block in self._read_blocks: if block._cached_data is base or block._data is base: # init options if block.header["flags"] & constants.BLOCK_FLAG_STREAMED: storage_type = "streamed" else: storage_type = "internal" options = Options(storage_type, block.header["compression"]) return options return None def get_options(self, array): """ Get Options for some array using either previously defined options (as set by ``set_options``) or settings read from a corresponding ReadBlock (one that shares the same base array). Note that if no options are found in the Store and options are found from a ReadBlock the resulting Options will be added to the Store. Parameters ---------- array : ndarray The base of this array (see `asdf.util.get_array_base`) will be used to lookup any Options in the Store. Returns ------- options : Options or None Options read from the Store or ReadBlocks or None if no options were found. """ base = util.get_array_base(array) options = self.lookup_by_object(base) if options is None: options = self.get_options_from_block(base) if options is not None: self.set_options(base, options) if options is None: options = Options() self.set_options(base, options) return options def set_options(self, array, options): """ Set Options for an array. Parameters ---------- array : ndarray The base of this array (see `asdf.util.get_array_base`) will be used to add options to the Store. options : Options The Options to add to the Store for this array. Raises ------ ValueError If more than one block is set as a streamed block. """ if options.storage_type == "streamed": for oid, by_key in self._by_id.items(): for key, opt in by_key.items(): if not key._is_valid(): continue if opt.storage_type == "streamed": if opt is options: continue msg = "Can not add second streaming block" raise ValueError(msg) base = util.get_array_base(array) self.assign_object(base, options) def get_output_compressions(self): """ Get all output compression types used for this Store of Options. Returns ------- compressions : list of bytes List of 4 byte compression labels used for this OptionsStore. """ compressions = set() cfg = config.get_config() if cfg.all_array_compression == "input": for blk in self._read_blocks: if blk.header["compression"]: compressions.add(blk.header["compression"]) else: compressions.add(cfg.all_array_compression) for _, by_key in self._by_id.items(): for key, opts in by_key.items(): if not key._is_valid(): continue if opts.compression: compressions.add(opts.compression) return compressions class Manager: """ ``Manager`` for reading, writing and storing options for ASDF blocks. This class does the heavy lifting of allowing ``asdf.AsdfFile`` instances to control ASDF blocks. It is responsible for reading and writing blocks primarily to maintain some consistency with the previous BlockManager. Block ``Options`` control the compression and type of storage for an ASDF block (see `asdf.AsdfFile.set_array_storage`, `asdf.AsdfFile.set_array_compression` `asdf.AsdfFile.set_array_compression` for relevant usage and information). These ``Options`` instances are stored and retrieved using the base of the array containing the data for an ASDF block. This allows arrays that share the same base array (ie views of the same array) to use the same ASDF block. Reading blocks occurs through use of ``Manager.read`` which will create ``ReadBlock`` instances for each read ASDF block. These ``ReadBlock`` will be used as the source for default ``Options`` for each block and ASDF block data can be read using ``DataCallback`` instances. These callbacks are used (instead of just accessing blocks by index) to allow block reorganization during ``update``.(Note that reading of external blocks is special as these are not stored within the block section of the ASDF file. These must be explicitly loaded using ``Manager._load_external``). Writing ASDF blocks occurs through use of ``Manager.write`` which will take any queued ``WriteBlocks`` (created via ``Manager.make_write_block`` and ``Manager.set_streamed_write_block``) and write them out to a file. This writing must occur within a ``Manager.write_context`` to allow the ``Manager`` to reset any ``Options`` changes that occur during write and to clean up the write queue. Update-in-place occurs through use of ``Manager.update`` which, like ``Manager.write`` must occur within a ``Manager.write_context``. Following a ``Manager.update`` the ``ReadBlock`` instances will be replaced with the newly written ASDF blocks and any ``DataCallbacks`` will be updated to reference the appropriate new ``ReadBlock``. """ def __init__(self, read_blocks=None, uri=None, lazy_load=False, memmap=False, validate_checksums=False): if read_blocks is None: read_blocks = ReadBlocks([]) self.options = OptionsStore(read_blocks) self._blocks = read_blocks self._external_block_cache = external.ExternalBlockCache() self._data_callbacks = store.Store() self._write_blocks = WriteBlocks() self._external_write_blocks = [] self._streamed_write_block = None self._streamed_obj_keys = set() self._write_fd = None # store the uri of the ASDF file here so that the Manager can # resolve and load external blocks without requiring a reference # to the AsdfFile instance self._uri = uri # general block settings self._lazy_load = lazy_load self._memmap = memmap self._validate_checksums = validate_checksums def close(self): self._external_block_cache.clear() self._clear_write() for blk in self.blocks: blk.close() self.options = OptionsStore(self.blocks) @property def blocks(self): """ Get any ReadBlocks that were read from an ASDF file Returns ------- read_blocks : list of ReadBlock List of ReadBlock instances created during a call to read or update. """ return self._blocks @blocks.setter def blocks(self, new_blocks): if not isinstance(new_blocks, ReadBlocks): new_blocks = ReadBlocks(new_blocks) self._blocks = new_blocks # we propagate these blocks to options so that # options lookups can fallback to the new read blocks self.options._read_blocks = new_blocks def read(self, fd, after_magic=False): """ Read blocks from an ASDF file and update the manager read_blocks. Parameters ---------- fd : file or generic_io.GenericIO File to read from. Reading starts at the current file position. after_magic : bool, optional, default False If True, the file pointer is past the block magic bytes of the first block. """ self.blocks = reader.read_blocks( fd, self._memmap, self._lazy_load, self._validate_checksums, after_magic=after_magic ) def _load_external(self, uri): value = self._external_block_cache.load(self._uri, uri, self._memmap, self._validate_checksums) if value is external.UseInternal: return self.blocks[0].data return value def _clear_write(self): self._write_blocks = WriteBlocks() self._external_write_blocks = [] self._streamed_write_block = None self._streamed_obj_keys = set() self._write_fd = None def _write_external_blocks(self): from asdf import AsdfFile if self._write_fd is None or self._write_fd.uri is None: msg = "Can't write external blocks, since URI of main file is unknown." raise ValueError(msg) for blk in self._external_write_blocks: uri = generic_io.resolve_uri(self._write_fd.uri, blk._uri) af = AsdfFile() with generic_io.get_file(uri, mode="w") as f: af.write_to(f, include_block_index=False) writer.write_blocks(f, [blk]) def make_write_block(self, data, options, obj): """ Make a WriteBlock with data and options and associate it with an object (obj). Parameters ---------- data : npdarray or callable Data to be written to an ASDF block. Can be provided as a callable function that when evaluated will return the data. options : Options or None Options instance used to define the ASDF block compression and storage type. If None, a new Options instance will be created. obj : object An object in the ASDF tree that will be associated with the new WriteBlock so that `AsdfFile.update` can map newly created blocks to blocks read from the original file. Returns ------- block_source : int or str The relative uri (str) if an external block was created or the index of the block (int) for an internal block. Raises ------ ValueError If a external block was created without a URI for the main file. """ if options is None: options = Options() if options.storage_type == "external": for index, blk in enumerate(self._external_write_blocks): if blk._data is data: # this external uri is already ready to go return blk._uri # need to set up new external block index = len(self._external_write_blocks) blk = writer.WriteBlock(data, options.compression, options.compression_kwargs) if self._write_fd is not None: base_uri = self._write_fd.uri or self._uri else: base_uri = self._uri if base_uri is None: msg = "Can't write external blocks, since URI of main file is unknown." raise ValueError(msg) blk._uri = external.relative_uri_for_index(base_uri, index) self._external_write_blocks.append(blk) return blk._uri # first, look for an existing block index = self._write_blocks.index_for_data(data) if index is not None: self._write_blocks.assign_object_to_index(obj, index) return index # if no block is found, make a new block blk = writer.WriteBlock(data, options.compression, options.compression_kwargs) index = self._write_blocks.append_block(blk, obj) return index def set_streamed_write_block(self, data, obj): """ Create a WriteBlock that will be written as an ASDF streamed block. Parameters ---------- data : ndarray or callable Data to be written to an ASDF block. Can be provided as a callable function that when evaluated will return the data. obj : object An object in the ASDF tree that will be associated with the new WriteBlock so that `AsdfFile.update` can map newly created blocks to blocks read from the original file. """ if self._streamed_write_block is not None and data is not self._streamed_write_block.data: msg = "Can not add second streaming block" raise ValueError(msg) if self._streamed_write_block is None: self._streamed_write_block = writer.WriteBlock(data) self._streamed_obj_keys.add(BlockKey(obj)) def _get_data_callback(self, index): return DataCallback(index, self.blocks) def _set_array_storage(self, data, storage): options = self.options.get_options(data) options.storage_type = storage self.options.set_options(data, options) def _get_array_storage(self, data): return self.options.get_options(data).storage_type def _set_array_compression(self, arr, compression, **compression_kwargs): # if this is input compression but we already have defined options # we need to re-lookup the options based off the block if compression == "input" and self.options.has_options(arr): from_block_options = self.options.get_options_from_block(arr) if from_block_options is not None: compression = from_block_options.compression options = self.options.get_options(arr) options.compression = compression options.compression_kwargs = compression_kwargs def _get_array_compression(self, arr): return self.options.get_options(arr).compression def _get_array_compression_kwargs(self, arr): return self.options.get_options(arr).compression_kwargs def get_output_compressions(self): return self.options.get_output_compressions() def _set_array_save_base(self, data, save_base): options = self.options.get_options(data) options.save_base = save_base self.options.set_options(data, options) def _get_array_save_base(self, data): return self.options.get_options(data).save_base @contextlib.contextmanager def options_context(self): """ Context manager that copies block options on entrance and restores the options when exited. """ previous_options = copy.deepcopy(self.options) yield self.options = previous_options self.options._read_blocks = self.blocks @contextlib.contextmanager def write_context(self, fd, copy_options=True): """ Context manager that copies block options on entrance and restores the options when exited. Parameters ---------- fd : file or generic_io.GenericIO File to be written to. This is required on entrance to this context so that any external blocks can resolve relative uris. copy_options : bool, optional, default True Copy options on entrance and restore them on exit (See `options_context`). """ self._clear_write() self._write_fd = fd if copy_options: with self.options_context(): yield else: yield self._clear_write() def write(self, pad_blocks, include_block_index): """ Write blocks that were set up during the current `write_context`. Parameters ---------- pad_blocks : bool, None or float If False, add no padding bytes between blocks. If True add some default amount of padding. If a float, add a number of padding bytes based off a ratio of the data size. include_block_index : bool If True, include a block index at the end of the file. If a streamed_block is provided (or the file is not seekable) no block index will be written. Raises ------ OSError If called outside a `write_context`. """ if self._write_fd is None: msg = "write called outside of valid write_context" raise OSError(msg) if len(self._write_blocks) or self._streamed_write_block: writer.write_blocks( self._write_fd, self._write_blocks, pad_blocks, streamed_block=self._streamed_write_block, write_index=include_block_index, ) if len(self._external_write_blocks): self._write_external_blocks() def update(self, new_tree_size, pad_blocks, include_block_index): """ Perform an update-in-place of ASDF blocks set up during a `write_context`. Parameters ---------- new_tree_size : int Size (in bytes) of the serialized ASDF tree (and any header bytes) that will be written at the start of the file being updated. pad_blocks : bool, None or float If False, add no padding bytes between blocks. If True add some default amount of padding. If a float, add a number of padding bytes based off a ratio of the data size. include_block_index : bool If True, include a block index at the end of the file. If a streamed_block is provided (or the file is not seekable) no block index will be written. Raises ------ OSError If called outside a `write_context`. """ if self._write_fd is None: msg = "update called outside of valid write_context" raise OSError(msg) # find where to start writing blocks (either end of new tree or end of last 'free' block) last_block = None for blk in self.blocks[::-1]: if not blk.memmap and (blk._cached_data is not None or not callable(blk._data)): continue last_block = blk break if last_block is None: new_block_start = new_tree_size else: new_block_start = max( last_block.data_offset + last_block.header["allocated_size"], new_tree_size, ) if len(self._external_write_blocks): self._write_external_blocks() # do we have any blocks to write? if len(self._write_blocks) or self._streamed_write_block: self._write_fd.seek(new_block_start) offsets, headers = writer.write_blocks( self._write_fd, self._write_blocks, pad_blocks, streamed_block=self._streamed_write_block, write_index=False, # don't write an index as we will modify the offsets ) new_block_end = self._write_fd.tell() # move blocks to start in increments of block_size n_bytes = new_block_end - new_block_start src, dst = new_block_start, new_tree_size block_size = self._write_fd.block_size while n_bytes > 0: self._write_fd.seek(src) bs = self._write_fd.read(min(n_bytes, block_size)) self._write_fd.seek(dst) self._write_fd.write(bs) n = len(bs) n_bytes -= n src += n dst += n # update offset to point at correct locations offsets = [o - (new_block_start - new_tree_size) for o in offsets] # write index if no streamed block if include_block_index and self._streamed_write_block is None: bio.write_block_index(self._write_fd, offsets) # map new blocks to old blocks new_read_blocks = ReadBlocks() for i, (offset, header) in enumerate(zip(offsets, headers)): # find all objects that assigned themselves to the write block at index i if i == len(self._write_blocks): # this is a streamed block obj_keys = self._streamed_obj_keys else: # find object associated with this write block obj_keys = set(self._write_blocks.object_keys_for_index(i)) # we have to be lazy here as any current memmap is invalid new_read_block = reader.ReadBlock(offset + 4, self._write_fd, self._memmap, True, False, header=header) new_read_blocks.append(new_read_block) new_index = len(new_read_blocks) - 1 # update all callbacks for obj_key in obj_keys: obj = obj_key._ref() if obj is None: # this object no longer exists so don't both assigning it continue # update data callbacks to point to new block cb = self._data_callbacks.lookup_by_object(obj) if cb is not None: cb._reassign(new_index, new_read_blocks) # update read blocks to reflect new state self.blocks = new_read_blocks ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_block/options.py0000644000175100001770000000533614653725311016271 0ustar00runnerdockerfrom asdf import _compression as mcompression from asdf.config import get_config class Options: """ Storage and compression options useful when reading or writing ASDF blocks. """ def __init__(self, storage_type=None, compression_type=None, compression_kwargs=None, save_base=None): if storage_type is None: storage_type = get_config().all_array_storage or "internal" if save_base is None: save_base = get_config().default_array_save_base self._storage_type = None self._compression = None self._compression_kwargs = None # set via setters self.compression_kwargs = compression_kwargs self.compression = compression_type self.storage_type = storage_type self.save_base = save_base @property def storage_type(self): return self._storage_type @storage_type.setter def storage_type(self, storage_type): if storage_type not in ["internal", "external", "streamed", "inline"]: msg = "array_storage must be one of 'internal', 'external', 'streamed' or 'inline'" raise ValueError(msg) self._storage_type = storage_type @property def compression(self): return self._compression @compression.setter def compression(self, compression): msg = f"Invalid compression type: {compression}" if compression == "input": # "input" compression will validate as the ASDF compression module made # some assumptions about availability of information (that the input block # is known). The Options here do not have the same assumption. # For a block read from a file, it's options will be initialized with # the compression value read from the block header so we should never # see 'input' at this point. raise ValueError(msg) try: compression = mcompression.validate(compression) except ValueError: raise ValueError(msg) self._compression = compression @property def compression_kwargs(self): return self._compression_kwargs @compression_kwargs.setter def compression_kwargs(self, kwargs): if not kwargs: kwargs = {} self._compression_kwargs = kwargs @property def save_base(self): return self._save_base @save_base.setter def save_base(self, save_base): if not (isinstance(save_base, bool) or save_base is None): msg = "save_base must be a bool or None" raise ValueError(msg) self._save_base = save_base def __copy__(self): return type(self)(self._storage_type, self._compression, self._compression_kwargs) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_block/reader.py0000644000175100001770000002222014653725311016027 0ustar00runnerdockerimport warnings import weakref from asdf import constants from asdf.exceptions import AsdfBlockIndexWarning, AsdfWarning from . import io as bio from .exceptions import BlockIndexError class ReadBlock: """ Represents an ASDF block read from a file. """ def __init__(self, offset, fd, memmap, lazy_load, validate_checksum, header=None, data_offset=None, data=None): self.offset = offset # after block magic bytes self._fd = weakref.ref(fd) self._header = header self.data_offset = data_offset self._data = data self._cached_data = None self.memmap = memmap self.lazy_load = lazy_load self.validate_checksum = validate_checksum if not lazy_load: self.load() def close(self): self._cached_data = None @property def loaded(self): return self._data is not None def load(self): """ Load the block data (if it is not already loaded). Raises ------ OSError If attempting to load from a closed file. """ if self.loaded: return fd = self._fd() if fd is None or fd.is_closed(): msg = "Attempt to load block from closed file" raise OSError(msg) position = fd.tell() _, self._header, self.data_offset, self._data = bio.read_block( fd, offset=self.offset, memmap=self.memmap, lazy_load=self.lazy_load ) fd.seek(position) @property def data(self): """ Read, parse and return data for an ASDF block. Returns ------- data : ndarray A one-dimensional ndarray of dypte uint8 read from an ASDF block Raises ------ ValueError If the header checksum does not match the checksum of the data and validate_checksums was set to True. """ if not self.loaded: self.load() if callable(self._data): data = self._data() else: data = self._data if self.validate_checksum: checksum = bio.calculate_block_checksum(data) if not self._header["flags"] & constants.BLOCK_FLAG_STREAMED and checksum != self._header["checksum"]: msg = f"Block at {self.offset} does not match given checksum" raise ValueError(msg) # only validate data the first time it's read self.validate_checksum = False return data @property def cached_data(self): """ Return cached data for an ASDF block. The first time this is called it may read data from the file (if lazy loaded). Subsequent calls will return the same ndarray. """ if self._cached_data is None: self._cached_data = self.data return self._cached_data @property def header(self): """ Get the block header. For a lazy loaded block the first time this is called the header will be read from the file and cached. Returns ------- header : dict Dictionary containing the read ASDF header. """ if not self.loaded: self.load() return self._header def _read_blocks_serially(fd, memmap=False, lazy_load=False, validate_checksums=False, after_magic=False): """ Read blocks serially from a file without looking for a block index. For parameter and return value descriptions see `read_blocks`. """ blocks = [] buff = b"" magic_len = len(constants.BLOCK_MAGIC) while True: # the expectation is that this will begin PRIOR to the block magic # read 4 bytes if not after_magic: buff += fd.read(magic_len - len(buff)) if len(buff) == 0: # we are done, there are no more blocks and no index break elif len(buff) < magic_len: # we have less than magic_len bytes, this is likely an error # in the input file/bytes if all([b == 0 for b in buff]): # if these are all 0, assume this was a 'truncated' file # so don't issue a warning break # if these are non-0 bytes issue a warning that the file # is likely corrupt msg = f"Read invalid bytes {buff!r} after blocks, your file might be corrupt" warnings.warn(msg, AsdfWarning) break if buff == constants.INDEX_HEADER[:magic_len]: # we hit the block index, which is not useful here break if after_magic or buff == constants.BLOCK_MAGIC: # this is another block offset, header, data_offset, data = bio.read_block(fd, memmap=memmap, lazy_load=lazy_load) blocks.append( ReadBlock( offset, fd, memmap, lazy_load, validate_checksums, header=header, data_offset=data_offset, data=data ) ) if blocks[-1].header["flags"] & constants.BLOCK_FLAG_STREAMED: # a file can only have 1 streamed block and it must be at the end so we # can stop looking for more blocks break buff = b"" after_magic = False else: if len(blocks) or buff[0] != 0: # if this is not the first block or we haven't found any # blocks and the first byte is non-zero msg = f"Invalid bytes while reading blocks {buff}" raise OSError(msg) # this is the first block, allow empty bytes before block buff = buff.strip(b"\0") return blocks def read_blocks(fd, memmap=False, lazy_load=False, validate_checksums=False, after_magic=False): """ Read a sequence of ASDF blocks from a file. If the file is seekable (and lazy_load is False) an attempt will made to find, read and parse a block index. If this fails, the blocks will be read serially. If parsing the block index succeeds, the first first and last blocks will be read (to confirm that those portions of the index are correct). All other blocks will not be read until they are accessed. Parameters ---------- fd : file or generic_io.GenericIO File to read. Reading will start at the current position. memmap : bool, optional, default False If true, memory map block data. lazy_load : bool, optional, default False If true, block data will be a callable that when executed will return the block data. See the ``lazy_load`` argument to ``asdf._block.io.read_block`` for more details. validate_checksums : bool, optional, default False When reading blocks compute the block data checksum and compare it to the checksum read from the block header. Note that this comparison will occur when the data is accessed if ``lazy_load`` was set to True. after_magic : bool, optional, default False If True don't expect block magic bytes for the first block read from the file. Returns ------- read_blocks : list of ReadBlock A list of ReadBlock instances. Raises ------ OSError Invalid bytes encountered while reading blocks. ValueError A read block has an invalid checksum. """ if not lazy_load or not fd.seekable(): # load all blocks serially return _read_blocks_serially(fd, memmap, lazy_load, validate_checksums, after_magic) # try to find block index starting_offset = fd.tell() index_offset = bio.find_block_index(fd, starting_offset) if index_offset is None: # if failed, load all blocks serially fd.seek(starting_offset) return _read_blocks_serially(fd, memmap, lazy_load, validate_checksums, after_magic) # setup empty blocks try: block_index = bio.read_block_index(fd, index_offset) except BlockIndexError as e: # failed to read block index, fall back to serial reading msg = f"Failed to read block index, falling back to serial reading: {e!s}" warnings.warn(msg, AsdfBlockIndexWarning) fd.seek(starting_offset) return _read_blocks_serially(fd, memmap, lazy_load, validate_checksums, after_magic) # skip magic for each block magic_len = len(constants.BLOCK_MAGIC) blocks = [ReadBlock(offset + magic_len, fd, memmap, lazy_load, validate_checksums) for offset in block_index] try: # load first and last blocks to check if the index looks correct for index in (0, -1): fd.seek(block_index[index]) buff = fd.read(magic_len) if buff != constants.BLOCK_MAGIC: msg = "Invalid block magic" raise OSError(msg) blocks[index].load() except (OSError, ValueError) as e: msg = f"Invalid block index contents for block {index}, falling back to serial reading: {e!s}" warnings.warn(msg, AsdfBlockIndexWarning) fd.seek(starting_offset) return _read_blocks_serially(fd, memmap, lazy_load, after_magic) return blocks ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_block/store.py0000644000175100001770000000563714653725311015736 0ustar00runnerdockerfrom .key import Key class Store: """ A key-value store that uses ``asdf._block.key.Key`` to allow use of keys that: - are not hashable (so any object can be used) - when the key is garbage collected, the value will be unretrievable """ def __init__(self): # store contains 2 layers of lookup: id(obj), Key self._by_id = {} def lookup_by_object(self, obj, default=None): if isinstance(obj, Key): # if obj is a Key, look up the object obj_id = id(obj._ref()) # and use the Key obj_key = obj else: obj_id = id(obj) obj_key = None # if id is unknown, return default if obj_id not in self._by_id: return default # first, lookup by id: O(1) by_key = self._by_id[obj_id] # if we have a key if obj_key: # use the key to get an existing value # or default if this Key is unknown return by_key.get(obj_key, default) # we have seen this id(obj) before # look for a matching key: O(N) for key, value in by_key.items(): if key._matches_object(obj): return value # no match, return default return default def assign_object(self, obj, value): if isinstance(obj, Key): if not obj._is_valid(): msg = "Invalid key used for assign_object" raise ValueError(msg) obj_id = id(obj._ref()) obj_key = obj else: obj_id = id(obj) obj_key = None # if the id is unknown, just set it if obj_id not in self._by_id: if obj_key is None: obj_key = Key(obj) self._by_id[obj_id] = {obj_key: value} return # if id is known by_key = self._by_id[obj_id] # look for a matching matching key if obj_key is None: for key in by_key: if key._matches_object(obj): by_key[key] = value return # we didn't find a matching key, so make one obj_key = Key(obj) # if no match was found, add using the key self._by_id[obj_id][obj_key] = value def keys_for_value(self, value): for oid, by_key in self._by_id.items(): for key, stored_value in by_key.items(): if stored_value == value and key._is_valid(): yield key def _cleanup(self, object_id=None): if object_id is None: for oid in set(self._by_id): self._cleanup(oid) return by_key = self._by_id[object_id] keys_to_remove = [k for k in by_key if not k._is_valid()] for key in keys_to_remove: del by_key[key] if not len(by_key): del self._by_id[object_id] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_block/writer.py0000644000175100001770000000765414653725311016117 0ustar00runnerdockerimport numpy as np from asdf import constants from . import io as bio class WriteBlock: """ Data and compression options needed to write an ASDF block. """ def __init__(self, data, compression=None, compression_kwargs=None): self._data = data self.compression = compression self.compression_kwargs = compression_kwargs @property def data(self): if callable(self._data): return self._data() return self._data @property def data_bytes(self): data = self.data if data is not None: return np.ndarray(-1, np.uint8, data.ravel(order="K").data) return np.ndarray(0, np.uint8) def write_blocks(fd, blocks, padding=False, streamed_block=None, write_index=True): """ Write a list of WriteBlocks to a file Parameters ---------- fd : file or generic_io.GenericIO File to write to. Writing will start at the current position. blocks : list of WriteBlock List of WriteBlock instances used to get the data and options to write to each ASDF block. padding : bool or float, optional, default False If False, add no padding bytes between blocks. If True add some default amount of padding. If a float, add a number of padding bytes based off a ratio of the data size. See ``asdf._block.io.write_block`` ``padding`` argument for more details. streamed_block : WriteBlock, optional If provided (not None) include this WriteBlock as the final block in the file and mark it as a streamed block. write_index : bool, optional, default True If True, include a block index at the end of the file. If a streamed_block is provided (or the file is not seekable) no block index will be written. Returns ------- offsets : list of int Byte offsets (from the start of the file) where each block was written (this is the start of the block magic bytes for each block). This list includes the offset of the streamed_block if it was provided. If the file written to is not seekable these offsets will all be None. headers : list of dict Headers written for each block (including the streamed_block if it was provided). """ # some non-seekable files return a valid `tell` result # others can raise an exception, others might always # return 0. See relevant issues: # https://github.com/asdf-format/asdf/issues/1545 # https://github.com/asdf-format/asdf/issues/1552 # https://github.com/asdf-format/asdf/issues/1542 # to enable writing a block index for all valid files # we will wrap tell to return None on an error def tell(): try: return fd.tell() except OSError: return None offsets = [] headers = [] for blk in blocks: offsets.append(tell()) fd.write(constants.BLOCK_MAGIC) headers.append( bio.write_block( fd, blk.data_bytes, compression_kwargs=blk.compression_kwargs, padding=padding, compression=blk.compression, ) ) if streamed_block is not None: offsets.append(tell()) fd.write(constants.BLOCK_MAGIC) headers.append(bio.write_block(fd, streamed_block.data_bytes, stream=True)) # os.pipe on windows returns a file-like object # that reports as seekable but tell always returns 0 # https://github.com/asdf-format/asdf/issues/1545 # when all offsets are 0 replace them with all Nones if all(o == 0 for o in offsets): offsets = [None for _ in offsets] # only write a block index if all conditions are met if streamed_block is None and write_index and len(offsets) and all(o is not None for o in offsets): bio.write_block_index(fd, offsets) return offsets, headers ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_compression.py0000644000175100001770000002454314653725311016046 0ustar00runnerdockerimport bz2 import struct import warnings import zlib import numpy as np from .config import get_config from .exceptions import AsdfWarning def validate(compression): """ Validate the compression string. Parameters ---------- compression : str, bytes or None Returns ------- compression : str or None In canonical form. Raises ------ ValueError """ if not compression or compression == b"\0\0\0\0": return None if isinstance(compression, bytes): compression = compression.decode("ascii") compression = compression.strip("\0") builtin_labels = ["zlib", "bzp2", "lz4", "input"] ext_labels = _get_all_compression_extension_labels() all_labels = ext_labels + builtin_labels # An extension is allowed to override a builtin compression or another extension, # but let's warn the user of this. # TODO: is this the desired behavior? for i, label in enumerate(all_labels): if label in all_labels[i + 1 :]: warnings.warn(f'Found more than one compressor for "{label}"', AsdfWarning) if compression not in all_labels: msg = f"Supported compression types are: {all_labels}, not '{compression}'" raise ValueError(msg) return compression class Lz4Compressor: def __init__(self): try: import lz4.block except ImportError as err: msg = ( "lz4 library in not installed in your Python environment, " "therefore the compressed block in this ASDF file " "can not be decompressed." ) raise ImportError(msg) from err self._api = lz4.block def compress(self, data, **kwargs): kwargs["mode"] = kwargs.get("mode", "default") compression_block_size = kwargs.pop("compression_block_size", 1 << 22) nelem = compression_block_size // data.itemsize for i in range(0, len(data), nelem): _output = self._api.compress(data[i : i + nelem], **kwargs) header = struct.pack("!I", len(_output)) yield header + _output def decompress(self, blocks, out, **kwargs): _size = 0 _pos = 0 _partial_len = b"" _buffer = None bytesout = 0 for block in blocks: cast = "c" blk = memoryview(block).cast(cast) # don't copy on slice while len(blk): if not _size: # Don't know the (compressed) length of this block yet if len(_partial_len) + len(blk) < 4: _partial_len += blk break # we've exhausted the block if _partial_len: # If we started to fill a len key, finish filling it remaining = 4 - len(_partial_len) if remaining: _partial_len += blk[:remaining] blk = blk[remaining:] _size = struct.unpack("!I", _partial_len)[0] _partial_len = b"" else: # Otherwise just read the len key directly _size = struct.unpack("!I", blk[:4])[0] blk = blk[4:] if len(blk) < _size or _buffer is not None: # If we have a partial block, or we're already filling a buffer, use the buffer if _buffer is None: _buffer = np.empty( _size, dtype=np.byte, ) # use numpy instead of bytearray so we can avoid zero initialization _pos = 0 newbytes = min(_size - _pos, len(blk)) # don't fill past the buffer len! _buffer[_pos : _pos + newbytes] = np.frombuffer(blk[:newbytes], dtype=np.byte) _pos += newbytes blk = blk[newbytes:] if _pos == _size: _out = self._api.decompress(_buffer, return_bytearray=True, **kwargs) out[bytesout : bytesout + len(_out)] = _out bytesout += len(_out) _buffer = None _size = 0 else: # We have at least one full block _out = self._api.decompress(memoryview(blk[:_size]), return_bytearray=True, **kwargs) out[bytesout : bytesout + len(_out)] = _out bytesout += len(_out) blk = blk[_size:] _size = 0 return bytesout class ZlibCompressor: def compress(self, data, **kwargs): comp = zlib.compress(data, **kwargs) yield comp def decompress(self, blocks, out, **kwargs): decompressor = zlib.decompressobj(**kwargs) i = 0 for block in blocks: decomp = decompressor.decompress(block) out[i : i + len(decomp)] = decomp i += len(decomp) return i class Bzp2Compressor: def compress(self, data, **kwargs): comp = bz2.compress(data, **kwargs) yield comp def decompress(self, blocks, out, **kwargs): decompressor = bz2.BZ2Decompressor(**kwargs) i = 0 for block in blocks: decomp = decompressor.decompress(block) out[i : i + len(decomp)] = decomp i += len(decomp) return i def _get_compressor_from_extensions(compression, return_extension=False): """ Look at the loaded ASDF extensions and return the first one (if any) that can handle this type of compression. `return_extension` can be used to return corresponding extension for bookkeeping purposes. Returns None if no match found. """ # TODO: in ASDF 3, this will be done by the ExtensionManager extensions = get_config().extensions for ext in extensions: for comp in ext.compressors: if compression == comp.label.decode("ascii"): if return_extension: return comp, ext return comp return None def _get_all_compression_extension_labels(): """ Get the list of compression labels supported via extensions """ # TODO: in ASDF 3, this will be done by the ExtensionManager labels = [] extensions = get_config().extensions for ext in extensions: for comp in ext.compressors: labels += [comp.label.decode("ascii")] return labels def _get_compressor(label): ext_comp = _get_compressor_from_extensions(label) if ext_comp is not None: # Use an extension before builtins comp = ext_comp elif label == "zlib": comp = ZlibCompressor() elif label == "bzp2": comp = Bzp2Compressor() elif label == "lz4": comp = Lz4Compressor() else: msg = f"Unknown compression type: '{label}'" raise ValueError(msg) return comp def to_compression_header(compression): """ Converts a compression string to the four byte field in a block header. """ if not compression: return b"\0\0\0\0" if isinstance(compression, str): return compression.encode("ascii") return compression def decompress(fd, used_size, data_size, compression, config=None): """ Decompress binary data in a file Parameters ---------- fd : generic_io.GenericIO object The file to read the compressed data from. used_size : int The size of the compressed data data_size : int The size of the uncompressed data compression : str The compression type used. config : dict or None, optional Any kwarg parameters to pass to the underlying decompression function Returns ------- array : numpy.array A flat uint8 containing the decompressed data. """ buffer = np.empty((data_size,), np.uint8) compression = validate(compression) decoder = _get_compressor(compression) if config is None: config = {} blocks = fd.read_blocks(used_size) # data is a generator len_decoded = decoder.decompress(blocks, out=buffer.data, **config) if len_decoded != data_size: msg = "Decompressed data wrong size" raise ValueError(msg) return buffer def compress(fd, data, compression, config=None): """ Compress array data and write to a file. Parameters ---------- fd : generic_io.GenericIO object The file to write to. data : buffer The buffer of uncompressed data. compression : str The type of compression to use. config : dict or None, optional Any kwarg parameters to pass to the underlying compression function """ compression = validate(compression) encoder = _get_compressor(compression) if config is None: config = {} # Get a contiguous, 1D memoryview of the underlying data, preserving data.itemsize # - contiguous: because we may not want to assume that all compressors can handle arbitrary strides # - 1D: so that len(data) works, not just data.nbytes # - itemsize: should preserve data.itemsize for compressors that want to use the record size # - memoryview: don't incur the expense of a memcpy, such as with tobytes() data = memoryview(data) if not data.contiguous: data = memoryview(data.tobytes()) # make a contiguous copy data = memoryview(np.frombuffer(data, dtype=data.format)) # get a 1D array that preserves byteorder if not data.contiguous: # the data will be contiguous by construction, but better safe than sorry! raise ValueError(data.contiguous) compressed = encoder.compress(data, **config) # Write block by block for comp in compressed: fd.write(comp) def get_compressed_size(data, compression, config=None): """ Returns the number of bytes required when the given data is compressed. Parameters ---------- See `compress()`. Returns ------- nbytes : int The size of the compressed data """ class _ByteCountingFile: def __init__(self): self.count = 0 def write(self, data): self.count += len(data) bcf = _ByteCountingFile() compress(bcf, data, compression, config=config) return bcf.count ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_convenience.py0000644000175100001770000000364514653725311016001 0ustar00runnerdocker""" Implementation of the asdf.info(...) function. This is just a thin wrapper around _display module code. """ import pathlib from contextlib import contextmanager from ._asdf import AsdfFile, open_asdf from ._display import DEFAULT_MAX_COLS, DEFAULT_MAX_ROWS, DEFAULT_SHOW_VALUES, render_tree __all__ = ["info"] def info(node_or_path, max_rows=DEFAULT_MAX_ROWS, max_cols=DEFAULT_MAX_COLS, show_values=DEFAULT_SHOW_VALUES): """ Print a rendering of an ASDF tree or sub-tree to stdout. Parameters ---------- node_or_path : str, pathlib.Path, asdf.asdf.AsdfFile, or any ASDF tree node The tree or sub-tree to render. Strings and Path objects will first be passed to asdf.open(...). max_rows : int, tuple, or None, optional Maximum number of lines to print. Nodes that cannot be displayed will be elided with a message. If int, constrain total number of displayed lines. If tuple, constrain lines per node at the depth corresponding \ to the tuple index. If None, display all lines. max_cols : int or None, optional Maximum length of line to print. Nodes that cannot be fully displayed will be truncated with a message. If int, constrain length of displayed lines. If None, line length is unconstrained. show_values : bool, optional Set to False to disable display of primitive values in the rendered tree. """ with _manage_node(node_or_path) as node: lines = render_tree(node, max_rows=max_rows, max_cols=max_cols, show_values=show_values, identifier="root") print("\n".join(lines)) @contextmanager def _manage_node(node_or_path): if isinstance(node_or_path, (str, pathlib.Path)): with open_asdf(node_or_path) as af: yield af.tree elif isinstance(node_or_path, AsdfFile): yield node_or_path.tree else: yield node_or_path ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.029096 asdf-3.4.0/asdf/_core/0000755000175100001770000000000014653725331014055 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_core/__init__.py0000644000175100001770000000000014653725311016152 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.029096 asdf-3.4.0/asdf/_core/_converters/0000755000175100001770000000000014653725331016406 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_core/_converters/__init__.py0000644000175100001770000000000014653725311020503 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_core/_converters/complex.py0000644000175100001770000000111714653725311020425 0ustar00runnerdockerimport re import numpy as np from asdf import util from asdf.extension import Converter _REPLACEMENTS = { re.compile("i(?!nf)"): "j", re.compile("I(?!NF)"): "J", } class ComplexConverter(Converter): tags = ["tag:stsci.edu:asdf/core/complex-1.0.0"] types = [*list(util._iter_subclasses(np.complexfloating)), complex] def to_yaml_tree(self, obj, tag, ctx): return str(obj) def from_yaml_tree(self, node, tag, ctx): for pattern, replacement in _REPLACEMENTS.items(): node = pattern.sub(replacement, node) return complex(node) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_core/_converters/constant.py0000644000175100001770000000056114653725311020611 0ustar00runnerdockerfrom asdf.extension import Converter class ConstantConverter(Converter): tags = ["tag:stsci.edu:asdf/core/constant-1.0.0"] types = ["asdf.tags.core.constant.Constant"] def to_yaml_tree(self, obj, tag, ctx): return obj.value def from_yaml_tree(self, node, tag, ctx): from asdf.tags.core import Constant return Constant(node) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_core/_converters/external_reference.py0000644000175100001770000000121414653725311022614 0ustar00runnerdockerfrom asdf.extension import Converter class ExternalArrayReferenceConverter(Converter): tags = ["tag:stsci.edu:asdf/core/externalarray-1.0.0"] types = ["asdf.tags.core.external_reference.ExternalArrayReference"] def to_yaml_tree(self, obj, tag, ctx): return { "fileuri": obj.fileuri, "target": obj.target, "datatype": obj.dtype, "shape": list(obj.shape), } def from_yaml_tree(self, node, tag, ctx): from asdf.tags.core import ExternalArrayReference return ExternalArrayReference(node["fileuri"], node["target"], node["datatype"], tuple(node["shape"])) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_core/_converters/integer.py0000644000175100001770000000210714653725311020413 0ustar00runnerdockerimport numpy as np from asdf.extension import Converter class IntegerConverter(Converter): tags = [ "tag:stsci.edu:asdf/core/integer-1.0.0", "tag:stsci.edu:asdf/core/integer-1.1.0", ] types = ["asdf.tags.core.integer.IntegerType"] def to_yaml_tree(self, obj, tag, ctx): abs_value = int(np.abs(obj._value)) # pack integer value into 32-bit words words = [] value = abs_value while value > 0: words.append(value & 0xFFFFFFFF) value >>= 32 array = np.array(words, dtype=np.uint32) tree = {} ctx.set_array_storage(array, obj._storage) tree["words"] = array tree["sign"] = obj._sign tree["string"] = str(int(obj._value)) return tree def from_yaml_tree(self, node, tag, ctx): from asdf.tags.core.integer import IntegerType value = 0 for x in node["words"][::-1]: value <<= 32 value |= int(x) if node["sign"] == "-": value = -value return IntegerType(value) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_core/_converters/ndarray.py0000644000175100001770000001650414653725311020424 0ustar00runnerdockerimport numpy as np from asdf.extension import Converter class NDArrayConverter(Converter): tags = [ "tag:stsci.edu:asdf/core/ndarray-1.0.0", "tag:stsci.edu:asdf/core/ndarray-1.1.0", ] types = [ np.ndarray, # we use the type here so the extension can find the sub-classes "numpy.ma.MaskedArray", # in numpy 2.0 "numpy.ma.core.MaskedArray", "asdf.tags.core.ndarray.NDArrayType", "asdf.tags.core.stream.Stream", ] def to_yaml_tree(self, obj, tag, ctx): import numpy as np from numpy import ma from asdf import config, util from asdf._block.options import Options from asdf.tags.core.ndarray import NDArrayType, numpy_array_to_list, numpy_dtype_to_asdf_datatype from asdf.tags.core.stream import Stream data = obj if isinstance(obj, Stream): # previously, stream never passed on data, we can do that here ctx._blocks.set_streamed_write_block(data._array, data) result = {} result["source"] = -1 result["shape"] = ["*", *data._shape] result["datatype"] = data._datatype result["byteorder"] = data._byteorder if data._strides is not None: result["strides"] = data._strides return result # sort out block writing options if isinstance(obj, NDArrayType) and isinstance(obj._source, str): # this is an external block, if we have no other settings, keep it as external options = ctx._blocks.options.lookup_by_object(data) if options is None: options = Options("external") else: options = ctx._blocks.options.get_options(data) # The ndarray-1.0.0 schema does not permit 0 valued strides. # Perhaps we'll want to allow this someday, to efficiently # represent an array of all the same value. if any(stride == 0 for stride in data.strides): data = np.ascontiguousarray(data) # Use the base array if that option is set or if the option # is unset and the AsdfConfig default is set cfg = config.get_config() if options.save_base or (options.save_base is None and cfg.default_array_save_base): base = util.get_array_base(data) else: base = data # The view computations that follow assume that the base array # is contiguous. If not, we need to make a copy to avoid # writing a nonsense view. if not base.flags.forc: data = np.ascontiguousarray(data) base = util.get_array_base(data) shape = data.shape # possibly override options based on config settings if cfg.all_array_storage is not None: options.storage_type = cfg.all_array_storage if cfg.all_array_compression != "input": options.compression = cfg.all_array_compression options.compression_kwargs = cfg.all_array_compression_kwargs inline_threshold = cfg.array_inline_threshold if inline_threshold is not None and options.storage_type in ("inline", "internal"): if data.size < inline_threshold: options.storage_type = "inline" else: options.storage_type = "internal" ctx._blocks.options.set_options(data, options) # Compute the offset relative to the base array and not the # block data, in case the block is compressed. offset = data.ctypes.data - base.ctypes.data strides = None if data.flags.c_contiguous else data.strides dtype, byteorder = numpy_dtype_to_asdf_datatype( data.dtype, include_byteorder=(options.storage_type != "inline"), ) result = {} result["shape"] = list(shape) if options.storage_type == "streamed": result["shape"][0] = "*" if options.storage_type == "inline": listdata = numpy_array_to_list(data) result["data"] = listdata result["datatype"] = dtype else: result["shape"] = list(shape) if options.storage_type == "streamed": result["shape"][0] = "*" result["source"] = -1 ctx._blocks.set_streamed_write_block(base, data) else: result["source"] = ctx._blocks.make_write_block(base, options, obj) result["datatype"] = dtype result["byteorder"] = byteorder if offset > 0: result["offset"] = offset if strides is not None: result["strides"] = list(strides) if isinstance(data, ma.MaskedArray): if options.storage_type == "inline": ctx._blocks._set_array_storage(data.mask, "inline") result["mask"] = data.mask return result def from_yaml_tree(self, node, tag, ctx): import sys import weakref from asdf.tags.core import NDArrayType from asdf.tags.core.ndarray import asdf_datatype_to_numpy_dtype if isinstance(node, list): instance = NDArrayType(node, None, None, None, None, None, None) ctx._blocks._set_array_storage(instance, "inline") return instance if isinstance(node, dict): shape = node.get("shape", None) if "source" in node and "data" in node: msg = "Both source and data may not be provided at the same time" raise ValueError(msg) if "source" in node: source = node["source"] byteorder = node["byteorder"] else: source = node["data"] byteorder = sys.byteorder dtype = asdf_datatype_to_numpy_dtype(node["datatype"], byteorder) if "datatype" in node else None offset = node.get("offset", 0) strides = node.get("strides", None) mask = node.get("mask", None) if isinstance(source, int): # internal block data_callback = ctx.get_block_data_callback(source) instance = NDArrayType(source, shape, dtype, offset, strides, "A", mask, data_callback) elif isinstance(source, str): # external def data_callback(_attr=None, _ref=weakref.ref(ctx._blocks)): if _attr not in (None, "cached_data", "data"): raise AttributeError(f"_attr {_attr} is not supported") blks = _ref() if blks is None: msg = "Failed to resolve reference to AsdfFile to read external block" raise OSError(msg) array = blks._load_external(source) blks._set_array_storage(array, "external") return array instance = NDArrayType(source, shape, dtype, offset, strides, "A", mask, data_callback) else: # inline instance = NDArrayType(source, shape, dtype, offset, strides, "A", mask) ctx._blocks._set_array_storage(instance, "inline") if not ctx._blocks._lazy_load: instance._make_array() return instance msg = "Invalid ndarray description." raise TypeError(msg) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_core/_converters/reference.py0000644000175100001770000000130714653725311020715 0ustar00runnerdockerfrom asdf.extension import Converter class ReferenceConverter(Converter): tags = [] types = ["asdf.reference.Reference"] def to_yaml_tree(self, obj, tag, ctx): from asdf.generic_io import relative_uri base_uri = None if ctx._blocks._write_fd is not None and ctx._blocks._write_fd.uri is not None: base_uri = ctx._blocks._write_fd.uri elif ctx.url is not None: base_uri = ctx.url uri = relative_uri(base_uri, obj._uri) if base_uri is not None else obj._uri return {"$ref": uri} def from_yaml_tree(self, node, tag, ctx): raise NotImplementedError() def select_tag(self, obj, tags, ctx): return None ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_core/_converters/tree.py0000644000175100001770000000361214653725311017717 0ustar00runnerdockerfrom asdf.extension import Converter class AsdfObjectConverter(Converter): # Since AsdfObject is just a dict, we're able to use the same converter # for both tag versions. tags = [ "tag:stsci.edu:asdf/core/asdf-1.0.0", "tag:stsci.edu:asdf/core/asdf-1.1.0", ] types = ["asdf.tags.core.AsdfObject"] def to_yaml_tree(self, obj, tag, ctx): return dict(obj) def from_yaml_tree(self, node, tag, ctx): from asdf.tags.core import AsdfObject return AsdfObject(node) class ExtensionMetadataConverter(Converter): tags = ["tag:stsci.edu:asdf/core/extension_metadata-1.0.0"] types = ["asdf.tags.core.ExtensionMetadata"] def to_yaml_tree(self, obj, tag, ctx): return dict(obj) def from_yaml_tree(self, node, tag, ctx): from asdf.tags.core import ExtensionMetadata return ExtensionMetadata(node) class HistoryEntryConverter(Converter): tags = ["tag:stsci.edu:asdf/core/history_entry-1.0.0"] types = ["asdf.tags.core.HistoryEntry"] def to_yaml_tree(self, obj, tag, ctx): return dict(obj) def from_yaml_tree(self, node, tag, ctx): from asdf.tags.core import HistoryEntry return HistoryEntry(node) class SoftwareConverter(Converter): tags = ["tag:stsci.edu:asdf/core/software-1.0.0"] types = ["asdf.tags.core.Software"] def to_yaml_tree(self, obj, tag, ctx): return dict(obj) def from_yaml_tree(self, node, tag, ctx): from asdf.tags.core import Software return Software(node) class SubclassMetadataConverter(Converter): tags = ["tag:stsci.edu:asdf/core/subclass_metadata-1.0.0"] types = ["asdf.tags.core.SubclassMetadata"] def to_yaml_tree(self, obj, tag, ctx): return dict(obj) def from_yaml_tree(self, node, tag, ctx): from asdf.tags.core import SubclassMetadata return SubclassMetadata(node) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_core/_extensions.py0000644000175100001770000000314214653725311016763 0ustar00runnerdockerfrom asdf.extension import ManifestExtension from ._converters.complex import ComplexConverter from ._converters.constant import ConstantConverter from ._converters.external_reference import ExternalArrayReferenceConverter from ._converters.integer import IntegerConverter from ._converters.ndarray import NDArrayConverter from ._converters.reference import ReferenceConverter from ._converters.tree import ( AsdfObjectConverter, ExtensionMetadataConverter, HistoryEntryConverter, SoftwareConverter, SubclassMetadataConverter, ) from ._validators import ndarray CONVERTERS = [ ComplexConverter(), ConstantConverter(), ExternalArrayReferenceConverter(), AsdfObjectConverter(), ExtensionMetadataConverter(), HistoryEntryConverter(), IntegerConverter(), SoftwareConverter(), SubclassMetadataConverter(), ReferenceConverter(), NDArrayConverter(), ] VALIDATORS = [ ndarray.NdimValidator(), ndarray.MaxNdimValidator(), ndarray.DatatypeValidator(), ] MANIFEST_URIS = [ "asdf://asdf-format.org/core/manifests/core-1.0.0", "asdf://asdf-format.org/core/manifests/core-1.1.0", "asdf://asdf-format.org/core/manifests/core-1.2.0", "asdf://asdf-format.org/core/manifests/core-1.3.0", "asdf://asdf-format.org/core/manifests/core-1.4.0", "asdf://asdf-format.org/core/manifests/core-1.5.0", "asdf://asdf-format.org/core/manifests/core-1.6.0", ] EXTENSIONS = [ ManifestExtension.from_uri( u, converters=CONVERTERS, validators=VALIDATORS, legacy_class_names=["asdf.extension.BuiltinExtension"] ) for u in MANIFEST_URIS ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_core/_integration.py0000644000175100001770000000067414653725311017116 0ustar00runnerdockerfrom asdf.resource import JsonschemaResourceMapping def get_extensions(): """ Get the extension instances for the core extensions. This method is registered with the asdf.extensions entry point. Returns ------- list of asdf.extension.Extension """ from . import _extensions return _extensions.EXTENSIONS def get_json_schema_resource_mappings(): return [ JsonschemaResourceMapping(), ] ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.029096 asdf-3.4.0/asdf/_core/_validators/0000755000175100001770000000000014653725331016364 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_core/_validators/__init__.py0000644000175100001770000000000014653725311020461 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_core/_validators/ndarray.py0000644000175100001770000000156414653725311020402 0ustar00runnerdockerfrom asdf.extension import Validator from asdf.tags.core.ndarray import validate_datatype, validate_max_ndim, validate_ndim class NdimValidator(Validator): schema_property = "ndim" # The validators in this module should really only be applied # to ndarray-* tags, but that will have to be a 3.0 change. tags = ["**"] def validate(self, expected_ndim, node, schema): yield from validate_ndim(None, expected_ndim, node, schema) class MaxNdimValidator(Validator): schema_property = "max_ndim" tags = ["**"] def validate(self, max_ndim, node, schema): yield from validate_max_ndim(None, max_ndim, node, schema) class DatatypeValidator(Validator): schema_property = "datatype" tags = ["**"] def validate(self, expected_datatype, node, schema): yield from validate_datatype(None, expected_datatype, node, schema) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_display.py0000644000175100001770000002164214653725311015147 0ustar00runnerdocker""" Utilities for displaying the content of an ASDF tree. Normally these tools only will introspect dicts, lists, and primitive values (with an exception for arrays). However, if the object that is generated by the converter mechanism has a __asdf_traverse__() method, then it will call that method expecting a dict or list to be returned. The method can return what it thinks is suitable for display. """ import numpy as np from ._node_info import create_tree from .tags.core.ndarray import NDArrayType __all__ = [ "DEFAULT_MAX_ROWS", "DEFAULT_MAX_COLS", "DEFAULT_SHOW_VALUES", "render_tree", "format_bold", "format_faint", "format_italic", ] DEFAULT_MAX_ROWS = 24 DEFAULT_MAX_COLS = 120 DEFAULT_SHOW_VALUES = True EXTENSION_MANAGER = None def render_tree( node, max_rows=DEFAULT_MAX_ROWS, max_cols=DEFAULT_MAX_COLS, show_values=DEFAULT_SHOW_VALUES, filters=None, identifier="root", refresh_extension_manager=False, ): """ Render a tree as text with indents showing depth. """ info = create_tree( key="title", node=node, identifier=identifier, filters=[] if filters is None else filters, refresh_extension_manager=refresh_extension_manager, ) if info is None: return [] renderer = _TreeRenderer( max_rows, max_cols, show_values, ) return renderer.render(info) def format_bold(value): """ Wrap the input value in the ANSI escape sequence for increased intensity. """ return _format_code(value, 1) def format_faint(value): """ Wrap the input value in the ANSI escape sequence for decreased intensity. """ return _format_code(value, 2) def format_italic(value): """ Wrap the input value in the ANSI escape sequence for italic. """ return _format_code(value, 3) def _format_code(value, code): return f"\x1B[{code}m{value}\x1B[0m" class _TreeRenderer: """ Render a _NodeInfo tree with indent showing depth. """ def __init__(self, max_rows, max_cols, show_values): self._max_rows = max_rows self._max_cols = max_cols self._show_values = show_values def render(self, info): self._mark_visible(info) lines, elided = self._render(info, set(), True) if elided: lines.append(format_faint(format_italic("Some nodes not shown."))) return lines def _mark_visible(self, root_info): """ Select nodes to display, respecting max_rows. Nodes at lower depths will be prioritized. """ if isinstance(self._max_rows, tuple): self._mark_visible_tuple(root_info) else: self._mark_visible_int(root_info) def _mark_visible_int(self, root_info): """ Select nodes to display, obeying max_rows as an overall limit on the number of lines returned. """ if self._max_rows is None: return if self._max_rows < 2: root_info.visible = False return current_infos = [root_info] # Reserve one row for the root node, and another for the # "Some nodes not shown." message. rows_left = self._max_rows - 2 while True: next_infos = [] for info in current_infos: if rows_left >= len(info.children): rows_left -= len(info.children) next_infos.extend(info.children) elif rows_left > 1: for child in info.children[rows_left - 1 :]: child.visible = False next_infos.extend(info.children[0 : rows_left - 1]) rows_left = 0 else: for child in info.children: child.visible = False if len(next_infos) == 0: break current_infos = next_infos def _mark_visible_tuple(self, root_info): """ Select nodes to display, obeying the per-node max_rows value for each tree depth. """ max_rows = (None, *self._max_rows) current_infos = [root_info] while True: next_infos = [] for info in current_infos: if info.depth + 1 < len(max_rows): rows_left = max_rows[info.depth + 1] if rows_left is None or rows_left >= len(info.children): next_infos.extend(info.children) elif rows_left > 1: for child in info.children[rows_left - 1 :]: child.visible = False next_infos.extend(info.children[0 : rows_left - 1]) else: for child in info.children: child.visible = False else: for child in info.children: child.visible = False if len(next_infos) == 0: break current_infos = next_infos def _render(self, info, active_depths, is_tail): """ Render the tree. Called recursively on child nodes. is_tail indicates if the child is the last of the children, needed to indicate the proper connecting character in the tree display. Likewise, active_depths is used to track which preceding depths are incomplete thus need continuing lines preceding in the tree display. """ lines = [] if info.visible is False: return lines, True lines.append(self._render_node(info, active_depths, is_tail)) elided = len(info.visible_children) < len(info.children) for i, child in enumerate(info.visible_children): if i == len(info.children) - 1: child_is_tail = True child_active_depths = active_depths else: child_is_tail = False child_active_depths = active_depths.union({info.depth}) child_list, child_elided = self._render(child, child_active_depths, child_is_tail) lines.extend(child_list) elided = elided or child_elided num_visible_children = len(info.visible_children) if num_visible_children > 0 and num_visible_children != len(info.children): hidden_count = len(info.children) - num_visible_children prefix = self._make_prefix(info.depth + 1, active_depths, True) message = format_faint(format_italic(str(hidden_count) + " not shown")) lines.append(f"{prefix}{message}") return lines, elided def _render_node(self, info, active_depths, is_tail): prefix = self._make_prefix(info.depth, active_depths, is_tail) value = self._render_node_value(info) line = ( f"{prefix}[{format_bold(info.identifier)}] {value}" if isinstance(info.parent_node, (list, tuple)) else f"{prefix}{format_bold(info.identifier)} {value}" ) if info.info is not None: line = line + format_faint(format_italic(" # " + info.info)) visible_children = info.visible_children if len(visible_children) == 0 and len(info.children) > 0: line = line + format_italic(" ...") if info.recursive: line = line + " " + format_faint(format_italic("(recursive reference)")) if self._max_cols is not None and len(line) > self._max_cols: message = " (truncated)" line = line[0 : (self._max_cols - len(message))] + format_faint(format_italic(message)) return line def _render_node_value(self, info): rendered_type = type(info.node).__name__ if isinstance(info.node, (NDArrayType, np.ndarray)): return f"({rendered_type}): shape={info.node.shape}, dtype={info.node.dtype.name}" if not info.children and self._show_values: try: s = f"{info.node}" except Exception: # if __str__ fails, don't fail info, instead use an empty string s = "" # if __str__ returns multiple lines also use an empty string if len(s.splitlines()) > 1: s = "" # if s is empty use the non-_show_values format below if s: return f"({rendered_type}): {s}" return f"({rendered_type})" def _make_prefix(self, depth, active_depths, is_tail): """ Create a prefix for a displayed node, accounting for depth and including lines that show connections to other nodes. """ prefix = "" if depth < 1: return prefix if depth >= 2: for n in range(0, depth - 1): prefix = prefix + "│ " if n in active_depths else prefix + " " prefix = prefix + "└─" if is_tail else prefix + "├─" return format_faint(prefix) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_entry_points.py0000644000175100001770000000523214653725311016234 0ustar00runnerdockerimport sys import warnings from .exceptions import AsdfWarning from .extension import ExtensionProxy from .resource import ResourceMappingProxy # The standard library importlib.metadata returns duplicate entrypoints # for all python versions up to and including 3.11 # https://github.com/python/importlib_metadata/issues/410#issuecomment-1304258228 # see PR https://github.com/asdf-format/asdf/pull/1260 # see issue https://github.com/asdf-format/asdf/issues/1254 if sys.version_info >= (3, 12): from importlib.metadata import entry_points else: from importlib_metadata import entry_points RESOURCE_MAPPINGS_GROUP = "asdf.resource_mappings" EXTENSIONS_GROUP = "asdf.extensions" def get_resource_mappings(): return _list_entry_points(RESOURCE_MAPPINGS_GROUP, ResourceMappingProxy) def get_extensions(): extensions = _list_entry_points(EXTENSIONS_GROUP, ExtensionProxy) return extensions def _list_entry_points(group, proxy_class): results = [] points = entry_points(group=group) # The order of plugins may be significant, since in the case of # duplicate functionality the first plugin in the list takes # precedence. It's not clear if entry points are ordered # in a consistent way across systems so we explicitly sort # by package name. Plugins from this package are placed # at the end so that other packages can override them. asdf_entry_points = [e for e in points if e.dist.name == "asdf"] other_entry_points = sorted((e for e in points if e.dist.name != "asdf"), key=lambda e: e.dist.name) for entry_point in other_entry_points + asdf_entry_points: package_name = entry_point.dist.name package_version = entry_point.dist.version def _handle_error(e): warnings.warn( f"{group} plugin from package {package_name}=={package_version} failed to load:\n\n" f"{e.__class__.__name__}: {e}", AsdfWarning, ) # Catch errors loading entry points and warn instead of raising try: with warnings.catch_warnings(): elements = entry_point.load()() except Exception as e: _handle_error(e) continue # Process the elements returned by the entry point if not isinstance(elements, list): elements = [elements] for element in elements: # Catch errors instantiating the proxy class and warn instead of raising try: results.append(proxy_class(element, package_name=package_name, package_version=package_version)) except Exception as e: _handle_error(e) return results ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.029096 asdf-3.4.0/asdf/_extern/0000755000175100001770000000000014653725331014432 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_extern/__init__.py0000644000175100001770000000001014653725311016530 0ustar00runnerdocker""" """ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_extern/atomicfile.py0000644000175100001770000001011214653725311017111 0ustar00runnerdockerimport os import tempfile import sys import errno if os.name == 'nt': # pragma: no cover import random import time _rename = lambda src, dst: False _rename_atomic = lambda src, dst: False import ctypes _MOVEFILE_REPLACE_EXISTING = 0x1 _MOVEFILE_WRITE_THROUGH = 0x8 _MoveFileEx = ctypes.windll.kernel32.MoveFileExW def _rename(src, dst): if not isinstance(src, str): src = str(src, sys.getfilesystemencoding()) if not isinstance(dst, str): dst = str(dst, sys.getfilesystemencoding()) if _rename_atomic(src, dst): return True retry = 0 rv = False while not rv and retry < 100: rv = _MoveFileEx(src, dst, _MOVEFILE_REPLACE_EXISTING | _MOVEFILE_WRITE_THROUGH) if not rv: time.sleep(0.001) retry += 1 return rv # new in Vista and Windows Server 2008 _CreateTransaction = ctypes.windll.ktmw32.CreateTransaction _CommitTransaction = ctypes.windll.ktmw32.CommitTransaction _MoveFileTransacted = ctypes.windll.kernel32.MoveFileTransactedW _CloseHandle = ctypes.windll.kernel32.CloseHandle def _rename_atomic(src, dst): ta = _CreateTransaction(None, 0, 0, 0, 0, 1000, 'Atomic rename') if ta == -1: return False try: retry = 0 rv = False while not rv and retry < 100: rv = _MoveFileTransacted(src, dst, None, None, _MOVEFILE_REPLACE_EXISTING | _MOVEFILE_WRITE_THROUGH, ta) if rv: rv = _CommitTransaction(ta) break else: time.sleep(0.001) retry += 1 return rv finally: _CloseHandle(ta) def atomic_rename(src, dst): # Try atomic or pseudo-atomic rename if _rename(src, dst): return # Fall back to "move away and replace" try: os.rename(src, dst) except OSError as e: if e.errno != errno.EEXIST: raise old = "%s-%08x" % (dst, random.randint(0, sys.maxsize)) os.rename(dst, old) os.rename(src, dst) try: os.unlink(old) except Exception: pass else: atomic_rename = os.rename class _AtomicWFile(object): """Helper class for :func:`atomic_open`.""" def __init__(self, f, tmp_filename, filename): self._f = f self._tmp_filename = tmp_filename self._filename = filename def __getattr__(self, attr): return getattr(self._f, attr) def __enter__(self): return self @property def name(self): return self._filename def close(self): if self._f.closed: return self._f.close() atomic_rename(self._tmp_filename, self._filename) def __exit__(self, exc_type, exc_value, tb): if exc_type is None: self.close() else: self._f.close() try: os.remove(self._tmp_filename) except OSError: pass def __repr__(self): return '<%s %s%r, mode %r>' % ( self.__class__.__name__, self._f.closed and 'closed ' or '', self._filename, self._f.mode ) def atomic_open(filename, mode='w'): """Works like a regular `open()` but writes updates into a temporary file instead of the given file and moves it over when the file is closed. The file returned behaves as if it was a regular Python """ if mode in ('r', 'rb', 'r+', 'rb+', 'a', 'ab'): raise TypeError('Read or append modes don\'t work with atomic_open') f = tempfile.NamedTemporaryFile(mode, prefix='.___atomic_write', dir=os.path.dirname(filename), delete=False) return _AtomicWFile(f, f.name, filename) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_helpers.py0000644000175100001770000000103614653725311015137 0ustar00runnerdockerfrom . import versioning from ._version import version as asdf_package_version def validate_version(version): # Account for the possibility of AsdfVersion version = str(version) if version not in versioning.supported_versions: msg = "ASDF Standard version {} is not supported by asdf=={}. Available ASDF Standard versions: {}".format( version, asdf_package_version, ", ".join(str(v) for v in versioning.supported_versions), ) raise ValueError(msg) return version ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.033096 asdf-3.4.0/asdf/_jsonschema/0000755000175100001770000000000014653725331015257 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/COPYING0000644000175100001770000000204114653725311016305 0ustar00runnerdockerCopyright (c) 2013 Julian Berman Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/README.md0000644000175100001770000000026314653725311016535 0ustar00runnerdockerThe files in this directory were originally cloned from jsonschema 4.17.3 https://github.com/python-jsonschema/jsonschema/releases/tag/v4.17.3 See COPYING for use restrictions ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/__init__.py0000644000175100001770000000327514653725311017375 0ustar00runnerdocker""" An implementation of JSON Schema for Python The main functionality is provided by the validator classes for each of the supported JSON Schema versions. Most commonly, `asdf._jsonschema.validators.validate` is the quickest way to simply validate a given instance under a schema, and will create a validator for you. """ import warnings from asdf._jsonschema._format import FormatChecker from asdf._jsonschema._types import TypeChecker from asdf._jsonschema.exceptions import ( ErrorTree, FormatError, RefResolutionError, SchemaError, ValidationError, ) from asdf._jsonschema.protocols import Validator from asdf._jsonschema.validators import ( Draft3Validator, Draft4Validator, Draft6Validator, Draft7Validator, Draft201909Validator, Draft202012Validator, RefResolver, validate, ) def __getattr__(name): format_checkers = { "draft3_format_checker": Draft3Validator, "draft4_format_checker": Draft4Validator, "draft6_format_checker": Draft6Validator, "draft7_format_checker": Draft7Validator, "draft201909_format_checker": Draft201909Validator, "draft202012_format_checker": Draft202012Validator, } ValidatorForFormat = format_checkers.get(name) if ValidatorForFormat is not None: warnings.warn( f"Accessing asdf._jsonschema.{name} is deprecated and will be " "removed in a future release. Instead, use the FORMAT_CHECKER " "attribute on the corresponding Validator.", DeprecationWarning, stacklevel=2, ) return ValidatorForFormat.FORMAT_CHECKER raise AttributeError(f"module {__name__} has no attribute {name}") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/_format.py0000644000175100001770000003437314653725311017270 0ustar00runnerdockerfrom __future__ import annotations from contextlib import suppress from uuid import UUID import datetime import ipaddress import re import typing import warnings from asdf._jsonschema.exceptions import FormatError _FormatCheckCallable = typing.Callable[[object], bool] _F = typing.TypeVar("_F", bound=_FormatCheckCallable) _RaisesType = typing.Union[ typing.Type[Exception], typing.Tuple[typing.Type[Exception], ...], ] class FormatChecker: """ A ``format`` property checker. JSON Schema does not mandate that the ``format`` property actually do any validation. If validation is desired however, instances of this class can be hooked into validators to enable format validation. `FormatChecker` objects always return ``True`` when asked about formats that they do not know how to validate. To add a check for a custom format use the `FormatChecker.checks` decorator. Arguments: formats: The known formats to validate. This argument can be used to limit which formats will be used during validation. """ checkers: dict[ str, tuple[_FormatCheckCallable, _RaisesType], ] = {} def __init__(self, formats: typing.Iterable[str] | None = None): if formats is None: formats = self.checkers.keys() self.checkers = {k: self.checkers[k] for k in formats} def __repr__(self): return "".format(sorted(self.checkers)) def checks( self, format: str, raises: _RaisesType = (), ) -> typing.Callable[[_F], _F]: """ Register a decorated function as validating a new format. Arguments: format: The format that the decorated function will check. raises: The exception(s) raised by the decorated function when an invalid instance is found. The exception object will be accessible as the `asdf._jsonschema.exceptions.ValidationError.cause` attribute of the resulting validation error. """ def _checks(func: _F) -> _F: self.checkers[format] = (func, raises) return func return _checks @classmethod def cls_checks( cls, format: str, raises: _RaisesType = (), ) -> typing.Callable[[_F], _F]: warnings.warn( ( "FormatChecker.cls_checks is deprecated. Call " "FormatChecker.checks on a specific FormatChecker instance " "instead." ), DeprecationWarning, stacklevel=2, ) return cls._cls_checks(format=format, raises=raises) @classmethod def _cls_checks( cls, format: str, raises: _RaisesType = (), ) -> typing.Callable[[_F], _F]: def _checks(func: _F) -> _F: cls.checkers[format] = (func, raises) return func return _checks def check(self, instance: object, format: str) -> None: """ Check whether the instance conforms to the given format. Arguments: instance (*any primitive type*, i.e. str, number, bool): The instance to check format: The format that instance should conform to Raises: FormatError: if the instance does not conform to ``format`` """ if format not in self.checkers: return func, raises = self.checkers[format] result, cause = None, None try: result = func(instance) except raises as e: cause = e if not result: raise FormatError(f"{instance!r} is not a {format!r}", cause=cause) def conforms(self, instance: object, format: str) -> bool: """ Check whether the instance conforms to the given format. Arguments: instance (*any primitive type*, i.e. str, number, bool): The instance to check format: The format that instance should conform to Returns: bool: whether it conformed """ try: self.check(instance, format) except FormatError: return False else: return True draft3_format_checker = FormatChecker() draft4_format_checker = FormatChecker() draft6_format_checker = FormatChecker() draft7_format_checker = FormatChecker() draft201909_format_checker = FormatChecker() draft202012_format_checker = FormatChecker() _draft_checkers: dict[str, FormatChecker] = dict( draft3=draft3_format_checker, draft4=draft4_format_checker, draft6=draft6_format_checker, draft7=draft7_format_checker, draft201909=draft201909_format_checker, draft202012=draft202012_format_checker, ) def _checks_drafts( name=None, draft3=None, draft4=None, draft6=None, draft7=None, draft201909=None, draft202012=None, raises=(), ) -> typing.Callable[[_F], _F]: draft3 = draft3 or name draft4 = draft4 or name draft6 = draft6 or name draft7 = draft7 or name draft201909 = draft201909 or name draft202012 = draft202012 or name def wrap(func: _F) -> _F: if draft3: func = _draft_checkers["draft3"].checks(draft3, raises)(func) if draft4: func = _draft_checkers["draft4"].checks(draft4, raises)(func) if draft6: func = _draft_checkers["draft6"].checks(draft6, raises)(func) if draft7: func = _draft_checkers["draft7"].checks(draft7, raises)(func) if draft201909: func = _draft_checkers["draft201909"].checks(draft201909, raises)( func, ) if draft202012: func = _draft_checkers["draft202012"].checks(draft202012, raises)( func, ) # Oy. This is bad global state, but relied upon for now, until # deprecation. See #519 and test_format_checkers_come_with_defaults FormatChecker._cls_checks( draft202012 or draft201909 or draft7 or draft6 or draft4 or draft3, raises, )(func) return func return wrap @_checks_drafts(name="idn-email") @_checks_drafts(name="email") def is_email(instance: object) -> bool: if not isinstance(instance, str): return True return "@" in instance @_checks_drafts( draft3="ip-address", draft4="ipv4", draft6="ipv4", draft7="ipv4", draft201909="ipv4", draft202012="ipv4", raises=ipaddress.AddressValueError, ) def is_ipv4(instance: object) -> bool: if not isinstance(instance, str): return True return bool(ipaddress.IPv4Address(instance)) @_checks_drafts(name="ipv6", raises=ipaddress.AddressValueError) def is_ipv6(instance: object) -> bool: if not isinstance(instance, str): return True address = ipaddress.IPv6Address(instance) return not getattr(address, "scope_id", "") with suppress(ImportError): from fqdn import FQDN @_checks_drafts( draft3="host-name", draft4="hostname", draft6="hostname", draft7="hostname", draft201909="hostname", draft202012="hostname", ) def is_host_name(instance: object) -> bool: if not isinstance(instance, str): return True return FQDN(instance).is_valid with suppress(ImportError): # The built-in `idna` codec only implements RFC 3890, so we go elsewhere. import idna @_checks_drafts( draft7="idn-hostname", draft201909="idn-hostname", draft202012="idn-hostname", raises=(idna.IDNAError, UnicodeError), ) def is_idn_host_name(instance: object) -> bool: if not isinstance(instance, str): return True idna.encode(instance) return True try: import rfc3987 except ImportError: with suppress(ImportError): from rfc3986_validator import validate_rfc3986 @_checks_drafts(name="uri") def is_uri(instance: object) -> bool: if not isinstance(instance, str): return True return validate_rfc3986(instance, rule="URI") @_checks_drafts( draft6="uri-reference", draft7="uri-reference", draft201909="uri-reference", draft202012="uri-reference", raises=ValueError, ) def is_uri_reference(instance: object) -> bool: if not isinstance(instance, str): return True return validate_rfc3986(instance, rule="URI_reference") else: @_checks_drafts( draft7="iri", draft201909="iri", draft202012="iri", raises=ValueError, ) def is_iri(instance: object) -> bool: if not isinstance(instance, str): return True return rfc3987.parse(instance, rule="IRI") @_checks_drafts( draft7="iri-reference", draft201909="iri-reference", draft202012="iri-reference", raises=ValueError, ) def is_iri_reference(instance: object) -> bool: if not isinstance(instance, str): return True return rfc3987.parse(instance, rule="IRI_reference") @_checks_drafts(name="uri", raises=ValueError) def is_uri(instance: object) -> bool: if not isinstance(instance, str): return True return rfc3987.parse(instance, rule="URI") @_checks_drafts( draft6="uri-reference", draft7="uri-reference", draft201909="uri-reference", draft202012="uri-reference", raises=ValueError, ) def is_uri_reference(instance: object) -> bool: if not isinstance(instance, str): return True return rfc3987.parse(instance, rule="URI_reference") with suppress(ImportError): from rfc3339_validator import validate_rfc3339 @_checks_drafts(name="date-time") def is_datetime(instance: object) -> bool: if not isinstance(instance, str): return True return validate_rfc3339(instance.upper()) @_checks_drafts( draft7="time", draft201909="time", draft202012="time", ) def is_time(instance: object) -> bool: if not isinstance(instance, str): return True return is_datetime("1970-01-01T" + instance) @_checks_drafts(name="regex", raises=re.error) def is_regex(instance: object) -> bool: if not isinstance(instance, str): return True return bool(re.compile(instance)) @_checks_drafts( draft3="date", draft7="date", draft201909="date", draft202012="date", raises=ValueError, ) def is_date(instance: object) -> bool: if not isinstance(instance, str): return True return bool(instance.isascii() and datetime.date.fromisoformat(instance)) @_checks_drafts(draft3="time", raises=ValueError) def is_draft3_time(instance: object) -> bool: if not isinstance(instance, str): return True return bool(datetime.datetime.strptime(instance, "%H:%M:%S")) with suppress(ImportError): from webcolors import CSS21_NAMES_TO_HEX import webcolors def is_css_color_code(instance: object) -> bool: return webcolors.normalize_hex(instance) @_checks_drafts(draft3="color", raises=(ValueError, TypeError)) def is_css21_color(instance: object) -> bool: if ( not isinstance(instance, str) or instance.lower() in CSS21_NAMES_TO_HEX ): return True return is_css_color_code(instance) with suppress(ImportError): import jsonpointer @_checks_drafts( draft6="json-pointer", draft7="json-pointer", draft201909="json-pointer", draft202012="json-pointer", raises=jsonpointer.JsonPointerException, ) def is_json_pointer(instance: object) -> bool: if not isinstance(instance, str): return True return bool(jsonpointer.JsonPointer(instance)) # TODO: I don't want to maintain this, so it # needs to go either into jsonpointer (pending # https://github.com/stefankoegl/python-json-pointer/issues/34) or # into a new external library. @_checks_drafts( draft7="relative-json-pointer", draft201909="relative-json-pointer", draft202012="relative-json-pointer", raises=jsonpointer.JsonPointerException, ) def is_relative_json_pointer(instance: object) -> bool: # Definition taken from: # https://tools.ietf.org/html/draft-handrews-relative-json-pointer-01#section-3 if not isinstance(instance, str): return True if not instance: return False non_negative_integer, rest = [], "" for i, character in enumerate(instance): if character.isdigit(): # digits with a leading "0" are not allowed if i > 0 and int(instance[i - 1]) == 0: return False non_negative_integer.append(character) continue if not non_negative_integer: return False rest = instance[i:] break return (rest == "#") or bool(jsonpointer.JsonPointer(rest)) with suppress(ImportError): import uri_template @_checks_drafts( draft6="uri-template", draft7="uri-template", draft201909="uri-template", draft202012="uri-template", ) def is_uri_template(instance: object) -> bool: if not isinstance(instance, str): return True return uri_template.validate(instance) with suppress(ImportError): import isoduration @_checks_drafts( draft201909="duration", draft202012="duration", raises=isoduration.DurationParsingException, ) def is_duration(instance: object) -> bool: if not isinstance(instance, str): return True isoduration.parse_duration(instance) # FIXME: See bolsote/isoduration#25 and bolsote/isoduration#21 return instance.endswith(tuple("DMYWHMS")) @_checks_drafts( draft201909="uuid", draft202012="uuid", raises=ValueError, ) def is_uuid(instance: object) -> bool: if not isinstance(instance, str): return True UUID(instance) return all(instance[position] == "-" for position in (8, 13, 18, 23)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/_legacy_validators.py0000644000175100001770000002450114653725311021464 0ustar00runnerdockerfrom asdf._jsonschema import _utils from asdf._jsonschema.exceptions import ValidationError def id_of_ignore_ref(property="$id"): def id_of(schema): """ Ignore an ``$id`` sibling of ``$ref`` if it is present. Otherwise, return the ID of the given schema. """ if schema is True or schema is False or "$ref" in schema: return "" return schema.get(property, "") return id_of def ignore_ref_siblings(schema): """ Ignore siblings of ``$ref`` if it is present. Otherwise, return all keywords. Suitable for use with `create`'s ``applicable_validators`` argument. """ ref = schema.get("$ref") if ref is not None: return [("$ref", ref)] else: return schema.items() def dependencies_draft3(validator, dependencies, instance, schema): if not validator.is_type(instance, "object"): return for property, dependency in dependencies.items(): if property not in instance: continue if validator.is_type(dependency, "object"): yield from validator.descend( instance, dependency, schema_path=property, ) elif validator.is_type(dependency, "string"): if dependency not in instance: message = f"{dependency!r} is a dependency of {property!r}" yield ValidationError(message) else: for each in dependency: if each not in instance: message = f"{each!r} is a dependency of {property!r}" yield ValidationError(message) def dependencies_draft4_draft6_draft7( validator, dependencies, instance, schema, ): """ Support for the ``dependencies`` keyword from pre-draft 2019-09. In later drafts, the keyword was split into separate ``dependentRequired`` and ``dependentSchemas`` validators. """ if not validator.is_type(instance, "object"): return for property, dependency in dependencies.items(): if property not in instance: continue if validator.is_type(dependency, "array"): for each in dependency: if each not in instance: message = f"{each!r} is a dependency of {property!r}" yield ValidationError(message) else: yield from validator.descend( instance, dependency, schema_path=property, ) def disallow_draft3(validator, disallow, instance, schema): for disallowed in _utils.ensure_list(disallow): if validator.evolve(schema={"type": [disallowed]}).is_valid(instance): message = f"{disallowed!r} is disallowed for {instance!r}" yield ValidationError(message) def extends_draft3(validator, extends, instance, schema): if validator.is_type(extends, "object"): yield from validator.descend(instance, extends) return for index, subschema in enumerate(extends): yield from validator.descend(instance, subschema, schema_path=index) def items_draft3_draft4(validator, items, instance, schema): if not validator.is_type(instance, "array"): return if validator.is_type(items, "object"): for index, item in enumerate(instance): yield from validator.descend(item, items, path=index) else: for (index, item), subschema in zip(enumerate(instance), items): yield from validator.descend( item, subschema, path=index, schema_path=index, ) def items_draft6_draft7_draft201909(validator, items, instance, schema): if not validator.is_type(instance, "array"): return if validator.is_type(items, "array"): for (index, item), subschema in zip(enumerate(instance), items): yield from validator.descend( item, subschema, path=index, schema_path=index, ) else: for index, item in enumerate(instance): yield from validator.descend(item, items, path=index) def minimum_draft3_draft4(validator, minimum, instance, schema): if not validator.is_type(instance, "number"): return if schema.get("exclusiveMinimum", False): failed = instance <= minimum cmp = "less than or equal to" else: failed = instance < minimum cmp = "less than" if failed: message = f"{instance!r} is {cmp} the minimum of {minimum!r}" yield ValidationError(message) def maximum_draft3_draft4(validator, maximum, instance, schema): if not validator.is_type(instance, "number"): return if schema.get("exclusiveMaximum", False): failed = instance >= maximum cmp = "greater than or equal to" else: failed = instance > maximum cmp = "greater than" if failed: message = f"{instance!r} is {cmp} the maximum of {maximum!r}" yield ValidationError(message) def properties_draft3(validator, properties, instance, schema): if not validator.is_type(instance, "object"): return for property, subschema in properties.items(): if property in instance: yield from validator.descend( instance[property], subschema, path=property, schema_path=property, ) elif subschema.get("required", False): error = ValidationError(f"{property!r} is a required property") error._set( validator="required", validator_value=subschema["required"], instance=instance, schema=schema, ) error.path.appendleft(property) error.schema_path.extend([property, "required"]) yield error def type_draft3(validator, types, instance, schema): types = _utils.ensure_list(types) all_errors = [] for index, type in enumerate(types): if validator.is_type(type, "object"): errors = list(validator.descend(instance, type, schema_path=index)) if not errors: return all_errors.extend(errors) else: if validator.is_type(instance, type): return else: reprs = [] for type in types: try: reprs.append(repr(type["name"])) except Exception: reprs.append(repr(type)) yield ValidationError( f"{instance!r} is not of type {', '.join(reprs)}", context=all_errors, ) def contains_draft6_draft7(validator, contains, instance, schema): if not validator.is_type(instance, "array"): return if not any( validator.evolve(schema=contains).is_valid(element) for element in instance ): yield ValidationError( f"None of {instance!r} are valid under the given schema", ) def recursiveRef(validator, recursiveRef, instance, schema): lookup_url, target = validator.resolver.resolution_scope, validator.schema for each in reversed(validator.resolver._scopes_stack[1:]): lookup_url, next_target = validator.resolver.resolve(each) if next_target.get("$recursiveAnchor"): target = next_target else: break fragment = recursiveRef.lstrip("#") subschema = validator.resolver.resolve_fragment(target, fragment) # FIXME: This is gutted (and not calling .descend) because it can trigger # recursion errors, so there's a bug here. Re-enable the tests to # see it. subschema return [] def find_evaluated_item_indexes_by_schema(validator, instance, schema): """ Get all indexes of items that get evaluated under the current schema Covers all keywords related to unevaluatedItems: items, prefixItems, if, then, else, contains, unevaluatedItems, allOf, oneOf, anyOf """ if validator.is_type(schema, "boolean"): return [] evaluated_indexes = [] if "additionalItems" in schema: return list(range(0, len(instance))) if "$ref" in schema: scope, resolved = validator.resolver.resolve(schema["$ref"]) validator.resolver.push_scope(scope) try: evaluated_indexes += find_evaluated_item_indexes_by_schema( validator, instance, resolved, ) finally: validator.resolver.pop_scope() if "items" in schema: if validator.is_type(schema["items"], "object"): return list(range(0, len(instance))) evaluated_indexes += list(range(0, len(schema["items"]))) if "if" in schema: if validator.evolve(schema=schema["if"]).is_valid(instance): evaluated_indexes += find_evaluated_item_indexes_by_schema( validator, instance, schema["if"], ) if "then" in schema: evaluated_indexes += find_evaluated_item_indexes_by_schema( validator, instance, schema["then"], ) else: if "else" in schema: evaluated_indexes += find_evaluated_item_indexes_by_schema( validator, instance, schema["else"], ) for keyword in ["contains", "unevaluatedItems"]: if keyword in schema: for k, v in enumerate(instance): if validator.evolve(schema=schema[keyword]).is_valid(v): evaluated_indexes.append(k) for keyword in ["allOf", "oneOf", "anyOf"]: if keyword in schema: for subschema in schema[keyword]: errs = list(validator.descend(instance, subschema)) if not errs: evaluated_indexes += find_evaluated_item_indexes_by_schema( validator, instance, subschema, ) return evaluated_indexes def unevaluatedItems_draft2019(validator, unevaluatedItems, instance, schema): if not validator.is_type(instance, "array"): return evaluated_item_indexes = find_evaluated_item_indexes_by_schema( validator, instance, schema, ) unevaluated_items = [ item for index, item in enumerate(instance) if index not in evaluated_item_indexes ] if unevaluated_items: error = "Unevaluated items are not allowed (%s %s unexpected)" yield ValidationError(error % _utils.extras_msg(unevaluated_items)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/_types.py0000644000175100001770000001135614653725311017140 0ustar00runnerdockerfrom __future__ import annotations import numbers import typing import attr from asdf._jsonschema.exceptions import UndefinedTypeCheck def _as_dict(init): init = init or {} return dict(init) def is_array(checker, instance): return isinstance(instance, list) def is_bool(checker, instance): return isinstance(instance, bool) def is_integer(checker, instance): # bool inherits from int, so ensure bools aren't reported as ints if isinstance(instance, bool): return False return isinstance(instance, int) def is_null(checker, instance): return instance is None def is_number(checker, instance): # bool inherits from int, so ensure bools aren't reported as ints if isinstance(instance, bool): return False return isinstance(instance, numbers.Number) def is_object(checker, instance): return isinstance(instance, dict) def is_string(checker, instance): return isinstance(instance, str) def is_any(checker, instance): return True @attr.s(frozen=True, repr=False) class TypeChecker: """ A :kw:`type` property checker. A `TypeChecker` performs type checking for a `Validator`, converting between the defined JSON Schema types and some associated Python types or objects. Modifying the behavior just mentioned by redefining which Python objects are considered to be of which JSON Schema types can be done using `TypeChecker.redefine` or `TypeChecker.redefine_many`, and types can be removed via `TypeChecker.remove`. Each of these return a new `TypeChecker`. Arguments: type_checkers: The initial mapping of types to their checking functions. """ _type_checkers = attr.ib(default={}, converter=_as_dict) def __repr__(self): types = ", ".join(repr(k) for k in sorted(self._type_checkers)) return f"<{self.__class__.__name__} types={{{types}}}>" def is_type(self, instance, type: str) -> bool: """ Check if the instance is of the appropriate type. Arguments: instance: The instance to check type: The name of the type that is expected. Raises: `asdf._jsonschema.exceptions.UndefinedTypeCheck`: if ``type`` is unknown to this object. """ try: fn = self._type_checkers[type] except KeyError: raise UndefinedTypeCheck(type) from None return fn(self, instance) def redefine(self, type: str, fn) -> "TypeChecker": """ Produce a new checker with the given type redefined. Arguments: type: The name of the type to check. fn (collections.abc.Callable): A callable taking exactly two parameters - the type checker calling the function and the instance to check. The function should return true if instance is of this type and false otherwise. """ return self.redefine_many({type: fn}) def redefine_many(self, definitions=()) -> "TypeChecker": """ Produce a new checker with the given types redefined. Arguments: definitions (dict): A dictionary mapping types to their checking functions. """ type_checkers = self._type_checkers.copy() type_checkers.update(definitions) return attr.evolve(self, type_checkers=type_checkers) def remove(self, *types) -> "TypeChecker": """ Produce a new checker with the given types forgotten. Arguments: types: the names of the types to remove. Raises: `asdf._jsonschema.exceptions.UndefinedTypeCheck`: if any given type is unknown to this object """ type_checkers = self._type_checkers.copy() for each in types: try: del type_checkers[each] except KeyError: raise UndefinedTypeCheck(each) return attr.evolve(self, type_checkers=type_checkers) draft3_type_checker = TypeChecker( { "any": is_any, "array": is_array, "boolean": is_bool, "integer": is_integer, "object": is_object, "null": is_null, "number": is_number, "string": is_string, }, ) draft4_type_checker = draft3_type_checker.remove("any") draft6_type_checker = draft4_type_checker.redefine( "integer", lambda checker, instance: ( is_integer(checker, instance) or isinstance(instance, float) and instance.is_integer() ), ) draft7_type_checker = draft6_type_checker draft201909_type_checker = draft7_type_checker draft202012_type_checker = draft201909_type_checker ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/_utils.py0000644000175100001770000002427514653725311017140 0ustar00runnerdockerfrom collections.abc import Mapping, MutableMapping, Sequence from urllib.parse import urlsplit import itertools import json import re import sys # The files() API was added in Python 3.9. if sys.version_info >= (3, 9): # pragma: no cover from importlib import resources else: # pragma: no cover import importlib_resources as resources # type: ignore class URIDict(MutableMapping): """ Dictionary which uses normalized URIs as keys. """ def normalize(self, uri): return urlsplit(uri).geturl() def __init__(self, *args, **kwargs): self.store = dict() self.store.update(*args, **kwargs) def __getitem__(self, uri): return self.store[self.normalize(uri)] def __setitem__(self, uri, value): self.store[self.normalize(uri)] = value def __delitem__(self, uri): del self.store[self.normalize(uri)] def __iter__(self): return iter(self.store) def __len__(self): return len(self.store) def __repr__(self): return repr(self.store) class Unset: """ An as-of-yet unset attribute or unprovided default parameter. """ def __repr__(self): return "" def load_schema(name): """ Load a schema from ./schemas/``name``.json and return it. """ path = resources.files(__package__).joinpath(f"schemas/{name}.json") data = path.read_text(encoding="utf-8") return json.loads(data) def format_as_index(container, indices): """ Construct a single string containing indexing operations for the indices. For example for a container ``bar``, [1, 2, "foo"] -> bar[1][2]["foo"] Arguments: container (str): A word to use for the thing being indexed indices (sequence): The indices to format. """ if not indices: return container return f"{container}[{']['.join(repr(index) for index in indices)}]" def find_additional_properties(instance, schema): """ Return the set of additional properties for the given ``instance``. Weeds out properties that should have been validated by ``properties`` and / or ``patternProperties``. Assumes ``instance`` is dict-like already. """ properties = schema.get("properties", {}) patterns = "|".join(schema.get("patternProperties", {})) for property in instance: if property not in properties: if patterns and re.search(patterns, property): continue yield property def extras_msg(extras): """ Create an error message for extra items or properties. """ if len(extras) == 1: verb = "was" else: verb = "were" return ", ".join(repr(extra) for extra in sorted(extras)), verb def ensure_list(thing): """ Wrap ``thing`` in a list if it's a single str. Otherwise, return it unchanged. """ if isinstance(thing, str): return [thing] return thing def _mapping_equal(one, two): """ Check if two mappings are equal using the semantics of `equal`. """ if len(one) != len(two): return False return all( key in two and equal(value, two[key]) for key, value in one.items() ) def _sequence_equal(one, two): """ Check if two sequences are equal using the semantics of `equal`. """ if len(one) != len(two): return False return all(equal(i, j) for i, j in zip(one, two)) def equal(one, two): """ Check if two things are equal evading some Python type hierarchy semantics. Specifically in JSON Schema, evade `bool` inheriting from `int`, recursing into sequences to do the same. """ if isinstance(one, str) or isinstance(two, str): return one == two if isinstance(one, Sequence) and isinstance(two, Sequence): return _sequence_equal(one, two) if isinstance(one, Mapping) and isinstance(two, Mapping): return _mapping_equal(one, two) return unbool(one) == unbool(two) def unbool(element, true=object(), false=object()): """ A hack to make True and 1 and False and 0 unique for ``uniq``. """ if element is True: return true elif element is False: return false return element def uniq(container): """ Check if all of a container's elements are unique. Tries to rely on the container being recursively sortable, or otherwise falls back on (slow) brute force. """ try: sort = sorted(unbool(i) for i in container) sliced = itertools.islice(sort, 1, None) for i, j in zip(sort, sliced): if equal(i, j): return False except (NotImplementedError, TypeError): seen = [] for e in container: e = unbool(e) for i in seen: if equal(i, e): return False seen.append(e) return True def find_evaluated_item_indexes_by_schema(validator, instance, schema): """ Get all indexes of items that get evaluated under the current schema Covers all keywords related to unevaluatedItems: items, prefixItems, if, then, else, contains, unevaluatedItems, allOf, oneOf, anyOf """ if validator.is_type(schema, "boolean"): return [] evaluated_indexes = [] if "items" in schema: return list(range(0, len(instance))) if "$ref" in schema: scope, resolved = validator.resolver.resolve(schema["$ref"]) validator.resolver.push_scope(scope) try: evaluated_indexes += find_evaluated_item_indexes_by_schema( validator, instance, resolved, ) finally: validator.resolver.pop_scope() if "prefixItems" in schema: evaluated_indexes += list(range(0, len(schema["prefixItems"]))) if "if" in schema: if validator.evolve(schema=schema["if"]).is_valid(instance): evaluated_indexes += find_evaluated_item_indexes_by_schema( validator, instance, schema["if"], ) if "then" in schema: evaluated_indexes += find_evaluated_item_indexes_by_schema( validator, instance, schema["then"], ) else: if "else" in schema: evaluated_indexes += find_evaluated_item_indexes_by_schema( validator, instance, schema["else"], ) for keyword in ["contains", "unevaluatedItems"]: if keyword in schema: for k, v in enumerate(instance): if validator.evolve(schema=schema[keyword]).is_valid(v): evaluated_indexes.append(k) for keyword in ["allOf", "oneOf", "anyOf"]: if keyword in schema: for subschema in schema[keyword]: errs = list(validator.descend(instance, subschema)) if not errs: evaluated_indexes += find_evaluated_item_indexes_by_schema( validator, instance, subschema, ) return evaluated_indexes def find_evaluated_property_keys_by_schema(validator, instance, schema): """ Get all keys of items that get evaluated under the current schema Covers all keywords related to unevaluatedProperties: properties, additionalProperties, unevaluatedProperties, patternProperties, dependentSchemas, allOf, oneOf, anyOf, if, then, else """ if validator.is_type(schema, "boolean"): return [] evaluated_keys = [] if "$ref" in schema: scope, resolved = validator.resolver.resolve(schema["$ref"]) validator.resolver.push_scope(scope) try: evaluated_keys += find_evaluated_property_keys_by_schema( validator, instance, resolved, ) finally: validator.resolver.pop_scope() for keyword in [ "properties", "additionalProperties", "unevaluatedProperties", ]: if keyword in schema: if validator.is_type(schema[keyword], "boolean"): for property, value in instance.items(): if validator.evolve(schema=schema[keyword]).is_valid( {property: value}, ): evaluated_keys.append(property) if validator.is_type(schema[keyword], "object"): for property, subschema in schema[keyword].items(): if property in instance and validator.evolve( schema=subschema, ).is_valid(instance[property]): evaluated_keys.append(property) if "patternProperties" in schema: for property, value in instance.items(): for pattern, _ in schema["patternProperties"].items(): if re.search(pattern, property) and validator.evolve( schema=schema["patternProperties"], ).is_valid({property: value}): evaluated_keys.append(property) if "dependentSchemas" in schema: for property, subschema in schema["dependentSchemas"].items(): if property not in instance: continue evaluated_keys += find_evaluated_property_keys_by_schema( validator, instance, subschema, ) for keyword in ["allOf", "oneOf", "anyOf"]: if keyword in schema: for subschema in schema[keyword]: errs = list(validator.descend(instance, subschema)) if not errs: evaluated_keys += find_evaluated_property_keys_by_schema( validator, instance, subschema, ) if "if" in schema: if validator.evolve(schema=schema["if"]).is_valid(instance): evaluated_keys += find_evaluated_property_keys_by_schema( validator, instance, schema["if"], ) if "then" in schema: evaluated_keys += find_evaluated_property_keys_by_schema( validator, instance, schema["then"], ) else: if "else" in schema: evaluated_keys += find_evaluated_property_keys_by_schema( validator, instance, schema["else"], ) return evaluated_keys ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/_validators.py0000644000175100001770000003714014653725311020143 0ustar00runnerdockerfrom fractions import Fraction from urllib.parse import urldefrag, urljoin import re from asdf._jsonschema._utils import ( ensure_list, equal, extras_msg, find_additional_properties, find_evaluated_item_indexes_by_schema, find_evaluated_property_keys_by_schema, unbool, uniq, ) from asdf._jsonschema.exceptions import FormatError, ValidationError def patternProperties(validator, patternProperties, instance, schema): if not validator.is_type(instance, "object"): return for pattern, subschema in patternProperties.items(): for k, v in instance.items(): if re.search(pattern, k): yield from validator.descend( v, subschema, path=k, schema_path=pattern, ) def propertyNames(validator, propertyNames, instance, schema): if not validator.is_type(instance, "object"): return for property in instance: yield from validator.descend(instance=property, schema=propertyNames) def additionalProperties(validator, aP, instance, schema): if not validator.is_type(instance, "object"): return extras = set(find_additional_properties(instance, schema)) if validator.is_type(aP, "object"): for extra in extras: yield from validator.descend(instance[extra], aP, path=extra) elif not aP and extras: if "patternProperties" in schema: if len(extras) == 1: verb = "does" else: verb = "do" joined = ", ".join(repr(each) for each in sorted(extras)) patterns = ", ".join( repr(each) for each in sorted(schema["patternProperties"]) ) error = f"{joined} {verb} not match any of the regexes: {patterns}" yield ValidationError(error) else: error = "Additional properties are not allowed (%s %s unexpected)" yield ValidationError(error % extras_msg(extras)) def items(validator, items, instance, schema): if not validator.is_type(instance, "array"): return prefix = len(schema.get("prefixItems", [])) total = len(instance) if items is False and total > prefix: message = f"Expected at most {prefix} items, but found {total}" yield ValidationError(message) else: for index in range(prefix, total): yield from validator.descend( instance=instance[index], schema=items, path=index, ) def additionalItems(validator, aI, instance, schema): if ( not validator.is_type(instance, "array") or validator.is_type(schema.get("items", {}), "object") ): return len_items = len(schema.get("items", [])) if validator.is_type(aI, "object"): for index, item in enumerate(instance[len_items:], start=len_items): yield from validator.descend(item, aI, path=index) elif not aI and len(instance) > len(schema.get("items", [])): error = "Additional items are not allowed (%s %s unexpected)" yield ValidationError( error % extras_msg(instance[len(schema.get("items", [])):]), ) def const(validator, const, instance, schema): if not equal(instance, const): yield ValidationError(f"{const!r} was expected") def contains(validator, contains, instance, schema): if not validator.is_type(instance, "array"): return matches = 0 min_contains = schema.get("minContains", 1) max_contains = schema.get("maxContains", len(instance)) for each in instance: if validator.evolve(schema=contains).is_valid(each): matches += 1 if matches > max_contains: yield ValidationError( "Too many items match the given schema " f"(expected at most {max_contains})", validator="maxContains", validator_value=max_contains, ) return if matches < min_contains: if not matches: yield ValidationError( f"{instance!r} does not contain items " "matching the given schema", ) else: yield ValidationError( "Too few items match the given schema (expected at least " f"{min_contains} but only {matches} matched)", validator="minContains", validator_value=min_contains, ) def exclusiveMinimum(validator, minimum, instance, schema): if not validator.is_type(instance, "number"): return if instance <= minimum: yield ValidationError( f"{instance!r} is less than or equal to " f"the minimum of {minimum!r}", ) def exclusiveMaximum(validator, maximum, instance, schema): if not validator.is_type(instance, "number"): return if instance >= maximum: yield ValidationError( f"{instance!r} is greater than or equal " f"to the maximum of {maximum!r}", ) def minimum(validator, minimum, instance, schema): if not validator.is_type(instance, "number"): return if instance < minimum: message = f"{instance!r} is less than the minimum of {minimum!r}" yield ValidationError(message) def maximum(validator, maximum, instance, schema): if not validator.is_type(instance, "number"): return if instance > maximum: message = f"{instance!r} is greater than the maximum of {maximum!r}" yield ValidationError(message) def multipleOf(validator, dB, instance, schema): if not validator.is_type(instance, "number"): return if isinstance(dB, float): quotient = instance / dB try: failed = int(quotient) != quotient except OverflowError: # When `instance` is large and `dB` is less than one, # quotient can overflow to infinity; and then casting to int # raises an error. # # In this case we fall back to Fraction logic, which is # exact and cannot overflow. The performance is also # acceptable: we try the fast all-float option first, and # we know that fraction(dB) can have at most a few hundred # digits in each part. The worst-case slowdown is therefore # for already-slow enormous integers or Decimals. failed = (Fraction(instance) / Fraction(dB)).denominator != 1 else: failed = instance % dB if failed: yield ValidationError(f"{instance!r} is not a multiple of {dB}") def minItems(validator, mI, instance, schema): if validator.is_type(instance, "array") and len(instance) < mI: yield ValidationError(f"{instance!r} is too short") def maxItems(validator, mI, instance, schema): if validator.is_type(instance, "array") and len(instance) > mI: yield ValidationError(f"{instance!r} is too long") def uniqueItems(validator, uI, instance, schema): if ( uI and validator.is_type(instance, "array") and not uniq(instance) ): yield ValidationError(f"{instance!r} has non-unique elements") def pattern(validator, patrn, instance, schema): if ( validator.is_type(instance, "string") and not re.search(patrn, instance) ): yield ValidationError(f"{instance!r} does not match {patrn!r}") def format(validator, format, instance, schema): if validator.format_checker is not None: try: validator.format_checker.check(instance, format) except FormatError as error: yield ValidationError(error.message, cause=error.cause) def minLength(validator, mL, instance, schema): if validator.is_type(instance, "string") and len(instance) < mL: yield ValidationError(f"{instance!r} is too short") def maxLength(validator, mL, instance, schema): if validator.is_type(instance, "string") and len(instance) > mL: yield ValidationError(f"{instance!r} is too long") def dependentRequired(validator, dependentRequired, instance, schema): if not validator.is_type(instance, "object"): return for property, dependency in dependentRequired.items(): if property not in instance: continue for each in dependency: if each not in instance: message = f"{each!r} is a dependency of {property!r}" yield ValidationError(message) def dependentSchemas(validator, dependentSchemas, instance, schema): if not validator.is_type(instance, "object"): return for property, dependency in dependentSchemas.items(): if property not in instance: continue yield from validator.descend( instance, dependency, schema_path=property, ) def enum(validator, enums, instance, schema): if instance == 0 or instance == 1: unbooled = unbool(instance) if all(unbooled != unbool(each) for each in enums): yield ValidationError(f"{instance!r} is not one of {enums!r}") elif instance not in enums: yield ValidationError(f"{instance!r} is not one of {enums!r}") def ref(validator, ref, instance, schema): resolve = getattr(validator.resolver, "resolve", None) if resolve is None: with validator.resolver.resolving(ref) as resolved: yield from validator.descend(instance, resolved) else: scope, resolved = validator.resolver.resolve(ref) validator.resolver.push_scope(scope) try: yield from validator.descend(instance, resolved) finally: validator.resolver.pop_scope() def dynamicRef(validator, dynamicRef, instance, schema): _, fragment = urldefrag(dynamicRef) for url in validator.resolver._scopes_stack: lookup_url = urljoin(url, dynamicRef) with validator.resolver.resolving(lookup_url) as subschema: if ("$dynamicAnchor" in subschema and fragment == subschema["$dynamicAnchor"]): yield from validator.descend(instance, subschema) break else: with validator.resolver.resolving(dynamicRef) as subschema: yield from validator.descend(instance, subschema) def type(validator, types, instance, schema): types = ensure_list(types) if not any(validator.is_type(instance, type) for type in types): reprs = ", ".join(repr(type) for type in types) yield ValidationError(f"{instance!r} is not of type {reprs}") def properties(validator, properties, instance, schema): if not validator.is_type(instance, "object"): return for property, subschema in properties.items(): if property in instance: yield from validator.descend( instance[property], subschema, path=property, schema_path=property, ) def required(validator, required, instance, schema): if not validator.is_type(instance, "object"): return for property in required: if property not in instance: yield ValidationError(f"{property!r} is a required property") def minProperties(validator, mP, instance, schema): if validator.is_type(instance, "object") and len(instance) < mP: yield ValidationError(f"{instance!r} does not have enough properties") def maxProperties(validator, mP, instance, schema): if not validator.is_type(instance, "object"): return if validator.is_type(instance, "object") and len(instance) > mP: yield ValidationError(f"{instance!r} has too many properties") def allOf(validator, allOf, instance, schema): for index, subschema in enumerate(allOf): yield from validator.descend(instance, subschema, schema_path=index) def anyOf(validator, anyOf, instance, schema): all_errors = [] for index, subschema in enumerate(anyOf): errs = list(validator.descend(instance, subschema, schema_path=index)) if not errs: break all_errors.extend(errs) else: yield ValidationError( f"{instance!r} is not valid under any of the given schemas", context=all_errors, ) def oneOf(validator, oneOf, instance, schema): subschemas = enumerate(oneOf) all_errors = [] for index, subschema in subschemas: errs = list(validator.descend(instance, subschema, schema_path=index)) if not errs: first_valid = subschema break all_errors.extend(errs) else: yield ValidationError( f"{instance!r} is not valid under any of the given schemas", context=all_errors, ) more_valid = [ each for _, each in subschemas if validator.evolve(schema=each).is_valid(instance) ] if more_valid: more_valid.append(first_valid) reprs = ", ".join(repr(schema) for schema in more_valid) yield ValidationError(f"{instance!r} is valid under each of {reprs}") def not_(validator, not_schema, instance, schema): if validator.evolve(schema=not_schema).is_valid(instance): message = f"{instance!r} should not be valid under {not_schema!r}" yield ValidationError(message) def if_(validator, if_schema, instance, schema): if validator.evolve(schema=if_schema).is_valid(instance): if "then" in schema: then = schema["then"] yield from validator.descend(instance, then, schema_path="then") elif "else" in schema: else_ = schema["else"] yield from validator.descend(instance, else_, schema_path="else") def unevaluatedItems(validator, unevaluatedItems, instance, schema): if not validator.is_type(instance, "array"): return evaluated_item_indexes = find_evaluated_item_indexes_by_schema( validator, instance, schema, ) unevaluated_items = [ item for index, item in enumerate(instance) if index not in evaluated_item_indexes ] if unevaluated_items: error = "Unevaluated items are not allowed (%s %s unexpected)" yield ValidationError(error % extras_msg(unevaluated_items)) def unevaluatedProperties(validator, unevaluatedProperties, instance, schema): if not validator.is_type(instance, "object"): return evaluated_keys = find_evaluated_property_keys_by_schema( validator, instance, schema, ) unevaluated_keys = [] for property in instance: if property not in evaluated_keys: for _ in validator.descend( instance[property], unevaluatedProperties, path=property, schema_path=property, ): # FIXME: Include context for each unevaluated property # indicating why it's invalid under the subschema. unevaluated_keys.append(property) if unevaluated_keys: if unevaluatedProperties is False: error = "Unevaluated properties are not allowed (%s %s unexpected)" yield ValidationError(error % extras_msg(unevaluated_keys)) else: error = ( "Unevaluated properties are not valid under " "the given schema (%s %s unevaluated and invalid)" ) yield ValidationError(error % extras_msg(unevaluated_keys)) def prefixItems(validator, prefixItems, instance, schema): if not validator.is_type(instance, "array"): return for (index, item), subschema in zip(enumerate(instance), prefixItems): yield from validator.descend( instance=item, schema=subschema, schema_path=index, path=index, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/conftest.py0000644000175100001770000000022714653725311017455 0ustar00runnerdocker import pytest collect_ignore_glob = [] def pytest_configure(config): if not config.option.jsonschema: collect_ignore_glob.append("*") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/exceptions.py0000644000175100001770000002614514653725311020020 0ustar00runnerdocker""" Validation errors, and some surrounding helpers. """ from __future__ import annotations from collections import defaultdict, deque from pprint import pformat from textwrap import dedent, indent import heapq import itertools import warnings import attr from asdf._jsonschema import _utils WEAK_MATCHES: frozenset[str] = frozenset(["anyOf", "oneOf"]) STRONG_MATCHES: frozenset[str] = frozenset() _unset = _utils.Unset() class _Error(Exception): def __init__( self, message, validator=_unset, path=(), cause=None, context=(), validator_value=_unset, instance=_unset, schema=_unset, schema_path=(), parent=None, type_checker=_unset, ): super(_Error, self).__init__( message, validator, path, cause, context, validator_value, instance, schema, schema_path, parent, ) self.message = message self.path = self.relative_path = deque(path) self.schema_path = self.relative_schema_path = deque(schema_path) self.context = list(context) self.cause = self.__cause__ = cause self.validator = validator self.validator_value = validator_value self.instance = instance self.schema = schema self.parent = parent self._type_checker = type_checker for error in context: error.parent = self def __repr__(self): return f"<{self.__class__.__name__}: {self.message!r}>" def __str__(self): essential_for_verbose = ( self.validator, self.validator_value, self.instance, self.schema, ) if any(m is _unset for m in essential_for_verbose): return self.message schema_path = _utils.format_as_index( container=self._word_for_schema_in_error_message, indices=list(self.relative_schema_path)[:-1], ) instance_path = _utils.format_as_index( container=self._word_for_instance_in_error_message, indices=self.relative_path, ) prefix = 16 * " " return dedent( f"""\ {self.message} Failed validating {self.validator!r} in {schema_path}: {indent(pformat(self.schema, width=72), prefix).lstrip()} On {instance_path}: {indent(pformat(self.instance, width=72), prefix).lstrip()} """.rstrip(), ) @classmethod def create_from(cls, other): return cls(**other._contents()) @property def absolute_path(self): parent = self.parent if parent is None: return self.relative_path path = deque(self.relative_path) path.extendleft(reversed(parent.absolute_path)) return path @property def absolute_schema_path(self): parent = self.parent if parent is None: return self.relative_schema_path path = deque(self.relative_schema_path) path.extendleft(reversed(parent.absolute_schema_path)) return path @property def json_path(self): path = "$" for elem in self.absolute_path: if isinstance(elem, int): path += "[" + str(elem) + "]" else: path += "." + elem return path def _set(self, type_checker=None, **kwargs): if type_checker is not None and self._type_checker is _unset: self._type_checker = type_checker for k, v in kwargs.items(): if getattr(self, k) is _unset: setattr(self, k, v) def _contents(self): attrs = ( "message", "cause", "context", "validator", "validator_value", "path", "schema_path", "instance", "schema", "parent", ) return dict((attr, getattr(self, attr)) for attr in attrs) def _matches_type(self): try: expected = self.schema["type"] except (KeyError, TypeError): return False if isinstance(expected, str): return self._type_checker.is_type(self.instance, expected) return any( self._type_checker.is_type(self.instance, expected_type) for expected_type in expected ) class ValidationError(_Error): """ An instance was invalid under a provided schema. """ _word_for_schema_in_error_message = "schema" _word_for_instance_in_error_message = "instance" class SchemaError(_Error): """ A schema was invalid under its corresponding metaschema. """ _word_for_schema_in_error_message = "metaschema" _word_for_instance_in_error_message = "schema" @attr.s(unsafe_hash=True) class RefResolutionError(Exception): """ A ref could not be resolved. """ _cause = attr.ib() def __str__(self): return str(self._cause) class UndefinedTypeCheck(Exception): """ A type checker was asked to check a type it did not have registered. """ def __init__(self, type): self.type = type def __str__(self): return f"Type {self.type!r} is unknown to this type checker" class UnknownType(Exception): """ A validator was asked to validate an instance against an unknown type. """ def __init__(self, type, instance, schema): self.type = type self.instance = instance self.schema = schema def __str__(self): prefix = 16 * " " return dedent( f"""\ Unknown type {self.type!r} for validator with schema: {indent(pformat(self.schema, width=72), prefix).lstrip()} While checking instance: {indent(pformat(self.instance, width=72), prefix).lstrip()} """.rstrip(), ) class FormatError(Exception): """ Validating a format failed. """ def __init__(self, message, cause=None): super(FormatError, self).__init__(message, cause) self.message = message self.cause = self.__cause__ = cause def __str__(self): return self.message class ErrorTree: """ ErrorTrees make it easier to check which validations failed. """ _instance = _unset def __init__(self, errors=()): self.errors = {} self._contents = defaultdict(self.__class__) for error in errors: container = self for element in error.path: container = container[element] container.errors[error.validator] = error container._instance = error.instance def __contains__(self, index): """ Check whether ``instance[index]`` has any errors. """ return index in self._contents def __getitem__(self, index): """ Retrieve the child tree one level down at the given ``index``. If the index is not in the instance that this tree corresponds to and is not known by this tree, whatever error would be raised by ``instance.__getitem__`` will be propagated (usually this is some subclass of `LookupError`. """ if self._instance is not _unset and index not in self: self._instance[index] return self._contents[index] def __setitem__(self, index, value): """ Add an error to the tree at the given ``index``. """ self._contents[index] = value def __iter__(self): """ Iterate (non-recursively) over the indices in the instance with errors. """ return iter(self._contents) def __len__(self): """ Return the `total_errors`. """ return self.total_errors def __repr__(self): total = len(self) errors = "error" if total == 1 else "errors" return f"<{self.__class__.__name__} ({total} total {errors})>" @property def total_errors(self): """ The total number of errors in the entire tree, including children. """ child_errors = sum(len(tree) for _, tree in self._contents.items()) return len(self.errors) + child_errors def by_relevance(weak=WEAK_MATCHES, strong=STRONG_MATCHES): """ Create a key function that can be used to sort errors by relevance. Arguments: weak (set): a collection of validation keywords to consider to be "weak". If there are two errors at the same level of the instance and one is in the set of weak validation keywords, the other error will take priority. By default, :kw:`anyOf` and :kw:`oneOf` are considered weak keywords and will be superseded by other same-level validation errors. strong (set): a collection of validation keywords to consider to be "strong" """ def relevance(error): validator = error.validator return ( -len(error.path), validator not in weak, validator in strong, not error._matches_type(), ) return relevance relevance = by_relevance() def best_match(errors, key=relevance): """ Try to find an error that appears to be the best match among given errors. In general, errors that are higher up in the instance (i.e. for which `ValidationError.path` is shorter) are considered better matches, since they indicate "more" is wrong with the instance. If the resulting match is either :kw:`oneOf` or :kw:`anyOf`, the *opposite* assumption is made -- i.e. the deepest error is picked, since these keywords only need to match once, and any other errors may not be relevant. Arguments: errors (collections.abc.Iterable): the errors to select from. Do not provide a mixture of errors from different validation attempts (i.e. from different instances or schemas), since it won't produce sensical output. key (collections.abc.Callable): the key to use when sorting errors. See `relevance` and transitively `by_relevance` for more details (the default is to sort with the defaults of that function). Changing the default is only useful if you want to change the function that rates errors but still want the error context descent done by this function. Returns: the best matching error, or ``None`` if the iterable was empty .. note:: This function is a heuristic. Its return value may change for a given set of inputs from version to version if better heuristics are added. """ errors = iter(errors) best = next(errors, None) if best is None: return best = max(itertools.chain([best], errors), key=key) while best.context: # Calculate the minimum via nsmallest, because we don't recurse if # all nested errors have the same relevance (i.e. if min == max == all) smallest = heapq.nsmallest(2, best.context, key=key) if len(smallest) == 2 and key(smallest[0]) == key(smallest[1]): return best best = smallest[0] return best ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.033096 asdf-3.4.0/asdf/_jsonschema/json/0000755000175100001770000000000014653725331016230 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/.gitignore0000644000175100001770000000600614653725311020220 0ustar00runnerdocker# Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover *.py,cover .hypothesis/ .pytest_cache/ cover/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 db.sqlite3-journal # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder .pybuilder/ target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv # For a library or package, you might want to ignore these files since the code is # intended to run in multiple environments; otherwise, check them in: # .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock # poetry # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. # This is especially recommended for binary packages to ensure reproducibility, and is more # commonly ignored for libraries. # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control #poetry.lock # pdm # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. #pdm.lock # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it # in version control. # https://pdm.fming.dev/#use-with-ide .pdm.toml # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm __pypackages__/ # Celery stuff celerybeat-schedule celerybeat.pid # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ # pytype static type analyzer .pytype/ # Cython debug symbols cython_debug/ # PyCharm # JetBrains specific template is maintained in a separate JetBrains.gitignore that can # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/CONTRIBUTING.md0000644000175100001770000001737714653725311020476 0ustar00runnerdocker# Contributing to the Suite All contributors to the test suite should familiarize themselves with this document. Both pull requests *and* reviews are welcome from any and all, regardless of their "formal" relationship (or lack thereof) with the JSON Schema organization. ## Commit Access Any existing members with commit access to the repository may nominate new members to get access, or a contributor may request access for themselves. Access generally should be granted liberally to anyone who has shown positive contributions to the repository or organization. All who are active in other parts of the JSON Schema organization should get access to this repository as well. Access for a former contributor may be removed after long periods of inactivity. ## Reviewing a Pull Request Pull requests may (and often should) be reviewed for approval by a single reviewer whose job it is to confirm the change is specified, correct, minimal and follows general style in the repository. A reviewer who does not feel comfortable signing off on the correctness of a change is free to comment without explicit approval. Other contributors are also encouraged to comment on pull requests whenever they have feedback, even if another contributor has submitted review comments. A submitter may also choose to request additional feedback if they feel the change is particularly technical or complex, or requires expertise in a particular area of the specification. If additional reviewers have participated in a pull request, the submitter should not rely on a single reviewer's approval without some form of confirmation that all participating reviewers are satisfied. On the other hand, whenever possible, reviewers who have minor comments should explicitly mention that they are OK with the PR being merged after or potentially *without* addressing them. When submitting a change, explicitly soliciting a specific reviewer explicitly is currently not needed, as the entire review team is generally pinged for pull requests. Nevertheless, submitters may choose to do so if they want specific review from an individual, or if a pull request is sitting without review for a period of time. For the latter scenario, leaving a comment on the pull request or in Slack is also reasonable. Confirming that a pull request runs successfully on an implementation is *not* generally sufficient to merge, though it is helpful evidence, and highly encouraged. Proposed changes should be confirmed by reading the specification and ensuring the behavior is specified and correct. Submitters are encouraged to link to the specification whenever doing so will be helpful to a reviewer. A reviewer may indicate that the proposed changes are too large for them to review. In such cases the submitter may wait for another reviewer who is comfortable reviewing the changes, but is generally strongly encouraged to split up the changes into multiple smaller ones. Reviewing pull requests is an extremely valuable contribution! New reviewers are highly encouraged to attempt to review pull requests even if they do not have experience doing so, and to themselves expect feedback from the submitter or from other reviewers on improving the quality of their reviews. In such cases the submitter should use their judgement to decide whether the new contributor's review is sufficient for merging, or whether they should wait for further feedback. ## Merging Changes Approval of a change may be given using the GitHub UI or via a comment reply. Once it has been given, the pull request may be merged at any point. To merge a pull request, *either* the submitter or reviewer must have commit access to the repo (though this is also partially simply because that party's access is needed to merge). *Either* the submitter or reviewer may be the one to do the actual merge (whether via hitting the merge button or externally to the GitHub UI). If the submitter wishes to make final changes after a review they should attempt to say so (and thereby take responsibility for merging themselves). Contributors *should not* leave pull requests stagnant whenever possible, and particularly after they have been reviewed and approved. Changes should not be merged while continuous integration is failing. Failures typically are not spurious and indicate issues with the changes. In the event the change is indeed correct and CI is flaky or itself incorrect, effort should be made by the submitter, reviewer, or a solicited other contributor to fix the CI before the change is made. Improvements to CI itself are very valuable as well, and reviewers who find repeated issues with proposed changes are highly encouraged to improve CI for any changes which may be automatically detected. Changes should be merged *as-is* and not squashed into single commits. Submitters are free to structure their commits as they wish throughout the review process, or in some cases to restructure the commits after a review is finished and they are merging the branch, but are not required to do so, and reviewers should not do so on behalf of the submitter without being requested to do so. Contributors with commit access may choose to merge pull requests (or commit directly) to the repository for trivial changes. The definition of "trivial" is intentionally slightly ambiguous, and intended to be followed by good-faith contributors. An example of a trivial change is fixing a typo in the README, or bumping a version of a dependency used by the continuous integration suite. If another contributor takes issue with a change merged in this fashion, simply commenting politely that they have concerns about the change (either in an issue or directly) is the right remedy. ## Writing Good Tests Be familiar with the test structure and assumptions documented in the [README](README.md). Test cases should include both valid and invalid instances which exercise the test case schema whenever possible. Exceptions include schemas where only one result is ever possible (such as the `false` schema, or ones using keywords which only produce annotations). Schemas should be *minimal*, by which we mean that they should contain only those keywords which are being tested by the specific test case, and should not contain complex values when simpler ones would do. The same applies to instances -- prefer simpler instances to more complex ones, and when testing string instances, consider using ones which are self-descriptive whenever it aids readability. Comments can and should be used to explain tests which are unclear or complex. The `comment` field is present both for test cases and individual tests for this purpose. Links to the relevant specification sections are also encouraged, though they can be tedious to maintain from one version to the next. When adding test cases, they should be added to all past (and future) versions of the specification which they apply to, potentially with minor modifications (e.g. changing `$id` to `id` or accounting for `$ref` not allowing siblings on older drafts). Changing the schema used in a particular test case should be done with extra caution, though it is not formally discouraged if the change simplifies the schema. Contributors should not generally append *additional* behavior to existing test case schemas, unless doing so has specific justification. Instead, new cases should be added, as it can often be subtle to predict which precise parts of a test case are unique. Adding additional *tests* however (instances) is of course safe and encouraged if gaps are found. Tests which are *incorrect* (against the specification) should be prioritized for fixing or removal whenever possible, as their continued presence in the suite can create confusion for downstream users of the suite. ## Proposing Changes to the Policy This policy itself is of course changeable, and changes to it may be proposed in a discussion. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/LICENSE0000644000175100001770000000204114653725311017230 0ustar00runnerdockerCopyright (c) 2012 Julian Berman Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/README.md0000644000175100001770000004111314653725311017505 0ustar00runnerdocker# JSON Schema Test Suite [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](https://github.com/json-schema-org/.github/blob/main/CODE_OF_CONDUCT.md) [![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active) [![Financial Contributors on Open Collective](https://opencollective.com/json-schema/all/badge.svg?label=financial+contributors)](https://opencollective.com/json-schema) [![DOI](https://zenodo.org/badge/5952934.svg)](https://zenodo.org/badge/latestdoi/5952934) [![Build Status](https://github.com/json-schema-org/JSON-Schema-Test-Suite/workflows/Test%20Suite%20Sanity%20Checking/badge.svg)](https://github.com/json-schema-org/JSON-Schema-Test-Suite/actions?query=workflow%3A%22Test+Suite+Sanity+Checking%22) This repository contains a set of JSON objects that implementers of JSON Schema validation libraries can use to test their validators. It is meant to be language agnostic and should require only a JSON parser. The conversion of the JSON objects into tests within a specific language and test framework of choice is left to be done by the validator implementer. ## Coverage All JSON Schema specification releases should be well covered by this suite, including drafts 2020-12, 2019-09, 07, 06, 04 and 03. Drafts 04 and 03 are considered "frozen" in that less effort is put in to backport new tests to these versions. Additional coverage is always welcome, particularly for bugs encountered in real-world implementations. If you see anything missing or incorrect, please feel free to [file an issue](https://github.com/json-schema-org/JSON-Schema-Test-Suite/issues) or [submit a PR](https://github.com/json-schema-org/JSON-Schema-Test-Suite). ## Introduction to the Test Suite Structure The tests in this suite are contained in the `tests` directory at the root of this repository. Inside that directory is a subdirectory for each released version of the specification. The structure and contents of each file in these directories is described below. In addition to the version-specific subdirectories, two additional directories are present: 1. `draft-next/`: containing tests for the next version of the specification whilst it is in development 2. `latest/`: a symbolic link which points to the directory which is the most recent release (which may be useful for implementations providing specific entry points for validating against the latest version of the specification) Inside each version directory there are a number of `.json` files each containing a collection of related tests. Often the grouping is by property under test, but not always. In addition to the `.json` files, each version directory contains one or more special subdirectories whose purpose is [described below](#subdirectories-within-each-draft), and which contain additional `.json` files. Each `.json` file consists of a single JSON array of test cases. ### Terminology For clarity, we first define this document's usage of some testing terminology: | term | definition | |-----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **test suite** | the entirety of the contents of this repository, containing tests for multiple different releases of the JSON Schema specification | | **test case** | a single schema, along with a description and an array of *test*s | | **test** | within a *test case*, a single test example, containing a description, instance and a boolean indicating whether the instance is valid under the test case schema | | **test runner** | a program, external to this repository and authored by a user of this suite, which is executing each of the tests in the suite | An example illustrating this structure is immediately below, and a JSON Schema containing a formal definition of the contents of test cases can be found [alongside this README](./test-schema.json). ### Sample Test Case Here is a single *test case*, containing one or more tests: ```json { "description": "The test case description", "schema": { "type": "string" }, "tests": [ { "description": "a test with a valid instance", "data": "a string", "valid": true }, { "description": "a test with an invalid instance", "data": 15, "valid": false } ] } ``` ### Subdirectories Within Each Draft There is currently only one additional subdirectory that may exist within each draft test directory. This is: 1. `optional/`: Contains tests that are considered optional. Note, the `optional/` subdirectory today conflates many reasons why a test may be optional -- it may be because tests within a particular file are indeed not required by the specification but still potentially useful to an implementer, or it may be because tests within it only apply to programming languages with particular functionality (in which case they are not truly optional in such a language). In the future this directory structure will be made richer to reflect these differences more clearly. ## Using the Suite to Test a Validator Implementation The test suite structure was described [above](#introduction-to-the-test-suite-structure). If you are authoring a new validator implementation, or adding support for an additional version of the specification, this section describes: 1. How to implement a test runner which passes tests to your validator 2. Assumptions the suite makes about how the test runner will configure your validator 3. Invariants the test suite claims to hold for its tests ### How to Implement a Test Runner Presented here is a possible implementation of a test runner. The precise steps described do not need to be followed exactly, but the results of your own procedure should produce the same effects. To test a specific version: * For 2019-09 and later published drafts, implementations that are able to detect the draft of each schema via `$schema` SHOULD be configured to do so * For draft-07 and earlier, draft-next, and implementations unable to detect via `$schema`, implementations MUST be configured to expect the draft matching the test directory name * Load any remote references [described below](additional-assumptions) and configure your implementation to retrieve them via their URIs * Walk the filesystem tree for that version's subdirectory and for each `.json` file found: * if the file is located in the root of the version directory: * for each test case present in the file: * load the schema from the `"schema"` property * load (or log) the test case description from the `"description"` property for debugging or outputting * for each test in the `"tests"` property: * load the instance to be tested from the `"data"` property * load (or log) the individual test description from the `"description"` property for debugging or outputting * use the schema loaded above to validate whether the instance is considered valid under your implementation * if the result from your implementation matches the value found in the `"valid"` property, your implementation correctly implements the specific example * if the result does not match, or your implementation errors or crashes, your implementation does not correctly implement the specific example * otherwise it is located in a special subdirectory as described above. Follow the additional assumptions and restrictions for the containing subdirectory, then run the test case as above. If your implementation supports multiple versions, run the above procedure for each version supported, configuring your implementation as appropriate to call each version individually. ### Additional Assumptions 1. The suite, notably in its `refRemote.json` file in each draft, expects a number of remote references to be configured. These are JSON documents, identified by URI, which are used by the suite to test the behavior of the `$ref` keyword (and related keywords). Depending on your implementation, you may configure how to "register" these *either*: * by directly retrieving them off the filesystem from the `remotes/` directory, in which case you should load each schema with a retrieval URI of `http://localhost:1234` followed by the relative path from the remotes directory -- e.g. a `$ref` to `http://localhost:1234/foo/bar/baz.json` is expected to resolve to the contents of the file at `remotes/foo/bar/baz.json` * or alternatively, by executing `bin/jsonschema_suite remotes` using the executable in the `bin/` directory, which will output a JSON object containing all of the remotes combined, e.g.: ``` $ bin/jsonschema_suite remotes ``` ```json { "http://localhost:1234/baseUriChange/folderInteger.json": { "type": "integer" }, "http://localhost:1234/baseUriChangeFolder/folderInteger.json": { "type": "integer" } } ``` 2. Test cases found within [special subdirectories](#subdirectories-within-each-draft) may require additional configuration to run. In particular, tests within the `optional/format` subdirectory may require implementations to change the way they treat the `"format"`keyword (particularly on older drafts which did not have a notion of vocabularies). ### Invariants & Guarantees The test suite guarantees a number of things about tests it defines. Any deviation from the below is generally considered a bug. If you suspect one, please [file an issue](https://github.com/json-schema-org/JSON-Schema-Test-Suite/issues/new): 1. All files containing test cases are valid JSON. 2. The contents of the `"schema"` property in a test case are always valid JSON Schemas under the corresponding specification. The rationale behind this is that we are testing instances in a test's `"data"` element, and not the schema itself. A number of tests *do* test the validity of a schema itself, but do so by representing the schema as an instance inside a test, with the associated meta-schema in the `"schema"` property (via the `"$ref"` keyword): ```json { "description": "Test the \"type\" schema keyword", "schema": { "$ref": "https://json-schema.org/draft/2019-09/schema" }, "tests": [ { "description": "Valid: string", "data": { "type": "string" }, "valid": true }, { "description": "Invalid: null", "data": { "type": null }, "valid": false } ] } ``` See below for some [known limitations](#known-limitations). ## Known Limitations This suite expresses its assertions about the behavior of an implementation *within* JSON Schema itself. Each test is the application of a schema to a particular instance. This means that the suite of tests can test against any behavior a schema can describe, and conversely cannot test against any behavior which a schema is incapable of representing, even if the behavior is mandated by the specification. For example, a schema can require that a string is a _URI-reference_ and even that it matches a certain pattern, but even though the specification contains [recommendations about URIs being normalized](https://json-schema.org/draft/2020-12/json-schema-core.html#name-the-id-keyword), a JSON schema cannot today represent this assertion within the core vocabularies of the specifications, so no test covers this behavior. ## Who Uses the Test Suite This suite is being used by: ### Clojure * [jinx](https://github.com/juxt/jinx) * [json-schema](https://github.com/tatut/json-schema) ### Coffeescript * [jsck](https://github.com/pandastrike/jsck) ### Common Lisp * [json-schema](https://github.com/fisxoj/json-schema) ### C++ * [Modern C++ JSON schema validator](https://github.com/pboettch/json-schema-validator) * [Valijson](https://github.com/tristanpenman/valijson) ### Dart * [json\_schema](https://github.com/patefacio/json_schema) ### Elixir * [ex\_json\_schema](https://github.com/jonasschmidt/ex_json_schema) ### Erlang * [jesse](https://github.com/for-GET/jesse) ### Go * [gojsonschema](https://github.com/sigu-399/gojsonschema) * [validate-json](https://github.com/cesanta/validate-json) ### Haskell * [aeson-schema](https://github.com/timjb/aeson-schema) * [hjsonschema](https://github.com/seagreen/hjsonschema) ### Java * [json-schema-validator](https://github.com/daveclayton/json-schema-validator) * [everit-org/json-schema](https://github.com/everit-org/json-schema) * [networknt/json-schema-validator](https://github.com/networknt/json-schema-validator) * [Justify](https://github.com/leadpony/justify) * [Snow](https://github.com/ssilverman/snowy-json) * [jsonschemafriend](https://github.com/jimblackler/jsonschemafriend) ### JavaScript * [json-schema-benchmark](https://github.com/Muscula/json-schema-benchmark) * [direct-schema](https://github.com/IreneKnapp/direct-schema) * [is-my-json-valid](https://github.com/mafintosh/is-my-json-valid) * [jassi](https://github.com/iclanzan/jassi) * [JaySchema](https://github.com/natesilva/jayschema) * [json-schema-valid](https://github.com/ericgj/json-schema-valid) * [Jsonary](https://github.com/jsonary-js/jsonary) * [jsonschema](https://github.com/tdegrunt/jsonschema) * [request-validator](https://github.com/bugventure/request-validator) * [skeemas](https://github.com/Prestaul/skeemas) * [tv4](https://github.com/geraintluff/tv4) * [z-schema](https://github.com/zaggino/z-schema) * [jsen](https://github.com/bugventure/jsen) * [ajv](https://github.com/epoberezkin/ajv) * [djv](https://github.com/korzio/djv) ### Node.js For node.js developers, the suite is also available as an [npm](https://www.npmjs.com/package/@json-schema-org/tests) package. Node-specific support is maintained in a [separate repository](https://github.com/json-schema-org/json-schema-test-suite-npm) which also welcomes your contributions! ### .NET * [JsonSchema.Net](https://github.com/gregsdennis/json-everything) * [Newtonsoft.Json.Schema](https://github.com/JamesNK/Newtonsoft.Json.Schema) ### Perl * [Test::JSON::Schema::Acceptance](https://github.com/karenetheridge/Test-JSON-Schema-Acceptance) (a wrapper of this test suite) * [JSON::Schema::Modern](https://github.com/karenetheridge/JSON-Schema-Modern) * [JSON::Schema::Tiny](https://github.com/karenetheridge/JSON-Schema-Tiny) ### PHP * [opis/json-schema](https://github.com/opis/json-schema) * [json-schema](https://github.com/justinrainbow/json-schema) * [json-guard](https://github.com/thephpleague/json-guard) ### PostgreSQL * [postgres-json-schema](https://github.com/gavinwahl/postgres-json-schema) * [is\_jsonb\_valid](https://github.com/furstenheim/is_jsonb_valid) ### Python * [jsonschema](https://github.com/Julian/jsonschema) * [fastjsonschema](https://github.com/seznam/python-fastjsonschema) * [hypothesis-jsonschema](https://github.com/Zac-HD/hypothesis-jsonschema) * [jschon](https://github.com/marksparkza/jschon) * [python-experimental, OpenAPI Generator](https://github.com/OpenAPITools/openapi-generator/blob/master/docs/generators/python-experimental.md) ### Ruby * [json-schema](https://github.com/hoxworth/json-schema) * [json\_schemer](https://github.com/davishmcclurg/json_schemer) ### Rust * [jsonschema](https://github.com/Stranger6667/jsonschema-rs) * [valico](https://github.com/rustless/valico) ### Scala * [typed-json](https://github.com/frawa/typed-json) ### Swift * [JSONSchema](https://github.com/kylef/JSONSchema.swift) If you use it as well, please fork and send a pull request adding yourself to the list :). ## Contributing If you see something missing or incorrect, a pull request is most welcome! There are some sanity checks in place for testing the test suite. You can run them with `bin/jsonschema_suite check` or `tox`. They will be run automatically by [GitHub Actions](https://github.com/json-schema-org/JSON-Schema-Test-Suite/actions?query=workflow%3A%22Test+Suite+Sanity+Checking%22) as well. This repository is maintained by the JSON Schema organization, and will be governed by the JSON Schema steering committee (once it exists). ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.033096 asdf-3.4.0/asdf/_jsonschema/json/bin/0000755000175100001770000000000014653725331017000 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/bin/jsonschema_suite0000755000175100001770000002672314653725311022301 0ustar00runnerdocker#! /usr/bin/env python3 from pathlib import Path from urllib.parse import urljoin import argparse import json import os import random import shutil import sys import textwrap import unittest import warnings try: import asdf._jsonschema.validators jsonschema = asdf._jsonschema except ImportError: jsonschema = None VALIDATORS = {} else: VALIDATORS = { "draft3": asdf._jsonschema.validators.Draft3Validator, "draft4": asdf._jsonschema.validators.Draft4Validator, "draft6": asdf._jsonschema.validators.Draft6Validator, "draft7": asdf._jsonschema.validators.Draft7Validator, "draft2019-09": asdf._jsonschema.validators.Draft201909Validator, "draft2020-12": asdf._jsonschema.validators.Draft202012Validator, "latest": asdf._jsonschema.validators.Draft202012Validator, } ROOT_DIR = Path(__file__).parent.parent SUITE_ROOT_DIR = ROOT_DIR / "tests" REMOTES_DIR = ROOT_DIR / "remotes" REMOTES_BASE_URL = "http://localhost:1234/" TESTSUITE_SCHEMA = json.loads((ROOT_DIR / "test-schema.json").read_text()) def files(paths): """ Each test file in the provided paths, as an array of test cases. """ for path in paths: yield path, json.loads(path.read_text()) def cases(paths): """ Each test case within each file in the provided paths. """ for _, test_file in files(paths): yield from test_file def tests(paths): """ Each individual test within all cases within the provided paths. """ for case in cases(paths): for test in case["tests"]: test["schema"] = case["schema"] yield test def collect(root_dir): """ All of the test file paths within the given root directory, recursively. """ return root_dir.glob("**/*.json") def url_for_path(path): """ Return the assumed remote URL for a file in the remotes/ directory. Tests in the refRemote.json file reference this URL, and assume the corresponding contents are available at the URL. """ return urljoin( REMOTES_BASE_URL, str(path.relative_to(REMOTES_DIR)).replace("\\", "/") # Windows... ) class SanityTests(unittest.TestCase): @classmethod def setUpClass(cls): print(f"Looking for tests in {SUITE_ROOT_DIR}") print(f"Looking for remotes in {REMOTES_DIR}") cls.test_files = list(collect(SUITE_ROOT_DIR)) assert cls.test_files, "Didn't find the test files!" print(f"Found {len(cls.test_files)} test files") cls.remote_files = list(collect(REMOTES_DIR)) assert cls.remote_files, "Didn't find the remote files!" print(f"Found {len(cls.remote_files)} remote files") def assertUnique(self, iterable): """ Assert that the elements of an iterable are unique. """ seen, duplicated = set(), set() for each in iterable: if each in seen: duplicated.add(each) seen.add(each) self.assertFalse(duplicated, "Elements are not unique.") def assertFollowsDescriptionStyle(self, description): """ Instead of saying "test that X frobs" or "X should frob" use "X frobs". See e.g. https://jml.io/pages/test-docstrings.html This test isn't comprehensive (it doesn't catch all the extra verbiage there), but it's just to catch whatever it manages to cover. """ message = ( "In descriptions, don't say 'Test that X frobs' or 'X should " "frob' or 'X should be valid'. Just say 'X frobs' or 'X is " "valid'. It's shorter, and the test suite is entirely about " "what *should* be already. " "See https://jml.io/pages/test-docstrings.html for help." ) self.assertNotRegex(description, r"\bshould\b", message) self.assertNotRegex(description, r"(?i)\btest(s)? that\b", message) def test_all_test_files_are_valid_json(self): """ All test files contain valid JSON. """ for path in self.test_files: with self.subTest(path=path): try: json.loads(path.read_text()) except ValueError as error: self.fail(f"{path} contains invalid JSON ({error})") def test_all_remote_files_are_valid_json(self): """ All remote files contain valid JSON. """ for path in self.remote_files: with self.subTest(path=path): try: json.loads(path.read_text()) except ValueError as error: self.fail(f"{path} contains invalid JSON ({error})") def test_all_case_descriptions_have_reasonable_length(self): """ All cases have reasonably long descriptions. """ for case in cases(self.test_files): with self.subTest(description=case["description"]): self.assertLess( len(case["description"]), 150, "Description is too long (keep it to less than 150 chars)." ) def test_all_test_descriptions_have_reasonable_length(self): """ All tests have reasonably long descriptions. """ for count, test in enumerate(tests(self.test_files)): with self.subTest(description=test["description"]): self.assertLess( len(test["description"]), 70, "Description is too long (keep it to less than 70 chars)." ) print(f"Found {count} tests.") def test_all_case_descriptions_are_unique(self): """ All cases have unique descriptions in their files. """ for path, cases in files(self.test_files): with self.subTest(path=path): self.assertUnique(case["description"] for case in cases) def test_all_test_descriptions_are_unique(self): """ All test cases have unique test descriptions in their tests. """ for count, case in enumerate(cases(self.test_files)): with self.subTest(description=case["description"]): self.assertUnique( test["description"] for test in case["tests"] ) print(f"Found {count} test cases.") def test_case_descriptions_do_not_use_modal_verbs(self): for case in cases(self.test_files): with self.subTest(description=case["description"]): self.assertFollowsDescriptionStyle(case["description"]) def test_test_descriptions_do_not_use_modal_verbs(self): for test in tests(self.test_files): with self.subTest(description=test["description"]): self.assertFollowsDescriptionStyle(test["description"]) @unittest.skipIf(jsonschema is None, "Validation library not present!") def test_all_schemas_are_valid(self): """ All schemas are valid under their metaschemas. """ for version in SUITE_ROOT_DIR.iterdir(): if not version.is_dir(): continue Validator = VALIDATORS.get(version.name) if Validator is not None: test_files = collect(version) for case in cases(test_files): with self.subTest(case=case): try: Validator.check_schema(case["schema"]) except asdf._jsonschema.SchemaError: self.fail( "Found an invalid schema." "See the traceback for details on why." ) else: warnings.warn(f"No schema validator for {version.name}") @unittest.skipIf(jsonschema is None, "Validation library not present!") def test_suites_are_valid(self): """ All test files are valid under test-schema.json. """ Validator = asdf._jsonschema.validators.validator_for(TESTSUITE_SCHEMA) validator = Validator(TESTSUITE_SCHEMA) for path, cases in files(self.test_files): with self.subTest(path=path): try: validator.validate(cases) except asdf._jsonschema.ValidationError as error: self.fail(str(error)) def main(arguments): if arguments.command == "check": suite = unittest.TestLoader().loadTestsFromTestCase(SanityTests) result = unittest.TextTestRunner().run(suite) sys.exit(not result.wasSuccessful()) elif arguments.command == "flatten": selected_cases = [case for case in cases(collect(arguments.version))] if arguments.randomize: random.shuffle(selected_cases) json.dump(selected_cases, sys.stdout, indent=4, sort_keys=True) elif arguments.command == "remotes": remotes = { url_for_path(path): json.loads(path.read_text()) for path in collect(REMOTES_DIR) } json.dump(remotes, sys.stdout, indent=4, sort_keys=True) elif arguments.command == "dump_remotes": if arguments.update: shutil.rmtree(arguments.out_dir, ignore_errors=True) try: shutil.copytree(REMOTES_DIR, arguments.out_dir) except FileExistsError: print(f"{arguments.out_dir} already exists. Aborting.") sys.exit(1) elif arguments.command == "serve": try: import flask except ImportError: print(textwrap.dedent(""" The Flask library is required to serve the remote schemas. You can install it by running `pip install Flask`. Alternatively, see the `jsonschema_suite remotes` or `jsonschema_suite dump_remotes` commands to create static files that can be served with your own web server. """.strip("\n"))) sys.exit(1) app = flask.Flask(__name__) @app.route("/") def serve_path(path): return flask.send_from_directory(REMOTES_DIR, path) app.run(port=1234) parser = argparse.ArgumentParser( description="JSON Schema Test Suite utilities", ) subparsers = parser.add_subparsers( help="utility commands", dest="command", metavar="COMMAND" ) subparsers.required = True check = subparsers.add_parser("check", help="Sanity check the test suite.") flatten = subparsers.add_parser( "flatten", help="Output a flattened file containing a selected version's test cases." ) flatten.add_argument( "--randomize", action="store_true", help="Randomize the order of the outputted cases.", ) flatten.add_argument( "version", help="The directory containing the version to output", ) remotes = subparsers.add_parser( "remotes", help="Output the expected URLs and their associated schemas for remote " "ref tests as a JSON object." ) dump_remotes = subparsers.add_parser( "dump_remotes", help="Dump the remote ref schemas into a file tree", ) dump_remotes.add_argument( "--update", action="store_true", help="Update the remotes in an existing directory.", ) dump_remotes.add_argument( "--out-dir", default=REMOTES_DIR, type=os.path.abspath, help="The output directory to create as the root of the file tree", ) serve = subparsers.add_parser( "serve", help="Start a webserver to serve schemas used by remote ref tests." ) if __name__ == "__main__": main(parser.parse_args()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/package.json0000644000175100001770000000050214653725311020511 0ustar00runnerdocker{ "name": "json-schema-test-suite", "version": "0.1.0", "description": "A language agnostic test suite for the JSON Schema specifications", "repository": "github:json-schema-org/JSON-Schema-Test-Suite", "keywords": [ "json-schema", "tests" ], "author": "http://json-schema.org", "license": "MIT" } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.033096 asdf-3.4.0/asdf/_jsonschema/json/remotes/0000755000175100001770000000000014653725331017706 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.037096 asdf-3.4.0/asdf/_jsonschema/json/remotes/baseUriChange/0000755000175100001770000000000014653725331022406 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/baseUriChange/folderInteger.json0000644000175100001770000000003214653725311026063 0ustar00runnerdocker{ "type": "integer" } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.037096 asdf-3.4.0/asdf/_jsonschema/json/remotes/baseUriChangeFolder/0000755000175100001770000000000014653725331023542 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/baseUriChangeFolder/folderInteger.json0000644000175100001770000000003214653725311027217 0ustar00runnerdocker{ "type": "integer" } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.037096 asdf-3.4.0/asdf/_jsonschema/json/remotes/baseUriChangeFolderInSubschema/0000755000175100001770000000000014653725331025664 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/baseUriChangeFolderInSubschema/folderInteger.json0000644000175100001770000000003214653725311031341 0ustar00runnerdocker{ "type": "integer" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/different-id-ref-string.json0000644000175100001770000000020414653725311025211 0ustar00runnerdocker{ "$id": "http://localhost:1234/real-id-ref-string.json", "$defs": {"bar": {"type": "string"}}, "$ref": "#/$defs/bar" } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.037096 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft-next/0000755000175100001770000000000014653725331021762 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.037096 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft-next/baseUriChange/0000755000175100001770000000000014653725331024462 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft-next/baseUriChange/folderInteger.json0000644000175100001770000000012614653725311030143 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/next/schema", "type": "integer" } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.037096 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft-next/baseUriChangeFolder/0000755000175100001770000000000014653725331025616 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft-next/baseUriChangeFolder/folderInteger.json0000644000175100001770000000012614653725311031277 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/next/schema", "type": "integer" } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.037096 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft-next/baseUriChangeFolderInSubschema/0000755000175100001770000000000014653725331027740 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000020500000000000010212 xustar00111 path=asdf-3.4.0/asdf/_jsonschema/json/remotes/draft-next/baseUriChangeFolderInSubschema/folderInteger.json 22 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft-next/baseUriChangeFolderInSubschema/folderInteger.jso0000644000175100001770000000012614653725311033243 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/next/schema", "type": "integer" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft-next/extendible-dynamic-ref.json0000644000175100001770000000101714653725311027171 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/next/schema", "description": "extendible array", "$id": "http://localhost:1234/draft-next/extendible-dynamic-ref.json", "type": "object", "properties": { "elements": { "type": "array", "items": { "$dynamicRef": "#elements" } } }, "required": ["elements"], "additionalProperties": false, "$defs": { "elements": { "$dynamicAnchor": "elements" } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft-next/format-assertion-false.json0000644000175100001770000000073114653725311027241 0ustar00runnerdocker{ "$id": "http://localhost:1234/draft-next/format-assertion-false.json", "$schema": "https://json-schema.org/draft/next/schema", "$vocabulary": { "https://json-schema.org/draft/next/vocab/core": true, "https://json-schema.org/draft/next/vocab/format-assertion": false }, "allOf": [ { "$ref": "https://json-schema.org/draft/next/meta/core" }, { "$ref": "https://json-schema.org/draft/next/meta/format-assertion" } ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft-next/format-assertion-true.json0000644000175100001770000000072714653725311027133 0ustar00runnerdocker{ "$id": "http://localhost:1234/draft-next/format-assertion-true.json", "$schema": "https://json-schema.org/draft/next/schema", "$vocabulary": { "https://json-schema.org/draft/next/vocab/core": true, "https://json-schema.org/draft/next/vocab/format-assertion": true }, "allOf": [ { "$ref": "https://json-schema.org/draft/next/meta/core" }, { "$ref": "https://json-schema.org/draft/next/meta/format-assertion" } ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft-next/integer.json0000644000175100001770000000012614653725311024307 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/next/schema", "type": "integer" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft-next/locationIndependentIdentifier.json0000644000175100001770000000035214653725311030644 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/next/schema", "$defs": { "refToInteger": { "$ref": "#foo" }, "A": { "$anchor": "foo", "type": "integer" } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft-next/metaschema-no-validation.json0000644000175100001770000000071614653725311027530 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/next/schema", "$id": "http://localhost:1234/draft-next/metaschema-no-validation.json", "$vocabulary": { "https://json-schema.org/draft/next/vocab/applicator": true, "https://json-schema.org/draft/next/vocab/core": true }, "allOf": [ { "$ref": "https://json-schema.org/draft/next/meta/applicator" }, { "$ref": "https://json-schema.org/draft/next/meta/core" } ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft-next/name-defs.json0000644000175100001770000000047214653725311024515 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/next/schema", "$defs": { "orNull": { "anyOf": [ { "type": "null" }, { "$ref": "#" } ] } }, "type": "string" } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.037096 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft-next/nested/0000755000175100001770000000000014653725331023244 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft-next/nested/foo-ref-string.json0000644000175100001770000000022714653725311026777 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "properties": { "foo": {"$ref": "string.json"} } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft-next/nested/string.json0000644000175100001770000000012514653725311025441 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/next/schema", "type": "string" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft-next/ref-and-defs.json0000644000175100001770000000044614653725311025112 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/next/schema", "$id": "http://localhost:1234/draft-next/ref-and-defs.json", "$defs": { "inner": { "properties": { "bar": { "type": "string" } } } }, "$ref": "#/$defs/inner" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft-next/subSchemas-defs.json0000644000175100001770000000033514653725311025670 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/next/schema", "$defs": { "integer": { "type": "integer" }, "refToInteger": { "$ref": "#/$defs/integer" } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft-next/subSchemas.json0000644000175100001770000000025214653725311024747 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/next/schema", "integer": { "type": "integer" }, "refToInteger": { "$ref": "#/integer" } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft-next/tree.json0000644000175100001770000000062514653725311023615 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/next/schema", "description": "tree schema, extensible", "$id": "http://localhost:1234/draft-next/tree.json", "$dynamicAnchor": "node", "type": "object", "properties": { "data": true, "children": { "type": "array", "items": { "$dynamicRef": "#node" } } } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0410962 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2019-09/0000755000175100001770000000000014653725331021550 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0410962 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2019-09/baseUriChange/0000755000175100001770000000000014653725331024250 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2019-09/baseUriChange/folderInteger.json0000644000175100001770000000013114653725311027725 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "integer" } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0410962 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2019-09/baseUriChangeFolder/0000755000175100001770000000000014653725331025404 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2019-09/baseUriChangeFolder/folderInteger.json0000644000175100001770000000013114653725311031061 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "integer" } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0410962 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2019-09/baseUriChangeFolderInSubschema/0000755000175100001770000000000014653725331027526 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000020700000000000010214 xustar00113 path=asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2019-09/baseUriChangeFolderInSubschema/folderInteger.json 22 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2019-09/baseUriChangeFolderInSubschema/folderInteger.j0000644000175100001770000000013114653725311032463 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "integer" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2019-09/dependentRequired.json0000644000175100001770000000030314653725311026104 0ustar00runnerdocker{ "$id": "http://localhost:1234/draft2019-09/dependentRequired.json", "$schema": "https://json-schema.org/draft/2019-09/schema", "dependentRequired": { "foo": ["bar"] } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2019-09/extendible-dynamic-ref.json0000644000175100001770000000102414653725311026755 0ustar00runnerdocker{ "description": "extendible array", "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "http://localhost:1234/draft2019-09/extendible-dynamic-ref.json", "type": "object", "properties": { "elements": { "type": "array", "items": { "$dynamicRef": "#elements" } } }, "required": ["elements"], "additionalProperties": false, "$defs": { "elements": { "$dynamicAnchor": "elements" } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2019-09/ignore-prefixItems.json0000644000175100001770000000030214653725311026214 0ustar00runnerdocker{ "$id": "http://localhost:1234/draft2019-09/ignore-prefixItems.json", "$schema": "https://json-schema.org/draft/2019-09/schema", "prefixItems": [ {"type": "string"} ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2019-09/integer.json0000644000175100001770000000013114653725311024071 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "integer" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2019-09/locationIndependentIdentifier.json0000644000175100001770000000035514653725311030435 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2019-09/schema", "$defs": { "refToInteger": { "$ref": "#foo" }, "A": { "$anchor": "foo", "type": "integer" } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2019-09/metaschema-no-validation.json0000644000175100001770000000073714653725311027321 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "http://localhost:1234/draft2019-09/metaschema-no-validation.json", "$vocabulary": { "https://json-schema.org/draft/2019-09/vocab/applicator": true, "https://json-schema.org/draft/2019-09/vocab/core": true }, "allOf": [ { "$ref": "https://json-schema.org/draft/2019-09/meta/applicator" }, { "$ref": "https://json-schema.org/draft/2019-09/meta/core" } ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2019-09/name-defs.json0000644000175100001770000000047514653725311024306 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2019-09/schema", "$defs": { "orNull": { "anyOf": [ { "type": "null" }, { "$ref": "#" } ] } }, "type": "string" } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0410962 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2019-09/nested/0000755000175100001770000000000014653725331023032 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2019-09/nested/foo-ref-string.json0000644000175100001770000000023214653725311026561 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "properties": { "foo": {"$ref": "string.json"} } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2019-09/nested/string.json0000644000175100001770000000013014653725311025223 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "string" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2019-09/ref-and-defs.json0000644000175100001770000000045314653725311024676 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "http://localhost:1234/draft2019-09/ref-and-defs.json", "$defs": { "inner": { "properties": { "bar": { "type": "string" } } } }, "$ref": "#/$defs/inner" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2019-09/subSchemas-defs.json0000644000175100001770000000034014653725311025452 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2019-09/schema", "$defs": { "integer": { "type": "integer" }, "refToInteger": { "$ref": "#/$defs/integer" } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2019-09/subSchemas.json0000644000175100001770000000025514653725311024540 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2019-09/schema", "integer": { "type": "integer" }, "refToInteger": { "$ref": "#/integer" } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2019-09/tree.json0000644000175100001770000000063214653725311023401 0ustar00runnerdocker{ "description": "tree schema, extensible", "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "http://localhost:1234/draft2019-09/tree.json", "$dynamicAnchor": "node", "type": "object", "properties": { "data": true, "children": { "type": "array", "items": { "$dynamicRef": "#node" } } } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0410962 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2020-12/0000755000175100001770000000000014653725331021532 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0410962 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2020-12/baseUriChange/0000755000175100001770000000000014653725331024232 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2020-12/baseUriChange/folderInteger.json0000644000175100001770000000013114653725311027707 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "integer" } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0410962 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2020-12/baseUriChangeFolder/0000755000175100001770000000000014653725331025366 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2020-12/baseUriChangeFolder/folderInteger.json0000644000175100001770000000013114653725311031043 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "integer" } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0450962 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2020-12/baseUriChangeFolderInSubschema/0000755000175100001770000000000014653725331027510 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000020700000000000010214 xustar00113 path=asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2020-12/baseUriChangeFolderInSubschema/folderInteger.json 22 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2020-12/baseUriChangeFolderInSubschema/folderInteger.j0000644000175100001770000000013114653725311032445 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "integer" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2020-12/extendible-dynamic-ref.json0000644000175100001770000000102414653725311026737 0ustar00runnerdocker{ "description": "extendible array", "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/extendible-dynamic-ref.json", "type": "object", "properties": { "elements": { "type": "array", "items": { "$dynamicRef": "#elements" } } }, "required": ["elements"], "additionalProperties": false, "$defs": { "elements": { "$dynamicAnchor": "elements" } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2020-12/format-assertion-false.json0000644000175100001770000000075214653725311027014 0ustar00runnerdocker{ "$id": "http://localhost:1234/draft2020-12/format-assertion-false.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "$vocabulary": { "https://json-schema.org/draft/2020-12/vocab/core": true, "https://json-schema.org/draft/2020-12/vocab/format-assertion": false }, "allOf": [ { "$ref": "https://json-schema.org/draft/2020-12/meta/core" }, { "$ref": "https://json-schema.org/draft/2020-12/meta/format-assertion" } ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2020-12/format-assertion-true.json0000644000175100001770000000075014653725311026677 0ustar00runnerdocker{ "$id": "http://localhost:1234/draft2020-12/format-assertion-true.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "$vocabulary": { "https://json-schema.org/draft/2020-12/vocab/core": true, "https://json-schema.org/draft/2020-12/vocab/format-assertion": true }, "allOf": [ { "$ref": "https://json-schema.org/draft/2020-12/meta/core" }, { "$ref": "https://json-schema.org/draft/2020-12/meta/format-assertion" } ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2020-12/integer.json0000644000175100001770000000013114653725311024053 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "integer" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2020-12/locationIndependentIdentifier.json0000644000175100001770000000035514653725311030417 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "refToInteger": { "$ref": "#foo" }, "A": { "$anchor": "foo", "type": "integer" } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2020-12/metaschema-no-validation.json0000644000175100001770000000073714653725311027303 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/metaschema-no-validation.json", "$vocabulary": { "https://json-schema.org/draft/2020-12/vocab/applicator": true, "https://json-schema.org/draft/2020-12/vocab/core": true }, "allOf": [ { "$ref": "https://json-schema.org/draft/2020-12/meta/applicator" }, { "$ref": "https://json-schema.org/draft/2020-12/meta/core" } ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2020-12/name-defs.json0000644000175100001770000000047514653725311024270 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "orNull": { "anyOf": [ { "type": "null" }, { "$ref": "#" } ] } }, "type": "string" } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0450962 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2020-12/nested/0000755000175100001770000000000014653725331023014 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2020-12/nested/foo-ref-string.json0000644000175100001770000000023214653725311026543 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": {"$ref": "string.json"} } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2020-12/nested/string.json0000644000175100001770000000013014653725311025205 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2020-12/prefixItems.json0000644000175100001770000000027314653725311024724 0ustar00runnerdocker{ "$id": "http://localhost:1234/draft2020-12/prefixItems.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [ {"type": "string"} ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2020-12/ref-and-defs.json0000644000175100001770000000045314653725311024660 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/ref-and-defs.json", "$defs": { "inner": { "properties": { "bar": { "type": "string" } } } }, "$ref": "#/$defs/inner" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2020-12/subSchemas-defs.json0000644000175100001770000000034014653725311025434 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "integer": { "type": "integer" }, "refToInteger": { "$ref": "#/$defs/integer" } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2020-12/subSchemas.json0000644000175100001770000000025514653725311024522 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2020-12/schema", "integer": { "type": "integer" }, "refToInteger": { "$ref": "#/integer" } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft2020-12/tree.json0000644000175100001770000000063214653725311023363 0ustar00runnerdocker{ "description": "tree schema, extensible", "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/tree.json", "$dynamicAnchor": "node", "type": "object", "properties": { "data": true, "children": { "type": "array", "items": { "$dynamicRef": "#node" } } } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0450962 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft7/0000755000175100001770000000000014653725331021075 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/draft7/ignore-dependentRequired.json0000644000175100001770000000025514653725311026720 0ustar00runnerdocker{ "$id": "http://localhost:1234/draft7/integer.json", "$schema": "http://json-schema.org/draft-07/schema#", "dependentRequired": { "foo": ["bar"] } }././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/extendible-dynamic-ref.json0000644000175100001770000000071014653725311025114 0ustar00runnerdocker{ "description": "extendible array", "$id": "http://localhost:1234/extendible-dynamic-ref.json", "type": "object", "properties": { "elements": { "type": "array", "items": { "$dynamicRef": "#elements" } } }, "required": ["elements"], "additionalProperties": false, "$defs": { "elements": { "$dynamicAnchor": "elements" } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/integer.json0000644000175100001770000000003214653725311022227 0ustar00runnerdocker{ "type": "integer" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/locationIndependentIdentifier.json0000644000175100001770000000025614653725311026573 0ustar00runnerdocker{ "$defs": { "refToInteger": { "$ref": "#foo" }, "A": { "$anchor": "foo", "type": "integer" } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/locationIndependentIdentifierDraft4.json0000644000175100001770000000026014653725311027633 0ustar00runnerdocker{ "definitions": { "refToInteger": { "$ref": "#foo" }, "A": { "id": "#foo", "type": "integer" } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/locationIndependentIdentifierPre2019.json0000644000175100001770000000026114653725311027552 0ustar00runnerdocker{ "definitions": { "refToInteger": { "$ref": "#foo" }, "A": { "$id": "#foo", "type": "integer" } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/name-defs.json0000644000175100001770000000037614653725311022444 0ustar00runnerdocker{ "$defs": { "orNull": { "anyOf": [ { "type": "null" }, { "$ref": "#" } ] } }, "type": "string" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/name.json0000644000175100001770000000040414653725311021515 0ustar00runnerdocker{ "definitions": { "orNull": { "anyOf": [ { "type": "null" }, { "$ref": "#" } ] } }, "type": "string" } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0450962 asdf-3.4.0/asdf/_jsonschema/json/remotes/nested/0000755000175100001770000000000014653725331021170 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/nested/foo-ref-string.json0000644000175100001770000000013314653725311024717 0ustar00runnerdocker{ "type": "object", "properties": { "foo": {"$ref": "string.json"} } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/nested/string.json0000644000175100001770000000003114653725311023361 0ustar00runnerdocker{ "type": "string" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/nested-absolute-ref-to-string.json0000644000175100001770000000031014653725311026365 0ustar00runnerdocker{ "$defs": { "bar": { "$id": "http://localhost:1234/the-nested-id.json", "type": "string" } }, "$ref": "http://localhost:1234/the-nested-id.json" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/ref-and-definitions.json0000644000175100001770000000040314653725311024421 0ustar00runnerdocker{ "$id": "http://localhost:1234/ref-and-definitions.json", "definitions": { "inner": { "properties": { "bar": { "type": "string" } } } }, "allOf": [ { "$ref": "#/definitions/inner" } ] } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/ref-and-defs.json0000644000175100001770000000033714653725311023035 0ustar00runnerdocker{ "$id": "http://localhost:1234/ref-and-defs.json", "$defs": { "inner": { "properties": { "bar": { "type": "string" } } } }, "$ref": "#/$defs/inner" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/subSchemas-defs.json0000644000175100001770000000024114653725311023610 0ustar00runnerdocker{ "$defs": { "integer": { "type": "integer" }, "refToInteger": { "$ref": "#/$defs/integer" } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/subSchemas.json0000644000175100001770000000015614653725311022676 0ustar00runnerdocker{ "integer": { "type": "integer" }, "refToInteger": { "$ref": "#/integer" } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/tree.json0000644000175100001770000000051614653725311021540 0ustar00runnerdocker{ "description": "tree schema, extensible", "$id": "http://localhost:1234/tree.json", "$dynamicAnchor": "node", "type": "object", "properties": { "data": true, "children": { "type": "array", "items": { "$dynamicRef": "#node" } } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/remotes/urn-ref-string.json0000644000175100001770000000020414653725311023455 0ustar00runnerdocker{ "$id": "urn:uuid:feebdaed-ffff-0000-ffff-0000deadbeef", "$defs": {"bar": {"type": "string"}}, "$ref": "#/$defs/bar" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/test-schema.json0000644000175100001770000000415314653725311021341 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "A schema for files contained within this suite", "type": "array", "minItems": 1, "items": { "description": "An individual test case, containing multiple tests of a single schema's behavior", "type": "object", "required": [ "description", "schema", "tests" ], "properties": { "description": { "description": "The test case description", "type": "string" }, "comment": { "description": "Any additional comments about the test case", "type": "string" }, "schema": { "description": "A valid JSON Schema (one written for the corresponding version directory that the file sits within)." }, "tests": { "description": "A set of related tests all using the same schema", "type": "array", "items": { "$ref": "#/$defs/test" }, "minItems": 1 } }, "additionalProperties": false }, "$defs": { "test": { "description": "A single test", "type": "object", "required": [ "description", "data", "valid" ], "properties": { "description": { "description": "The test description, briefly explaining which behavior it exercises", "type": "string" }, "comment": { "description": "Any additional comments about the test", "type": "string" }, "data": { "description": "The instance which should be validated against the schema in \"schema\"." }, "valid": { "description": "Whether the validation process of this instance should consider the instance valid or not", "type": "boolean" } }, "additionalProperties": false } } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0130956 asdf-3.4.0/asdf/_jsonschema/json/tests/0000755000175100001770000000000014653725331017372 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0530963 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/0000755000175100001770000000000014653725331021446 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/additionalProperties.json0000644000175100001770000001147414653725311026533 0ustar00runnerdocker[ { "description": "additionalProperties being false does not allow other properties", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": {"foo": {}, "bar": {}}, "patternProperties": { "^v": {} }, "additionalProperties": false }, "tests": [ { "description": "no additional properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "an additional property is invalid", "data": {"foo" : 1, "bar" : 2, "quux" : "boom"}, "valid": false }, { "description": "ignores arrays", "data": [1, 2, 3], "valid": true }, { "description": "ignores strings", "data": "foobarbaz", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "patternProperties are not additional properties", "data": {"foo":1, "vroom": 2}, "valid": true } ] }, { "description": "non-ASCII pattern with additionalProperties", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "patternProperties": {"^á": {}}, "additionalProperties": false }, "tests": [ { "description": "matching the pattern is valid", "data": {"ármányos": 2}, "valid": true }, { "description": "not matching the pattern is invalid", "data": {"élmény": 2}, "valid": false } ] }, { "description": "additionalProperties with schema", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": {"foo": {}, "bar": {}}, "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "no additional properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "an additional valid property is valid", "data": {"foo" : 1, "bar" : 2, "quux" : true}, "valid": true }, { "description": "an additional invalid property is invalid", "data": {"foo" : 1, "bar" : 2, "quux" : 12}, "valid": false } ] }, { "description": "additionalProperties can exist by itself", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "an additional valid property is valid", "data": {"foo" : true}, "valid": true }, { "description": "an additional invalid property is invalid", "data": {"foo" : 1}, "valid": false } ] }, { "description": "additionalProperties are allowed by default", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": {"foo": {}, "bar": {}} }, "tests": [ { "description": "additional properties are allowed", "data": {"foo": 1, "bar": 2, "quux": true}, "valid": true } ] }, { "description": "additionalProperties does not look in applicators", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "allOf": [ {"properties": {"foo": {}}} ], "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "properties defined in allOf are not examined", "data": {"foo": 1, "bar": true}, "valid": false } ] }, { "description": "additionalProperties with null valued instance properties", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "additionalProperties": { "type": "null" } }, "tests": [ { "description": "allows null values", "data": {"foo": null}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/allOf.json0000644000175100001770000002073114653725311023377 0ustar00runnerdocker[ { "description": "allOf", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "allOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "allOf", "data": {"foo": "baz", "bar": 2}, "valid": true }, { "description": "mismatch second", "data": {"foo": "baz"}, "valid": false }, { "description": "mismatch first", "data": {"bar": 2}, "valid": false }, { "description": "wrong type", "data": {"foo": "baz", "bar": "quux"}, "valid": false } ] }, { "description": "allOf with base schema", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": {"bar": {"type": "integer"}}, "required": ["bar"], "allOf" : [ { "properties": { "foo": {"type": "string"} }, "required": ["foo"] }, { "properties": { "baz": {"type": "null"} }, "required": ["baz"] } ] }, "tests": [ { "description": "valid", "data": {"foo": "quux", "bar": 2, "baz": null}, "valid": true }, { "description": "mismatch base schema", "data": {"foo": "quux", "baz": null}, "valid": false }, { "description": "mismatch first allOf", "data": {"bar": 2, "baz": null}, "valid": false }, { "description": "mismatch second allOf", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "mismatch both", "data": {"bar": 2}, "valid": false } ] }, { "description": "allOf simple types", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "allOf": [ {"maximum": 30}, {"minimum": 20} ] }, "tests": [ { "description": "valid", "data": 25, "valid": true }, { "description": "mismatch one", "data": 35, "valid": false } ] }, { "description": "allOf with boolean schemas, all true", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "allOf": [true, true] }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "allOf with boolean schemas, some false", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "allOf": [true, false] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "allOf with boolean schemas, all false", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "allOf": [false, false] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "allOf with one empty schema", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "allOf": [ {} ] }, "tests": [ { "description": "any data is valid", "data": 1, "valid": true } ] }, { "description": "allOf with two empty schemas", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "allOf": [ {}, {} ] }, "tests": [ { "description": "any data is valid", "data": 1, "valid": true } ] }, { "description": "allOf with the first empty schema", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "allOf": [ {}, { "type": "number" } ] }, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is invalid", "data": "foo", "valid": false } ] }, { "description": "allOf with the last empty schema", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "allOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is invalid", "data": "foo", "valid": false } ] }, { "description": "nested allOf, to check validation semantics", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "allOf": [ { "allOf": [ { "type": "null" } ] } ] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "anything non-null is invalid", "data": 123, "valid": false } ] }, { "description": "allOf combined with anyOf, oneOf", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "allOf": [ { "multipleOf": 2 } ], "anyOf": [ { "multipleOf": 3 } ], "oneOf": [ { "multipleOf": 5 } ] }, "tests": [ { "description": "allOf: false, anyOf: false, oneOf: false", "data": 1, "valid": false }, { "description": "allOf: false, anyOf: false, oneOf: true", "data": 5, "valid": false }, { "description": "allOf: false, anyOf: true, oneOf: false", "data": 3, "valid": false }, { "description": "allOf: false, anyOf: true, oneOf: true", "data": 15, "valid": false }, { "description": "allOf: true, anyOf: false, oneOf: false", "data": 2, "valid": false }, { "description": "allOf: true, anyOf: false, oneOf: true", "data": 10, "valid": false }, { "description": "allOf: true, anyOf: true, oneOf: false", "data": 6, "valid": false }, { "description": "allOf: true, anyOf: true, oneOf: true", "data": 30, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/anchor.json0000644000175100001770000001574014653725311023620 0ustar00runnerdocker[ { "description": "Location-independent identifier", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$ref": "#foo", "$defs": { "A": { "$anchor": "foo", "type": "integer" } } }, "tests": [ { "data": 1, "description": "match", "valid": true }, { "data": "a", "description": "mismatch", "valid": false } ] }, { "description": "Location-independent identifier with absolute URI", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$ref": "http://localhost:1234/draft-next/bar#foo", "$defs": { "A": { "$id": "http://localhost:1234/draft-next/bar", "$anchor": "foo", "type": "integer" } } }, "tests": [ { "data": 1, "description": "match", "valid": true }, { "data": "a", "description": "mismatch", "valid": false } ] }, { "description": "Location-independent identifier with base URI change in subschema", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "http://localhost:1234/draft-next/root", "$ref": "http://localhost:1234/draft-next/nested.json#foo", "$defs": { "A": { "$id": "nested.json", "$defs": { "B": { "$anchor": "foo", "type": "integer" } } } } }, "tests": [ { "data": 1, "description": "match", "valid": true }, { "data": "a", "description": "mismatch", "valid": false } ] }, { "description": "$anchor inside an enum is not a real identifier", "comment": "the implementation must not be confused by an $anchor buried in the enum", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$defs": { "anchor_in_enum": { "enum": [ { "$anchor": "my_anchor", "type": "null" } ] }, "real_identifier_in_schema": { "$anchor": "my_anchor", "type": "string" }, "zzz_anchor_in_const": { "const": { "$anchor": "my_anchor", "type": "null" } } }, "anyOf": [ { "$ref": "#/$defs/anchor_in_enum" }, { "$ref": "#my_anchor" } ] }, "tests": [ { "description": "exact match to enum, and type matches", "data": { "$anchor": "my_anchor", "type": "null" }, "valid": true }, { "description": "in implementations that strip $anchor, this may match either $def", "data": { "type": "null" }, "valid": false }, { "description": "match $ref to $anchor", "data": "a string to match #/$defs/anchor_in_enum", "valid": true }, { "description": "no match on enum or $ref to $anchor", "data": 1, "valid": false } ] }, { "description": "same $anchor with different base uri", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "http://localhost:1234/draft-next/foobar", "$defs": { "A": { "$id": "child1", "allOf": [ { "$id": "child2", "$anchor": "my_anchor", "type": "number" }, { "$anchor": "my_anchor", "type": "string" } ] } }, "$ref": "child1#my_anchor" }, "tests": [ { "description": "$ref resolves to /$defs/A/allOf/1", "data": "a", "valid": true }, { "description": "$ref does not resolve to /$defs/A/allOf/0", "data": 1, "valid": false } ] }, { "description": "non-schema object containing an $anchor property", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$defs": { "const_not_anchor": { "const": { "$anchor": "not_a_real_anchor" } } }, "if": { "const": "skip not_a_real_anchor" }, "then": true, "else" : { "$ref": "#/$defs/const_not_anchor" } }, "tests": [ { "description": "skip traversing definition for a valid result", "data": "skip not_a_real_anchor", "valid": true }, { "description": "const at const_not_anchor does not match", "data": 1, "valid": false } ] }, { "description": "invalid anchors", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$ref": "https://json-schema.org/draft/next/schema" }, "tests": [ { "description": "MUST start with a letter (and not #)", "data": { "$anchor" : "#foo" }, "valid": false }, { "description": "JSON pointers are not valid", "data": { "$anchor" : "/a/b" }, "valid": false }, { "description": "invalid with valid beginning", "data": { "$anchor" : "foo#something" }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/anyOf.json0000644000175100001770000001247514653725311023424 0ustar00runnerdocker[ { "description": "anyOf", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "anyOf": [ { "type": "integer" }, { "minimum": 2 } ] }, "tests": [ { "description": "first anyOf valid", "data": 1, "valid": true }, { "description": "second anyOf valid", "data": 2.5, "valid": true }, { "description": "both anyOf valid", "data": 3, "valid": true }, { "description": "neither anyOf valid", "data": 1.5, "valid": false } ] }, { "description": "anyOf with base schema", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "string", "anyOf" : [ { "maxLength": 2 }, { "minLength": 4 } ] }, "tests": [ { "description": "mismatch base schema", "data": 3, "valid": false }, { "description": "one anyOf valid", "data": "foobar", "valid": true }, { "description": "both anyOf invalid", "data": "foo", "valid": false } ] }, { "description": "anyOf with boolean schemas, all true", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "anyOf": [true, true] }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "anyOf with boolean schemas, some true", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "anyOf": [true, false] }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "anyOf with boolean schemas, all false", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "anyOf": [false, false] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "anyOf complex types", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "anyOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "first anyOf valid (complex)", "data": {"bar": 2}, "valid": true }, { "description": "second anyOf valid (complex)", "data": {"foo": "baz"}, "valid": true }, { "description": "both anyOf valid (complex)", "data": {"foo": "baz", "bar": 2}, "valid": true }, { "description": "neither anyOf valid (complex)", "data": {"foo": 2, "bar": "quux"}, "valid": false } ] }, { "description": "anyOf with one empty schema", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "anyOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "string is valid", "data": "foo", "valid": true }, { "description": "number is valid", "data": 123, "valid": true } ] }, { "description": "nested anyOf, to check validation semantics", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "anyOf": [ { "anyOf": [ { "type": "null" } ] } ] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "anything non-null is invalid", "data": 123, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/boolean_schema.json0000644000175100001770000000540214653725311025277 0ustar00runnerdocker[ { "description": "boolean schema 'true'", "schema": true, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is valid", "data": "foo", "valid": true }, { "description": "boolean true is valid", "data": true, "valid": true }, { "description": "boolean false is valid", "data": false, "valid": true }, { "description": "null is valid", "data": null, "valid": true }, { "description": "object is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "empty object is valid", "data": {}, "valid": true }, { "description": "array is valid", "data": ["foo"], "valid": true }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "boolean schema 'false'", "schema": false, "tests": [ { "description": "number is invalid", "data": 1, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false }, { "description": "boolean true is invalid", "data": true, "valid": false }, { "description": "boolean false is invalid", "data": false, "valid": false }, { "description": "null is invalid", "data": null, "valid": false }, { "description": "object is invalid", "data": {"foo": "bar"}, "valid": false }, { "description": "empty object is invalid", "data": {}, "valid": false }, { "description": "array is invalid", "data": ["foo"], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/const.json0000644000175100001770000002527014653725311023473 0ustar00runnerdocker[ { "description": "const validation", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "const": 2 }, "tests": [ { "description": "same value is valid", "data": 2, "valid": true }, { "description": "another value is invalid", "data": 5, "valid": false }, { "description": "another type is invalid", "data": "a", "valid": false } ] }, { "description": "const with object", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "const": {"foo": "bar", "baz": "bax"} }, "tests": [ { "description": "same object is valid", "data": {"foo": "bar", "baz": "bax"}, "valid": true }, { "description": "same object with different property order is valid", "data": {"baz": "bax", "foo": "bar"}, "valid": true }, { "description": "another object is invalid", "data": {"foo": "bar"}, "valid": false }, { "description": "another type is invalid", "data": [1, 2], "valid": false } ] }, { "description": "const with array", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "const": [{ "foo": "bar" }] }, "tests": [ { "description": "same array is valid", "data": [{"foo": "bar"}], "valid": true }, { "description": "another array item is invalid", "data": [2], "valid": false }, { "description": "array with additional items is invalid", "data": [1, 2, 3], "valid": false } ] }, { "description": "const with null", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "const": null }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "not null is invalid", "data": 0, "valid": false } ] }, { "description": "const with false does not match 0", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "const": false }, "tests": [ { "description": "false is valid", "data": false, "valid": true }, { "description": "integer zero is invalid", "data": 0, "valid": false }, { "description": "float zero is invalid", "data": 0.0, "valid": false } ] }, { "description": "const with true does not match 1", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "const": true }, "tests": [ { "description": "true is valid", "data": true, "valid": true }, { "description": "integer one is invalid", "data": 1, "valid": false }, { "description": "float one is invalid", "data": 1.0, "valid": false } ] }, { "description": "const with [false] does not match [0]", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "const": [false] }, "tests": [ { "description": "[false] is valid", "data": [false], "valid": true }, { "description": "[0] is invalid", "data": [0], "valid": false }, { "description": "[0.0] is invalid", "data": [0.0], "valid": false } ] }, { "description": "const with [true] does not match [1]", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "const": [true] }, "tests": [ { "description": "[true] is valid", "data": [true], "valid": true }, { "description": "[1] is invalid", "data": [1], "valid": false }, { "description": "[1.0] is invalid", "data": [1.0], "valid": false } ] }, { "description": "const with {\"a\": false} does not match {\"a\": 0}", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "const": {"a": false} }, "tests": [ { "description": "{\"a\": false} is valid", "data": {"a": false}, "valid": true }, { "description": "{\"a\": 0} is invalid", "data": {"a": 0}, "valid": false }, { "description": "{\"a\": 0.0} is invalid", "data": {"a": 0.0}, "valid": false } ] }, { "description": "const with {\"a\": true} does not match {\"a\": 1}", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "const": {"a": true} }, "tests": [ { "description": "{\"a\": true} is valid", "data": {"a": true}, "valid": true }, { "description": "{\"a\": 1} is invalid", "data": {"a": 1}, "valid": false }, { "description": "{\"a\": 1.0} is invalid", "data": {"a": 1.0}, "valid": false } ] }, { "description": "const with 0 does not match other zero-like types", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "const": 0 }, "tests": [ { "description": "false is invalid", "data": false, "valid": false }, { "description": "integer zero is valid", "data": 0, "valid": true }, { "description": "float zero is valid", "data": 0.0, "valid": true }, { "description": "empty object is invalid", "data": {}, "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false }, { "description": "empty string is invalid", "data": "", "valid": false } ] }, { "description": "const with 1 does not match true", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "const": 1 }, "tests": [ { "description": "true is invalid", "data": true, "valid": false }, { "description": "integer one is valid", "data": 1, "valid": true }, { "description": "float one is valid", "data": 1.0, "valid": true } ] }, { "description": "const with -2.0 matches integer and float types", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "const": -2.0 }, "tests": [ { "description": "integer -2 is valid", "data": -2, "valid": true }, { "description": "integer 2 is invalid", "data": 2, "valid": false }, { "description": "float -2.0 is valid", "data": -2.0, "valid": true }, { "description": "float 2.0 is invalid", "data": 2.0, "valid": false }, { "description": "float -2.00001 is invalid", "data": -2.00001, "valid": false } ] }, { "description": "float and integers are equal up to 64-bit representation limits", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "const": 9007199254740992 }, "tests": [ { "description": "integer is valid", "data": 9007199254740992, "valid": true }, { "description": "integer minus one is invalid", "data": 9007199254740991, "valid": false }, { "description": "float is valid", "data": 9007199254740992.0, "valid": true }, { "description": "float minus one is invalid", "data": 9007199254740991.0, "valid": false } ] }, { "description": "nul characters in strings", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "const": "hello\u0000there" }, "tests": [ { "description": "match string with nul", "data": "hello\u0000there", "valid": true }, { "description": "do not match string lacking nul", "data": "hellothere", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/contains.json0000644000175100001770000002035014653725311024155 0ustar00runnerdocker[ { "description": "contains keyword validation", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "contains": { "minimum": 5 } }, "tests": [ { "description": "array with item matching schema (5) is valid", "data": [3, 4, 5], "valid": true }, { "description": "array with item matching schema (6) is valid", "data": [3, 4, 6], "valid": true }, { "description": "array with two items matching schema (5, 6) is valid", "data": [3, 4, 5, 6], "valid": true }, { "description": "array without items matching schema is invalid", "data": [2, 3, 4], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false }, { "description": "object with property matching schema (5) is valid", "data": { "a": 3, "b": 4, "c": 5 }, "valid": true }, { "description": "object with property matching schema (6) is valid", "data": { "a": 3, "b": 4, "c": 6 }, "valid": true }, { "description": "object with two properties matching schema (5, 6) is valid", "data": { "a": 3, "b": 4, "c": 5, "d": 6 }, "valid": true }, { "description": "object without properties matching schema is invalid", "data": { "a": 2, "b": 3, "c": 4 }, "valid": false }, { "description": "empty object is invalid", "data": {}, "valid": false }, { "description": "not array or object is valid", "data": 42, "valid": true } ] }, { "description": "contains keyword with const keyword", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "contains": { "const": 5 } }, "tests": [ { "description": "array with item 5 is valid", "data": [3, 4, 5], "valid": true }, { "description": "array with two items 5 is valid", "data": [3, 4, 5, 5], "valid": true }, { "description": "array without item 5 is invalid", "data": [1, 2, 3, 4], "valid": false }, { "description": "object with property 5 is valid", "data": { "a": 3, "b": 4, "c": 5 }, "valid": true }, { "description": "object with two properties 5 is valid", "data": { "a": 3, "b": 4, "c": 5, "d": 5 }, "valid": true }, { "description": "object without property 5 is invalid", "data": { "a": 1, "b": 2, "c": 3, "d": 4 }, "valid": false } ] }, { "description": "contains keyword with boolean schema true", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "contains": true }, "tests": [ { "description": "any non-empty array is valid", "data": ["foo"], "valid": true }, { "description": "empty array is invalid", "data": [], "valid": false }, { "description": "any non-empty object is valid", "data": { "a": "foo" }, "valid": true }, { "description": "empty object is invalid", "data": {}, "valid": false } ] }, { "description": "contains keyword with boolean schema false", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "contains": false }, "tests": [ { "description": "any non-empty array is invalid", "data": ["foo"], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false }, { "description": "any non-empty object is invalid", "data": ["foo"], "valid": false }, { "description": "empty object is invalid", "data": {}, "valid": false }, { "description": "non-arrays/objects are valid", "data": "contains does not apply to strings", "valid": true } ] }, { "description": "items + contains", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "additionalProperties": { "multipleOf": 2 }, "items": { "multipleOf": 2 }, "contains": { "multipleOf": 3 } }, "tests": [ { "description": "matches items, does not match contains", "data": [2, 4, 8], "valid": false }, { "description": "does not match items, matches contains", "data": [3, 6, 9], "valid": false }, { "description": "matches both items and contains", "data": [6, 12], "valid": true }, { "description": "matches neither items nor contains", "data": [1, 5], "valid": false }, { "description": "matches additionalProperties, does not match contains", "data": { "a": 2, "b": 4, "c": 8 }, "valid": false }, { "description": "does not match additionalProperties, matches contains", "data": { "a": 3, "b": 6, "c": 9 }, "valid": false }, { "description": "matches both additionalProperties and contains", "data": { "a": 6, "b": 12 }, "valid": true }, { "description": "matches neither additionalProperties nor contains", "data": { "a": 1, "b": 5 }, "valid": false } ] }, { "description": "contains with false if subschema", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "contains": { "if": false, "else": true } }, "tests": [ { "description": "any non-empty array is valid", "data": ["foo"], "valid": true }, { "description": "empty array is invalid", "data": [], "valid": false }, { "description": "any non-empty object is valid", "data": { "a": "foo" }, "valid": true }, { "description": "empty object is invalid", "data": {}, "valid": false } ] }, { "description": "contains with null instance elements", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "contains": { "type": "null" } }, "tests": [ { "description": "allows null items", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/content.json0000644000175100001770000001044114653725311024011 0ustar00runnerdocker[ { "description": "validation of string-encoded content based on media type", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "contentMediaType": "application/json" }, "tests": [ { "description": "a valid JSON document", "data": "{\"foo\": \"bar\"}", "valid": true }, { "description": "an invalid JSON document; validates true", "data": "{:}", "valid": true }, { "description": "ignores non-strings", "data": 100, "valid": true } ] }, { "description": "validation of binary string-encoding", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "contentEncoding": "base64" }, "tests": [ { "description": "a valid base64 string", "data": "eyJmb28iOiAiYmFyIn0K", "valid": true }, { "description": "an invalid base64 string (% is not a valid character); validates true", "data": "eyJmb28iOi%iYmFyIn0K", "valid": true }, { "description": "ignores non-strings", "data": 100, "valid": true } ] }, { "description": "validation of binary-encoded media type documents", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "contentMediaType": "application/json", "contentEncoding": "base64" }, "tests": [ { "description": "a valid base64-encoded JSON document", "data": "eyJmb28iOiAiYmFyIn0K", "valid": true }, { "description": "a validly-encoded invalid JSON document; validates true", "data": "ezp9Cg==", "valid": true }, { "description": "an invalid base64 string that is valid JSON; validates true", "data": "{}", "valid": true }, { "description": "ignores non-strings", "data": 100, "valid": true } ] }, { "description": "validation of binary-encoded media type documents with schema", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "contentMediaType": "application/json", "contentEncoding": "base64", "contentSchema": { "type": "object", "required": ["foo"], "properties": { "foo": { "type": "string" } } } }, "tests": [ { "description": "a valid base64-encoded JSON document", "data": "eyJmb28iOiAiYmFyIn0K", "valid": true }, { "description": "another valid base64-encoded JSON document", "data": "eyJib28iOiAyMCwgImZvbyI6ICJiYXoifQ==", "valid": true }, { "description": "an invalid base64-encoded JSON document; validates true", "data": "eyJib28iOiAyMH0=", "valid": true }, { "description": "an empty object as a base64-encoded JSON document; validates true", "data": "e30=", "valid": true }, { "description": "an empty array as a base64-encoded JSON document", "data": "W10=", "valid": true }, { "description": "a validly-encoded invalid JSON document; validates true", "data": "ezp9Cg==", "valid": true }, { "description": "an invalid base64 string that is valid JSON; validates true", "data": "{}", "valid": true }, { "description": "ignores non-strings", "data": 100, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/default.json0000644000175100001770000000460314653725311023766 0ustar00runnerdocker[ { "description": "invalid type for default", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": { "foo": { "type": "integer", "default": [] } } }, "tests": [ { "description": "valid when property is specified", "data": {"foo": 13}, "valid": true }, { "description": "still valid when the invalid default is used", "data": {}, "valid": true } ] }, { "description": "invalid string value for default", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": { "bar": { "type": "string", "minLength": 4, "default": "bad" } } }, "tests": [ { "description": "valid when property is specified", "data": {"bar": "good"}, "valid": true }, { "description": "still valid when the invalid default is used", "data": {}, "valid": true } ] }, { "description": "the default keyword does not do anything if the property is missing", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "properties": { "alpha": { "type": "number", "maximum": 3, "default": 5 } } }, "tests": [ { "description": "an explicit property value is checked against maximum (passing)", "data": { "alpha": 1 }, "valid": true }, { "description": "an explicit property value is checked against maximum (failing)", "data": { "alpha": 5 }, "valid": false }, { "description": "missing properties are not filled in with the default", "data": {}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/defs.json0000644000175100001770000000116714653725311023265 0ustar00runnerdocker[ { "description": "validate definition against metaschema", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$ref": "https://json-schema.org/draft/next/schema" }, "tests": [ { "description": "valid definition schema", "data": {"$defs": {"foo": {"type": "integer"}}}, "valid": true }, { "description": "invalid definition schema", "data": {"$defs": {"foo": {"type": 1}}}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/dependentRequired.json0000644000175100001770000001027214653725311026010 0ustar00runnerdocker[ { "description": "single dependency", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "dependentRequired": {"bar": ["foo"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependant", "data": {"foo": 1}, "valid": true }, { "description": "with dependency", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "missing dependency", "data": {"bar": 2}, "valid": false }, { "description": "ignores arrays", "data": ["bar"], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "empty dependents", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "dependentRequired": {"bar": []} }, "tests": [ { "description": "empty object", "data": {}, "valid": true }, { "description": "object with one property", "data": {"bar": 2}, "valid": true }, { "description": "non-object is valid", "data": 1, "valid": true } ] }, { "description": "multiple dependents required", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "dependentRequired": {"quux": ["foo", "bar"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependants", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "with dependencies", "data": {"foo": 1, "bar": 2, "quux": 3}, "valid": true }, { "description": "missing dependency", "data": {"foo": 1, "quux": 2}, "valid": false }, { "description": "missing other dependency", "data": {"bar": 1, "quux": 2}, "valid": false }, { "description": "missing both dependencies", "data": {"quux": 1}, "valid": false } ] }, { "description": "dependencies with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "dependentRequired": { "foo\nbar": ["foo\rbar"], "foo\"bar": ["foo'bar"] } }, "tests": [ { "description": "CRLF", "data": { "foo\nbar": 1, "foo\rbar": 2 }, "valid": true }, { "description": "quoted quotes", "data": { "foo'bar": 1, "foo\"bar": 2 }, "valid": true }, { "description": "CRLF missing dependent", "data": { "foo\nbar": 1, "foo": 2 }, "valid": false }, { "description": "quoted quotes missing dependent", "data": { "foo\"bar": 2 }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/dependentSchemas.json0000644000175100001770000000742614653725311025622 0ustar00runnerdocker[ { "description": "single dependency", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "dependentSchemas": { "bar": { "properties": { "foo": {"type": "integer"}, "bar": {"type": "integer"} } } } }, "tests": [ { "description": "valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "no dependency", "data": {"foo": "quux"}, "valid": true }, { "description": "wrong type", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "wrong type other", "data": {"foo": 2, "bar": "quux"}, "valid": false }, { "description": "wrong type both", "data": {"foo": "quux", "bar": "quux"}, "valid": false }, { "description": "ignores arrays", "data": ["bar"], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "boolean subschemas", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "dependentSchemas": { "foo": true, "bar": false } }, "tests": [ { "description": "object with property having schema true is valid", "data": {"foo": 1}, "valid": true }, { "description": "object with property having schema false is invalid", "data": {"bar": 2}, "valid": false }, { "description": "object with both properties is invalid", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "dependencies with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "dependentSchemas": { "foo\tbar": {"minProperties": 4}, "foo'bar": {"required": ["foo\"bar"]} } }, "tests": [ { "description": "quoted tab", "data": { "foo\tbar": 1, "a": 2, "b": 3, "c": 4 }, "valid": true }, { "description": "quoted quote", "data": { "foo'bar": {"foo\"bar": 1} }, "valid": false }, { "description": "quoted tab invalid under dependent schema", "data": { "foo\tbar": 1, "a": 2 }, "valid": false }, { "description": "quoted quote invalid under dependent schema", "data": {"foo'bar": 1}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/dynamicRef.json0000644000175100001770000004550414653725311024430 0ustar00runnerdocker[ { "description": "A $dynamicRef to a $dynamicAnchor in the same schema resource behaves like a normal $ref to an $anchor", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "https://test.json-schema.org/dynamicRef-dynamicAnchor-same-schema/root", "type": "array", "items": { "$dynamicRef": "#items" }, "$defs": { "foo": { "$dynamicAnchor": "items", "type": "string" } } }, "tests": [ { "description": "An array of strings is valid", "data": ["foo", "bar"], "valid": true }, { "description": "An array containing non-strings is invalid", "data": ["foo", 42], "valid": false } ] }, { "description": "A $ref to a $dynamicAnchor in the same schema resource behaves like a normal $ref to an $anchor", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "https://test.json-schema.org/ref-dynamicAnchor-same-schema/root", "type": "array", "items": { "$ref": "#items" }, "$defs": { "foo": { "$dynamicAnchor": "items", "type": "string" } } }, "tests": [ { "description": "An array of strings is valid", "data": ["foo", "bar"], "valid": true }, { "description": "An array containing non-strings is invalid", "data": ["foo", 42], "valid": false } ] }, { "description": "A $dynamicRef resolves to the first $dynamicAnchor still in scope that is encountered when the schema is evaluated", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "https://test.json-schema.org/typical-dynamic-resolution/root", "$ref": "list", "$defs": { "foo": { "$dynamicAnchor": "items", "type": "string" }, "list": { "$id": "list", "type": "array", "items": { "$dynamicRef": "#items" } } } }, "tests": [ { "description": "An array of strings is valid", "data": ["foo", "bar"], "valid": true }, { "description": "An array containing non-strings is invalid", "data": ["foo", 42], "valid": false } ] }, { "description": "A $dynamicRef with intermediate scopes that don't include a matching $dynamicAnchor does not affect dynamic scope resolution", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "https://test.json-schema.org/dynamic-resolution-with-intermediate-scopes/root", "$ref": "intermediate-scope", "$defs": { "foo": { "$dynamicAnchor": "items", "type": "string" }, "intermediate-scope": { "$id": "intermediate-scope", "$ref": "list" }, "list": { "$id": "list", "type": "array", "items": { "$dynamicRef": "#items" } } } }, "tests": [ { "description": "An array of strings is valid", "data": ["foo", "bar"], "valid": true }, { "description": "An array containing non-strings is invalid", "data": ["foo", 42], "valid": false } ] }, { "description": "An $anchor with the same name as a $dynamicAnchor is not used for dynamic scope resolution", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "https://test.json-schema.org/dynamic-resolution-ignores-anchors/root", "$ref": "list", "$defs": { "foo": { "$anchor": "items", "type": "string" }, "list": { "$id": "list", "type": "array", "items": { "$dynamicRef": "#items" }, "$defs": { "items": { "$dynamicAnchor": "items" } } } } }, "tests": [ { "description": "Any array is valid", "data": ["foo", 42], "valid": true } ] }, { "description": "A $dynamicRef that initially resolves to a schema with a matching $dynamicAnchor resolves to the first $dynamicAnchor in the dynamic scope", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "https://test.json-schema.org/relative-dynamic-reference/root", "$dynamicAnchor": "meta", "type": "object", "properties": { "foo": { "const": "pass" } }, "$ref": "extended", "$defs": { "extended": { "$id": "extended", "$dynamicAnchor": "meta", "type": "object", "properties": { "bar": { "$ref": "bar" } } }, "bar": { "$id": "bar", "type": "object", "properties": { "baz": { "$dynamicRef": "extended#meta" } } } } }, "tests": [ { "description": "The recursive part is valid against the root", "data": { "foo": "pass", "bar": { "baz": { "foo": "pass" } } }, "valid": true }, { "description": "The recursive part is not valid against the root", "data": { "foo": "pass", "bar": { "baz": { "foo": "fail" } } }, "valid": false } ] }, { "description": "multiple dynamic paths to the $dynamicRef keyword", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "https://test.json-schema.org/dynamic-ref-with-multiple-paths/main", "$defs": { "inner": { "$id": "inner", "$dynamicAnchor": "foo", "title": "inner", "additionalProperties": { "$dynamicRef": "#foo" } } }, "if": { "propertyNames": { "pattern": "^[a-m]" } }, "then": { "title": "any type of node", "$id": "anyLeafNode", "$dynamicAnchor": "foo", "$ref": "inner" }, "else": { "title": "integer node", "$id": "integerNode", "$dynamicAnchor": "foo", "type": [ "object", "integer" ], "$ref": "inner" } }, "tests": [ { "description": "recurse to anyLeafNode - floats are allowed", "data": { "alpha": 1.1 }, "valid": true }, { "description": "recurse to integerNode - floats are not allowed", "data": { "november": 1.1 }, "valid": false } ] }, { "description": "after leaving a dynamic scope, it is not used by a $dynamicRef", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "https://test.json-schema.org/dynamic-ref-leaving-dynamic-scope/main", "if": { "$id": "first_scope", "$defs": { "thingy": { "$comment": "this is first_scope#thingy", "$dynamicAnchor": "thingy", "type": "number" } } }, "then": { "$id": "second_scope", "$ref": "start", "$defs": { "thingy": { "$comment": "this is second_scope#thingy, the final destination of the $dynamicRef", "$dynamicAnchor": "thingy", "type": "null" } } }, "$defs": { "start": { "$comment": "this is the landing spot from $ref", "$id": "start", "$dynamicRef": "inner_scope#thingy" }, "thingy": { "$comment": "this is the first stop for the $dynamicRef", "$id": "inner_scope", "$dynamicAnchor": "thingy", "type": "string" } } }, "tests": [ { "description": "string matches /$defs/thingy, but the $dynamicRef does not stop here", "data": "a string", "valid": false }, { "description": "first_scope is not in dynamic scope for the $dynamicRef", "data": 42, "valid": false }, { "description": "/then/$defs/thingy is the final stop for the $dynamicRef", "data": null, "valid": true } ] }, { "description": "strict-tree schema, guards against misspelled properties", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "http://localhost:1234/draft-next/strict-tree.json", "$dynamicAnchor": "node", "$ref": "tree.json", "unevaluatedProperties": false }, "tests": [ { "description": "instance with misspelled field", "data": { "children": [{ "daat": 1 }] }, "valid": false }, { "description": "instance with correct field", "data": { "children": [{ "data": 1 }] }, "valid": true } ] }, { "description": "tests for implementation dynamic anchor and reference link", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "http://localhost:1234/draft-next/strict-extendible.json", "$ref": "extendible-dynamic-ref.json", "$defs": { "elements": { "$dynamicAnchor": "elements", "properties": { "a": true }, "required": ["a"], "additionalProperties": false } } }, "tests": [ { "description": "incorrect parent schema", "data": { "a": true }, "valid": false }, { "description": "incorrect extended schema", "data": { "elements": [ { "b": 1 } ] }, "valid": false }, { "description": "correct extended schema", "data": { "elements": [ { "a": 1 } ] }, "valid": true } ] }, { "description": "$ref and $dynamicAnchor are independent of order - $defs first", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "http://localhost:1234/draft-next/strict-extendible-allof-defs-first.json", "allOf": [ { "$ref": "extendible-dynamic-ref.json" }, { "$defs": { "elements": { "$dynamicAnchor": "elements", "properties": { "a": true }, "required": ["a"], "additionalProperties": false } } } ] }, "tests": [ { "description": "incorrect parent schema", "data": { "a": true }, "valid": false }, { "description": "incorrect extended schema", "data": { "elements": [ { "b": 1 } ] }, "valid": false }, { "description": "correct extended schema", "data": { "elements": [ { "a": 1 } ] }, "valid": true } ] }, { "description": "$ref and $dynamicAnchor are independent of order - $ref first", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "http://localhost:1234/draft-next/strict-extendible-allof-ref-first.json", "allOf": [ { "$defs": { "elements": { "$dynamicAnchor": "elements", "properties": { "a": true }, "required": ["a"], "additionalProperties": false } } }, { "$ref": "extendible-dynamic-ref.json" } ] }, "tests": [ { "description": "incorrect parent schema", "data": { "a": true }, "valid": false }, { "description": "incorrect extended schema", "data": { "elements": [ { "b": 1 } ] }, "valid": false }, { "description": "correct extended schema", "data": { "elements": [ { "a": 1 } ] }, "valid": true } ] }, { "description": "$dynamicAnchor inside propertyDependencies", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/dynamicanchor-in-propertydependencies.json", "$defs": { "inner": { "$id": "inner", "$dynamicAnchor": "foo", "type": "object", "additionalProperties": { "$dynamicRef": "#foo" } } }, "propertyDependencies": { "expectedTypes": { "strings": { "$id": "east", "$ref": "inner", "$defs": { "foo": { "$dynamicAnchor": "foo", "type": "string" } } }, "integers": { "$id": "west", "$ref": "inner", "$defs": { "foo": { "$dynamicAnchor": "foo", "type": "integer" } } } } } }, "tests": [ { "description": "expected strings - additional property as string is valid", "data": { "expectedTypes": "strings", "anotherProperty": "also a string" }, "valid": true }, { "description": "expected strings - additional property as not string is invalid", "data": { "expectedTypes": "strings", "anotherProperty": 42 }, "valid": false }, { "description": "expected integers - additional property as integer is valid", "data": { "expectedTypes": "integers", "anotherProperty": 42 }, "valid": true }, { "description": "expected integers - additional property as not integer is invalid", "data": { "expectedTypes": "integers", "anotherProperty": "a string" }, "valid": false }, { "description": "expected missing - additional property as an object is valid", "data": { "anotherProperty": {} }, "valid": true }, { "description": "expected missing - additional property as not object is invalid", "data": { "anotherProperty": 42 }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/enum.json0000644000175100001770000001636714653725311023320 0ustar00runnerdocker[ { "description": "simple enum validation", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "enum": [1, 2, 3] }, "tests": [ { "description": "one of the enum is valid", "data": 1, "valid": true }, { "description": "something else is invalid", "data": 4, "valid": false } ] }, { "description": "heterogeneous enum validation", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "enum": [6, "foo", [], true, {"foo": 12}] }, "tests": [ { "description": "one of the enum is valid", "data": [], "valid": true }, { "description": "something else is invalid", "data": null, "valid": false }, { "description": "objects are deep compared", "data": {"foo": false}, "valid": false }, { "description": "valid object matches", "data": {"foo": 12}, "valid": true }, { "description": "extra properties in object is invalid", "data": {"foo": 12, "boo": 42}, "valid": false } ] }, { "description": "heterogeneous enum-with-null validation", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "enum": [6, null] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "number is valid", "data": 6, "valid": true }, { "description": "something else is invalid", "data": "test", "valid": false } ] }, { "description": "enums in properties", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type":"object", "properties": { "foo": {"enum":["foo"]}, "bar": {"enum":["bar"]} }, "required": ["bar"] }, "tests": [ { "description": "both properties are valid", "data": {"foo":"foo", "bar":"bar"}, "valid": true }, { "description": "wrong foo value", "data": {"foo":"foot", "bar":"bar"}, "valid": false }, { "description": "wrong bar value", "data": {"foo":"foo", "bar":"bart"}, "valid": false }, { "description": "missing optional property is valid", "data": {"bar":"bar"}, "valid": true }, { "description": "missing required property is invalid", "data": {"foo":"foo"}, "valid": false }, { "description": "missing all properties is invalid", "data": {}, "valid": false } ] }, { "description": "enum with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "enum": ["foo\nbar", "foo\rbar"] }, "tests": [ { "description": "member 1 is valid", "data": "foo\nbar", "valid": true }, { "description": "member 2 is valid", "data": "foo\rbar", "valid": true }, { "description": "another string is invalid", "data": "abc", "valid": false } ] }, { "description": "enum with false does not match 0", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "enum": [false] }, "tests": [ { "description": "false is valid", "data": false, "valid": true }, { "description": "integer zero is invalid", "data": 0, "valid": false }, { "description": "float zero is invalid", "data": 0.0, "valid": false } ] }, { "description": "enum with true does not match 1", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "enum": [true] }, "tests": [ { "description": "true is valid", "data": true, "valid": true }, { "description": "integer one is invalid", "data": 1, "valid": false }, { "description": "float one is invalid", "data": 1.0, "valid": false } ] }, { "description": "enum with 0 does not match false", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "enum": [0] }, "tests": [ { "description": "false is invalid", "data": false, "valid": false }, { "description": "integer zero is valid", "data": 0, "valid": true }, { "description": "float zero is valid", "data": 0.0, "valid": true } ] }, { "description": "enum with 1 does not match true", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "enum": [1] }, "tests": [ { "description": "true is invalid", "data": true, "valid": false }, { "description": "integer one is valid", "data": 1, "valid": true }, { "description": "float one is valid", "data": 1.0, "valid": true } ] }, { "description": "nul characters in strings", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "enum": [ "hello\u0000there" ] }, "tests": [ { "description": "match string with nul", "data": "hello\u0000there", "valid": true }, { "description": "do not match string lacking nul", "data": "hellothere", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/exclusiveMaximum.json0000644000175100001770000000151314653725311025704 0ustar00runnerdocker[ { "description": "exclusiveMaximum validation", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "exclusiveMaximum": 3.0 }, "tests": [ { "description": "below the exclusiveMaximum is valid", "data": 2.2, "valid": true }, { "description": "boundary point is invalid", "data": 3.0, "valid": false }, { "description": "above the exclusiveMaximum is invalid", "data": 3.5, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/exclusiveMinimum.json0000644000175100001770000000151314653725311025702 0ustar00runnerdocker[ { "description": "exclusiveMinimum validation", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "exclusiveMinimum": 1.1 }, "tests": [ { "description": "above the exclusiveMinimum is valid", "data": 1.2, "valid": true }, { "description": "boundary point is invalid", "data": 1.1, "valid": false }, { "description": "below the exclusiveMinimum is invalid", "data": 0.6, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/format.json0000644000175100001770000005253714653725311023643 0ustar00runnerdocker[ { "description": "email format", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "idn-email format", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "idn-email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "regex format", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "regex" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "ipv4 format", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "ipv4" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "ipv6 format", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "ipv6" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "idn-hostname format", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "idn-hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "hostname format", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "date format", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "date" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "date-time format", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "date-time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "time format", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "json-pointer format", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "json-pointer" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "relative-json-pointer format", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "relative-json-pointer" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "iri format", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "iri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "iri-reference format", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "iri-reference" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uri format", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "uri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uri-reference format", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "uri-reference" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uri-template format", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "uri-template" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uuid format", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "uuid" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "duration format", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "duration" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/id.json0000644000175100001770000002376014653725311022743 0ustar00runnerdocker[ { "description": "Invalid use of fragments in location-independent $id", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$ref": "https://json-schema.org/draft/next/schema" }, "tests": [ { "description": "Identifier name", "data": { "$ref": "#foo", "$defs": { "A": { "$id": "#foo", "type": "integer" } } }, "valid": false }, { "description": "Identifier name and no ref", "data": { "$defs": { "A": { "$id": "#foo" } } }, "valid": false }, { "description": "Identifier path", "data": { "$ref": "#/a/b", "$defs": { "A": { "$id": "#/a/b", "type": "integer" } } }, "valid": false }, { "description": "Identifier name with absolute URI", "data": { "$ref": "http://localhost:1234/draft-next/bar#foo", "$defs": { "A": { "$id": "http://localhost:1234/draft-next/bar#foo", "type": "integer" } } }, "valid": false }, { "description": "Identifier path with absolute URI", "data": { "$ref": "http://localhost:1234/draft-next/bar#/a/b", "$defs": { "A": { "$id": "http://localhost:1234/draft-next/bar#/a/b", "type": "integer" } } }, "valid": false }, { "description": "Identifier name with base URI change in subschema", "data": { "$id": "http://localhost:1234/draft-next/root", "$ref": "http://localhost:1234/draft-next/nested.json#foo", "$defs": { "A": { "$id": "nested.json", "$defs": { "B": { "$id": "#foo", "type": "integer" } } } } }, "valid": false }, { "description": "Identifier path with base URI change in subschema", "data": { "$id": "http://localhost:1234/draft-next/root", "$ref": "http://localhost:1234/draft-next/nested.json#/a/b", "$defs": { "A": { "$id": "nested.json", "$defs": { "B": { "$id": "#/a/b", "type": "integer" } } } } }, "valid": false } ] }, { "description": "Valid use of empty fragments in location-independent $id", "comment": "These are allowed but discouraged", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$ref": "https://json-schema.org/draft/next/schema" }, "tests": [ { "description": "Identifier name with absolute URI", "data": { "$ref": "http://localhost:1234/draft-next/bar", "$defs": { "A": { "$id": "http://localhost:1234/draft-next/bar#", "type": "integer" } } }, "valid": true }, { "description": "Identifier name with base URI change in subschema", "data": { "$id": "http://localhost:1234/draft-next/root", "$ref": "http://localhost:1234/draft-next/nested.json#/$defs/B", "$defs": { "A": { "$id": "nested.json", "$defs": { "B": { "$id": "#", "type": "integer" } } } } }, "valid": true } ] }, { "description": "Unnormalized $ids are allowed but discouraged", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$ref": "https://json-schema.org/draft/next/schema" }, "tests": [ { "description": "Unnormalized identifier", "data": { "$ref": "http://localhost:1234/draft-next/foo/baz", "$defs": { "A": { "$id": "http://localhost:1234/draft-next/foo/bar/../baz", "type": "integer" } } }, "valid": true }, { "description": "Unnormalized identifier and no ref", "data": { "$defs": { "A": { "$id": "http://localhost:1234/draft-next/foo/bar/../baz", "type": "integer" } } }, "valid": true }, { "description": "Unnormalized identifier with empty fragment", "data": { "$ref": "http://localhost:1234/draft-next/foo/baz", "$defs": { "A": { "$id": "http://localhost:1234/draft-next/foo/bar/../baz#", "type": "integer" } } }, "valid": true }, { "description": "Unnormalized identifier with empty fragment and no ref", "data": { "$defs": { "A": { "$id": "http://localhost:1234/draft-next/foo/bar/../baz#", "type": "integer" } } }, "valid": true } ] }, { "description": "$id inside an enum is not a real identifier", "comment": "the implementation must not be confused by an $id buried in the enum", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$defs": { "id_in_enum": { "enum": [ { "$id": "https://localhost:1234/draft-next/id/my_identifier.json", "type": "null" } ] }, "real_id_in_schema": { "$id": "https://localhost:1234/draft-next/id/my_identifier.json", "type": "string" }, "zzz_id_in_const": { "const": { "$id": "https://localhost:1234/draft-next/id/my_identifier.json", "type": "null" } } }, "anyOf": [ { "$ref": "#/$defs/id_in_enum" }, { "$ref": "https://localhost:1234/draft-next/id/my_identifier.json" } ] }, "tests": [ { "description": "exact match to enum, and type matches", "data": { "$id": "https://localhost:1234/draft-next/id/my_identifier.json", "type": "null" }, "valid": true }, { "description": "match $ref to $id", "data": "a string to match #/$defs/id_in_enum", "valid": true }, { "description": "no match on enum or $ref to $id", "data": 1, "valid": false } ] }, { "description": "non-schema object containing an $id property", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$defs": { "const_not_id": { "const": { "$id": "not_a_real_id" } } }, "if": { "const": "skip not_a_real_id" }, "then": true, "else" : { "$ref": "#/$defs/const_not_id" } }, "tests": [ { "description": "skip traversing definition for a valid result", "data": "skip not_a_real_id", "valid": true }, { "description": "const at const_not_id does not match", "data": 1, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/if-then-else.json0000644000175100001770000001657214653725311024632 0ustar00runnerdocker[ { "description": "ignore if without then or else", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "if": { "const": 0 } }, "tests": [ { "description": "valid when valid against lone if", "data": 0, "valid": true }, { "description": "valid when invalid against lone if", "data": "hello", "valid": true } ] }, { "description": "ignore then without if", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "then": { "const": 0 } }, "tests": [ { "description": "valid when valid against lone then", "data": 0, "valid": true }, { "description": "valid when invalid against lone then", "data": "hello", "valid": true } ] }, { "description": "ignore else without if", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "else": { "const": 0 } }, "tests": [ { "description": "valid when valid against lone else", "data": 0, "valid": true }, { "description": "valid when invalid against lone else", "data": "hello", "valid": true } ] }, { "description": "if and then without else", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "if": { "exclusiveMaximum": 0 }, "then": { "minimum": -10 } }, "tests": [ { "description": "valid through then", "data": -1, "valid": true }, { "description": "invalid through then", "data": -100, "valid": false }, { "description": "valid when if test fails", "data": 3, "valid": true } ] }, { "description": "if and else without then", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "if": { "exclusiveMaximum": 0 }, "else": { "multipleOf": 2 } }, "tests": [ { "description": "valid when if test passes", "data": -1, "valid": true }, { "description": "valid through else", "data": 4, "valid": true }, { "description": "invalid through else", "data": 3, "valid": false } ] }, { "description": "validate against correct branch, then vs else", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "if": { "exclusiveMaximum": 0 }, "then": { "minimum": -10 }, "else": { "multipleOf": 2 } }, "tests": [ { "description": "valid through then", "data": -1, "valid": true }, { "description": "invalid through then", "data": -100, "valid": false }, { "description": "valid through else", "data": 4, "valid": true }, { "description": "invalid through else", "data": 3, "valid": false } ] }, { "description": "non-interference across combined schemas", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "allOf": [ { "if": { "exclusiveMaximum": 0 } }, { "then": { "minimum": -10 } }, { "else": { "multipleOf": 2 } } ] }, "tests": [ { "description": "valid, but would have been invalid through then", "data": -100, "valid": true }, { "description": "valid, but would have been invalid through else", "data": 3, "valid": true } ] }, { "description": "if with boolean schema true", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "if": true, "then": { "const": "then" }, "else": { "const": "else" } }, "tests": [ { "description": "boolean schema true in if always chooses the then path (valid)", "data": "then", "valid": true }, { "description": "boolean schema true in if always chooses the then path (invalid)", "data": "else", "valid": false } ] }, { "description": "if with boolean schema false", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "if": false, "then": { "const": "then" }, "else": { "const": "else" } }, "tests": [ { "description": "boolean schema false in if always chooses the else path (invalid)", "data": "then", "valid": false }, { "description": "boolean schema false in if always chooses the else path (valid)", "data": "else", "valid": true } ] }, { "description": "if appears at the end when serialized (keyword processing sequence)", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "then": { "const": "yes" }, "else": { "const": "other" }, "if": { "maxLength": 4 } }, "tests": [ { "description": "yes redirects to then and passes", "data": "yes", "valid": true }, { "description": "other redirects to else and passes", "data": "other", "valid": true }, { "description": "no redirects to then and fails", "data": "no", "valid": false }, { "description": "invalid redirects to else and fails", "data": "invalid", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/infinite-loop-detection.json0000644000175100001770000000203014653725311027062 0ustar00runnerdocker[ { "description": "evaluating the same schema location against the same data location twice is not a sign of an infinite loop", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$defs": { "int": { "type": "integer" } }, "allOf": [ { "properties": { "foo": { "$ref": "#/$defs/int" } } }, { "additionalProperties": { "$ref": "#/$defs/int" } } ] }, "tests": [ { "description": "passing case", "data": { "foo": 1 }, "valid": true }, { "description": "failing case", "data": { "foo": "a string" }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/items.json0000644000175100001770000002064114653725311023463 0ustar00runnerdocker[ { "description": "a schema given for items", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "items": {"type": "integer"} }, "tests": [ { "description": "valid items", "data": [ 1, 2, 3 ], "valid": true }, { "description": "wrong type of items", "data": [1, "x"], "valid": false }, { "description": "ignores non-arrays", "data": {"foo" : "bar"}, "valid": true }, { "description": "JavaScript pseudo-array is valid", "data": { "0": "invalid", "length": 1 }, "valid": true } ] }, { "description": "items with boolean schema (true)", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "items": true }, "tests": [ { "description": "any array is valid", "data": [ 1, "foo", true ], "valid": true }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "items with boolean schema (false)", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "items": false }, "tests": [ { "description": "any non-empty array is invalid", "data": [ 1, "foo", true ], "valid": false }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "items and subitems", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$defs": { "item": { "type": "array", "items": false, "prefixItems": [ { "$ref": "#/$defs/sub-item" }, { "$ref": "#/$defs/sub-item" } ] }, "sub-item": { "type": "object", "required": ["foo"] } }, "type": "array", "items": false, "prefixItems": [ { "$ref": "#/$defs/item" }, { "$ref": "#/$defs/item" }, { "$ref": "#/$defs/item" } ] }, "tests": [ { "description": "valid items", "data": [ [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": true }, { "description": "too many items", "data": [ [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "too many sub-items", "data": [ [ {"foo": null}, {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "wrong item", "data": [ {"foo": null}, [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "wrong sub-item", "data": [ [ {}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "fewer items is valid", "data": [ [ {"foo": null} ], [ {"foo": null} ] ], "valid": true } ] }, { "description": "nested items", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "array", "items": { "type": "array", "items": { "type": "array", "items": { "type": "array", "items": { "type": "number" } } } } }, "tests": [ { "description": "valid nested array", "data": [[[[1]], [[2],[3]]], [[[4], [5], [6]]]], "valid": true }, { "description": "nested array with invalid type", "data": [[[["1"]], [[2],[3]]], [[[4], [5], [6]]]], "valid": false }, { "description": "not deep enough", "data": [[[1], [2],[3]], [[4], [5], [6]]], "valid": false } ] }, { "description": "prefixItems with no additional items allowed", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "prefixItems": [{}, {}, {}], "items": false }, "tests": [ { "description": "empty array", "data": [ ], "valid": true }, { "description": "fewer number of items present (1)", "data": [ 1 ], "valid": true }, { "description": "fewer number of items present (2)", "data": [ 1, 2 ], "valid": true }, { "description": "equal number of items present", "data": [ 1, 2, 3 ], "valid": true }, { "description": "additional items are not permitted", "data": [ 1, 2, 3, 4 ], "valid": false } ] }, { "description": "items does not look in applicators, valid case", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "allOf": [ { "prefixItems": [ { "minimum": 3 } ] } ], "items": { "minimum": 5 } }, "tests": [ { "description": "prefixItems in allOf does not constrain items, invalid case", "data": [ 3, 5 ], "valid": false }, { "description": "prefixItems in allOf does not constrain items, valid case", "data": [ 5, 5 ], "valid": true } ] }, { "description": "prefixItems validation adjusts the starting index for items", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "prefixItems": [ { "type": "string" } ], "items": { "type": "integer" } }, "tests": [ { "description": "valid items", "data": [ "x", 2, 3 ], "valid": true }, { "description": "wrong type of second item", "data": [ "x", "y" ], "valid": false } ] }, { "description": "items with null instance elements", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "items": { "type": "null" } }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/maxContains.json0000644000175100001770000001132514653725311024625 0ustar00runnerdocker[ { "description": "maxContains without contains is ignored", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "maxContains": 1 }, "tests": [ { "description": "one item valid against lone maxContains", "data": [1], "valid": true }, { "description": "two items still valid against lone maxContains", "data": [1, 2], "valid": true }, { "description": "one property valid against lone maxContains", "data": { "a": 1 }, "valid": true }, { "description": "two properties still valid against lone maxContains", "data": { "a": 1, "b": 2 }, "valid": true } ] }, { "description": "maxContains with contains", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "contains": { "const": 1 }, "maxContains": 1 }, "tests": [ { "description": "empty array", "data": [], "valid": false }, { "description": "all elements match, valid maxContains", "data": [1], "valid": true }, { "description": "all elements match, invalid maxContains", "data": [1, 1], "valid": false }, { "description": "some elements match, valid maxContains", "data": [1, 2], "valid": true }, { "description": "some elements match, invalid maxContains", "data": [1, 2, 1], "valid": false }, { "description": "empty object", "data": {}, "valid": false }, { "description": "all properties match, valid maxContains", "data": { "a": 1 }, "valid": true }, { "description": "all properties match, invalid maxContains", "data": { "a": 1, "b": 1 }, "valid": false }, { "description": "some properties match, valid maxContains", "data": { "a": 1, "b": 2 }, "valid": true }, { "description": "some properties match, invalid maxContains", "data": { "a": 1, "b": 2, "c": 1 }, "valid": false } ] }, { "description": "maxContains with contains, value with a decimal", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "contains": {"const": 1}, "maxContains": 1.0 }, "tests": [ { "description": "one element matches, valid maxContains", "data": [ 1 ], "valid": true }, { "description": "too many elements match, invalid maxContains", "data": [ 1, 1 ], "valid": false } ] }, { "description": "minContains < maxContains", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "contains": { "const": 1 }, "minContains": 1, "maxContains": 3 }, "tests": [ { "description": "array with actual < minContains < maxContains", "data": [], "valid": false }, { "description": "array with minContains < actual < maxContains", "data": [1, 1], "valid": true }, { "description": "array with minContains < maxContains < actual", "data": [1, 1, 1, 1], "valid": false }, { "description": "object with actual < minContains < maxContains", "data": {}, "valid": false }, { "description": "object with minContains < actual < maxContains", "data": { "a": 1, "b": 1 }, "valid": true }, { "description": "object with minContains < maxContains < actual", "data": { "a": 1, "b": 1, "c": 1, "d": 1 }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/maxItems.json0000644000175100001770000000244114653725311024127 0ustar00runnerdocker[ { "description": "maxItems validation", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "maxItems": 2 }, "tests": [ { "description": "shorter is valid", "data": [1], "valid": true }, { "description": "exact length is valid", "data": [1, 2], "valid": true }, { "description": "too long is invalid", "data": [1, 2, 3], "valid": false }, { "description": "ignores non-arrays", "data": "foobar", "valid": true } ] }, { "description": "maxItems validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "maxItems": 2.0 }, "tests": [ { "description": "shorter is valid", "data": [1], "valid": true }, { "description": "too long is invalid", "data": [1, 2, 3], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/maxLength.json0000644000175100001770000000273514653725311024275 0ustar00runnerdocker[ { "description": "maxLength validation", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "maxLength": 2 }, "tests": [ { "description": "shorter is valid", "data": "f", "valid": true }, { "description": "exact length is valid", "data": "fo", "valid": true }, { "description": "too long is invalid", "data": "foo", "valid": false }, { "description": "ignores non-strings", "data": 100, "valid": true }, { "description": "two supplementary Unicode code points is long enough", "data": "\uD83D\uDCA9\uD83D\uDCA9", "valid": true } ] }, { "description": "maxLength validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "maxLength": 2.0 }, "tests": [ { "description": "shorter is valid", "data": "f", "valid": true }, { "description": "too long is invalid", "data": "foo", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/maxProperties.json0000644000175100001770000000426714653725311025212 0ustar00runnerdocker[ { "description": "maxProperties validation", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "maxProperties": 2 }, "tests": [ { "description": "shorter is valid", "data": {"foo": 1}, "valid": true }, { "description": "exact length is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "too long is invalid", "data": {"foo": 1, "bar": 2, "baz": 3}, "valid": false }, { "description": "ignores arrays", "data": [1, 2, 3], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "maxProperties validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "maxProperties": 2.0 }, "tests": [ { "description": "shorter is valid", "data": {"foo": 1}, "valid": true }, { "description": "too long is invalid", "data": {"foo": 1, "bar": 2, "baz": 3}, "valid": false } ] }, { "description": "maxProperties = 0 means the object is empty", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "maxProperties": 0 }, "tests": [ { "description": "no properties is valid", "data": {}, "valid": true }, { "description": "one property is invalid", "data": { "foo": 1 }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/maximum.json0000644000175100001770000000317014653725311024015 0ustar00runnerdocker[ { "description": "maximum validation", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "maximum": 3.0 }, "tests": [ { "description": "below the maximum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 3.0, "valid": true }, { "description": "above the maximum is invalid", "data": 3.5, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] }, { "description": "maximum validation with unsigned integer", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "maximum": 300 }, "tests": [ { "description": "below the maximum is invalid", "data": 299.97, "valid": true }, { "description": "boundary point integer is valid", "data": 300, "valid": true }, { "description": "boundary point float is valid", "data": 300.00, "valid": true }, { "description": "above the maximum is invalid", "data": 300.5, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/minContains.json0000644000175100001770000001462714653725311024633 0ustar00runnerdocker[ { "description": "minContains without contains is ignored", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "minContains": 1 }, "tests": [ { "description": "one item valid against lone minContains", "data": [1], "valid": true }, { "description": "zero items still valid against lone minContains", "data": [], "valid": true } ] }, { "description": "minContains=1 with contains", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "contains": { "const": 1 }, "minContains": 1 }, "tests": [ { "description": "empty data", "data": [], "valid": false }, { "description": "no elements match", "data": [2], "valid": false }, { "description": "single element matches, valid minContains", "data": [1], "valid": true }, { "description": "some elements match, valid minContains", "data": [1, 2], "valid": true }, { "description": "all elements match, valid minContains", "data": [1, 1], "valid": true } ] }, { "description": "minContains=2 with contains", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "contains": { "const": 1 }, "minContains": 2 }, "tests": [ { "description": "empty data", "data": [], "valid": false }, { "description": "all elements match, invalid minContains", "data": [1], "valid": false }, { "description": "some elements match, invalid minContains", "data": [1, 2], "valid": false }, { "description": "all elements match, valid minContains (exactly as needed)", "data": [1, 1], "valid": true }, { "description": "all elements match, valid minContains (more than needed)", "data": [1, 1, 1], "valid": true }, { "description": "some elements match, valid minContains", "data": [1, 2, 1], "valid": true } ] }, { "description": "minContains=2 with contains with a decimal value", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "contains": {"const": 1}, "minContains": 2.0 }, "tests": [ { "description": "one element matches, invalid minContains", "data": [ 1 ], "valid": false }, { "description": "both elements match, valid minContains", "data": [ 1, 1 ], "valid": true } ] }, { "description": "maxContains = minContains", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "contains": { "const": 1 }, "maxContains": 2, "minContains": 2 }, "tests": [ { "description": "empty data", "data": [], "valid": false }, { "description": "all elements match, invalid minContains", "data": [1], "valid": false }, { "description": "all elements match, invalid maxContains", "data": [1, 1, 1], "valid": false }, { "description": "all elements match, valid maxContains and minContains", "data": [1, 1], "valid": true } ] }, { "description": "maxContains < minContains", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "contains": { "const": 1 }, "maxContains": 1, "minContains": 3 }, "tests": [ { "description": "empty data", "data": [], "valid": false }, { "description": "invalid minContains", "data": [1], "valid": false }, { "description": "invalid maxContains", "data": [1, 1, 1], "valid": false }, { "description": "invalid maxContains and minContains", "data": [1, 1], "valid": false } ] }, { "description": "minContains = 0", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "contains": { "const": 1 }, "minContains": 0 }, "tests": [ { "description": "empty data", "data": [], "valid": true }, { "description": "minContains = 0 makes contains always pass", "data": [2], "valid": true } ] }, { "description": "minContains = 0 with maxContains", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "contains": {"const": 1}, "minContains": 0, "maxContains": 1 }, "tests": [ { "description": "empty data", "data": [ ], "valid": true }, { "description": "not more than maxContains", "data": [ 1 ], "valid": true }, { "description": "too many", "data": [ 1, 1 ], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/minItems.json0000644000175100001770000000242014653725311024122 0ustar00runnerdocker[ { "description": "minItems validation", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "minItems": 1 }, "tests": [ { "description": "longer is valid", "data": [1, 2], "valid": true }, { "description": "exact length is valid", "data": [1], "valid": true }, { "description": "too short is invalid", "data": [], "valid": false }, { "description": "ignores non-arrays", "data": "", "valid": true } ] }, { "description": "minItems validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "minItems": 1.0 }, "tests": [ { "description": "longer is valid", "data": [1, 2], "valid": true }, { "description": "too short is invalid", "data": [], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/minLength.json0000644000175100001770000000272314653725311024270 0ustar00runnerdocker[ { "description": "minLength validation", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "minLength": 2 }, "tests": [ { "description": "longer is valid", "data": "foo", "valid": true }, { "description": "exact length is valid", "data": "fo", "valid": true }, { "description": "too short is invalid", "data": "f", "valid": false }, { "description": "ignores non-strings", "data": 1, "valid": true }, { "description": "one supplementary Unicode code point is not long enough", "data": "\uD83D\uDCA9", "valid": false } ] }, { "description": "minLength validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "minLength": 2.0 }, "tests": [ { "description": "longer is valid", "data": "foo", "valid": true }, { "description": "too short is invalid", "data": "f", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/minProperties.json0000644000175100001770000000313714653725311025203 0ustar00runnerdocker[ { "description": "minProperties validation", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "minProperties": 1 }, "tests": [ { "description": "longer is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "exact length is valid", "data": {"foo": 1}, "valid": true }, { "description": "too short is invalid", "data": {}, "valid": false }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "minProperties validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "minProperties": 1.0 }, "tests": [ { "description": "longer is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "too short is invalid", "data": {}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/minimum.json0000644000175100001770000000407614653725311024021 0ustar00runnerdocker[ { "description": "minimum validation", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "minimum": 1.1 }, "tests": [ { "description": "above the minimum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 1.1, "valid": true }, { "description": "below the minimum is invalid", "data": 0.6, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] }, { "description": "minimum validation with signed integer", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "minimum": -2 }, "tests": [ { "description": "negative above the minimum is valid", "data": -1, "valid": true }, { "description": "positive above the minimum is valid", "data": 0, "valid": true }, { "description": "boundary point is valid", "data": -2, "valid": true }, { "description": "boundary point with float is valid", "data": -2.0, "valid": true }, { "description": "float below the minimum is invalid", "data": -2.0001, "valid": false }, { "description": "int below the minimum is invalid", "data": -3, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/multipleOf.json0000644000175100001770000000430614653725311024462 0ustar00runnerdocker[ { "description": "by int", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "multipleOf": 2 }, "tests": [ { "description": "int by int", "data": 10, "valid": true }, { "description": "int by int fail", "data": 7, "valid": false }, { "description": "ignores non-numbers", "data": "foo", "valid": true } ] }, { "description": "by number", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "multipleOf": 1.5 }, "tests": [ { "description": "zero is multiple of anything", "data": 0, "valid": true }, { "description": "4.5 is multiple of 1.5", "data": 4.5, "valid": true }, { "description": "35 is not multiple of 1.5", "data": 35, "valid": false } ] }, { "description": "by small number", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "multipleOf": 0.0001 }, "tests": [ { "description": "0.0075 is multiple of 0.0001", "data": 0.0075, "valid": true }, { "description": "0.00751 is not multiple of 0.0001", "data": 0.00751, "valid": false } ] }, { "description": "float division = inf", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "integer", "multipleOf": 0.123456789 }, "tests": [ { "description": "always invalid, but naive implementations may raise an overflow error", "data": 1e308, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/not.json0000644000175100001770000000630214653725311023140 0ustar00runnerdocker[ { "description": "not", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "not": {"type": "integer"} }, "tests": [ { "description": "allowed", "data": "foo", "valid": true }, { "description": "disallowed", "data": 1, "valid": false } ] }, { "description": "not multiple types", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "not": {"type": ["integer", "boolean"]} }, "tests": [ { "description": "valid", "data": "foo", "valid": true }, { "description": "mismatch", "data": 1, "valid": false }, { "description": "other mismatch", "data": true, "valid": false } ] }, { "description": "not more complex schema", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "not": { "type": "object", "properties": { "foo": { "type": "string" } } } }, "tests": [ { "description": "match", "data": 1, "valid": true }, { "description": "other match", "data": {"foo": 1}, "valid": true }, { "description": "mismatch", "data": {"foo": "bar"}, "valid": false } ] }, { "description": "forbidden property", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": { "foo": { "not": {} } } }, "tests": [ { "description": "property present", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "property absent", "data": {"bar": 1, "baz": 2}, "valid": true } ] }, { "description": "not with boolean schema true", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "not": true }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "not with boolean schema false", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "not": false }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/oneOf.json0000644000175100001770000001762714653725311023422 0ustar00runnerdocker[ { "description": "oneOf", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "oneOf": [ { "type": "integer" }, { "minimum": 2 } ] }, "tests": [ { "description": "first oneOf valid", "data": 1, "valid": true }, { "description": "second oneOf valid", "data": 2.5, "valid": true }, { "description": "both oneOf valid", "data": 3, "valid": false }, { "description": "neither oneOf valid", "data": 1.5, "valid": false } ] }, { "description": "oneOf with base schema", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "string", "oneOf" : [ { "minLength": 2 }, { "maxLength": 4 } ] }, "tests": [ { "description": "mismatch base schema", "data": 3, "valid": false }, { "description": "one oneOf valid", "data": "foobar", "valid": true }, { "description": "both oneOf valid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, all true", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "oneOf": [true, true, true] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, one true", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "oneOf": [true, false, false] }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "oneOf with boolean schemas, more than one true", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "oneOf": [true, true, false] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, all false", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "oneOf": [false, false, false] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf complex types", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "oneOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "first oneOf valid (complex)", "data": {"bar": 2}, "valid": true }, { "description": "second oneOf valid (complex)", "data": {"foo": "baz"}, "valid": true }, { "description": "both oneOf valid (complex)", "data": {"foo": "baz", "bar": 2}, "valid": false }, { "description": "neither oneOf valid (complex)", "data": {"foo": 2, "bar": "quux"}, "valid": false } ] }, { "description": "oneOf with empty schema", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "oneOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "one valid - valid", "data": "foo", "valid": true }, { "description": "both valid - invalid", "data": 123, "valid": false } ] }, { "description": "oneOf with required", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "oneOf": [ { "required": ["foo", "bar"] }, { "required": ["foo", "baz"] } ] }, "tests": [ { "description": "both invalid - invalid", "data": {"bar": 2}, "valid": false }, { "description": "first valid - valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "second valid - valid", "data": {"foo": 1, "baz": 3}, "valid": true }, { "description": "both valid - invalid", "data": {"foo": 1, "bar": 2, "baz" : 3}, "valid": false } ] }, { "description": "oneOf with missing optional property", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "oneOf": [ { "properties": { "bar": true, "baz": true }, "required": ["bar"] }, { "properties": { "foo": true }, "required": ["foo"] } ] }, "tests": [ { "description": "first oneOf valid", "data": {"bar": 8}, "valid": true }, { "description": "second oneOf valid", "data": {"foo": "foo"}, "valid": true }, { "description": "both oneOf valid", "data": {"foo": "foo", "bar": 8}, "valid": false }, { "description": "neither oneOf valid", "data": {"baz": "quux"}, "valid": false } ] }, { "description": "nested oneOf, to check validation semantics", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "oneOf": [ { "oneOf": [ { "type": "null" } ] } ] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "anything non-null is invalid", "data": 123, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0530963 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/0000755000175100001770000000000014653725331023273 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/bignum.json0000644000175100001770000000650114653725311025447 0ustar00runnerdocker[ { "description": "integer", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "integer" }, "tests": [ { "description": "a bignum is an integer", "data": 12345678910111213141516171819202122232425262728293031, "valid": true }, { "description": "a negative bignum is an integer", "data": -12345678910111213141516171819202122232425262728293031, "valid": true } ] }, { "description": "number", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "number" }, "tests": [ { "description": "a bignum is a number", "data": 98249283749234923498293171823948729348710298301928331, "valid": true }, { "description": "a negative bignum is a number", "data": -98249283749234923498293171823948729348710298301928331, "valid": true } ] }, { "description": "string", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "string" }, "tests": [ { "description": "a bignum is not a string", "data": 98249283749234923498293171823948729348710298301928331, "valid": false } ] }, { "description": "maximum integer comparison", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "maximum": 18446744073709551615 }, "tests": [ { "description": "comparison works for high numbers", "data": 18446744073709551600, "valid": true } ] }, { "description": "float comparison with high precision", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "exclusiveMaximum": 972783798187987123879878123.18878137 }, "tests": [ { "description": "comparison works for high numbers", "data": 972783798187987123879878123.188781371, "valid": false } ] }, { "description": "minimum integer comparison", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "minimum": -18446744073709551615 }, "tests": [ { "description": "comparison works for very negative numbers", "data": -18446744073709551600, "valid": true } ] }, { "description": "float comparison with high precision on negative numbers", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "exclusiveMinimum": -972783798187987123879878123.18878137 }, "tests": [ { "description": "comparison works for very negative numbers", "data": -972783798187987123879878123.188781371, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/dependencies-compatibility.json0000644000175100001770000001767314653725311031477 0ustar00runnerdocker[ { "description": "single dependency", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "dependencies": {"bar": ["foo"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependant", "data": {"foo": 1}, "valid": true }, { "description": "with dependency", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "missing dependency", "data": {"bar": 2}, "valid": false }, { "description": "ignores arrays", "data": ["bar"], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "empty dependents", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "dependencies": {"bar": []} }, "tests": [ { "description": "empty object", "data": {}, "valid": true }, { "description": "object with one property", "data": {"bar": 2}, "valid": true }, { "description": "non-object is valid", "data": 1, "valid": true } ] }, { "description": "multiple dependents required", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "dependencies": {"quux": ["foo", "bar"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependants", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "with dependencies", "data": {"foo": 1, "bar": 2, "quux": 3}, "valid": true }, { "description": "missing dependency", "data": {"foo": 1, "quux": 2}, "valid": false }, { "description": "missing other dependency", "data": {"bar": 1, "quux": 2}, "valid": false }, { "description": "missing both dependencies", "data": {"quux": 1}, "valid": false } ] }, { "description": "dependencies with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "dependencies": { "foo\nbar": ["foo\rbar"], "foo\"bar": ["foo'bar"] } }, "tests": [ { "description": "CRLF", "data": { "foo\nbar": 1, "foo\rbar": 2 }, "valid": true }, { "description": "quoted quotes", "data": { "foo'bar": 1, "foo\"bar": 2 }, "valid": true }, { "description": "CRLF missing dependent", "data": { "foo\nbar": 1, "foo": 2 }, "valid": false }, { "description": "quoted quotes missing dependent", "data": { "foo\"bar": 2 }, "valid": false } ] }, { "description": "single schema dependency", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "dependencies": { "bar": { "properties": { "foo": {"type": "integer"}, "bar": {"type": "integer"} } } } }, "tests": [ { "description": "valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "no dependency", "data": {"foo": "quux"}, "valid": true }, { "description": "wrong type", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "wrong type other", "data": {"foo": 2, "bar": "quux"}, "valid": false }, { "description": "wrong type both", "data": {"foo": "quux", "bar": "quux"}, "valid": false }, { "description": "ignores arrays", "data": ["bar"], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "boolean subschemas", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "dependencies": { "foo": true, "bar": false } }, "tests": [ { "description": "object with property having schema true is valid", "data": {"foo": 1}, "valid": true }, { "description": "object with property having schema false is invalid", "data": {"bar": 2}, "valid": false }, { "description": "object with both properties is invalid", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "schema dependencies with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "dependencies": { "foo\tbar": {"minProperties": 4}, "foo'bar": {"required": ["foo\"bar"]} } }, "tests": [ { "description": "quoted tab", "data": { "foo\tbar": 1, "a": 2, "b": 3, "c": 4 }, "valid": true }, { "description": "quoted quote", "data": { "foo'bar": {"foo\"bar": 1} }, "valid": false }, { "description": "quoted tab invalid under dependent schema", "data": { "foo\tbar": 1, "a": 2 }, "valid": false }, { "description": "quoted quote invalid under dependent schema", "data": {"foo'bar": 1}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/ecmascript-regex.json0000644000175100001770000004764414653725311027445 0ustar00runnerdocker[ { "description": "ECMA 262 regex $ does not match trailing newline", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "string", "pattern": "^abc$" }, "tests": [ { "description": "matches in Python, but not in ECMA 262", "data": "abc\\n", "valid": false }, { "description": "matches", "data": "abc", "valid": true } ] }, { "description": "ECMA 262 regex converts \\t to horizontal tab", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "string", "pattern": "^\\t$" }, "tests": [ { "description": "does not match", "data": "\\t", "valid": false }, { "description": "matches", "data": "\u0009", "valid": true } ] }, { "description": "ECMA 262 regex escapes control codes with \\c and upper letter", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "string", "pattern": "^\\cC$" }, "tests": [ { "description": "does not match", "data": "\\cC", "valid": false }, { "description": "matches", "data": "\u0003", "valid": true } ] }, { "description": "ECMA 262 regex escapes control codes with \\c and lower letter", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "string", "pattern": "^\\cc$" }, "tests": [ { "description": "does not match", "data": "\\cc", "valid": false }, { "description": "matches", "data": "\u0003", "valid": true } ] }, { "description": "ECMA 262 \\d matches ascii digits only", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "string", "pattern": "^\\d$" }, "tests": [ { "description": "ASCII zero matches", "data": "0", "valid": true }, { "description": "NKO DIGIT ZERO does not match (unlike e.g. Python)", "data": "߀", "valid": false }, { "description": "NKO DIGIT ZERO (as \\u escape) does not match", "data": "\u07c0", "valid": false } ] }, { "description": "ECMA 262 \\D matches everything but ascii digits", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "string", "pattern": "^\\D$" }, "tests": [ { "description": "ASCII zero does not match", "data": "0", "valid": false }, { "description": "NKO DIGIT ZERO matches (unlike e.g. Python)", "data": "߀", "valid": true }, { "description": "NKO DIGIT ZERO (as \\u escape) matches", "data": "\u07c0", "valid": true } ] }, { "description": "ECMA 262 \\w matches ascii letters only", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "string", "pattern": "^\\w$" }, "tests": [ { "description": "ASCII 'a' matches", "data": "a", "valid": true }, { "description": "latin-1 e-acute does not match (unlike e.g. Python)", "data": "é", "valid": false } ] }, { "description": "ECMA 262 \\W matches everything but ascii letters", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "string", "pattern": "^\\W$" }, "tests": [ { "description": "ASCII 'a' does not match", "data": "a", "valid": false }, { "description": "latin-1 e-acute matches (unlike e.g. Python)", "data": "é", "valid": true } ] }, { "description": "ECMA 262 \\s matches whitespace", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "string", "pattern": "^\\s$" }, "tests": [ { "description": "ASCII space matches", "data": " ", "valid": true }, { "description": "Character tabulation matches", "data": "\t", "valid": true }, { "description": "Line tabulation matches", "data": "\u000b", "valid": true }, { "description": "Form feed matches", "data": "\u000c", "valid": true }, { "description": "latin-1 non-breaking-space matches", "data": "\u00a0", "valid": true }, { "description": "zero-width whitespace matches", "data": "\ufeff", "valid": true }, { "description": "line feed matches (line terminator)", "data": "\u000a", "valid": true }, { "description": "paragraph separator matches (line terminator)", "data": "\u2029", "valid": true }, { "description": "EM SPACE matches (Space_Separator)", "data": "\u2003", "valid": true }, { "description": "Non-whitespace control does not match", "data": "\u0001", "valid": false }, { "description": "Non-whitespace does not match", "data": "\u2013", "valid": false } ] }, { "description": "ECMA 262 \\S matches everything but whitespace", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "string", "pattern": "^\\S$" }, "tests": [ { "description": "ASCII space does not match", "data": " ", "valid": false }, { "description": "Character tabulation does not match", "data": "\t", "valid": false }, { "description": "Line tabulation does not match", "data": "\u000b", "valid": false }, { "description": "Form feed does not match", "data": "\u000c", "valid": false }, { "description": "latin-1 non-breaking-space does not match", "data": "\u00a0", "valid": false }, { "description": "zero-width whitespace does not match", "data": "\ufeff", "valid": false }, { "description": "line feed does not match (line terminator)", "data": "\u000a", "valid": false }, { "description": "paragraph separator does not match (line terminator)", "data": "\u2029", "valid": false }, { "description": "EM SPACE does not match (Space_Separator)", "data": "\u2003", "valid": false }, { "description": "Non-whitespace control matches", "data": "\u0001", "valid": true }, { "description": "Non-whitespace matches", "data": "\u2013", "valid": true } ] }, { "description": "patterns always use unicode semantics with pattern", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "pattern": "\\p{Letter}cole" }, "tests": [ { "description": "ascii character in json string", "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", "valid": true }, { "description": "literal unicode character in json string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": true }, { "description": "unicode character in hex format in string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": true }, { "description": "unicode matching is case-sensitive", "data": "LES HIVERS DE MON ENFANCE ÉTAIENT DES SAISONS LONGUES, LONGUES. NOUS VIVIONS EN TROIS LIEUX: L'ÉCOLE, L'ÉGLISE ET LA PATINOIRE; MAIS LA VRAIE VIE ÉTAIT SUR LA PATINOIRE.", "valid": false } ] }, { "description": "\\w in patterns matches [A-Za-z0-9_], not unicode letters", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "pattern": "\\wcole" }, "tests": [ { "description": "ascii character in json string", "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", "valid": true }, { "description": "literal unicode character in json string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "unicode character in hex format in string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "unicode matching is case-sensitive", "data": "LES HIVERS DE MON ENFANCE ÉTAIENT DES SAISONS LONGUES, LONGUES. NOUS VIVIONS EN TROIS LIEUX: L'ÉCOLE, L'ÉGLISE ET LA PATINOIRE; MAIS LA VRAIE VIE ÉTAIT SUR LA PATINOIRE.", "valid": false } ] }, { "description": "pattern with ASCII ranges", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "pattern": "[a-z]cole" }, "tests": [ { "description": "literal unicode character in json string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "unicode character in hex format in string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "ascii characters match", "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", "valid": true } ] }, { "description": "\\d in pattern matches [0-9], not unicode digits", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "pattern": "^\\d+$" }, "tests": [ { "description": "ascii digits", "data": "42", "valid": true }, { "description": "ascii non-digits", "data": "-%#", "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": "৪২", "valid": false } ] }, { "description": "\\a is not an ECMA 262 control escape", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$ref": "https://json-schema.org/draft/next/schema" }, "tests": [ { "description": "when used as a pattern", "data": { "pattern": "\\a" }, "valid": false } ] }, { "description": "pattern with non-ASCII digits", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "pattern": "^\\p{digit}+$" }, "tests": [ { "description": "ascii digits", "data": "42", "valid": true }, { "description": "ascii non-digits", "data": "-%#", "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": "৪২", "valid": true } ] }, { "description": "patterns always use unicode semantics with patternProperties", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "patternProperties": { "\\p{Letter}cole": true }, "additionalProperties": false }, "tests": [ { "description": "ascii character in json string", "data": { "l'ecole": "pas de vraie vie" }, "valid": true }, { "description": "literal unicode character in json string", "data": { "l'école": "pas de vraie vie" }, "valid": true }, { "description": "unicode character in hex format in string", "data": { "l'\u00e9cole": "pas de vraie vie" }, "valid": true }, { "description": "unicode matching is case-sensitive", "data": { "L'ÉCOLE": "PAS DE VRAIE VIE" }, "valid": false } ] }, { "description": "\\w in patternProperties matches [A-Za-z0-9_], not unicode letters", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "patternProperties": { "\\wcole": true }, "additionalProperties": false }, "tests": [ { "description": "ascii character in json string", "data": { "l'ecole": "pas de vraie vie" }, "valid": true }, { "description": "literal unicode character in json string", "data": { "l'école": "pas de vraie vie" }, "valid": false }, { "description": "unicode character in hex format in string", "data": { "l'\u00e9cole": "pas de vraie vie" }, "valid": false }, { "description": "unicode matching is case-sensitive", "data": { "L'ÉCOLE": "PAS DE VRAIE VIE" }, "valid": false } ] }, { "description": "patternProperties with ASCII ranges", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "patternProperties": { "[a-z]cole": true }, "additionalProperties": false }, "tests": [ { "description": "literal unicode character in json string", "data": { "l'école": "pas de vraie vie" }, "valid": false }, { "description": "unicode character in hex format in string", "data": { "l'\u00e9cole": "pas de vraie vie" }, "valid": false }, { "description": "ascii characters match", "data": { "l'ecole": "pas de vraie vie" }, "valid": true } ] }, { "description": "\\d in patternProperties matches [0-9], not unicode digits", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "patternProperties": { "^\\d+$": true }, "additionalProperties": false }, "tests": [ { "description": "ascii digits", "data": { "42": "life, the universe, and everything" }, "valid": true }, { "description": "ascii non-digits", "data": { "-%#": "spending the year dead for tax reasons" }, "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": { "৪২": "khajit has wares if you have coin" }, "valid": false } ] }, { "description": "patternProperties with non-ASCII digits", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "patternProperties": { "^\\p{digit}+$": true }, "additionalProperties": false }, "tests": [ { "description": "ascii digits", "data": { "42": "life, the universe, and everything" }, "valid": true }, { "description": "ascii non-digits", "data": { "-%#": "spending the year dead for tax reasons" }, "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": { "৪২": "khajit has wares if you have coin" }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/float-overflow.json0000644000175100001770000000071714653725311027137 0ustar00runnerdocker[ { "description": "all integers are multiples of 0.5, if overflow is handled", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "integer", "multipleOf": 0.5 }, "tests": [ { "description": "valid if optional overflow handling is implemented", "data": 1e308, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0570965 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/format/0000755000175100001770000000000014653725331024563 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/format/date-time.json0000644000175100001770000001121014653725311027320 0ustar00runnerdocker[ { "description": "validation of date-time strings", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "date-time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid date-time string", "data": "1963-06-19T08:30:06.283185Z", "valid": true }, { "description": "a valid date-time string without second fraction", "data": "1963-06-19T08:30:06Z", "valid": true }, { "description": "a valid date-time string with plus offset", "data": "1937-01-01T12:00:27.87+00:20", "valid": true }, { "description": "a valid date-time string with minus offset", "data": "1990-12-31T15:59:50.123-08:00", "valid": true }, { "description": "a valid date-time with a leap second, UTC", "data": "1998-12-31T23:59:60Z", "valid": true }, { "description": "a valid date-time with a leap second, with minus offset", "data": "1998-12-31T15:59:60.123-08:00", "valid": true }, { "description": "an invalid date-time past leap second, UTC", "data": "1998-12-31T23:59:61Z", "valid": false }, { "description": "an invalid date-time with leap second on a wrong minute, UTC", "data": "1998-12-31T23:58:60Z", "valid": false }, { "description": "an invalid date-time with leap second on a wrong hour, UTC", "data": "1998-12-31T22:59:60Z", "valid": false }, { "description": "an invalid day in date-time string", "data": "1990-02-31T15:59:59.123-08:00", "valid": false }, { "description": "an invalid offset in date-time string", "data": "1990-12-31T15:59:59-24:00", "valid": false }, { "description": "an invalid closing Z after time-zone offset", "data": "1963-06-19T08:30:06.28123+01:00Z", "valid": false }, { "description": "an invalid date-time string", "data": "06/19/1963 08:30:06 PST", "valid": false }, { "description": "case-insensitive T and Z", "data": "1963-06-19t08:30:06.283185z", "valid": true }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "2013-350T01:01:01", "valid": false }, { "description": "invalid non-padded month dates", "data": "1963-6-19T08:30:06.283185Z", "valid": false }, { "description": "invalid non-padded day dates", "data": "1963-06-1T08:30:06.283185Z", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4) in date portion", "data": "1963-06-1৪T00:00:00Z", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4) in time portion", "data": "1963-06-11T0৪:00:00Z", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/format/date.json0000644000175100001770000001656014653725311026401 0ustar00runnerdocker[ { "description": "validation of date strings", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "date" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid date string", "data": "1963-06-19", "valid": true }, { "description": "a valid date string with 31 days in January", "data": "2020-01-31", "valid": true }, { "description": "a invalid date string with 32 days in January", "data": "2020-01-32", "valid": false }, { "description": "a valid date string with 28 days in February (normal)", "data": "2021-02-28", "valid": true }, { "description": "a invalid date string with 29 days in February (normal)", "data": "2021-02-29", "valid": false }, { "description": "a valid date string with 29 days in February (leap)", "data": "2020-02-29", "valid": true }, { "description": "a invalid date string with 30 days in February (leap)", "data": "2020-02-30", "valid": false }, { "description": "a valid date string with 31 days in March", "data": "2020-03-31", "valid": true }, { "description": "a invalid date string with 32 days in March", "data": "2020-03-32", "valid": false }, { "description": "a valid date string with 30 days in April", "data": "2020-04-30", "valid": true }, { "description": "a invalid date string with 31 days in April", "data": "2020-04-31", "valid": false }, { "description": "a valid date string with 31 days in May", "data": "2020-05-31", "valid": true }, { "description": "a invalid date string with 32 days in May", "data": "2020-05-32", "valid": false }, { "description": "a valid date string with 30 days in June", "data": "2020-06-30", "valid": true }, { "description": "a invalid date string with 31 days in June", "data": "2020-06-31", "valid": false }, { "description": "a valid date string with 31 days in July", "data": "2020-07-31", "valid": true }, { "description": "a invalid date string with 32 days in July", "data": "2020-07-32", "valid": false }, { "description": "a valid date string with 31 days in August", "data": "2020-08-31", "valid": true }, { "description": "a invalid date string with 32 days in August", "data": "2020-08-32", "valid": false }, { "description": "a valid date string with 30 days in September", "data": "2020-09-30", "valid": true }, { "description": "a invalid date string with 31 days in September", "data": "2020-09-31", "valid": false }, { "description": "a valid date string with 31 days in October", "data": "2020-10-31", "valid": true }, { "description": "a invalid date string with 32 days in October", "data": "2020-10-32", "valid": false }, { "description": "a valid date string with 30 days in November", "data": "2020-11-30", "valid": true }, { "description": "a invalid date string with 31 days in November", "data": "2020-11-31", "valid": false }, { "description": "a valid date string with 31 days in December", "data": "2020-12-31", "valid": true }, { "description": "a invalid date string with 32 days in December", "data": "2020-12-32", "valid": false }, { "description": "a invalid date string with invalid month", "data": "2020-13-01", "valid": false }, { "description": "an invalid date string", "data": "06/19/1963", "valid": false }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "2013-350", "valid": false }, { "description": "non-padded month dates are not valid", "data": "1998-1-20", "valid": false }, { "description": "non-padded day dates are not valid", "data": "1998-01-1", "valid": false }, { "description": "invalid month", "data": "1998-13-01", "valid": false }, { "description": "invalid month-day combination", "data": "1998-04-31", "valid": false }, { "description": "2021 is not a leap year", "data": "2021-02-29", "valid": false }, { "description": "2020 is a leap year", "data": "2020-02-29", "valid": true }, { "description": "invalid non-ASCII '৪' (a Bengali 4)", "data": "1963-06-1৪", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/format/duration.json0000644000175100001770000000771514653725311027313 0ustar00runnerdocker[ { "description": "validation of duration strings", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "duration" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid duration string", "data": "P4DT12H30M5S", "valid": true }, { "description": "an invalid duration string", "data": "PT1D", "valid": false }, { "description": "no elements present", "data": "P", "valid": false }, { "description": "no time elements present", "data": "P1YT", "valid": false }, { "description": "no date or time elements present", "data": "PT", "valid": false }, { "description": "elements out of order", "data": "P2D1Y", "valid": false }, { "description": "missing time separator", "data": "P1D2H", "valid": false }, { "description": "time element in the date position", "data": "P2S", "valid": false }, { "description": "four years duration", "data": "P4Y", "valid": true }, { "description": "zero time, in seconds", "data": "PT0S", "valid": true }, { "description": "zero time, in days", "data": "P0D", "valid": true }, { "description": "one month duration", "data": "P1M", "valid": true }, { "description": "one minute duration", "data": "PT1M", "valid": true }, { "description": "one and a half days, in hours", "data": "PT36H", "valid": true }, { "description": "one and a half days, in days and hours", "data": "P1DT12H", "valid": true }, { "description": "two weeks", "data": "P2W", "valid": true }, { "description": "weeks cannot be combined with other units", "data": "P1Y2W", "valid": false }, { "description": "invalid non-ASCII '২' (a Bengali 2)", "data": "P২Y", "valid": false }, { "description": "element without unit", "data": "P1", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/format/email.json0000644000175100001770000000772114653725311026552 0ustar00runnerdocker[ { "description": "validation of e-mail addresses", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid e-mail address", "data": "joe.bloggs@example.com", "valid": true }, { "description": "an invalid e-mail address", "data": "2962", "valid": false }, { "description": "tilde in local part is valid", "data": "te~st@example.com", "valid": true }, { "description": "tilde before local part is valid", "data": "~test@example.com", "valid": true }, { "description": "tilde after local part is valid", "data": "test~@example.com", "valid": true }, { "description": "a quoted string with a space in the local part is valid", "data": "\"joe bloggs\"@example.com", "valid": true }, { "description": "a quoted string with a double dot in the local part is valid", "data": "\"joe..bloggs\"@example.com", "valid": true }, { "description": "a quoted string with a @ in the local part is valid", "data": "\"joe@bloggs\"@example.com", "valid": true }, { "description": "an IPv4-address-literal after the @ is valid", "data": "joe.bloggs@[127.0.0.1]", "valid": true }, { "description": "an IPv6-address-literal after the @ is valid", "data": "joe.bloggs@[IPv6:::1]", "valid": true }, { "description": "dot before local part is not valid", "data": ".test@example.com", "valid": false }, { "description": "dot after local part is not valid", "data": "test.@example.com", "valid": false }, { "description": "two separated dots inside local part are valid", "data": "te.s.t@example.com", "valid": true }, { "description": "two subsequent dots inside local part are not valid", "data": "te..st@example.com", "valid": false }, { "description": "an invalid domain", "data": "joe.bloggs@invalid=domain.com", "valid": false }, { "description": "an invalid IPv4-address-literal", "data": "joe.bloggs@[127.0.0.300]", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/format/hostname.json0000644000175100001770000000635414653725311027302 0ustar00runnerdocker[ { "description": "validation of host names", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid host name", "data": "www.example.com", "valid": true }, { "description": "a valid punycoded IDN hostname", "data": "xn--4gbwdl.xn--wgbh1c", "valid": true }, { "description": "a host name starting with an illegal character", "data": "-a-host-name-that-starts-with--", "valid": false }, { "description": "a host name containing illegal characters", "data": "not_a_valid_host_name", "valid": false }, { "description": "a host name with a component too long", "data": "a-vvvvvvvvvvvvvvvveeeeeeeeeeeeeeeerrrrrrrrrrrrrrrryyyyyyyyyyyyyyyy-long-host-name-component", "valid": false }, { "description": "starts with hyphen", "data": "-hostname", "valid": false }, { "description": "ends with hyphen", "data": "hostname-", "valid": false }, { "description": "starts with underscore", "data": "_hostname", "valid": false }, { "description": "ends with underscore", "data": "hostname_", "valid": false }, { "description": "contains underscore", "data": "host_name", "valid": false }, { "description": "maximum label length", "data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.com", "valid": true }, { "description": "exceeds maximum label length", "data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl.com", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/format/idn-email.json0000644000175100001770000000350414653725311027315 0ustar00runnerdocker[ { "description": "validation of an internationalized e-mail addresses", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "idn-email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid idn e-mail (example@example.test in Hangul)", "data": "실례@실례.테스트", "valid": true }, { "description": "an invalid idn e-mail address", "data": "2962", "valid": false }, { "description": "a valid e-mail address", "data": "joe.bloggs@example.com", "valid": true }, { "description": "an invalid e-mail address", "data": "2962", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/format/idn-hostname.json0000644000175100001770000003477114653725311030056 0ustar00runnerdocker[ { "description": "validation of internationalized host names", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "idn-hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid host name (example.test in Hangul)", "data": "실례.테스트", "valid": true }, { "description": "illegal first char U+302E Hangul single dot tone mark", "data": "〮실례.테스트", "valid": false }, { "description": "contains illegal char U+302E Hangul single dot tone mark", "data": "실〮례.테스트", "valid": false }, { "description": "a host name with a component too long", "data": "실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실례례테스트례례례례례례례례례례례례례례례례례테스트례례례례례례례례례례례례례례례례례례례테스트례례례례례례례례례례례례테스트례례실례.테스트", "valid": false }, { "description": "invalid label, correct Punycode", "comment": "https://tools.ietf.org/html/rfc5890#section-2.3.2.1 https://tools.ietf.org/html/rfc5891#section-4.4 https://tools.ietf.org/html/rfc3492#section-7.1", "data": "-> $1.00 <--", "valid": false }, { "description": "valid Chinese Punycode", "comment": "https://tools.ietf.org/html/rfc5890#section-2.3.2.1 https://tools.ietf.org/html/rfc5891#section-4.4", "data": "xn--ihqwcrb4cv8a8dqg056pqjye", "valid": true }, { "description": "invalid Punycode", "comment": "https://tools.ietf.org/html/rfc5891#section-4.4 https://tools.ietf.org/html/rfc5890#section-2.3.2.1", "data": "xn--X", "valid": false }, { "description": "U-label contains \"--\" in the 3rd and 4th position", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1 https://tools.ietf.org/html/rfc5890#section-2.3.2.1", "data": "XN--aa---o47jg78q", "valid": false }, { "description": "U-label starts with a dash", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1", "data": "-hello", "valid": false }, { "description": "U-label ends with a dash", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1", "data": "hello-", "valid": false }, { "description": "U-label starts and ends with a dash", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1", "data": "-hello-", "valid": false }, { "description": "Begins with a Spacing Combining Mark", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2", "data": "\u0903hello", "valid": false }, { "description": "Begins with a Nonspacing Mark", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2", "data": "\u0300hello", "valid": false }, { "description": "Begins with an Enclosing Mark", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2", "data": "\u0488hello", "valid": false }, { "description": "Exceptions that are PVALID, left-to-right chars", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6", "data": "\u00df\u03c2\u0f0b\u3007", "valid": true }, { "description": "Exceptions that are PVALID, right-to-left chars", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6", "data": "\u06fd\u06fe", "valid": true }, { "description": "Exceptions that are DISALLOWED, right-to-left chars", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6", "data": "\u0640\u07fa", "valid": false }, { "description": "Exceptions that are DISALLOWED, left-to-right chars", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6 Note: The two combining marks (U+302E and U+302F) are in the middle and not at the start", "data": "\u3031\u3032\u3033\u3034\u3035\u302e\u302f\u303b", "valid": false }, { "description": "MIDDLE DOT with no preceding 'l'", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "a\u00b7l", "valid": false }, { "description": "MIDDLE DOT with nothing preceding", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "\u00b7l", "valid": false }, { "description": "MIDDLE DOT with no following 'l'", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "l\u00b7a", "valid": false }, { "description": "MIDDLE DOT with nothing following", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "l\u00b7", "valid": false }, { "description": "MIDDLE DOT with surrounding 'l's", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "l\u00b7l", "valid": true }, { "description": "Greek KERAIA not followed by Greek", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4", "data": "\u03b1\u0375S", "valid": false }, { "description": "Greek KERAIA not followed by anything", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4", "data": "\u03b1\u0375", "valid": false }, { "description": "Greek KERAIA followed by Greek", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4", "data": "\u03b1\u0375\u03b2", "valid": true }, { "description": "Hebrew GERESH not preceded by Hebrew", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5", "data": "A\u05f3\u05d1", "valid": false }, { "description": "Hebrew GERESH not preceded by anything", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5", "data": "\u05f3\u05d1", "valid": false }, { "description": "Hebrew GERESH preceded by Hebrew", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5", "data": "\u05d0\u05f3\u05d1", "valid": true }, { "description": "Hebrew GERSHAYIM not preceded by Hebrew", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6", "data": "A\u05f4\u05d1", "valid": false }, { "description": "Hebrew GERSHAYIM not preceded by anything", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6", "data": "\u05f4\u05d1", "valid": false }, { "description": "Hebrew GERSHAYIM preceded by Hebrew", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6", "data": "\u05d0\u05f4\u05d1", "valid": true }, { "description": "KATAKANA MIDDLE DOT with no Hiragana, Katakana, or Han", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "def\u30fbabc", "valid": false }, { "description": "KATAKANA MIDDLE DOT with no other characters", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "\u30fb", "valid": false }, { "description": "KATAKANA MIDDLE DOT with Hiragana", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "\u30fb\u3041", "valid": true }, { "description": "KATAKANA MIDDLE DOT with Katakana", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "\u30fb\u30a1", "valid": true }, { "description": "KATAKANA MIDDLE DOT with Han", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "\u30fb\u4e08", "valid": true }, { "description": "Arabic-Indic digits mixed with Extended Arabic-Indic digits", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.8", "data": "\u0660\u06f0", "valid": false }, { "description": "Arabic-Indic digits not mixed with Extended Arabic-Indic digits", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.8", "data": "\u0628\u0660\u0628", "valid": true }, { "description": "Extended Arabic-Indic digits not mixed with Arabic-Indic digits", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.9", "data": "\u06f00", "valid": true }, { "description": "ZERO WIDTH JOINER not preceded by Virama", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf", "data": "\u0915\u200d\u0937", "valid": false }, { "description": "ZERO WIDTH JOINER not preceded by anything", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf", "data": "\u200d\u0937", "valid": false }, { "description": "ZERO WIDTH JOINER preceded by Virama", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf", "data": "\u0915\u094d\u200d\u0937", "valid": true }, { "description": "ZERO WIDTH NON-JOINER preceded by Virama", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.1", "data": "\u0915\u094d\u200c\u0937", "valid": true }, { "description": "ZERO WIDTH NON-JOINER not preceded by Virama but matches regexp", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.1 https://www.w3.org/TR/alreq/#h_disjoining_enforcement", "data": "\u0628\u064a\u200c\u0628\u064a", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/format/ipv4.json0000644000175100001770000000553414653725311026345 0ustar00runnerdocker[ { "description": "validation of IP addresses", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "ipv4" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IP address", "data": "192.168.0.1", "valid": true }, { "description": "an IP address with too many components", "data": "127.0.0.0.1", "valid": false }, { "description": "an IP address with out-of-range values", "data": "256.256.256.256", "valid": false }, { "description": "an IP address without 4 components", "data": "127.0", "valid": false }, { "description": "an IP address as an integer", "data": "0x7f000001", "valid": false }, { "description": "an IP address as an integer (decimal)", "data": "2130706433", "valid": false }, { "description": "invalid leading zeroes, as they are treated as octals", "comment": "see https://sick.codes/universal-netmask-npm-package-used-by-270000-projects-vulnerable-to-octal-input-data-server-side-request-forgery-remote-file-inclusion-local-file-inclusion-and-more-cve-2021-28918/", "data": "087.10.0.1", "valid": false }, { "description": "value without leading zero is valid", "data": "87.10.0.1", "valid": true }, { "description": "invalid non-ASCII '২' (a Bengali 2)", "data": "1২7.0.0.1", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/format/ipv6.json0000644000175100001770000001556714653725311026356 0ustar00runnerdocker[ { "description": "validation of IPv6 addresses", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "ipv6" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IPv6 address", "data": "::1", "valid": true }, { "description": "an IPv6 address with out-of-range values", "data": "12345::", "valid": false }, { "description": "trailing 4 hex symbols is valid", "data": "::abef", "valid": true }, { "description": "trailing 5 hex symbols is invalid", "data": "::abcef", "valid": false }, { "description": "an IPv6 address with too many components", "data": "1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1", "valid": false }, { "description": "an IPv6 address containing illegal characters", "data": "::laptop", "valid": false }, { "description": "no digits is valid", "data": "::", "valid": true }, { "description": "leading colons is valid", "data": "::42:ff:1", "valid": true }, { "description": "trailing colons is valid", "data": "d6::", "valid": true }, { "description": "missing leading octet is invalid", "data": ":2:3:4:5:6:7:8", "valid": false }, { "description": "missing trailing octet is invalid", "data": "1:2:3:4:5:6:7:", "valid": false }, { "description": "missing leading octet with omitted octets later", "data": ":2:3:4::8", "valid": false }, { "description": "single set of double colons in the middle is valid", "data": "1:d6::42", "valid": true }, { "description": "two sets of double colons is invalid", "data": "1::d6::42", "valid": false }, { "description": "mixed format with the ipv4 section as decimal octets", "data": "1::d6:192.168.0.1", "valid": true }, { "description": "mixed format with double colons between the sections", "data": "1:2::192.168.0.1", "valid": true }, { "description": "mixed format with ipv4 section with octet out of range", "data": "1::2:192.168.256.1", "valid": false }, { "description": "mixed format with ipv4 section with a hex octet", "data": "1::2:192.168.ff.1", "valid": false }, { "description": "mixed format with leading double colons (ipv4-mapped ipv6 address)", "data": "::ffff:192.168.0.1", "valid": true }, { "description": "triple colons is invalid", "data": "1:2:3:4:5:::8", "valid": false }, { "description": "8 octets", "data": "1:2:3:4:5:6:7:8", "valid": true }, { "description": "insufficient octets without double colons", "data": "1:2:3:4:5:6:7", "valid": false }, { "description": "no colons is invalid", "data": "1", "valid": false }, { "description": "ipv4 is not ipv6", "data": "127.0.0.1", "valid": false }, { "description": "ipv4 segment must have 4 octets", "data": "1:2:3:4:1.2.3", "valid": false }, { "description": "leading whitespace is invalid", "data": " ::1", "valid": false }, { "description": "trailing whitespace is invalid", "data": "::1 ", "valid": false }, { "description": "netmask is not a part of ipv6 address", "data": "fe80::/64", "valid": false }, { "description": "zone id is not a part of ipv6 address", "data": "fe80::a%eth1", "valid": false }, { "description": "a long valid ipv6", "data": "1000:1000:1000:1000:1000:1000:255.255.255.255", "valid": true }, { "description": "a long invalid ipv6, below length limit, first", "data": "100:100:100:100:100:100:255.255.255.255.255", "valid": false }, { "description": "a long invalid ipv6, below length limit, second", "data": "100:100:100:100:100:100:100:255.255.255.255", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4)", "data": "1:2:3:4:5:6:7:৪", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4) in the IPv4 portion", "data": "1:2::192.16৪.0.1", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/format/iri-reference.json0000644000175100001770000000444214653725311030177 0ustar00runnerdocker[ { "description": "validation of IRI References", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "iri-reference" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IRI", "data": "http://ƒøø.ßår/?∂éœ=πîx#πîüx", "valid": true }, { "description": "a valid protocol-relative IRI Reference", "data": "//ƒøø.ßår/?∂éœ=πîx#πîüx", "valid": true }, { "description": "a valid relative IRI Reference", "data": "/âππ", "valid": true }, { "description": "an invalid IRI Reference", "data": "\\\\WINDOWS\\filëßåré", "valid": false }, { "description": "a valid IRI Reference", "data": "âππ", "valid": true }, { "description": "a valid IRI fragment", "data": "#Æ’rägmênt", "valid": true }, { "description": "an invalid IRI fragment", "data": "#Æ’räg\\mênt", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/format/iri.json0000644000175100001770000000545414653725311026247 0ustar00runnerdocker[ { "description": "validation of IRIs", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "iri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IRI with anchor tag", "data": "http://ƒøø.ßår/?∂éœ=πîx#πîüx", "valid": true }, { "description": "a valid IRI with anchor tag and parentheses", "data": "http://ƒøø.com/blah_(wîkïpédiÃ¥)_blah#ßité-1", "valid": true }, { "description": "a valid IRI with URL-encoded stuff", "data": "http://ƒøø.ßår/?q=Test%20URL-encoded%20stuff", "valid": true }, { "description": "a valid IRI with many special characters", "data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", "valid": true }, { "description": "a valid IRI based on IPv6", "data": "http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]", "valid": true }, { "description": "an invalid IRI based on IPv6", "data": "http://2001:0db8:85a3:0000:0000:8a2e:0370:7334", "valid": false }, { "description": "an invalid relative IRI Reference", "data": "/abc", "valid": false }, { "description": "an invalid IRI", "data": "\\\\WINDOWS\\filëßåré", "valid": false }, { "description": "an invalid IRI though valid IRI reference", "data": "âππ", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/format/json-pointer.json0000644000175100001770000001521314653725311030105 0ustar00runnerdocker[ { "description": "validation of JSON-pointers (JSON String Representation)", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "json-pointer" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid JSON-pointer", "data": "/foo/bar~0/baz~1/%a", "valid": true }, { "description": "not a valid JSON-pointer (~ not escaped)", "data": "/foo/bar~", "valid": false }, { "description": "valid JSON-pointer with empty segment", "data": "/foo//bar", "valid": true }, { "description": "valid JSON-pointer with the last empty segment", "data": "/foo/bar/", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #1", "data": "", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #2", "data": "/foo", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #3", "data": "/foo/0", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #4", "data": "/", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #5", "data": "/a~1b", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #6", "data": "/c%d", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #7", "data": "/e^f", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #8", "data": "/g|h", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #9", "data": "/i\\j", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #10", "data": "/k\"l", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #11", "data": "/ ", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #12", "data": "/m~0n", "valid": true }, { "description": "valid JSON-pointer used adding to the last array position", "data": "/foo/-", "valid": true }, { "description": "valid JSON-pointer (- used as object member name)", "data": "/foo/-/bar", "valid": true }, { "description": "valid JSON-pointer (multiple escaped characters)", "data": "/~1~0~0~1~1", "valid": true }, { "description": "valid JSON-pointer (escaped with fraction part) #1", "data": "/~1.1", "valid": true }, { "description": "valid JSON-pointer (escaped with fraction part) #2", "data": "/~0.1", "valid": true }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #1", "data": "#", "valid": false }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #2", "data": "#/", "valid": false }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #3", "data": "#a", "valid": false }, { "description": "not a valid JSON-pointer (some escaped, but not all) #1", "data": "/~0~", "valid": false }, { "description": "not a valid JSON-pointer (some escaped, but not all) #2", "data": "/~0/~", "valid": false }, { "description": "not a valid JSON-pointer (wrong escape character) #1", "data": "/~2", "valid": false }, { "description": "not a valid JSON-pointer (wrong escape character) #2", "data": "/~-1", "valid": false }, { "description": "not a valid JSON-pointer (multiple characters not escaped)", "data": "/~~", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #1", "data": "a", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #2", "data": "0", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #3", "data": "a/a", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/format/regex.json0000644000175100001770000000274614653725311026577 0ustar00runnerdocker[ { "description": "validation of regular expressions", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "regex" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid regular expression", "data": "([abc])+\\s+$", "valid": true }, { "description": "a regular expression with unclosed parens is invalid", "data": "^(abc]", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/format/relative-json-pointer.json0000644000175100001770000000607314653725311031722 0ustar00runnerdocker[ { "description": "validation of Relative JSON Pointers (RJP)", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "relative-json-pointer" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid upwards RJP", "data": "1", "valid": true }, { "description": "a valid downwards RJP", "data": "0/foo/bar", "valid": true }, { "description": "a valid up and then down RJP, with array index", "data": "2/0/baz/1/zip", "valid": true }, { "description": "a valid RJP taking the member or index name", "data": "0#", "valid": true }, { "description": "an invalid RJP that is a valid JSON Pointer", "data": "/foo/bar", "valid": false }, { "description": "negative prefix", "data": "-1/foo/bar", "valid": false }, { "description": "explicit positive prefix", "data": "+1/foo/bar", "valid": false }, { "description": "## is not a valid json-pointer", "data": "0##", "valid": false }, { "description": "zero cannot be followed by other digits, plus json-pointer", "data": "01/a", "valid": false }, { "description": "zero cannot be followed by other digits, plus octothorpe", "data": "01#", "valid": false }, { "description": "empty string", "data": "", "valid": false }, { "description": "multi-digit integer prefix", "data": "120/foo/bar", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/format/time.json0000644000175100001770000001631614653725311026421 0ustar00runnerdocker[ { "description": "validation of time strings", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid time string", "data": "08:30:06Z", "valid": true }, { "description": "a valid time string with leap second, Zulu", "data": "23:59:60Z", "valid": true }, { "description": "invalid leap second, Zulu (wrong hour)", "data": "22:59:60Z", "valid": false }, { "description": "invalid leap second, Zulu (wrong minute)", "data": "23:58:60Z", "valid": false }, { "description": "valid leap second, zero time-offset", "data": "23:59:60+00:00", "valid": true }, { "description": "invalid leap second, zero time-offset (wrong hour)", "data": "22:59:60+00:00", "valid": false }, { "description": "invalid leap second, zero time-offset (wrong minute)", "data": "23:58:60+00:00", "valid": false }, { "description": "valid leap second, positive time-offset", "data": "01:29:60+01:30", "valid": true }, { "description": "valid leap second, large positive time-offset", "data": "23:29:60+23:30", "valid": true }, { "description": "invalid leap second, positive time-offset (wrong hour)", "data": "23:59:60+01:00", "valid": false }, { "description": "invalid leap second, positive time-offset (wrong minute)", "data": "23:59:60+00:30", "valid": false }, { "description": "valid leap second, negative time-offset", "data": "15:59:60-08:00", "valid": true }, { "description": "valid leap second, large negative time-offset", "data": "00:29:60-23:30", "valid": true }, { "description": "invalid leap second, negative time-offset (wrong hour)", "data": "23:59:60-01:00", "valid": false }, { "description": "invalid leap second, negative time-offset (wrong minute)", "data": "23:59:60-00:30", "valid": false }, { "description": "a valid time string with second fraction", "data": "23:20:50.52Z", "valid": true }, { "description": "a valid time string with precise second fraction", "data": "08:30:06.283185Z", "valid": true }, { "description": "a valid time string with plus offset", "data": "08:30:06+00:20", "valid": true }, { "description": "a valid time string with minus offset", "data": "08:30:06-08:00", "valid": true }, { "description": "a valid time string with case-insensitive Z", "data": "08:30:06z", "valid": true }, { "description": "an invalid time string with invalid hour", "data": "24:00:00Z", "valid": false }, { "description": "an invalid time string with invalid minute", "data": "00:60:00Z", "valid": false }, { "description": "an invalid time string with invalid second", "data": "00:00:61Z", "valid": false }, { "description": "an invalid time string with invalid leap second (wrong hour)", "data": "22:59:60Z", "valid": false }, { "description": "an invalid time string with invalid leap second (wrong minute)", "data": "23:58:60Z", "valid": false }, { "description": "an invalid time string with invalid time numoffset hour", "data": "01:02:03+24:00", "valid": false }, { "description": "an invalid time string with invalid time numoffset minute", "data": "01:02:03+00:60", "valid": false }, { "description": "an invalid time string with invalid time with both Z and numoffset", "data": "01:02:03Z+00:30", "valid": false }, { "description": "an invalid offset indicator", "data": "08:30:06 PST", "valid": false }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "01:01:01,1111", "valid": false }, { "description": "no time offset", "data": "12:00:00", "valid": false }, { "description": "no time offset with second fraction", "data": "12:00:00.52", "valid": false }, { "description": "invalid non-ASCII '২' (a Bengali 2)", "data": "1২:00:00Z", "valid": false }, { "description": "offset not starting with plus or minus", "data": "08:30:06#00:20", "valid": false }, { "description": "contains letters", "data": "ab:cd:ef", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/format/uri-reference.json0000644000175100001770000000436714653725311030221 0ustar00runnerdocker[ { "description": "validation of URI References", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "uri-reference" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid URI", "data": "http://foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid protocol-relative URI Reference", "data": "//foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid relative URI Reference", "data": "/abc", "valid": true }, { "description": "an invalid URI Reference", "data": "\\\\WINDOWS\\fileshare", "valid": false }, { "description": "a valid URI Reference", "data": "abc", "valid": true }, { "description": "a valid URI fragment", "data": "#fragment", "valid": true }, { "description": "an invalid URI fragment", "data": "#frag\\ment", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/format/uri-template.json0000644000175100001770000000356114653725311030071 0ustar00runnerdocker[ { "description": "format: uri-template", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "uri-template" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid uri-template", "data": "http://example.com/dictionary/{term:1}/{term}", "valid": true }, { "description": "an invalid uri-template", "data": "http://example.com/dictionary/{term:1}/{term", "valid": false }, { "description": "a valid uri-template without variables", "data": "http://example.com/dictionary", "valid": true }, { "description": "a valid relative uri-template", "data": "dictionary/{term:1}/{term}", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/format/uri.json0000644000175100001770000001116414653725311026256 0ustar00runnerdocker[ { "description": "validation of URIs", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "uri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid URL with anchor tag", "data": "http://foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid URL with anchor tag and parentheses", "data": "http://foo.com/blah_(wikipedia)_blah#cite-1", "valid": true }, { "description": "a valid URL with URL-encoded stuff", "data": "http://foo.bar/?q=Test%20URL-encoded%20stuff", "valid": true }, { "description": "a valid puny-coded URL ", "data": "http://xn--nw2a.xn--j6w193g/", "valid": true }, { "description": "a valid URL with many special characters", "data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", "valid": true }, { "description": "a valid URL based on IPv4", "data": "http://223.255.255.254", "valid": true }, { "description": "a valid URL with ftp scheme", "data": "ftp://ftp.is.co.za/rfc/rfc1808.txt", "valid": true }, { "description": "a valid URL for a simple text file", "data": "http://www.ietf.org/rfc/rfc2396.txt", "valid": true }, { "description": "a valid URL ", "data": "ldap://[2001:db8::7]/c=GB?objectClass?one", "valid": true }, { "description": "a valid mailto URI", "data": "mailto:John.Doe@example.com", "valid": true }, { "description": "a valid newsgroup URI", "data": "news:comp.infosystems.www.servers.unix", "valid": true }, { "description": "a valid tel URI", "data": "tel:+1-816-555-1212", "valid": true }, { "description": "a valid URN", "data": "urn:oasis:names:specification:docbook:dtd:xml:4.1.2", "valid": true }, { "description": "an invalid protocol-relative URI Reference", "data": "//foo.bar/?baz=qux#quux", "valid": false }, { "description": "an invalid relative URI Reference", "data": "/abc", "valid": false }, { "description": "an invalid URI", "data": "\\\\WINDOWS\\fileshare", "valid": false }, { "description": "an invalid URI though valid URI reference", "data": "abc", "valid": false }, { "description": "an invalid URI with spaces", "data": "http:// shouldfail.com", "valid": false }, { "description": "an invalid URI with spaces and missing scheme", "data": ":// should fail", "valid": false }, { "description": "an invalid URI with comma in scheme", "data": "bar,baz:foo", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/format/uuid.json0000644000175100001770000000725414653725311026432 0ustar00runnerdocker[ { "description": "uuid format", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "format": "uuid" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "all upper-case", "data": "2EB8AA08-AA98-11EA-B4AA-73B441D16380", "valid": true }, { "description": "all lower-case", "data": "2eb8aa08-aa98-11ea-b4aa-73b441d16380", "valid": true }, { "description": "mixed case", "data": "2eb8aa08-AA98-11ea-B4Aa-73B441D16380", "valid": true }, { "description": "all zeroes is valid", "data": "00000000-0000-0000-0000-000000000000", "valid": true }, { "description": "wrong length", "data": "2eb8aa08-aa98-11ea-b4aa-73b441d1638", "valid": false }, { "description": "missing section", "data": "2eb8aa08-aa98-11ea-73b441d16380", "valid": false }, { "description": "bad characters (not hex)", "data": "2eb8aa08-aa98-11ea-b4ga-73b441d16380", "valid": false }, { "description": "no dashes", "data": "2eb8aa08aa9811eab4aa73b441d16380", "valid": false }, { "description": "too few dashes", "data": "2eb8aa08aa98-11ea-b4aa73b441d16380", "valid": false }, { "description": "too many dashes", "data": "2eb8-aa08-aa98-11ea-b4aa73b44-1d16380", "valid": false }, { "description": "dashes in the wrong spot", "data": "2eb8aa08aa9811eab4aa73b441d16380----", "valid": false }, { "description": "valid version 4", "data": "98d80576-482e-427f-8434-7f86890ab222", "valid": true }, { "description": "valid version 5", "data": "99c17cbb-656f-564a-940f-1a4568f03487", "valid": true }, { "description": "hypothetical version 6", "data": "99c17cbb-656f-664a-940f-1a4568f03487", "valid": true }, { "description": "hypothetical version 15", "data": "99c17cbb-656f-f64a-940f-1a4568f03487", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/format-assertion.json0000644000175100001770000000253014653725311027461 0ustar00runnerdocker[ { "description": "schema that uses custom metaschema with format-assertion: false", "schema": { "$id": "https://schema/using/format-assertion/false", "$schema": "http://localhost:1234/draft-next/format-assertion-false.json", "format": "ipv4" }, "tests": [ { "description": "format-assertion: false: valid string", "data": "127.0.0.1", "valid": true }, { "description": "format-assertion: false: invalid string", "data": "not-an-ipv4", "valid": false } ] }, { "description": "schema that uses custom metaschema with format-assertion: true", "schema": { "$id": "https://schema/using/format-assertion/true", "$schema": "http://localhost:1234/draft-next/format-assertion-true.json", "format": "ipv4" }, "tests": [ { "description": "format-assertion: true: valid string", "data": "127.0.0.1", "valid": true }, { "description": "format-assertion: true: invalid string", "data": "not-an-ipv4", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/non-bmp-regex.json0000644000175100001770000000477214653725311026654 0ustar00runnerdocker[ { "description": "Proper UTF-16 surrogate pair handling: pattern", "comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "pattern": "^ðŸ²*$" }, "tests": [ { "description": "matches empty", "data": "", "valid": true }, { "description": "matches single", "data": "ðŸ²", "valid": true }, { "description": "matches two", "data": "ðŸ²ðŸ²", "valid": true }, { "description": "doesn't match one", "data": "ðŸ‰", "valid": false }, { "description": "doesn't match two", "data": "ðŸ‰ðŸ‰", "valid": false }, { "description": "doesn't match one ASCII", "data": "D", "valid": false }, { "description": "doesn't match two ASCII", "data": "DD", "valid": false } ] }, { "description": "Proper UTF-16 surrogate pair handling: patternProperties", "comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "patternProperties": { "^ðŸ²*$": { "type": "integer" } } }, "tests": [ { "description": "matches empty", "data": { "": 1 }, "valid": true }, { "description": "matches single", "data": { "ðŸ²": 1 }, "valid": true }, { "description": "matches two", "data": { "ðŸ²ðŸ²": 1 }, "valid": true }, { "description": "doesn't match one", "data": { "ðŸ²": "hello" }, "valid": false }, { "description": "doesn't match two", "data": { "ðŸ²ðŸ²": "hello" }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/optional/refOfUnknownKeyword.json0000644000175100001770000000242414653725311030154 0ustar00runnerdocker[ { "description": "reference of a root arbitrary keyword ", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "unknown-keyword": {"type": "integer"}, "properties": { "bar": {"$ref": "#/unknown-keyword"} } }, "tests": [ { "description": "match", "data": {"bar": 3}, "valid": true }, { "description": "mismatch", "data": {"bar": true}, "valid": false } ] }, { "description": "reference of an arbitrary keyword of a sub-schema", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": { "foo": {"unknown-keyword": {"type": "integer"}}, "bar": {"$ref": "#/properties/foo/unknown-keyword"} } }, "tests": [ { "description": "match", "data": {"bar": 3}, "valid": true }, { "description": "mismatch", "data": {"bar": true}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/pattern.json0000644000175100001770000000326714653725311024024 0ustar00runnerdocker[ { "description": "pattern validation", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "pattern": "^a*$" }, "tests": [ { "description": "a matching pattern is valid", "data": "aaa", "valid": true }, { "description": "a non-matching pattern is invalid", "data": "abc", "valid": false }, { "description": "ignores booleans", "data": true, "valid": true }, { "description": "ignores integers", "data": 123, "valid": true }, { "description": "ignores floats", "data": 1.0, "valid": true }, { "description": "ignores objects", "data": {}, "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores null", "data": null, "valid": true } ] }, { "description": "pattern is not anchored", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "pattern": "a+" }, "tests": [ { "description": "matches a substring", "data": "xxaayy", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/patternProperties.json0000644000175100001770000001261514653725311026076 0ustar00runnerdocker[ { "description": "patternProperties validates properties matching a regex", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "patternProperties": { "f.*o": {"type": "integer"} } }, "tests": [ { "description": "a single valid match is valid", "data": {"foo": 1}, "valid": true }, { "description": "multiple valid matches is valid", "data": {"foo": 1, "foooooo" : 2}, "valid": true }, { "description": "a single invalid match is invalid", "data": {"foo": "bar", "fooooo": 2}, "valid": false }, { "description": "multiple invalid matches is invalid", "data": {"foo": "bar", "foooooo" : "baz"}, "valid": false }, { "description": "ignores arrays", "data": ["foo"], "valid": true }, { "description": "ignores strings", "data": "foo", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "multiple simultaneous patternProperties are validated", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "patternProperties": { "a*": {"type": "integer"}, "aaa*": {"maximum": 20} } }, "tests": [ { "description": "a single valid match is valid", "data": {"a": 21}, "valid": true }, { "description": "a simultaneous match is valid", "data": {"aaaa": 18}, "valid": true }, { "description": "multiple matches is valid", "data": {"a": 21, "aaaa": 18}, "valid": true }, { "description": "an invalid due to one is invalid", "data": {"a": "bar"}, "valid": false }, { "description": "an invalid due to the other is invalid", "data": {"aaaa": 31}, "valid": false }, { "description": "an invalid due to both is invalid", "data": {"aaa": "foo", "aaaa": 31}, "valid": false } ] }, { "description": "regexes are not anchored by default and are case sensitive", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "patternProperties": { "[0-9]{2,}": { "type": "boolean" }, "X_": { "type": "string" } } }, "tests": [ { "description": "non recognized members are ignored", "data": { "answer 1": "42" }, "valid": true }, { "description": "recognized members are accounted for", "data": { "a31b": null }, "valid": false }, { "description": "regexes are case sensitive", "data": { "a_x_3": 3 }, "valid": true }, { "description": "regexes are case sensitive, 2", "data": { "a_X_3": 3 }, "valid": false } ] }, { "description": "patternProperties with boolean schemas", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "patternProperties": { "f.*": true, "b.*": false } }, "tests": [ { "description": "object with property matching schema true is valid", "data": {"foo": 1}, "valid": true }, { "description": "object with property matching schema false is invalid", "data": {"bar": 2}, "valid": false }, { "description": "object with both properties is invalid", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "object with a property matching both true and false is invalid", "data": {"foobar":1}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "patternProperties with null valued instance properties", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "patternProperties": { "^.*bar$": {"type": "null"} } }, "tests": [ { "description": "allows null values", "data": {"foobar": null}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/prefixItems.json0000644000175100001770000000554514653725311024647 0ustar00runnerdocker[ { "description": "a schema given for prefixItems", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "prefixItems": [ {"type": "integer"}, {"type": "string"} ] }, "tests": [ { "description": "correct types", "data": [ 1, "foo" ], "valid": true }, { "description": "wrong types", "data": [ "foo", 1 ], "valid": false }, { "description": "incomplete array of items", "data": [ 1 ], "valid": true }, { "description": "array with additional items", "data": [ 1, "foo", true ], "valid": true }, { "description": "empty array", "data": [ ], "valid": true }, { "description": "JavaScript pseudo-array is valid", "data": { "0": "invalid", "1": "valid", "length": 2 }, "valid": true } ] }, { "description": "prefixItems with boolean schemas", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "prefixItems": [true, false] }, "tests": [ { "description": "array with one item is valid", "data": [ 1 ], "valid": true }, { "description": "array with two items is invalid", "data": [ 1, "foo" ], "valid": false }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "additional items are allowed by default", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "prefixItems": [{"type": "integer"}] }, "tests": [ { "description": "only the first item is validated", "data": [1, "foo", false], "valid": true } ] }, { "description": "prefixItems with null instance elements", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "prefixItems": [ { "type": "null" } ] }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/properties.json0000644000175100001770000001704114653725311024536 0ustar00runnerdocker[ { "description": "object properties validation", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": { "foo": {"type": "integer"}, "bar": {"type": "string"} } }, "tests": [ { "description": "both properties present and valid is valid", "data": {"foo": 1, "bar": "baz"}, "valid": true }, { "description": "one property invalid is invalid", "data": {"foo": 1, "bar": {}}, "valid": false }, { "description": "both properties invalid is invalid", "data": {"foo": [], "bar": {}}, "valid": false }, { "description": "doesn't invalidate other properties", "data": {"quux": []}, "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "properties, patternProperties, additionalProperties interaction", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": { "foo": {"type": "array", "maxItems": 3}, "bar": {"type": "array"} }, "patternProperties": {"f.o": {"minItems": 2}}, "additionalProperties": {"type": "integer"} }, "tests": [ { "description": "property validates property", "data": {"foo": [1, 2]}, "valid": true }, { "description": "property invalidates property", "data": {"foo": [1, 2, 3, 4]}, "valid": false }, { "description": "patternProperty invalidates property", "data": {"foo": []}, "valid": false }, { "description": "patternProperty validates nonproperty", "data": {"fxo": [1, 2]}, "valid": true }, { "description": "patternProperty invalidates nonproperty", "data": {"fxo": []}, "valid": false }, { "description": "additionalProperty ignores property", "data": {"bar": []}, "valid": true }, { "description": "additionalProperty validates others", "data": {"quux": 3}, "valid": true }, { "description": "additionalProperty invalidates others", "data": {"quux": "foo"}, "valid": false } ] }, { "description": "properties with boolean schema", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": { "foo": true, "bar": false } }, "tests": [ { "description": "no property present is valid", "data": {}, "valid": true }, { "description": "only 'true' property present is valid", "data": {"foo": 1}, "valid": true }, { "description": "only 'false' property present is invalid", "data": {"bar": 2}, "valid": false }, { "description": "both properties present is invalid", "data": {"foo": 1, "bar": 2}, "valid": false } ] }, { "description": "properties with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": { "foo\nbar": {"type": "number"}, "foo\"bar": {"type": "number"}, "foo\\bar": {"type": "number"}, "foo\rbar": {"type": "number"}, "foo\tbar": {"type": "number"}, "foo\fbar": {"type": "number"} } }, "tests": [ { "description": "object with all numbers is valid", "data": { "foo\nbar": 1, "foo\"bar": 1, "foo\\bar": 1, "foo\rbar": 1, "foo\tbar": 1, "foo\fbar": 1 }, "valid": true }, { "description": "object with strings is invalid", "data": { "foo\nbar": "1", "foo\"bar": "1", "foo\\bar": "1", "foo\rbar": "1", "foo\tbar": "1", "foo\fbar": "1" }, "valid": false } ] }, { "description": "properties with null valued instance properties", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": { "foo": {"type": "null"} } }, "tests": [ { "description": "allows null values", "data": {"foo": null}, "valid": true } ] }, { "description": "properties whose names are Javascript object property names", "comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": { "__proto__": {"type": "number"}, "toString": { "properties": { "length": { "type": "string" } } }, "constructor": {"type": "number"} } }, "tests": [ { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "none of the properties mentioned", "data": {}, "valid": true }, { "description": "__proto__ not valid", "data": { "__proto__": "foo" }, "valid": false }, { "description": "toString not valid", "data": { "toString": { "length": 37 } }, "valid": false }, { "description": "constructor not valid", "data": { "constructor": { "length": 37 } }, "valid": false }, { "description": "all present and valid", "data": { "__proto__": 12, "toString": { "length": "foo" }, "constructor": 37 }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/propertyDependencies.json0000644000175100001770000001113014653725311026526 0ustar00runnerdocker[ { "description": "propertyDependencies doesn't act on non-objects", "schema": { "propertyDependencies": { "foo": {"bar": false} } }, "tests": [ { "description": "ignores booleans", "data": true, "valid": true }, { "description": "ignores integers", "data": 123, "valid": true }, { "description": "ignores floats", "data": 1.0, "valid": true }, { "description": "ignores strings", "data": "abc", "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores null", "data": null, "valid": true } ] }, { "description": "propertyDependencies doesn't act on non-string property values", "schema": { "propertyDependencies": { "foo": {"bar": false} } }, "tests": [ { "description": "ignores booleans", "data": {"foo": false}, "valid": true }, { "description": "ignores integers", "data": {"foo": 2}, "valid": true }, { "description": "ignores floats", "data": {"foo": 1.1}, "valid": true }, { "description": "ignores objects", "data": {"foo": {}}, "valid": true }, { "description": "ignores objects wth a key of the expected value", "data": {"foo": {"bar": "baz"}}, "valid": true }, { "description": "ignores objects with the expected value nested in structure", "data": {"foo": {"baz": "bar"}}, "valid": true }, { "description": "ignores arrays", "data": {"foo": []}, "valid": true }, { "description": "ignores null", "data": {"foo": null}, "valid": true } ] }, { "description": "multiple options selects the right one", "schema": { "propertyDependencies": { "foo": { "bar": { "minProperties": 2, "maxProperties": 2 }, "baz": {"maxProperties": 1}, "qux": true, "quux": false } } }, "tests": [ { "description": "bar with exactly 2 properties is valid", "data": { "foo": "bar", "other-foo": "other-bar" }, "valid": true }, { "description": "bar with more than 2 properties is invalid", "data": { "foo": "bar", "other-foo": "other-bar", "too": "many" }, "valid": false }, { "description": "bar with fewer than 2 properties is invalid", "data": {"foo": "bar"}, "valid": false }, { "description": "baz alone is valid", "data": {"foo": "baz"}, "valid": true }, { "description": "baz with other properties is invalid", "data": { "foo": "baz", "other-foo": "other-bar" }, "valid": false }, { "description": "anything allowed with qux", "data": { "foo": "qux", "blah": ["some other property"], "more": "properties" }, "valid": true }, { "description": "quux is disallowed", "data": { "foo": "quux" }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/propertyNames.json0000644000175100001770000000452014653725311025210 0ustar00runnerdocker[ { "description": "propertyNames validation", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "propertyNames": {"maxLength": 3} }, "tests": [ { "description": "all property names valid", "data": { "f": {}, "foo": {} }, "valid": true }, { "description": "some property names invalid", "data": { "foo": {}, "foobar": {} }, "valid": false }, { "description": "object without properties is valid", "data": {}, "valid": true }, { "description": "ignores arrays", "data": [1, 2, 3, 4], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "propertyNames with boolean schema true", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "propertyNames": true }, "tests": [ { "description": "object with any properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "propertyNames with boolean schema false", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "propertyNames": false }, "tests": [ { "description": "object with any properties is invalid", "data": {"foo": 1}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/ref.json0000644000175100001770000006541614653725311023127 0ustar00runnerdocker[ { "description": "root pointer ref", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": { "foo": {"$ref": "#"} }, "additionalProperties": false }, "tests": [ { "description": "match", "data": {"foo": false}, "valid": true }, { "description": "recursive match", "data": {"foo": {"foo": false}}, "valid": true }, { "description": "mismatch", "data": {"bar": false}, "valid": false }, { "description": "recursive mismatch", "data": {"foo": {"bar": false}}, "valid": false } ] }, { "description": "relative pointer ref to object", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": { "foo": {"type": "integer"}, "bar": {"$ref": "#/properties/foo"} } }, "tests": [ { "description": "match", "data": {"bar": 3}, "valid": true }, { "description": "mismatch", "data": {"bar": true}, "valid": false } ] }, { "description": "relative pointer ref to array", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "prefixItems": [ {"type": "integer"}, {"$ref": "#/prefixItems/0"} ] }, "tests": [ { "description": "match array", "data": [1, 2], "valid": true }, { "description": "mismatch array", "data": [1, "foo"], "valid": false } ] }, { "description": "escaped pointer ref", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$defs": { "tilde~field": {"type": "integer"}, "slash/field": {"type": "integer"}, "percent%field": {"type": "integer"} }, "properties": { "tilde": {"$ref": "#/$defs/tilde~0field"}, "slash": {"$ref": "#/$defs/slash~1field"}, "percent": {"$ref": "#/$defs/percent%25field"} } }, "tests": [ { "description": "slash invalid", "data": {"slash": "aoeu"}, "valid": false }, { "description": "tilde invalid", "data": {"tilde": "aoeu"}, "valid": false }, { "description": "percent invalid", "data": {"percent": "aoeu"}, "valid": false }, { "description": "slash valid", "data": {"slash": 123}, "valid": true }, { "description": "tilde valid", "data": {"tilde": 123}, "valid": true }, { "description": "percent valid", "data": {"percent": 123}, "valid": true } ] }, { "description": "nested refs", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$defs": { "a": {"type": "integer"}, "b": {"$ref": "#/$defs/a"}, "c": {"$ref": "#/$defs/b"} }, "$ref": "#/$defs/c" }, "tests": [ { "description": "nested ref valid", "data": 5, "valid": true }, { "description": "nested ref invalid", "data": "a", "valid": false } ] }, { "description": "ref applies alongside sibling keywords", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$defs": { "reffed": { "type": "array" } }, "properties": { "foo": { "$ref": "#/$defs/reffed", "maxItems": 2 } } }, "tests": [ { "description": "ref valid, maxItems valid", "data": { "foo": [] }, "valid": true }, { "description": "ref valid, maxItems invalid", "data": { "foo": [1, 2, 3] }, "valid": false }, { "description": "ref invalid", "data": { "foo": "string" }, "valid": false } ] }, { "description": "remote ref, containing refs itself", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$ref": "https://json-schema.org/draft/next/schema" }, "tests": [ { "description": "remote ref valid", "data": {"minLength": 1}, "valid": true }, { "description": "remote ref invalid", "data": {"minLength": -1}, "valid": false } ] }, { "description": "property named $ref that is not a reference", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": { "$ref": {"type": "string"} } }, "tests": [ { "description": "property named $ref valid", "data": {"$ref": "a"}, "valid": true }, { "description": "property named $ref invalid", "data": {"$ref": 2}, "valid": false } ] }, { "description": "property named $ref, containing an actual $ref", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": { "$ref": {"$ref": "#/$defs/is-string"} }, "$defs": { "is-string": { "type": "string" } } }, "tests": [ { "description": "property named $ref valid", "data": {"$ref": "a"}, "valid": true }, { "description": "property named $ref invalid", "data": {"$ref": 2}, "valid": false } ] }, { "description": "$ref to boolean schema true", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$ref": "#/$defs/bool", "$defs": { "bool": true } }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "$ref to boolean schema false", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$ref": "#/$defs/bool", "$defs": { "bool": false } }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "Recursive references between schemas", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "http://localhost:1234/draft-next/tree", "description": "tree of nodes", "type": "object", "properties": { "meta": {"type": "string"}, "nodes": { "type": "array", "items": {"$ref": "node"} } }, "required": ["meta", "nodes"], "$defs": { "node": { "$id": "http://localhost:1234/draft-next/node", "description": "node", "type": "object", "properties": { "value": {"type": "number"}, "subtree": {"$ref": "tree"} }, "required": ["value"] } } }, "tests": [ { "description": "valid tree", "data": { "meta": "root", "nodes": [ { "value": 1, "subtree": { "meta": "child", "nodes": [ {"value": 1.1}, {"value": 1.2} ] } }, { "value": 2, "subtree": { "meta": "child", "nodes": [ {"value": 2.1}, {"value": 2.2} ] } } ] }, "valid": true }, { "description": "invalid tree", "data": { "meta": "root", "nodes": [ { "value": 1, "subtree": { "meta": "child", "nodes": [ {"value": "string is invalid"}, {"value": 1.2} ] } }, { "value": 2, "subtree": { "meta": "child", "nodes": [ {"value": 2.1}, {"value": 2.2} ] } } ] }, "valid": false } ] }, { "description": "refs with quote", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": { "foo\"bar": {"$ref": "#/$defs/foo%22bar"} }, "$defs": { "foo\"bar": {"type": "number"} } }, "tests": [ { "description": "object with numbers is valid", "data": { "foo\"bar": 1 }, "valid": true }, { "description": "object with strings is invalid", "data": { "foo\"bar": "1" }, "valid": false } ] }, { "description": "ref creates new scope when adjacent to keywords", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$defs": { "A": { "unevaluatedProperties": false } }, "properties": { "prop1": { "type": "string" } }, "$ref": "#/$defs/A" }, "tests": [ { "description": "referenced subschema doesn't see annotations from properties", "data": { "prop1": "match" }, "valid": false } ] }, { "description": "naive replacement of $ref with its destination is not correct", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$defs": { "a_string": { "type": "string" } }, "enum": [ { "$ref": "#/$defs/a_string" } ] }, "tests": [ { "description": "do not evaluate the $ref inside the enum, matching any string", "data": "this is a string", "valid": false }, { "description": "do not evaluate the $ref inside the enum, definition exact match", "data": { "type": "string" }, "valid": false }, { "description": "match the enum exactly", "data": { "$ref": "#/$defs/a_string" }, "valid": true } ] }, { "description": "refs with relative uris and defs", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "http://example.com/schema-relative-uri-defs1.json", "properties": { "foo": { "$id": "schema-relative-uri-defs2.json", "$defs": { "inner": { "properties": { "bar": { "type": "string" } } } }, "$ref": "#/$defs/inner" } }, "$ref": "schema-relative-uri-defs2.json" }, "tests": [ { "description": "invalid on inner field", "data": { "foo": { "bar": 1 }, "bar": "a" }, "valid": false }, { "description": "invalid on outer field", "data": { "foo": { "bar": "a" }, "bar": 1 }, "valid": false }, { "description": "valid on both fields", "data": { "foo": { "bar": "a" }, "bar": "a" }, "valid": true } ] }, { "description": "relative refs with absolute uris and defs", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "http://example.com/schema-refs-absolute-uris-defs1.json", "properties": { "foo": { "$id": "http://example.com/schema-refs-absolute-uris-defs2.json", "$defs": { "inner": { "properties": { "bar": { "type": "string" } } } }, "$ref": "#/$defs/inner" } }, "$ref": "schema-refs-absolute-uris-defs2.json" }, "tests": [ { "description": "invalid on inner field", "data": { "foo": { "bar": 1 }, "bar": "a" }, "valid": false }, { "description": "invalid on outer field", "data": { "foo": { "bar": "a" }, "bar": 1 }, "valid": false }, { "description": "valid on both fields", "data": { "foo": { "bar": "a" }, "bar": "a" }, "valid": true } ] }, { "description": "$id must be resolved against nearest parent, not just immediate parent", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "http://example.com/a.json", "$defs": { "x": { "$id": "http://example.com/b/c.json", "not": { "$defs": { "y": { "$id": "d.json", "type": "number" } } } } }, "allOf": [ { "$ref": "http://example.com/b/d.json" } ] }, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "non-number is invalid", "data": "a", "valid": false } ] }, { "description": "order of evaluation: $id and $ref", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$comment": "$id must be evaluated before $ref to get the proper $ref destination", "$id": "/draft/next/ref-and-id1/base.json", "$ref": "int.json", "$defs": { "bigint": { "$comment": "canonical uri: /ref-and-id1/int.json", "$id": "int.json", "maximum": 10 }, "smallint": { "$comment": "canonical uri: /ref-and-id1-int.json", "$id": "/draft/next/ref-and-id1-int.json", "maximum": 2 } } }, "tests": [ { "description": "data is valid against first definition", "data": 5, "valid": true }, { "description": "data is invalid against first definition", "data": 50, "valid": false } ] }, { "description": "order of evaluation: $id and $anchor and $ref", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$comment": "$id must be evaluated before $ref to get the proper $ref destination", "$id": "/draft/next/ref-and-id2/base.json", "$ref": "#bigint", "$defs": { "bigint": { "$comment": "canonical uri: /ref-and-id2/base.json#/$defs/bigint; another valid uri for this location: /ref-and-id2/base.json#bigint", "$anchor": "bigint", "maximum": 10 }, "smallint": { "$comment": "canonical uri: /ref-and-id2#/$defs/smallint; another valid uri for this location: /ref-and-id2/#bigint", "$id": "/draft/next/ref-and-id2/", "$anchor": "bigint", "maximum": 2 } } }, "tests": [ { "description": "data is valid against first definition", "data": 5, "valid": true }, { "description": "data is invalid against first definition", "data": 50, "valid": false } ] }, { "description": "simple URN base URI with $ref via the URN", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$comment": "URIs do not have to have HTTP(s) schemes", "$id": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed", "minimum": 30, "properties": { "foo": {"$ref": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed"} } }, "tests": [ { "description": "valid under the URN IDed schema", "data": {"foo": 37}, "valid": true }, { "description": "invalid under the URN IDed schema", "data": {"foo": 12}, "valid": false } ] }, { "description": "simple URN base URI with JSON pointer", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$comment": "URIs do not have to have HTTP(s) schemes", "$id": "urn:uuid:deadbeef-1234-00ff-ff00-4321feebdaed", "properties": { "foo": {"$ref": "#/$defs/bar"} }, "$defs": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with NSS", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$comment": "RFC 8141 §2.2", "$id": "urn:example:1/406/47452/2", "properties": { "foo": {"$ref": "#/$defs/bar"} }, "$defs": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with r-component", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$comment": "RFC 8141 §2.3.1", "$id": "urn:example:foo-bar-baz-qux?+CCResolve:cc=uk", "properties": { "foo": {"$ref": "#/$defs/bar"} }, "$defs": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with q-component", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$comment": "RFC 8141 §2.3.2", "$id": "urn:example:weather?=op=map&lat=39.56&lon=-104.85&datetime=1969-07-21T02:56:15Z", "properties": { "foo": {"$ref": "#/$defs/bar"} }, "$defs": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with f-component", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$comment": "RFC 8141 §2.3.3, but we don't allow fragments", "$ref": "https://json-schema.org/draft/next/schema" }, "tests": [ { "description": "is invalid", "data": {"$id": "urn:example:foo-bar-baz-qux#somepart"}, "valid": false } ] }, { "description": "URN base URI with URN and JSON pointer ref", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed", "properties": { "foo": {"$ref": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed#/$defs/bar"} }, "$defs": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with URN and anchor ref", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed", "properties": { "foo": {"$ref": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed#something"} }, "$defs": { "bar": { "$anchor": "something", "type": "string" } } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN ref with nested pointer ref", "schema": { "$ref": "urn:uuid:deadbeef-4321-ffff-ffff-1234feebdaed", "$defs": { "foo": { "$id": "urn:uuid:deadbeef-4321-ffff-ffff-1234feebdaed", "$defs": {"bar": {"type": "string"}}, "$ref": "#/$defs/bar" } } }, "tests": [ { "description": "a string is valid", "data": "bar", "valid": true }, { "description": "a non-string is invalid", "data": 12, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/refRemote.json0000644000175100001770000002114114653725311024266 0ustar00runnerdocker[ { "description": "remote ref", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$ref": "http://localhost:1234/draft-next/integer.json" }, "tests": [ { "description": "remote ref valid", "data": 1, "valid": true }, { "description": "remote ref invalid", "data": "a", "valid": false } ] }, { "description": "fragment within remote ref", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$ref": "http://localhost:1234/draft-next/subSchemas-defs.json#/$defs/integer" }, "tests": [ { "description": "remote fragment valid", "data": 1, "valid": true }, { "description": "remote fragment invalid", "data": "a", "valid": false } ] }, { "description": "ref within remote ref", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$ref": "http://localhost:1234/draft-next/subSchemas-defs.json#/$defs/refToInteger" }, "tests": [ { "description": "ref within ref valid", "data": 1, "valid": true }, { "description": "ref within ref invalid", "data": "a", "valid": false } ] }, { "description": "base URI change", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "http://localhost:1234/draft-next/", "items": { "$id": "baseUriChange/", "items": {"$ref": "folderInteger.json"} } }, "tests": [ { "description": "base URI change ref valid", "data": [[1]], "valid": true }, { "description": "base URI change ref invalid", "data": [["a"]], "valid": false } ] }, { "description": "base URI change - change folder", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "http://localhost:1234/draft-next/scope_change_defs1.json", "type" : "object", "properties": {"list": {"$ref": "baseUriChangeFolder/"}}, "$defs": { "baz": { "$id": "baseUriChangeFolder/", "type": "array", "items": {"$ref": "folderInteger.json"} } } }, "tests": [ { "description": "number is valid", "data": {"list": [1]}, "valid": true }, { "description": "string is invalid", "data": {"list": ["a"]}, "valid": false } ] }, { "description": "base URI change - change folder in subschema", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "http://localhost:1234/draft-next/scope_change_defs2.json", "type" : "object", "properties": {"list": {"$ref": "baseUriChangeFolderInSubschema/#/$defs/bar"}}, "$defs": { "baz": { "$id": "baseUriChangeFolderInSubschema/", "$defs": { "bar": { "type": "array", "items": {"$ref": "folderInteger.json"} } } } } }, "tests": [ { "description": "number is valid", "data": {"list": [1]}, "valid": true }, { "description": "string is invalid", "data": {"list": ["a"]}, "valid": false } ] }, { "description": "root ref in remote ref", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "http://localhost:1234/draft-next/object", "type": "object", "properties": { "name": {"$ref": "name-defs.json#/$defs/orNull"} } }, "tests": [ { "description": "string is valid", "data": { "name": "foo" }, "valid": true }, { "description": "null is valid", "data": { "name": null }, "valid": true }, { "description": "object is invalid", "data": { "name": { "name": null } }, "valid": false } ] }, { "description": "remote ref with ref to defs", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "http://localhost:1234/draft-next/schema-remote-ref-ref-defs1.json", "$ref": "ref-and-defs.json" }, "tests": [ { "description": "invalid", "data": { "bar": 1 }, "valid": false }, { "description": "valid", "data": { "bar": "a" }, "valid": true } ] }, { "description": "Location-independent identifier in remote ref", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$ref": "http://localhost:1234/draft-next/locationIndependentIdentifier.json#/$defs/refToInteger" }, "tests": [ { "description": "integer is valid", "data": 1, "valid": true }, { "description": "string is invalid", "data": "foo", "valid": false } ] }, { "description": "retrieved nested refs resolve relative to their URI not $id", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$id": "http://localhost:1234/draft-next/some-id", "properties": { "name": {"$ref": "nested/foo-ref-string.json"} } }, "tests": [ { "description": "number is invalid", "data": { "name": {"foo": 1} }, "valid": false }, { "description": "string is valid", "data": { "name": {"foo": "a"} }, "valid": true } ] }, { "description": "remote HTTP ref with different $id", "schema": {"$ref": "http://localhost:1234/different-id-ref-string.json"}, "tests": [ { "description": "number is invalid", "data": 1, "valid": false }, { "description": "string is valid", "data": "foo", "valid": true } ] }, { "description": "remote HTTP ref with different URN $id", "schema": {"$ref": "http://localhost:1234/urn-ref-string.json"}, "tests": [ { "description": "number is invalid", "data": 1, "valid": false }, { "description": "string is valid", "data": "foo", "valid": true } ] }, { "description": "remote HTTP ref with nested absolute ref", "schema": {"$ref": "http://localhost:1234/nested-absolute-ref-to-string.json"}, "tests": [ { "description": "number is invalid", "data": 1, "valid": false }, { "description": "string is valid", "data": "foo", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/required.json0000644000175100001770000001100414653725311024153 0ustar00runnerdocker[ { "description": "required validation", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": { "foo": {}, "bar": {} }, "required": ["foo"] }, "tests": [ { "description": "present required property is valid", "data": {"foo": 1}, "valid": true }, { "description": "non-present required property is invalid", "data": {"bar": 1}, "valid": false }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "required default validation", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": { "foo": {} } }, "tests": [ { "description": "not required by default", "data": {}, "valid": true } ] }, { "description": "required with empty array", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": { "foo": {} }, "required": [] }, "tests": [ { "description": "property not required", "data": {}, "valid": true } ] }, { "description": "required with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "required": [ "foo\nbar", "foo\"bar", "foo\\bar", "foo\rbar", "foo\tbar", "foo\fbar" ] }, "tests": [ { "description": "object with all properties present is valid", "data": { "foo\nbar": 1, "foo\"bar": 1, "foo\\bar": 1, "foo\rbar": 1, "foo\tbar": 1, "foo\fbar": 1 }, "valid": true }, { "description": "object with some properties missing is invalid", "data": { "foo\nbar": "1", "foo\"bar": "1" }, "valid": false } ] }, { "description": "required properties whose names are Javascript object property names", "comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "required": ["__proto__", "toString", "constructor"] }, "tests": [ { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "none of the properties mentioned", "data": {}, "valid": false }, { "description": "__proto__ present", "data": { "__proto__": "foo" }, "valid": false }, { "description": "toString present", "data": { "toString": { "length": 37 } }, "valid": false }, { "description": "constructor present", "data": { "constructor": { "length": 37 } }, "valid": false }, { "description": "all present", "data": { "__proto__": 12, "toString": { "length": "foo" }, "constructor": 37 }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/type.json0000644000175100001770000003377414653725311023336 0ustar00runnerdocker[ { "description": "integer type matches integers", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "integer" }, "tests": [ { "description": "an integer is an integer", "data": 1, "valid": true }, { "description": "a float with zero fractional part is an integer", "data": 1.0, "valid": true }, { "description": "a float is not an integer", "data": 1.1, "valid": false }, { "description": "a string is not an integer", "data": "foo", "valid": false }, { "description": "a string is still not an integer, even if it looks like one", "data": "1", "valid": false }, { "description": "an object is not an integer", "data": {}, "valid": false }, { "description": "an array is not an integer", "data": [], "valid": false }, { "description": "a boolean is not an integer", "data": true, "valid": false }, { "description": "null is not an integer", "data": null, "valid": false } ] }, { "description": "number type matches numbers", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "number" }, "tests": [ { "description": "an integer is a number", "data": 1, "valid": true }, { "description": "a float with zero fractional part is a number (and an integer)", "data": 1.0, "valid": true }, { "description": "a float is a number", "data": 1.1, "valid": true }, { "description": "a string is not a number", "data": "foo", "valid": false }, { "description": "a string is still not a number, even if it looks like one", "data": "1", "valid": false }, { "description": "an object is not a number", "data": {}, "valid": false }, { "description": "an array is not a number", "data": [], "valid": false }, { "description": "a boolean is not a number", "data": true, "valid": false }, { "description": "null is not a number", "data": null, "valid": false } ] }, { "description": "string type matches strings", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "string" }, "tests": [ { "description": "1 is not a string", "data": 1, "valid": false }, { "description": "a float is not a string", "data": 1.1, "valid": false }, { "description": "a string is a string", "data": "foo", "valid": true }, { "description": "a string is still a string, even if it looks like a number", "data": "1", "valid": true }, { "description": "an empty string is still a string", "data": "", "valid": true }, { "description": "an object is not a string", "data": {}, "valid": false }, { "description": "an array is not a string", "data": [], "valid": false }, { "description": "a boolean is not a string", "data": true, "valid": false }, { "description": "null is not a string", "data": null, "valid": false } ] }, { "description": "object type matches objects", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object" }, "tests": [ { "description": "an integer is not an object", "data": 1, "valid": false }, { "description": "a float is not an object", "data": 1.1, "valid": false }, { "description": "a string is not an object", "data": "foo", "valid": false }, { "description": "an object is an object", "data": {}, "valid": true }, { "description": "an array is not an object", "data": [], "valid": false }, { "description": "a boolean is not an object", "data": true, "valid": false }, { "description": "null is not an object", "data": null, "valid": false } ] }, { "description": "array type matches arrays", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "array" }, "tests": [ { "description": "an integer is not an array", "data": 1, "valid": false }, { "description": "a float is not an array", "data": 1.1, "valid": false }, { "description": "a string is not an array", "data": "foo", "valid": false }, { "description": "an object is not an array", "data": {}, "valid": false }, { "description": "an array is an array", "data": [], "valid": true }, { "description": "a boolean is not an array", "data": true, "valid": false }, { "description": "null is not an array", "data": null, "valid": false } ] }, { "description": "boolean type matches booleans", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "boolean" }, "tests": [ { "description": "an integer is not a boolean", "data": 1, "valid": false }, { "description": "zero is not a boolean", "data": 0, "valid": false }, { "description": "a float is not a boolean", "data": 1.1, "valid": false }, { "description": "a string is not a boolean", "data": "foo", "valid": false }, { "description": "an empty string is not a boolean", "data": "", "valid": false }, { "description": "an object is not a boolean", "data": {}, "valid": false }, { "description": "an array is not a boolean", "data": [], "valid": false }, { "description": "true is a boolean", "data": true, "valid": true }, { "description": "false is a boolean", "data": false, "valid": true }, { "description": "null is not a boolean", "data": null, "valid": false } ] }, { "description": "null type matches only the null object", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "null" }, "tests": [ { "description": "an integer is not null", "data": 1, "valid": false }, { "description": "a float is not null", "data": 1.1, "valid": false }, { "description": "zero is not null", "data": 0, "valid": false }, { "description": "a string is not null", "data": "foo", "valid": false }, { "description": "an empty string is not null", "data": "", "valid": false }, { "description": "an object is not null", "data": {}, "valid": false }, { "description": "an array is not null", "data": [], "valid": false }, { "description": "true is not null", "data": true, "valid": false }, { "description": "false is not null", "data": false, "valid": false }, { "description": "null is null", "data": null, "valid": true } ] }, { "description": "multiple types can be specified in an array", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": ["integer", "string"] }, "tests": [ { "description": "an integer is valid", "data": 1, "valid": true }, { "description": "a string is valid", "data": "foo", "valid": true }, { "description": "a float is invalid", "data": 1.1, "valid": false }, { "description": "an object is invalid", "data": {}, "valid": false }, { "description": "an array is invalid", "data": [], "valid": false }, { "description": "a boolean is invalid", "data": true, "valid": false }, { "description": "null is invalid", "data": null, "valid": false } ] }, { "description": "type as array with one item", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": ["string"] }, "tests": [ { "description": "string is valid", "data": "foo", "valid": true }, { "description": "number is invalid", "data": 123, "valid": false } ] }, { "description": "type: array or object", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": ["array", "object"] }, "tests": [ { "description": "array is valid", "data": [1,2,3], "valid": true }, { "description": "object is valid", "data": {"foo": 123}, "valid": true }, { "description": "number is invalid", "data": 123, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false }, { "description": "null is invalid", "data": null, "valid": false } ] }, { "description": "type: array, object or null", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": ["array", "object", "null"] }, "tests": [ { "description": "array is valid", "data": [1,2,3], "valid": true }, { "description": "object is valid", "data": {"foo": 123}, "valid": true }, { "description": "null is valid", "data": null, "valid": true }, { "description": "number is invalid", "data": 123, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/unevaluatedItems.json0000644000175100001770000004640314653725311025665 0ustar00runnerdocker[ { "description": "unevaluatedItems true", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "unevaluatedItems": true }, "tests": [ { "description": "with no unevaluated items", "data": [], "valid": true }, { "description": "with unevaluated items", "data": ["foo"], "valid": true } ] }, { "description": "unevaluatedItems false", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "unevaluatedItems": false }, "tests": [ { "description": "with no unevaluated items", "data": [], "valid": true }, { "description": "with unevaluated items", "data": ["foo"], "valid": false } ] }, { "description": "unevaluatedItems as schema", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "unevaluatedItems": { "type": "string" } }, "tests": [ { "description": "with no unevaluated items", "data": [], "valid": true }, { "description": "with valid unevaluated items", "data": ["foo"], "valid": true }, { "description": "with invalid unevaluated items", "data": [42], "valid": false } ] }, { "description": "unevaluatedItems with uniform items", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "items": { "type": "string" }, "unevaluatedItems": false }, "tests": [ { "description": "unevaluatedItems doesn't apply", "data": ["foo", "bar"], "valid": true } ] }, { "description": "unevaluatedItems with tuple", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "prefixItems": [ { "type": "string" } ], "unevaluatedItems": false }, "tests": [ { "description": "with no unevaluated items", "data": ["foo"], "valid": true }, { "description": "with unevaluated items", "data": ["foo", "bar"], "valid": false } ] }, { "description": "unevaluatedItems with items", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "prefixItems": [ { "type": "string" } ], "items": true, "unevaluatedItems": false }, "tests": [ { "description": "unevaluatedItems doesn't apply", "data": ["foo", 42], "valid": true } ] }, { "description": "unevaluatedItems with nested tuple", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "prefixItems": [ { "type": "string" } ], "allOf": [ { "prefixItems": [ true, { "type": "number" } ] } ], "unevaluatedItems": false }, "tests": [ { "description": "with no unevaluated items", "data": ["foo", 42], "valid": true }, { "description": "with unevaluated items", "data": ["foo", 42, true], "valid": false } ] }, { "description": "unevaluatedItems with nested items", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "unevaluatedItems": {"type": "boolean"}, "anyOf": [ { "items": {"type": "string"} }, true ] }, "tests": [ { "description": "with only (valid) additional items", "data": [true, false], "valid": true }, { "description": "with no additional items", "data": ["yes", "no"], "valid": true }, { "description": "with invalid additional item", "data": ["yes", false], "valid": false } ] }, { "description": "unevaluatedItems with nested prefixItems and items", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "allOf": [ { "prefixItems": [ { "type": "string" } ], "items": true } ], "unevaluatedItems": false }, "tests": [ { "description": "with no additional items", "data": ["foo"], "valid": true }, { "description": "with additional items", "data": ["foo", 42, true], "valid": true } ] }, { "description": "unevaluatedItems with nested unevaluatedItems", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "allOf": [ { "prefixItems": [ { "type": "string" } ] }, { "unevaluatedItems": true } ], "unevaluatedItems": false }, "tests": [ { "description": "with no additional items", "data": ["foo"], "valid": true }, { "description": "with additional items", "data": ["foo", 42, true], "valid": true } ] }, { "description": "unevaluatedItems with anyOf", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "prefixItems": [ { "const": "foo" } ], "anyOf": [ { "prefixItems": [ true, { "const": "bar" } ] }, { "prefixItems": [ true, true, { "const": "baz" } ] } ], "unevaluatedItems": false }, "tests": [ { "description": "when one schema matches and has no unevaluated items", "data": ["foo", "bar"], "valid": true }, { "description": "when one schema matches and has unevaluated items", "data": ["foo", "bar", 42], "valid": false }, { "description": "when two schemas match and has no unevaluated items", "data": ["foo", "bar", "baz"], "valid": true }, { "description": "when two schemas match and has unevaluated items", "data": ["foo", "bar", "baz", 42], "valid": false } ] }, { "description": "unevaluatedItems with oneOf", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "prefixItems": [ { "const": "foo" } ], "oneOf": [ { "prefixItems": [ true, { "const": "bar" } ] }, { "prefixItems": [ true, { "const": "baz" } ] } ], "unevaluatedItems": false }, "tests": [ { "description": "with no unevaluated items", "data": ["foo", "bar"], "valid": true }, { "description": "with unevaluated items", "data": ["foo", "bar", 42], "valid": false } ] }, { "description": "unevaluatedItems with not", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "prefixItems": [ { "const": "foo" } ], "not": { "not": { "prefixItems": [ true, { "const": "bar" } ] } }, "unevaluatedItems": false }, "tests": [ { "description": "with unevaluated items", "data": ["foo", "bar"], "valid": false } ] }, { "description": "unevaluatedItems with if/then/else", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "prefixItems": [ { "const": "foo" } ], "if": { "prefixItems": [ true, { "const": "bar" } ] }, "then": { "prefixItems": [ true, true, { "const": "then" } ] }, "else": { "prefixItems": [ true, true, true, { "const": "else" } ] }, "unevaluatedItems": false }, "tests": [ { "description": "when if matches and it has no unevaluated items", "data": ["foo", "bar", "then"], "valid": true }, { "description": "when if matches and it has unevaluated items", "data": ["foo", "bar", "then", "else"], "valid": false }, { "description": "when if doesn't match and it has no unevaluated items", "data": ["foo", 42, 42, "else"], "valid": true }, { "description": "when if doesn't match and it has unevaluated items", "data": ["foo", 42, 42, "else", 42], "valid": false } ] }, { "description": "unevaluatedItems with boolean schemas", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "allOf": [true], "unevaluatedItems": false }, "tests": [ { "description": "with no unevaluated items", "data": [], "valid": true }, { "description": "with unevaluated items", "data": ["foo"], "valid": false } ] }, { "description": "unevaluatedItems with $ref", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$ref": "#/$defs/bar", "prefixItems": [ { "type": "string" } ], "unevaluatedItems": false, "$defs": { "bar": { "prefixItems": [ true, { "type": "string" } ] } } }, "tests": [ { "description": "with no unevaluated items", "data": ["foo", "bar"], "valid": true }, { "description": "with unevaluated items", "data": ["foo", "bar", "baz"], "valid": false } ] }, { "description": "unevaluatedItems can't see inside cousins", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "allOf": [ { "prefixItems": [ true ] }, { "unevaluatedItems": false } ] }, "tests": [ { "description": "always fails", "data": [ 1 ], "valid": false } ] }, { "description": "item is evaluated in an uncle schema to unevaluatedItems", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": { "foo": { "prefixItems": [ { "type": "string" } ], "unevaluatedItems": false } }, "anyOf": [ { "properties": { "foo": { "prefixItems": [ true, { "type": "string" } ] } } } ] }, "tests": [ { "description": "no extra items", "data": { "foo": [ "test" ] }, "valid": true }, { "description": "uncle keyword evaluation is not significant", "data": { "foo": [ "test", "test" ] }, "valid": false } ] }, { "description": "unevaluatedItems depends on adjacent contains", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "prefixItems": [true], "contains": {"type": "string"}, "unevaluatedItems": false }, "tests": [ { "description": "second item is evaluated by contains", "data": [ 1, "foo" ], "valid": true }, { "description": "contains fails, second item is not evaluated", "data": [ 1, 2 ], "valid": false }, { "description": "contains passes, second item is not evaluated", "data": [ 1, 2, "foo" ], "valid": false } ] }, { "description": "unevaluatedItems depends on multiple nested contains", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "allOf": [ { "contains": { "multipleOf": 2 } }, { "contains": { "multipleOf": 3 } } ], "unevaluatedItems": { "multipleOf": 5 } }, "tests": [ { "description": "5 not evaluated, passes unevaluatedItems", "data": [ 2, 3, 4, 5, 6 ], "valid": true }, { "description": "7 not evaluated, fails unevaluatedItems", "data": [ 2, 3, 4, 7, 8 ], "valid": false } ] }, { "description": "unevaluatedItems and contains interact to control item dependency relationship", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "if": { "contains": {"const": "a"} }, "then": { "if": { "contains": {"const": "b"} }, "then": { "if": { "contains": {"const": "c"} } } }, "unevaluatedItems": false }, "tests": [ { "description": "empty array is valid", "data": [], "valid": true }, { "description": "only a's are valid", "data": [ "a", "a" ], "valid": true }, { "description": "a's and b's are valid", "data": [ "a", "b", "a", "b", "a" ], "valid": true }, { "description": "a's, b's and c's are valid", "data": [ "c", "a", "c", "c", "b", "a" ], "valid": true }, { "description": "only b's are invalid", "data": [ "b", "b" ], "valid": false }, { "description": "only c's are invalid", "data": [ "c", "c" ], "valid": false }, { "description": "only b's and c's are invalid", "data": [ "c", "b", "c", "b", "c" ], "valid": false }, { "description": "only a's and c's are invalid", "data": [ "c", "a", "c", "a", "c" ], "valid": false } ] }, { "description": "non-array instances are valid", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "unevaluatedItems": false }, "tests": [ { "description": "ignores booleans", "data": true, "valid": true }, { "description": "ignores integers", "data": 123, "valid": true }, { "description": "ignores floats", "data": 1.0, "valid": true }, { "description": "ignores objects", "data": {}, "valid": true }, { "description": "ignores strings", "data": "foo", "valid": true }, { "description": "ignores null", "data": null, "valid": true } ] }, { "description": "unevaluatedItems with null instance elements", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "unevaluatedItems": { "type": "null" } }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/unevaluatedProperties.json0000644000175100001770000013007014653725311026732 0ustar00runnerdocker[ { "description": "unevaluatedProperties true", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "unevaluatedProperties": true }, "tests": [ { "description": "with no unevaluated properties", "data": {}, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo" }, "valid": true } ] }, { "description": "unevaluatedProperties schema", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "unevaluatedProperties": { "type": "string", "minLength": 3 } }, "tests": [ { "description": "with no unevaluated properties", "data": {}, "valid": true }, { "description": "with valid unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with invalid unevaluated properties", "data": { "foo": "fo" }, "valid": false } ] }, { "description": "unevaluatedProperties false", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": {}, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo" }, "valid": false } ] }, { "description": "unevaluatedProperties with adjacent properties", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "unevaluatedProperties with adjacent patternProperties", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "patternProperties": { "^foo": { "type": "string" } }, "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "unevaluatedProperties with adjacent additionalProperties", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "additionalProperties": true, "unevaluatedProperties": false }, "tests": [ { "description": "with no additional properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with additional properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true } ] }, { "description": "unevaluatedProperties with nested properties", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "properties": { "bar": { "type": "string" } } } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no additional properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "with additional properties", "data": { "foo": "foo", "bar": "bar", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties with nested patternProperties", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "patternProperties": { "^bar": { "type": "string" } } } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no additional properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "with additional properties", "data": { "foo": "foo", "bar": "bar", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties with nested additionalProperties", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "additionalProperties": true } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no additional properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with additional properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true } ] }, { "description": "unevaluatedProperties with nested unevaluatedProperties", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "unevaluatedProperties": true } ], "unevaluatedProperties": { "type": "string", "maxLength": 2 } }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true } ] }, { "description": "unevaluatedProperties with anyOf", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "anyOf": [ { "properties": { "bar": { "const": "bar" } }, "required": ["bar"] }, { "properties": { "baz": { "const": "baz" } }, "required": ["baz"] }, { "properties": { "quux": { "const": "quux" } }, "required": ["quux"] } ], "unevaluatedProperties": false }, "tests": [ { "description": "when one matches and has no unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "when one matches and has unevaluated properties", "data": { "foo": "foo", "bar": "bar", "baz": "not-baz" }, "valid": false }, { "description": "when two match and has no unevaluated properties", "data": { "foo": "foo", "bar": "bar", "baz": "baz" }, "valid": true }, { "description": "when two match and has unevaluated properties", "data": { "foo": "foo", "bar": "bar", "baz": "baz", "quux": "not-quux" }, "valid": false } ] }, { "description": "unevaluatedProperties with oneOf", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "oneOf": [ { "properties": { "bar": { "const": "bar" } }, "required": ["bar"] }, { "properties": { "baz": { "const": "baz" } }, "required": ["baz"] } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo", "bar": "bar", "quux": "quux" }, "valid": false } ] }, { "description": "unevaluatedProperties with not", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "not": { "not": { "properties": { "bar": { "const": "bar" } }, "required": ["bar"] } }, "unevaluatedProperties": false }, "tests": [ { "description": "with unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "unevaluatedProperties with if/then/else", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "if": { "properties": { "foo": { "const": "then" } }, "required": ["foo"] }, "then": { "properties": { "bar": { "type": "string" } }, "required": ["bar"] }, "else": { "properties": { "baz": { "type": "string" } }, "required": ["baz"] }, "unevaluatedProperties": false }, "tests": [ { "description": "when if is true and has no unevaluated properties", "data": { "foo": "then", "bar": "bar" }, "valid": true }, { "description": "when if is true and has unevaluated properties", "data": { "foo": "then", "bar": "bar", "baz": "baz" }, "valid": false }, { "description": "when if is false and has no unevaluated properties", "data": { "baz": "baz" }, "valid": true }, { "description": "when if is false and has unevaluated properties", "data": { "foo": "else", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties with if/then/else, then not defined", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "if": { "properties": { "foo": { "const": "then" } }, "required": ["foo"] }, "else": { "properties": { "baz": { "type": "string" } }, "required": ["baz"] }, "unevaluatedProperties": false }, "tests": [ { "description": "when if is true and has no unevaluated properties", "data": { "foo": "then", "bar": "bar" }, "valid": false }, { "description": "when if is true and has unevaluated properties", "data": { "foo": "then", "bar": "bar", "baz": "baz" }, "valid": false }, { "description": "when if is false and has no unevaluated properties", "data": { "baz": "baz" }, "valid": true }, { "description": "when if is false and has unevaluated properties", "data": { "foo": "else", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties with if/then/else, else not defined", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "if": { "properties": { "foo": { "const": "then" } }, "required": ["foo"] }, "then": { "properties": { "bar": { "type": "string" } }, "required": ["bar"] }, "unevaluatedProperties": false }, "tests": [ { "description": "when if is true and has no unevaluated properties", "data": { "foo": "then", "bar": "bar" }, "valid": true }, { "description": "when if is true and has unevaluated properties", "data": { "foo": "then", "bar": "bar", "baz": "baz" }, "valid": false }, { "description": "when if is false and has no unevaluated properties", "data": { "baz": "baz" }, "valid": false }, { "description": "when if is false and has unevaluated properties", "data": { "foo": "else", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties with dependentSchemas", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "dependentSchemas": { "foo": { "properties": { "bar": { "const": "bar" } }, "required": ["bar"] } }, "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "with unevaluated properties", "data": { "bar": "bar" }, "valid": false } ] }, { "description": "unevaluatedProperties with boolean schemas", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [true], "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with unevaluated properties", "data": { "bar": "bar" }, "valid": false } ] }, { "description": "unevaluatedProperties with $ref", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "$ref": "#/$defs/bar", "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": false, "$defs": { "bar": { "properties": { "bar": { "type": "string" } } } } }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo", "bar": "bar", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties can't see inside cousins", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "allOf": [ { "properties": { "foo": true } }, { "unevaluatedProperties": false } ] }, "tests": [ { "description": "always fails", "data": { "foo": 1 }, "valid": false } ] }, { "description": "unevaluatedProperties can't see inside cousins (reverse order)", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "allOf": [ { "unevaluatedProperties": false }, { "properties": { "foo": true } } ] }, "tests": [ { "description": "always fails", "data": { "foo": 1 }, "valid": false } ] }, { "description": "nested unevaluatedProperties, outer false, inner true, properties outside", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "unevaluatedProperties": true } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true } ] }, { "description": "nested unevaluatedProperties, outer false, inner true, properties inside", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "allOf": [ { "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": true } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true } ] }, { "description": "nested unevaluatedProperties, outer true, inner false, properties outside", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "unevaluatedProperties": false } ], "unevaluatedProperties": true }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": false }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "nested unevaluatedProperties, outer true, inner false, properties inside", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "allOf": [ { "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": false } ], "unevaluatedProperties": true }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "cousin unevaluatedProperties, true and false, true with properties", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "allOf": [ { "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": true }, { "unevaluatedProperties": false } ] }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": false }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "cousin unevaluatedProperties, true and false, false with properties", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "allOf": [ { "unevaluatedProperties": true }, { "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": false } ] }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "property is evaluated in an uncle schema to unevaluatedProperties", "comment": "see https://stackoverflow.com/questions/66936884/deeply-nested-unevaluatedproperties-and-their-expectations", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "properties": { "foo": { "type": "object", "properties": { "bar": { "type": "string" } }, "unevaluatedProperties": false } }, "anyOf": [ { "properties": { "foo": { "properties": { "faz": { "type": "string" } } } } } ] }, "tests": [ { "description": "no extra properties", "data": { "foo": { "bar": "test" } }, "valid": true }, { "description": "uncle keyword evaluation is not significant", "data": { "foo": { "bar": "test", "faz": "test" } }, "valid": false } ] }, { "description": "in-place applicator siblings, allOf has unevaluated", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "allOf": [ { "properties": { "foo": true }, "unevaluatedProperties": false } ], "anyOf": [ { "properties": { "bar": true } } ] }, "tests": [ { "description": "base case: both properties present", "data": { "foo": 1, "bar": 1 }, "valid": false }, { "description": "in place applicator siblings, bar is missing", "data": { "foo": 1 }, "valid": true }, { "description": "in place applicator siblings, foo is missing", "data": { "bar": 1 }, "valid": false } ] }, { "description": "in-place applicator siblings, anyOf has unevaluated", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "allOf": [ { "properties": { "foo": true } } ], "anyOf": [ { "properties": { "bar": true }, "unevaluatedProperties": false } ] }, "tests": [ { "description": "base case: both properties present", "data": { "foo": 1, "bar": 1 }, "valid": false }, { "description": "in place applicator siblings, bar is missing", "data": { "foo": 1 }, "valid": false }, { "description": "in place applicator siblings, foo is missing", "data": { "bar": 1 }, "valid": true } ] }, { "description": "unevaluatedProperties + single cyclic ref", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "type": "object", "properties": { "x": { "$ref": "#" } }, "unevaluatedProperties": false }, "tests": [ { "description": "Empty is valid", "data": {}, "valid": true }, { "description": "Single is valid", "data": { "x": {} }, "valid": true }, { "description": "Unevaluated on 1st level is invalid", "data": { "x": {}, "y": {} }, "valid": false }, { "description": "Nested is valid", "data": { "x": { "x": {} } }, "valid": true }, { "description": "Unevaluated on 2nd level is invalid", "data": { "x": { "x": {}, "y": {} } }, "valid": false }, { "description": "Deep nested is valid", "data": { "x": { "x": { "x": {} } } }, "valid": true }, { "description": "Unevaluated on 3rd level is invalid", "data": { "x": { "x": { "x": {}, "y": {} } } }, "valid": false } ] }, { "description": "unevaluatedProperties + ref inside allOf / oneOf", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$defs": { "one": { "properties": { "a": true } }, "two": { "required": ["x"], "properties": { "x": true } } }, "allOf": [ { "$ref": "#/$defs/one" }, { "properties": { "b": true } }, { "oneOf": [ { "$ref": "#/$defs/two" }, { "required": ["y"], "properties": { "y": true } } ] } ], "unevaluatedProperties": false }, "tests": [ { "description": "Empty is invalid (no x or y)", "data": {}, "valid": false }, { "description": "a and b are invalid (no x or y)", "data": { "a": 1, "b": 1 }, "valid": false }, { "description": "x and y are invalid", "data": { "x": 1, "y": 1 }, "valid": false }, { "description": "a and x are valid", "data": { "a": 1, "x": 1 }, "valid": true }, { "description": "a and y are valid", "data": { "a": 1, "y": 1 }, "valid": true }, { "description": "a and b and x are valid", "data": { "a": 1, "b": 1, "x": 1 }, "valid": true }, { "description": "a and b and y are valid", "data": { "a": 1, "b": 1, "y": 1 }, "valid": true }, { "description": "a and b and x and y are invalid", "data": { "a": 1, "b": 1, "x": 1, "y": 1 }, "valid": false } ] }, { "description": "dynamic evalation inside nested refs", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$defs": { "one": { "oneOf": [ { "$ref": "#/$defs/two" }, { "required": ["b"], "properties": { "b": true } }, { "required": ["xx"], "patternProperties": { "x": true } }, { "required": ["all"], "unevaluatedProperties": true } ] }, "two": { "oneOf": [ { "required": ["c"], "properties": { "c": true } }, { "required": ["d"], "properties": { "d": true } } ] } }, "oneOf": [ { "$ref": "#/$defs/one" }, { "required": ["a"], "properties": { "a": true } } ], "unevaluatedProperties": false }, "tests": [ { "description": "Empty is invalid", "data": {}, "valid": false }, { "description": "a is valid", "data": { "a": 1 }, "valid": true }, { "description": "b is valid", "data": { "b": 1 }, "valid": true }, { "description": "c is valid", "data": { "c": 1 }, "valid": true }, { "description": "d is valid", "data": { "d": 1 }, "valid": true }, { "description": "a + b is invalid", "data": { "a": 1, "b": 1 }, "valid": false }, { "description": "a + c is invalid", "data": { "a": 1, "c": 1 }, "valid": false }, { "description": "a + d is invalid", "data": { "a": 1, "d": 1 }, "valid": false }, { "description": "b + c is invalid", "data": { "b": 1, "c": 1 }, "valid": false }, { "description": "b + d is invalid", "data": { "b": 1, "d": 1 }, "valid": false }, { "description": "c + d is invalid", "data": { "c": 1, "d": 1 }, "valid": false }, { "description": "xx is valid", "data": { "xx": 1 }, "valid": true }, { "description": "xx + foox is valid", "data": { "xx": 1, "foox": 1 }, "valid": true }, { "description": "xx + foo is invalid", "data": { "xx": 1, "foo": 1 }, "valid": false }, { "description": "xx + a is invalid", "data": { "xx": 1, "a": 1 }, "valid": false }, { "description": "xx + b is invalid", "data": { "xx": 1, "b": 1 }, "valid": false }, { "description": "xx + c is invalid", "data": { "xx": 1, "c": 1 }, "valid": false }, { "description": "xx + d is invalid", "data": { "xx": 1, "d": 1 }, "valid": false }, { "description": "all is valid", "data": { "all": 1 }, "valid": true }, { "description": "all + foo is valid", "data": { "all": 1, "foo": 1 }, "valid": true }, { "description": "all + a is invalid", "data": { "all": 1, "a": 1 }, "valid": false } ] }, { "description": "unevaluatedProperties depends on adjacent contains", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "properties": { "foo": { "type": "number" } }, "contains": { "type": "string" }, "unevaluatedProperties": false }, "tests": [ { "description": "bar is evaluated by contains", "data": { "foo": 1, "bar": "foo" }, "valid": true }, { "description": "contains fails, bar is not evaluated", "data": { "foo": 1, "bar": 2 }, "valid": false }, { "description": "contains passes, bar is not evaluated", "data": { "foo": 1, "bar": 2, "baz": "foo" }, "valid": false } ] }, { "description": "unevaluatedProperties depends on multiple nested contains", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "allOf": [ { "contains": { "multipleOf": 2 } }, { "contains": { "multipleOf": 3 } } ], "unevaluatedProperties": { "multipleOf": 5 } }, "tests": [ { "description": "5 not evaluated, passes unevaluatedItems", "data": { "a": 2, "b": 3, "c": 4, "d": 5, "e": 6 }, "valid": true }, { "description": "7 not evaluated, fails unevaluatedItems", "data": { "a": 2, "b": 3, "c": 4, "d": 7, "e": 8 }, "valid": false } ] }, { "description": "non-object instances are valid", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "unevaluatedProperties": false }, "tests": [ { "description": "ignores booleans", "data": true, "valid": true }, { "description": "ignores integers", "data": 123, "valid": true }, { "description": "ignores floats", "data": 1.0, "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "foo", "valid": true }, { "description": "ignores null", "data": null, "valid": true } ] }, { "description": "unevaluatedProperties with null valued instance properties", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "unevaluatedProperties": { "type": "null" } }, "tests": [ { "description": "allows null valued properties", "data": {"foo": null}, "valid": true } ] }, { "description": "unevaluatedProperties can see inside propertyDependencies", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "propertyDependencies": { "foo": { "foo1": { "properties": { "bar": true } } } }, "unevaluatedProperties": false }, "tests": [ { "description": "allows bar if foo = foo1", "data": { "foo": "foo1", "bar": 42 }, "valid": true }, { "description": "disallows bar if foo != foo1", "data": { "foo": "foo2", "bar": 42 }, "valid": false }, { "description": "disallows bar if foo is absent", "data": { "bar": 42 }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/uniqueItems.json0000644000175100001770000003364614653725311024663 0ustar00runnerdocker[ { "description": "uniqueItems validation", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "uniqueItems": true }, "tests": [ { "description": "unique array of integers is valid", "data": [1, 2], "valid": true }, { "description": "non-unique array of integers is invalid", "data": [1, 1], "valid": false }, { "description": "non-unique array of more than two integers is invalid", "data": [1, 2, 1], "valid": false }, { "description": "numbers are unique if mathematically unequal", "data": [1.0, 1.00, 1], "valid": false }, { "description": "false is not equal to zero", "data": [0, false], "valid": true }, { "description": "true is not equal to one", "data": [1, true], "valid": true }, { "description": "unique array of strings is valid", "data": ["foo", "bar", "baz"], "valid": true }, { "description": "non-unique array of strings is invalid", "data": ["foo", "bar", "foo"], "valid": false }, { "description": "unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "baz"}], "valid": true }, { "description": "non-unique array of objects is invalid", "data": [{"foo": "bar"}, {"foo": "bar"}], "valid": false }, { "description": "unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : false}}} ], "valid": true }, { "description": "non-unique array of nested objects is invalid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : true}}} ], "valid": false }, { "description": "unique array of arrays is valid", "data": [["foo"], ["bar"]], "valid": true }, { "description": "non-unique array of arrays is invalid", "data": [["foo"], ["foo"]], "valid": false }, { "description": "non-unique array of more than two arrays is invalid", "data": [["foo"], ["bar"], ["foo"]], "valid": false }, { "description": "1 and true are unique", "data": [1, true], "valid": true }, { "description": "0 and false are unique", "data": [0, false], "valid": true }, { "description": "[1] and [true] are unique", "data": [[1], [true]], "valid": true }, { "description": "[0] and [false] are unique", "data": [[0], [false]], "valid": true }, { "description": "nested [1] and [true] are unique", "data": [[[1], "foo"], [[true], "foo"]], "valid": true }, { "description": "nested [0] and [false] are unique", "data": [[[0], "foo"], [[false], "foo"]], "valid": true }, { "description": "unique heterogeneous types are valid", "data": [{}, [1], true, null, 1, "{}"], "valid": true }, { "description": "non-unique heterogeneous types are invalid", "data": [{}, [1], true, null, {}, 1], "valid": false }, { "description": "different objects are unique", "data": [{"a": 1, "b": 2}, {"a": 2, "b": 1}], "valid": true }, { "description": "objects are non-unique despite key order", "data": [{"a": 1, "b": 2}, {"b": 2, "a": 1}], "valid": false }, { "description": "{\"a\": false} and {\"a\": 0} are unique", "data": [{"a": false}, {"a": 0}], "valid": true }, { "description": "{\"a\": true} and {\"a\": 1} are unique", "data": [{"a": true}, {"a": 1}], "valid": true } ] }, { "description": "uniqueItems with an array of items", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "prefixItems": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": true }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is not valid", "data": [false, false], "valid": false }, { "description": "[true, true] from items array is not valid", "data": [true, true], "valid": false }, { "description": "unique array extended from [false, true] is valid", "data": [false, true, "foo", "bar"], "valid": true }, { "description": "unique array extended from [true, false] is valid", "data": [true, false, "foo", "bar"], "valid": true }, { "description": "non-unique array extended from [false, true] is not valid", "data": [false, true, "foo", "foo"], "valid": false }, { "description": "non-unique array extended from [true, false] is not valid", "data": [true, false, "foo", "foo"], "valid": false } ] }, { "description": "uniqueItems with an array of items and additionalItems=false", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "prefixItems": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": true, "items": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is not valid", "data": [false, false], "valid": false }, { "description": "[true, true] from items array is not valid", "data": [true, true], "valid": false }, { "description": "extra items are invalid even if unique", "data": [false, true, null], "valid": false } ] }, { "description": "uniqueItems=false validation", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "uniqueItems": false }, "tests": [ { "description": "unique array of integers is valid", "data": [1, 2], "valid": true }, { "description": "non-unique array of integers is valid", "data": [1, 1], "valid": true }, { "description": "numbers are unique if mathematically unequal", "data": [1.0, 1.00, 1], "valid": true }, { "description": "false is not equal to zero", "data": [0, false], "valid": true }, { "description": "true is not equal to one", "data": [1, true], "valid": true }, { "description": "unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "baz"}], "valid": true }, { "description": "non-unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "bar"}], "valid": true }, { "description": "unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : false}}} ], "valid": true }, { "description": "non-unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : true}}} ], "valid": true }, { "description": "unique array of arrays is valid", "data": [["foo"], ["bar"]], "valid": true }, { "description": "non-unique array of arrays is valid", "data": [["foo"], ["foo"]], "valid": true }, { "description": "1 and true are unique", "data": [1, true], "valid": true }, { "description": "0 and false are unique", "data": [0, false], "valid": true }, { "description": "unique heterogeneous types are valid", "data": [{}, [1], true, null, 1], "valid": true }, { "description": "non-unique heterogeneous types are valid", "data": [{}, [1], true, null, {}, 1], "valid": true } ] }, { "description": "uniqueItems=false with an array of items", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "prefixItems": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is valid", "data": [false, false], "valid": true }, { "description": "[true, true] from items array is valid", "data": [true, true], "valid": true }, { "description": "unique array extended from [false, true] is valid", "data": [false, true, "foo", "bar"], "valid": true }, { "description": "unique array extended from [true, false] is valid", "data": [true, false, "foo", "bar"], "valid": true }, { "description": "non-unique array extended from [false, true] is valid", "data": [false, true, "foo", "foo"], "valid": true }, { "description": "non-unique array extended from [true, false] is valid", "data": [true, false, "foo", "foo"], "valid": true } ] }, { "description": "uniqueItems=false with an array of items and additionalItems=false", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "prefixItems": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": false, "items": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is valid", "data": [false, false], "valid": true }, { "description": "[true, true] from items array is valid", "data": [true, true], "valid": true }, { "description": "extra items are invalid even if unique", "data": [false, true, null], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/unknownKeyword.json0000644000175100001770000000410014653725311025376 0ustar00runnerdocker[ { "description": "$id inside an unknown keyword is not a real identifier", "comment": "the implementation must not be confused by an $id in locations we do not know how to parse", "schema": { "$schema": "https://json-schema.org/draft/next/schema", "$defs": { "id_in_unknown0": { "not": { "array_of_schemas": [ { "$id": "https://localhost:1234/draft-next/unknownKeyword/my_identifier.json", "type": "null" } ] } }, "real_id_in_schema": { "$id": "https://localhost:1234/draft-next/unknownKeyword/my_identifier.json", "type": "string" }, "id_in_unknown1": { "not": { "object_of_schemas": { "foo": { "$id": "https://localhost:1234/draft-next/unknownKeyword/my_identifier.json", "type": "integer" } } } } }, "anyOf": [ { "$ref": "#/$defs/id_in_unknown0" }, { "$ref": "#/$defs/id_in_unknown1" }, { "$ref": "https://localhost:1234/draft-next/unknownKeyword/my_identifier.json" } ] }, "tests": [ { "description": "type matches second anyOf, which has a real schema in it", "data": "a string", "valid": true }, { "description": "type matches non-schema in first anyOf", "data": null, "valid": false }, { "description": "type matches non-schema in third anyOf", "data": 1, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft-next/vocabulary.json0000644000175100001770000000221514653725311024506 0ustar00runnerdocker[ { "description": "schema that uses custom metaschema with with no validation vocabulary", "schema": { "$id": "https://schema/using/no/validation", "$schema": "http://localhost:1234/draft-next/metaschema-no-validation.json", "properties": { "badProperty": false, "numberProperty": { "minimum": 10 } } }, "tests": [ { "description": "applicator vocabulary still works", "data": { "badProperty": "this property should not exist" }, "valid": false }, { "description": "no validation: valid number", "data": { "numberProperty": 20 }, "valid": true }, { "description": "no validation: invalid number, but it still validates", "data": { "numberProperty": 1 }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0610967 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/0000755000175100001770000000000014653725331021234 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/additionalItems.json0000644000175100001770000001242214653725311025240 0ustar00runnerdocker[ { "description": "additionalItems as schema", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": [{}], "additionalItems": {"type": "integer"} }, "tests": [ { "description": "additional items match schema", "data": [ null, 2, 3, 4 ], "valid": true }, { "description": "additional items do not match schema", "data": [ null, 2, 3, "foo" ], "valid": false } ] }, { "description": "when items is schema, additionalItems does nothing", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": {}, "additionalItems": false }, "tests": [ { "description": "all items match schema", "data": [ 1, 2, 3, 4, 5 ], "valid": true } ] }, { "description": "array of items with no additionalItems permitted", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": [{}, {}, {}], "additionalItems": false }, "tests": [ { "description": "empty array", "data": [ ], "valid": true }, { "description": "fewer number of items present (1)", "data": [ 1 ], "valid": true }, { "description": "fewer number of items present (2)", "data": [ 1, 2 ], "valid": true }, { "description": "equal number of items present", "data": [ 1, 2, 3 ], "valid": true }, { "description": "additional items are not permitted", "data": [ 1, 2, 3, 4 ], "valid": false } ] }, { "description": "additionalItems as false without items", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "additionalItems": false }, "tests": [ { "description": "items defaults to empty schema so everything is valid", "data": [ 1, 2, 3, 4, 5 ], "valid": true }, { "description": "ignores non-arrays", "data": {"foo" : "bar"}, "valid": true } ] }, { "description": "additionalItems are allowed by default", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": [{"type": "integer"}] }, "tests": [ { "description": "only the first item is validated", "data": [1, "foo", false], "valid": true } ] }, { "description": "additionalItems does not look in applicators, valid case", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "allOf": [ { "items": [ { "type": "integer" } ] } ], "additionalItems": { "type": "boolean" } }, "tests": [ { "description": "items defined in allOf are not examined", "data": [ 1, null ], "valid": true } ] }, { "description": "additionalItems does not look in applicators, invalid case", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "allOf": [ { "items": [ { "type": "integer" }, { "type": "string" } ] } ], "items": [ {"type": "integer" } ], "additionalItems": { "type": "boolean" } }, "tests": [ { "description": "items defined in allOf are not examined", "data": [ 1, "hello" ], "valid": false } ] }, { "description": "items validation adjusts the starting index for additionalItems", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": [ { "type": "string" } ], "additionalItems": { "type": "integer" } }, "tests": [ { "description": "valid items", "data": [ "x", 2, 3 ], "valid": true }, { "description": "wrong type of second item", "data": [ "x", "y" ], "valid": false } ] }, { "description": "additionalItems with null instance elements", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "additionalItems": { "type": "null" } }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/additionalProperties.json0000644000175100001770000001152114653725311026312 0ustar00runnerdocker[ { "description": "additionalProperties being false does not allow other properties", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": {"foo": {}, "bar": {}}, "patternProperties": { "^v": {} }, "additionalProperties": false }, "tests": [ { "description": "no additional properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "an additional property is invalid", "data": {"foo" : 1, "bar" : 2, "quux" : "boom"}, "valid": false }, { "description": "ignores arrays", "data": [1, 2, 3], "valid": true }, { "description": "ignores strings", "data": "foobarbaz", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "patternProperties are not additional properties", "data": {"foo":1, "vroom": 2}, "valid": true } ] }, { "description": "non-ASCII pattern with additionalProperties", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "patternProperties": {"^á": {}}, "additionalProperties": false }, "tests": [ { "description": "matching the pattern is valid", "data": {"ármányos": 2}, "valid": true }, { "description": "not matching the pattern is invalid", "data": {"élmény": 2}, "valid": false } ] }, { "description": "additionalProperties with schema", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": {"foo": {}, "bar": {}}, "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "no additional properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "an additional valid property is valid", "data": {"foo" : 1, "bar" : 2, "quux" : true}, "valid": true }, { "description": "an additional invalid property is invalid", "data": {"foo" : 1, "bar" : 2, "quux" : 12}, "valid": false } ] }, { "description": "additionalProperties can exist by itself", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "an additional valid property is valid", "data": {"foo" : true}, "valid": true }, { "description": "an additional invalid property is invalid", "data": {"foo" : 1}, "valid": false } ] }, { "description": "additionalProperties are allowed by default", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": {"foo": {}, "bar": {}} }, "tests": [ { "description": "additional properties are allowed", "data": {"foo": 1, "bar": 2, "quux": true}, "valid": true } ] }, { "description": "additionalProperties does not look in applicators", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "allOf": [ {"properties": {"foo": {}}} ], "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "properties defined in allOf are not examined", "data": {"foo": 1, "bar": true}, "valid": false } ] }, { "description": "additionalProperties with null valued instance properties", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "additionalProperties": { "type": "null" } }, "tests": [ { "description": "allows null values", "data": {"foo": null}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/allOf.json0000644000175100001770000002077514653725311023175 0ustar00runnerdocker[ { "description": "allOf", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "allOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "allOf", "data": {"foo": "baz", "bar": 2}, "valid": true }, { "description": "mismatch second", "data": {"foo": "baz"}, "valid": false }, { "description": "mismatch first", "data": {"bar": 2}, "valid": false }, { "description": "wrong type", "data": {"foo": "baz", "bar": "quux"}, "valid": false } ] }, { "description": "allOf with base schema", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": {"bar": {"type": "integer"}}, "required": ["bar"], "allOf" : [ { "properties": { "foo": {"type": "string"} }, "required": ["foo"] }, { "properties": { "baz": {"type": "null"} }, "required": ["baz"] } ] }, "tests": [ { "description": "valid", "data": {"foo": "quux", "bar": 2, "baz": null}, "valid": true }, { "description": "mismatch base schema", "data": {"foo": "quux", "baz": null}, "valid": false }, { "description": "mismatch first allOf", "data": {"bar": 2, "baz": null}, "valid": false }, { "description": "mismatch second allOf", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "mismatch both", "data": {"bar": 2}, "valid": false } ] }, { "description": "allOf simple types", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "allOf": [ {"maximum": 30}, {"minimum": 20} ] }, "tests": [ { "description": "valid", "data": 25, "valid": true }, { "description": "mismatch one", "data": 35, "valid": false } ] }, { "description": "allOf with boolean schemas, all true", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "allOf": [true, true] }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "allOf with boolean schemas, some false", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "allOf": [true, false] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "allOf with boolean schemas, all false", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "allOf": [false, false] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "allOf with one empty schema", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "allOf": [ {} ] }, "tests": [ { "description": "any data is valid", "data": 1, "valid": true } ] }, { "description": "allOf with two empty schemas", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "allOf": [ {}, {} ] }, "tests": [ { "description": "any data is valid", "data": 1, "valid": true } ] }, { "description": "allOf with the first empty schema", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "allOf": [ {}, { "type": "number" } ] }, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is invalid", "data": "foo", "valid": false } ] }, { "description": "allOf with the last empty schema", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "allOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is invalid", "data": "foo", "valid": false } ] }, { "description": "nested allOf, to check validation semantics", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "allOf": [ { "allOf": [ { "type": "null" } ] } ] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "anything non-null is invalid", "data": 123, "valid": false } ] }, { "description": "allOf combined with anyOf, oneOf", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "allOf": [ { "multipleOf": 2 } ], "anyOf": [ { "multipleOf": 3 } ], "oneOf": [ { "multipleOf": 5 } ] }, "tests": [ { "description": "allOf: false, anyOf: false, oneOf: false", "data": 1, "valid": false }, { "description": "allOf: false, anyOf: false, oneOf: true", "data": 5, "valid": false }, { "description": "allOf: false, anyOf: true, oneOf: false", "data": 3, "valid": false }, { "description": "allOf: false, anyOf: true, oneOf: true", "data": 15, "valid": false }, { "description": "allOf: true, anyOf: false, oneOf: false", "data": 2, "valid": false }, { "description": "allOf: true, anyOf: false, oneOf: true", "data": 10, "valid": false }, { "description": "allOf: true, anyOf: true, oneOf: false", "data": 6, "valid": false }, { "description": "allOf: true, anyOf: true, oneOf: true", "data": 30, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/anchor.json0000644000175100001770000001604614653725311023406 0ustar00runnerdocker[ { "description": "Location-independent identifier", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$ref": "#foo", "$defs": { "A": { "$anchor": "foo", "type": "integer" } } }, "tests": [ { "data": 1, "description": "match", "valid": true }, { "data": "a", "description": "mismatch", "valid": false } ] }, { "description": "Location-independent identifier with absolute URI", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$ref": "http://localhost:1234/draft2019-09/bar#foo", "$defs": { "A": { "$id": "http://localhost:1234/draft2019-09/bar", "$anchor": "foo", "type": "integer" } } }, "tests": [ { "data": 1, "description": "match", "valid": true }, { "data": "a", "description": "mismatch", "valid": false } ] }, { "description": "Location-independent identifier with base URI change in subschema", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "http://localhost:1234/draft2019-09/root", "$ref": "http://localhost:1234/draft2019-09/nested.json#foo", "$defs": { "A": { "$id": "nested.json", "$defs": { "B": { "$anchor": "foo", "type": "integer" } } } } }, "tests": [ { "data": 1, "description": "match", "valid": true }, { "data": "a", "description": "mismatch", "valid": false } ] }, { "description": "$anchor inside an enum is not a real identifier", "comment": "the implementation must not be confused by an $anchor buried in the enum", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$defs": { "anchor_in_enum": { "enum": [ { "$anchor": "my_anchor", "type": "null" } ] }, "real_identifier_in_schema": { "$anchor": "my_anchor", "type": "string" }, "zzz_anchor_in_const": { "const": { "$anchor": "my_anchor", "type": "null" } } }, "anyOf": [ { "$ref": "#/$defs/anchor_in_enum" }, { "$ref": "#my_anchor" } ] }, "tests": [ { "description": "exact match to enum, and type matches", "data": { "$anchor": "my_anchor", "type": "null" }, "valid": true }, { "description": "in implementations that strip $anchor, this may match either $def", "data": { "type": "null" }, "valid": false }, { "description": "match $ref to $anchor", "data": "a string to match #/$defs/anchor_in_enum", "valid": true }, { "description": "no match on enum or $ref to $anchor", "data": 1, "valid": false } ] }, { "description": "same $anchor with different base uri", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "http://localhost:1234/draft2019-09/foobar", "$defs": { "A": { "$id": "child1", "allOf": [ { "$id": "child2", "$anchor": "my_anchor", "type": "number" }, { "$anchor": "my_anchor", "type": "string" } ] } }, "$ref": "child1#my_anchor" }, "tests": [ { "description": "$ref resolves to /$defs/A/allOf/1", "data": "a", "valid": true }, { "description": "$ref does not resolve to /$defs/A/allOf/0", "data": 1, "valid": false } ] }, { "description": "non-schema object containing an $anchor property", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$defs": { "const_not_anchor": { "const": { "$anchor": "not_a_real_anchor" } } }, "if": { "const": "skip not_a_real_anchor" }, "then": true, "else" : { "$ref": "#/$defs/const_not_anchor" } }, "tests": [ { "description": "skip traversing definition for a valid result", "data": "skip not_a_real_anchor", "valid": true }, { "description": "const at const_not_anchor does not match", "data": 1, "valid": false } ] }, { "description": "invalid anchors", "comment": "Section 8.2.3", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$ref": "https://json-schema.org/draft/2019-09/schema" }, "tests": [ { "description": "MUST start with a letter (and not #)", "data": { "$anchor" : "#foo" }, "valid": false }, { "description": "JSON pointers are not valid", "data": { "$anchor" : "/a/b" }, "valid": false }, { "description": "invalid with valid beginning", "data": { "$anchor" : "foo#something" }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/anyOf.json0000644000175100001770000001252514653725311023206 0ustar00runnerdocker[ { "description": "anyOf", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "anyOf": [ { "type": "integer" }, { "minimum": 2 } ] }, "tests": [ { "description": "first anyOf valid", "data": 1, "valid": true }, { "description": "second anyOf valid", "data": 2.5, "valid": true }, { "description": "both anyOf valid", "data": 3, "valid": true }, { "description": "neither anyOf valid", "data": 1.5, "valid": false } ] }, { "description": "anyOf with base schema", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "string", "anyOf" : [ { "maxLength": 2 }, { "minLength": 4 } ] }, "tests": [ { "description": "mismatch base schema", "data": 3, "valid": false }, { "description": "one anyOf valid", "data": "foobar", "valid": true }, { "description": "both anyOf invalid", "data": "foo", "valid": false } ] }, { "description": "anyOf with boolean schemas, all true", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "anyOf": [true, true] }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "anyOf with boolean schemas, some true", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "anyOf": [true, false] }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "anyOf with boolean schemas, all false", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "anyOf": [false, false] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "anyOf complex types", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "anyOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "first anyOf valid (complex)", "data": {"bar": 2}, "valid": true }, { "description": "second anyOf valid (complex)", "data": {"foo": "baz"}, "valid": true }, { "description": "both anyOf valid (complex)", "data": {"foo": "baz", "bar": 2}, "valid": true }, { "description": "neither anyOf valid (complex)", "data": {"foo": 2, "bar": "quux"}, "valid": false } ] }, { "description": "anyOf with one empty schema", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "anyOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "string is valid", "data": "foo", "valid": true }, { "description": "number is valid", "data": 123, "valid": true } ] }, { "description": "nested anyOf, to check validation semantics", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "anyOf": [ { "anyOf": [ { "type": "null" } ] } ] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "anything non-null is invalid", "data": 123, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/boolean_schema.json0000644000175100001770000000540214653725311025065 0ustar00runnerdocker[ { "description": "boolean schema 'true'", "schema": true, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is valid", "data": "foo", "valid": true }, { "description": "boolean true is valid", "data": true, "valid": true }, { "description": "boolean false is valid", "data": false, "valid": true }, { "description": "null is valid", "data": null, "valid": true }, { "description": "object is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "empty object is valid", "data": {}, "valid": true }, { "description": "array is valid", "data": ["foo"], "valid": true }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "boolean schema 'false'", "schema": false, "tests": [ { "description": "number is invalid", "data": 1, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false }, { "description": "boolean true is invalid", "data": true, "valid": false }, { "description": "boolean false is invalid", "data": false, "valid": false }, { "description": "null is invalid", "data": null, "valid": false }, { "description": "object is invalid", "data": {"foo": "bar"}, "valid": false }, { "description": "empty object is invalid", "data": {}, "valid": false }, { "description": "array is invalid", "data": ["foo"], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/const.json0000644000175100001770000002534514653725311023264 0ustar00runnerdocker[ { "description": "const validation", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "const": 2 }, "tests": [ { "description": "same value is valid", "data": 2, "valid": true }, { "description": "another value is invalid", "data": 5, "valid": false }, { "description": "another type is invalid", "data": "a", "valid": false } ] }, { "description": "const with object", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "const": {"foo": "bar", "baz": "bax"} }, "tests": [ { "description": "same object is valid", "data": {"foo": "bar", "baz": "bax"}, "valid": true }, { "description": "same object with different property order is valid", "data": {"baz": "bax", "foo": "bar"}, "valid": true }, { "description": "another object is invalid", "data": {"foo": "bar"}, "valid": false }, { "description": "another type is invalid", "data": [1, 2], "valid": false } ] }, { "description": "const with array", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "const": [{ "foo": "bar" }] }, "tests": [ { "description": "same array is valid", "data": [{"foo": "bar"}], "valid": true }, { "description": "another array item is invalid", "data": [2], "valid": false }, { "description": "array with additional items is invalid", "data": [1, 2, 3], "valid": false } ] }, { "description": "const with null", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "const": null }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "not null is invalid", "data": 0, "valid": false } ] }, { "description": "const with false does not match 0", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "const": false }, "tests": [ { "description": "false is valid", "data": false, "valid": true }, { "description": "integer zero is invalid", "data": 0, "valid": false }, { "description": "float zero is invalid", "data": 0.0, "valid": false } ] }, { "description": "const with true does not match 1", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "const": true }, "tests": [ { "description": "true is valid", "data": true, "valid": true }, { "description": "integer one is invalid", "data": 1, "valid": false }, { "description": "float one is invalid", "data": 1.0, "valid": false } ] }, { "description": "const with [false] does not match [0]", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "const": [false] }, "tests": [ { "description": "[false] is valid", "data": [false], "valid": true }, { "description": "[0] is invalid", "data": [0], "valid": false }, { "description": "[0.0] is invalid", "data": [0.0], "valid": false } ] }, { "description": "const with [true] does not match [1]", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "const": [true] }, "tests": [ { "description": "[true] is valid", "data": [true], "valid": true }, { "description": "[1] is invalid", "data": [1], "valid": false }, { "description": "[1.0] is invalid", "data": [1.0], "valid": false } ] }, { "description": "const with {\"a\": false} does not match {\"a\": 0}", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "const": {"a": false} }, "tests": [ { "description": "{\"a\": false} is valid", "data": {"a": false}, "valid": true }, { "description": "{\"a\": 0} is invalid", "data": {"a": 0}, "valid": false }, { "description": "{\"a\": 0.0} is invalid", "data": {"a": 0.0}, "valid": false } ] }, { "description": "const with {\"a\": true} does not match {\"a\": 1}", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "const": {"a": true} }, "tests": [ { "description": "{\"a\": true} is valid", "data": {"a": true}, "valid": true }, { "description": "{\"a\": 1} is invalid", "data": {"a": 1}, "valid": false }, { "description": "{\"a\": 1.0} is invalid", "data": {"a": 1.0}, "valid": false } ] }, { "description": "const with 0 does not match other zero-like types", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "const": 0 }, "tests": [ { "description": "false is invalid", "data": false, "valid": false }, { "description": "integer zero is valid", "data": 0, "valid": true }, { "description": "float zero is valid", "data": 0.0, "valid": true }, { "description": "empty object is invalid", "data": {}, "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false }, { "description": "empty string is invalid", "data": "", "valid": false } ] }, { "description": "const with 1 does not match true", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "const": 1 }, "tests": [ { "description": "true is invalid", "data": true, "valid": false }, { "description": "integer one is valid", "data": 1, "valid": true }, { "description": "float one is valid", "data": 1.0, "valid": true } ] }, { "description": "const with -2.0 matches integer and float types", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "const": -2.0 }, "tests": [ { "description": "integer -2 is valid", "data": -2, "valid": true }, { "description": "integer 2 is invalid", "data": 2, "valid": false }, { "description": "float -2.0 is valid", "data": -2.0, "valid": true }, { "description": "float 2.0 is invalid", "data": 2.0, "valid": false }, { "description": "float -2.00001 is invalid", "data": -2.00001, "valid": false } ] }, { "description": "float and integers are equal up to 64-bit representation limits", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "const": 9007199254740992 }, "tests": [ { "description": "integer is valid", "data": 9007199254740992, "valid": true }, { "description": "integer minus one is invalid", "data": 9007199254740991, "valid": false }, { "description": "float is valid", "data": 9007199254740992.0, "valid": true }, { "description": "float minus one is invalid", "data": 9007199254740991.0, "valid": false } ] }, { "description": "nul characters in strings", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "const": "hello\u0000there" }, "tests": [ { "description": "match string with nul", "data": "hello\u0000there", "valid": true }, { "description": "do not match string lacking nul", "data": "hellothere", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/contains.json0000644000175100001770000001206614653725311023750 0ustar00runnerdocker[ { "description": "contains keyword validation", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "contains": {"minimum": 5} }, "tests": [ { "description": "array with item matching schema (5) is valid", "data": [3, 4, 5], "valid": true }, { "description": "array with item matching schema (6) is valid", "data": [3, 4, 6], "valid": true }, { "description": "array with two items matching schema (5, 6) is valid", "data": [3, 4, 5, 6], "valid": true }, { "description": "array without items matching schema is invalid", "data": [2, 3, 4], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false }, { "description": "not array is valid", "data": {}, "valid": true } ] }, { "description": "contains keyword with const keyword", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "contains": { "const": 5 } }, "tests": [ { "description": "array with item 5 is valid", "data": [3, 4, 5], "valid": true }, { "description": "array with two items 5 is valid", "data": [3, 4, 5, 5], "valid": true }, { "description": "array without item 5 is invalid", "data": [1, 2, 3, 4], "valid": false } ] }, { "description": "contains keyword with boolean schema true", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "contains": true }, "tests": [ { "description": "any non-empty array is valid", "data": ["foo"], "valid": true }, { "description": "empty array is invalid", "data": [], "valid": false } ] }, { "description": "contains keyword with boolean schema false", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "contains": false }, "tests": [ { "description": "any non-empty array is invalid", "data": ["foo"], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false }, { "description": "non-arrays are valid", "data": "contains does not apply to strings", "valid": true } ] }, { "description": "items + contains", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": { "multipleOf": 2 }, "contains": { "multipleOf": 3 } }, "tests": [ { "description": "matches items, does not match contains", "data": [ 2, 4, 8 ], "valid": false }, { "description": "does not match items, matches contains", "data": [ 3, 6, 9 ], "valid": false }, { "description": "matches both items and contains", "data": [ 6, 12 ], "valid": true }, { "description": "matches neither items nor contains", "data": [ 1, 5 ], "valid": false } ] }, { "description": "contains with false if subschema", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "contains": { "if": false, "else": true } }, "tests": [ { "description": "any non-empty array is valid", "data": ["foo"], "valid": true }, { "description": "empty array is invalid", "data": [], "valid": false } ] }, { "description": "contains with null instance elements", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "contains": { "type": "null" } }, "tests": [ { "description": "allows null items", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/content.json0000644000175100001770000001045514653725311023604 0ustar00runnerdocker[ { "description": "validation of string-encoded content based on media type", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "contentMediaType": "application/json" }, "tests": [ { "description": "a valid JSON document", "data": "{\"foo\": \"bar\"}", "valid": true }, { "description": "an invalid JSON document; validates true", "data": "{:}", "valid": true }, { "description": "ignores non-strings", "data": 100, "valid": true } ] }, { "description": "validation of binary string-encoding", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "contentEncoding": "base64" }, "tests": [ { "description": "a valid base64 string", "data": "eyJmb28iOiAiYmFyIn0K", "valid": true }, { "description": "an invalid base64 string (% is not a valid character); validates true", "data": "eyJmb28iOi%iYmFyIn0K", "valid": true }, { "description": "ignores non-strings", "data": 100, "valid": true } ] }, { "description": "validation of binary-encoded media type documents", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "contentMediaType": "application/json", "contentEncoding": "base64" }, "tests": [ { "description": "a valid base64-encoded JSON document", "data": "eyJmb28iOiAiYmFyIn0K", "valid": true }, { "description": "a validly-encoded invalid JSON document; validates true", "data": "ezp9Cg==", "valid": true }, { "description": "an invalid base64 string that is valid JSON; validates true", "data": "{}", "valid": true }, { "description": "ignores non-strings", "data": 100, "valid": true } ] }, { "description": "validation of binary-encoded media type documents with schema", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "contentMediaType": "application/json", "contentEncoding": "base64", "contentSchema": { "type": "object", "required": ["foo"], "properties": { "foo": { "type": "string" } } } }, "tests": [ { "description": "a valid base64-encoded JSON document", "data": "eyJmb28iOiAiYmFyIn0K", "valid": true }, { "description": "another valid base64-encoded JSON document", "data": "eyJib28iOiAyMCwgImZvbyI6ICJiYXoifQ==", "valid": true }, { "description": "an invalid base64-encoded JSON document; validates true", "data": "eyJib28iOiAyMH0=", "valid": true }, { "description": "an empty object as a base64-encoded JSON document; validates true", "data": "e30=", "valid": true }, { "description": "an empty array as a base64-encoded JSON document", "data": "W10=", "valid": true }, { "description": "a validly-encoded invalid JSON document; validates true", "data": "ezp9Cg==", "valid": true }, { "description": "an invalid base64 string that is valid JSON; validates true", "data": "{}", "valid": true }, { "description": "ignores non-strings", "data": 100, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/default.json0000644000175100001770000000461414653725311023556 0ustar00runnerdocker[ { "description": "invalid type for default", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": { "foo": { "type": "integer", "default": [] } } }, "tests": [ { "description": "valid when property is specified", "data": {"foo": 13}, "valid": true }, { "description": "still valid when the invalid default is used", "data": {}, "valid": true } ] }, { "description": "invalid string value for default", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": { "bar": { "type": "string", "minLength": 4, "default": "bad" } } }, "tests": [ { "description": "valid when property is specified", "data": {"bar": "good"}, "valid": true }, { "description": "still valid when the invalid default is used", "data": {}, "valid": true } ] }, { "description": "the default keyword does not do anything if the property is missing", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "properties": { "alpha": { "type": "number", "maximum": 3, "default": 5 } } }, "tests": [ { "description": "an explicit property value is checked against maximum (passing)", "data": { "alpha": 1 }, "valid": true }, { "description": "an explicit property value is checked against maximum (failing)", "data": { "alpha": 5 }, "valid": false }, { "description": "missing properties are not filled in with the default", "data": {}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/defs.json0000644000175100001770000000117514653725311023052 0ustar00runnerdocker[ { "description": "validate definition against metaschema", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$ref": "https://json-schema.org/draft/2019-09/schema" }, "tests": [ { "description": "valid definition schema", "data": {"$defs": {"foo": {"type": "integer"}}}, "valid": true }, { "description": "invalid definition schema", "data": {"$defs": {"foo": {"type": 1}}}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/dependentRequired.json0000644000175100001770000001030614653725311025574 0ustar00runnerdocker[ { "description": "single dependency", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "dependentRequired": {"bar": ["foo"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependant", "data": {"foo": 1}, "valid": true }, { "description": "with dependency", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "missing dependency", "data": {"bar": 2}, "valid": false }, { "description": "ignores arrays", "data": ["bar"], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "empty dependents", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "dependentRequired": {"bar": []} }, "tests": [ { "description": "empty object", "data": {}, "valid": true }, { "description": "object with one property", "data": {"bar": 2}, "valid": true }, { "description": "non-object is valid", "data": 1, "valid": true } ] }, { "description": "multiple dependents required", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "dependentRequired": {"quux": ["foo", "bar"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependants", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "with dependencies", "data": {"foo": 1, "bar": 2, "quux": 3}, "valid": true }, { "description": "missing dependency", "data": {"foo": 1, "quux": 2}, "valid": false }, { "description": "missing other dependency", "data": {"bar": 1, "quux": 2}, "valid": false }, { "description": "missing both dependencies", "data": {"quux": 1}, "valid": false } ] }, { "description": "dependencies with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "dependentRequired": { "foo\nbar": ["foo\rbar"], "foo\"bar": ["foo'bar"] } }, "tests": [ { "description": "CRLF", "data": { "foo\nbar": 1, "foo\rbar": 2 }, "valid": true }, { "description": "quoted quotes", "data": { "foo'bar": 1, "foo\"bar": 2 }, "valid": true }, { "description": "CRLF missing dependent", "data": { "foo\nbar": 1, "foo": 2 }, "valid": false }, { "description": "quoted quotes missing dependent", "data": { "foo\"bar": 2 }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/dependentSchemas.json0000644000175100001770000000743714653725311025412 0ustar00runnerdocker[ { "description": "single dependency", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "dependentSchemas": { "bar": { "properties": { "foo": {"type": "integer"}, "bar": {"type": "integer"} } } } }, "tests": [ { "description": "valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "no dependency", "data": {"foo": "quux"}, "valid": true }, { "description": "wrong type", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "wrong type other", "data": {"foo": 2, "bar": "quux"}, "valid": false }, { "description": "wrong type both", "data": {"foo": "quux", "bar": "quux"}, "valid": false }, { "description": "ignores arrays", "data": ["bar"], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "boolean subschemas", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "dependentSchemas": { "foo": true, "bar": false } }, "tests": [ { "description": "object with property having schema true is valid", "data": {"foo": 1}, "valid": true }, { "description": "object with property having schema false is invalid", "data": {"bar": 2}, "valid": false }, { "description": "object with both properties is invalid", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "dependencies with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "dependentSchemas": { "foo\tbar": {"minProperties": 4}, "foo'bar": {"required": ["foo\"bar"]} } }, "tests": [ { "description": "quoted tab", "data": { "foo\tbar": 1, "a": 2, "b": 3, "c": 4 }, "valid": true }, { "description": "quoted quote", "data": { "foo'bar": {"foo\"bar": 1} }, "valid": false }, { "description": "quoted tab invalid under dependent schema", "data": { "foo\tbar": 1, "a": 2 }, "valid": false }, { "description": "quoted quote invalid under dependent schema", "data": {"foo'bar": 1}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/enum.json0000644000175100001770000001642514653725311023101 0ustar00runnerdocker[ { "description": "simple enum validation", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "enum": [1, 2, 3] }, "tests": [ { "description": "one of the enum is valid", "data": 1, "valid": true }, { "description": "something else is invalid", "data": 4, "valid": false } ] }, { "description": "heterogeneous enum validation", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "enum": [6, "foo", [], true, {"foo": 12}] }, "tests": [ { "description": "one of the enum is valid", "data": [], "valid": true }, { "description": "something else is invalid", "data": null, "valid": false }, { "description": "objects are deep compared", "data": {"foo": false}, "valid": false }, { "description": "valid object matches", "data": {"foo": 12}, "valid": true }, { "description": "extra properties in object is invalid", "data": {"foo": 12, "boo": 42}, "valid": false } ] }, { "description": "heterogeneous enum-with-null validation", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "enum": [6, null] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "number is valid", "data": 6, "valid": true }, { "description": "something else is invalid", "data": "test", "valid": false } ] }, { "description": "enums in properties", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type":"object", "properties": { "foo": {"enum":["foo"]}, "bar": {"enum":["bar"]} }, "required": ["bar"] }, "tests": [ { "description": "both properties are valid", "data": {"foo":"foo", "bar":"bar"}, "valid": true }, { "description": "wrong foo value", "data": {"foo":"foot", "bar":"bar"}, "valid": false }, { "description": "wrong bar value", "data": {"foo":"foo", "bar":"bart"}, "valid": false }, { "description": "missing optional property is valid", "data": {"bar":"bar"}, "valid": true }, { "description": "missing required property is invalid", "data": {"foo":"foo"}, "valid": false }, { "description": "missing all properties is invalid", "data": {}, "valid": false } ] }, { "description": "enum with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "enum": ["foo\nbar", "foo\rbar"] }, "tests": [ { "description": "member 1 is valid", "data": "foo\nbar", "valid": true }, { "description": "member 2 is valid", "data": "foo\rbar", "valid": true }, { "description": "another string is invalid", "data": "abc", "valid": false } ] }, { "description": "enum with false does not match 0", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "enum": [false] }, "tests": [ { "description": "false is valid", "data": false, "valid": true }, { "description": "integer zero is invalid", "data": 0, "valid": false }, { "description": "float zero is invalid", "data": 0.0, "valid": false } ] }, { "description": "enum with true does not match 1", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "enum": [true] }, "tests": [ { "description": "true is valid", "data": true, "valid": true }, { "description": "integer one is invalid", "data": 1, "valid": false }, { "description": "float one is invalid", "data": 1.0, "valid": false } ] }, { "description": "enum with 0 does not match false", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "enum": [0] }, "tests": [ { "description": "false is invalid", "data": false, "valid": false }, { "description": "integer zero is valid", "data": 0, "valid": true }, { "description": "float zero is valid", "data": 0.0, "valid": true } ] }, { "description": "enum with 1 does not match true", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "enum": [1] }, "tests": [ { "description": "true is invalid", "data": true, "valid": false }, { "description": "integer one is valid", "data": 1, "valid": true }, { "description": "float one is valid", "data": 1.0, "valid": true } ] }, { "description": "nul characters in strings", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "enum": [ "hello\u0000there" ] }, "tests": [ { "description": "match string with nul", "data": "hello\u0000there", "valid": true }, { "description": "do not match string lacking nul", "data": "hellothere", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/exclusiveMaximum.json0000644000175100001770000000151614653725311025475 0ustar00runnerdocker[ { "description": "exclusiveMaximum validation", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "exclusiveMaximum": 3.0 }, "tests": [ { "description": "below the exclusiveMaximum is valid", "data": 2.2, "valid": true }, { "description": "boundary point is invalid", "data": 3.0, "valid": false }, { "description": "above the exclusiveMaximum is invalid", "data": 3.5, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/exclusiveMinimum.json0000644000175100001770000000151614653725311025473 0ustar00runnerdocker[ { "description": "exclusiveMinimum validation", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "exclusiveMinimum": 1.1 }, "tests": [ { "description": "above the exclusiveMinimum is valid", "data": 1.2, "valid": true }, { "description": "boundary point is invalid", "data": 1.1, "valid": false }, { "description": "below the exclusiveMinimum is invalid", "data": 0.6, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/format.json0000644000175100001770000005263014653725311023423 0ustar00runnerdocker[ { "description": "email format", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "idn-email format", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "idn-email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "regex format", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "regex" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "ipv4 format", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "ipv4" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "ipv6 format", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "ipv6" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "idn-hostname format", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "idn-hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "hostname format", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "date format", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "date" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "date-time format", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "date-time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "time format", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "json-pointer format", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "json-pointer" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "relative-json-pointer format", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "relative-json-pointer" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "iri format", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "iri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "iri-reference format", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "iri-reference" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uri format", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "uri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uri-reference format", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "uri-reference" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uri-template format", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "uri-template" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uuid format", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "uuid" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "duration format", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "duration" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/id.json0000644000175100001770000002406614653725311022531 0ustar00runnerdocker[ { "description": "Invalid use of fragments in location-independent $id", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$ref": "https://json-schema.org/draft/2019-09/schema" }, "tests": [ { "description": "Identifier name", "data": { "$ref": "#foo", "$defs": { "A": { "$id": "#foo", "type": "integer" } } }, "valid": false }, { "description": "Identifier name and no ref", "data": { "$defs": { "A": { "$id": "#foo" } } }, "valid": false }, { "description": "Identifier path", "data": { "$ref": "#/a/b", "$defs": { "A": { "$id": "#/a/b", "type": "integer" } } }, "valid": false }, { "description": "Identifier name with absolute URI", "data": { "$ref": "http://localhost:1234/draft2019-09/bar#foo", "$defs": { "A": { "$id": "http://localhost:1234/draft2019-09/bar#foo", "type": "integer" } } }, "valid": false }, { "description": "Identifier path with absolute URI", "data": { "$ref": "http://localhost:1234/draft2019-09/bar#/a/b", "$defs": { "A": { "$id": "http://localhost:1234/draft2019-09/bar#/a/b", "type": "integer" } } }, "valid": false }, { "description": "Identifier name with base URI change in subschema", "data": { "$id": "http://localhost:1234/draft2019-09/root", "$ref": "http://localhost:1234/draft2019-09/nested.json#foo", "$defs": { "A": { "$id": "nested.json", "$defs": { "B": { "$id": "#foo", "type": "integer" } } } } }, "valid": false }, { "description": "Identifier path with base URI change in subschema", "data": { "$id": "http://localhost:1234/draft2019-09/root", "$ref": "http://localhost:1234/draft2019-09/nested.json#/a/b", "$defs": { "A": { "$id": "nested.json", "$defs": { "B": { "$id": "#/a/b", "type": "integer" } } } } }, "valid": false } ] }, { "description": "Valid use of empty fragments in location-independent $id", "comment": "These are allowed but discouraged", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$ref": "https://json-schema.org/draft/2019-09/schema" }, "tests": [ { "description": "Identifier name with absolute URI", "data": { "$ref": "http://localhost:1234/draft2019-09/bar", "$defs": { "A": { "$id": "http://localhost:1234/draft2019-09/bar#", "type": "integer" } } }, "valid": true }, { "description": "Identifier name with base URI change in subschema", "data": { "$id": "http://localhost:1234/draft2019-09/root", "$ref": "http://localhost:1234/draft2019-09/nested.json#/$defs/B", "$defs": { "A": { "$id": "nested.json", "$defs": { "B": { "$id": "#", "type": "integer" } } } } }, "valid": true } ] }, { "description": "Unnormalized $ids are allowed but discouraged", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$ref": "https://json-schema.org/draft/2019-09/schema" }, "tests": [ { "description": "Unnormalized identifier", "data": { "$ref": "http://localhost:1234/draft2019-09/foo/baz", "$defs": { "A": { "$id": "http://localhost:1234/draft2019-09/foo/bar/../baz", "type": "integer" } } }, "valid": true }, { "description": "Unnormalized identifier and no ref", "data": { "$defs": { "A": { "$id": "http://localhost:1234/draft2019-09/foo/bar/../baz", "type": "integer" } } }, "valid": true }, { "description": "Unnormalized identifier with empty fragment", "data": { "$ref": "http://localhost:1234/draft2019-09/foo/baz", "$defs": { "A": { "$id": "http://localhost:1234/draft2019-09/foo/bar/../baz#", "type": "integer" } } }, "valid": true }, { "description": "Unnormalized identifier with empty fragment and no ref", "data": { "$defs": { "A": { "$id": "http://localhost:1234/draft2019-09/foo/bar/../baz#", "type": "integer" } } }, "valid": true } ] }, { "description": "$id inside an enum is not a real identifier", "comment": "the implementation must not be confused by an $id buried in the enum", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$defs": { "id_in_enum": { "enum": [ { "$id": "https://localhost:1234/draft2019-09/id/my_identifier.json", "type": "null" } ] }, "real_id_in_schema": { "$id": "https://localhost:1234/draft2019-09/id/my_identifier.json", "type": "string" }, "zzz_id_in_const": { "const": { "$id": "https://localhost:1234/draft2019-09/id/my_identifier.json", "type": "null" } } }, "anyOf": [ { "$ref": "#/$defs/id_in_enum" }, { "$ref": "https://localhost:1234/draft2019-09/id/my_identifier.json" } ] }, "tests": [ { "description": "exact match to enum, and type matches", "data": { "$id": "https://localhost:1234/draft2019-09/id/my_identifier.json", "type": "null" }, "valid": true }, { "description": "match $ref to $id", "data": "a string to match #/$defs/id_in_enum", "valid": true }, { "description": "no match on enum or $ref to $id", "data": 1, "valid": false } ] }, { "description": "non-schema object containing an $id property", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$defs": { "const_not_id": { "const": { "$id": "not_a_real_id" } } }, "if": { "const": "skip not_a_real_id" }, "then": true, "else" : { "$ref": "#/$defs/const_not_id" } }, "tests": [ { "description": "skip traversing definition for a valid result", "data": "skip not_a_real_id", "valid": true }, { "description": "const at const_not_id does not match", "data": 1, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/if-then-else.json0000644000175100001770000001663014653725311024413 0ustar00runnerdocker[ { "description": "ignore if without then or else", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "if": { "const": 0 } }, "tests": [ { "description": "valid when valid against lone if", "data": 0, "valid": true }, { "description": "valid when invalid against lone if", "data": "hello", "valid": true } ] }, { "description": "ignore then without if", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "then": { "const": 0 } }, "tests": [ { "description": "valid when valid against lone then", "data": 0, "valid": true }, { "description": "valid when invalid against lone then", "data": "hello", "valid": true } ] }, { "description": "ignore else without if", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "else": { "const": 0 } }, "tests": [ { "description": "valid when valid against lone else", "data": 0, "valid": true }, { "description": "valid when invalid against lone else", "data": "hello", "valid": true } ] }, { "description": "if and then without else", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "if": { "exclusiveMaximum": 0 }, "then": { "minimum": -10 } }, "tests": [ { "description": "valid through then", "data": -1, "valid": true }, { "description": "invalid through then", "data": -100, "valid": false }, { "description": "valid when if test fails", "data": 3, "valid": true } ] }, { "description": "if and else without then", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "if": { "exclusiveMaximum": 0 }, "else": { "multipleOf": 2 } }, "tests": [ { "description": "valid when if test passes", "data": -1, "valid": true }, { "description": "valid through else", "data": 4, "valid": true }, { "description": "invalid through else", "data": 3, "valid": false } ] }, { "description": "validate against correct branch, then vs else", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "if": { "exclusiveMaximum": 0 }, "then": { "minimum": -10 }, "else": { "multipleOf": 2 } }, "tests": [ { "description": "valid through then", "data": -1, "valid": true }, { "description": "invalid through then", "data": -100, "valid": false }, { "description": "valid through else", "data": 4, "valid": true }, { "description": "invalid through else", "data": 3, "valid": false } ] }, { "description": "non-interference across combined schemas", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "allOf": [ { "if": { "exclusiveMaximum": 0 } }, { "then": { "minimum": -10 } }, { "else": { "multipleOf": 2 } } ] }, "tests": [ { "description": "valid, but would have been invalid through then", "data": -100, "valid": true }, { "description": "valid, but would have been invalid through else", "data": 3, "valid": true } ] }, { "description": "if with boolean schema true", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "if": true, "then": { "const": "then" }, "else": { "const": "else" } }, "tests": [ { "description": "boolean schema true in if always chooses the then path (valid)", "data": "then", "valid": true }, { "description": "boolean schema true in if always chooses the then path (invalid)", "data": "else", "valid": false } ] }, { "description": "if with boolean schema false", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "if": false, "then": { "const": "then" }, "else": { "const": "else" } }, "tests": [ { "description": "boolean schema false in if always chooses the else path (invalid)", "data": "then", "valid": false }, { "description": "boolean schema false in if always chooses the else path (valid)", "data": "else", "valid": true } ] }, { "description": "if appears at the end when serialized (keyword processing sequence)", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "then": { "const": "yes" }, "else": { "const": "other" }, "if": { "maxLength": 4 } }, "tests": [ { "description": "yes redirects to then and passes", "data": "yes", "valid": true }, { "description": "other redirects to else and passes", "data": "other", "valid": true }, { "description": "no redirects to then and fails", "data": "no", "valid": false }, { "description": "invalid redirects to else and fails", "data": "invalid", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/infinite-loop-detection.json0000644000175100001770000000203314653725311026653 0ustar00runnerdocker[ { "description": "evaluating the same schema location against the same data location twice is not a sign of an infinite loop", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$defs": { "int": { "type": "integer" } }, "allOf": [ { "properties": { "foo": { "$ref": "#/$defs/int" } } }, { "additionalProperties": { "$ref": "#/$defs/int" } } ] }, "tests": [ { "description": "passing case", "data": { "foo": 1 }, "valid": true }, { "description": "failing case", "data": { "foo": "a string" }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/items.json0000644000175100001770000002102314653725311023244 0ustar00runnerdocker[ { "description": "a schema given for items", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": {"type": "integer"} }, "tests": [ { "description": "valid items", "data": [ 1, 2, 3 ], "valid": true }, { "description": "wrong type of items", "data": [1, "x"], "valid": false }, { "description": "ignores non-arrays", "data": {"foo" : "bar"}, "valid": true }, { "description": "JavaScript pseudo-array is valid", "data": { "0": "invalid", "length": 1 }, "valid": true } ] }, { "description": "an array of schemas for items", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": [ {"type": "integer"}, {"type": "string"} ] }, "tests": [ { "description": "correct types", "data": [ 1, "foo" ], "valid": true }, { "description": "wrong types", "data": [ "foo", 1 ], "valid": false }, { "description": "incomplete array of items", "data": [ 1 ], "valid": true }, { "description": "array with additional items", "data": [ 1, "foo", true ], "valid": true }, { "description": "empty array", "data": [ ], "valid": true }, { "description": "JavaScript pseudo-array is valid", "data": { "0": "invalid", "1": "valid", "length": 2 }, "valid": true } ] }, { "description": "items with boolean schema (true)", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": true }, "tests": [ { "description": "any array is valid", "data": [ 1, "foo", true ], "valid": true }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "items with boolean schema (false)", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": false }, "tests": [ { "description": "any non-empty array is invalid", "data": [ 1, "foo", true ], "valid": false }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "items with boolean schemas", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": [true, false] }, "tests": [ { "description": "array with one item is valid", "data": [ 1 ], "valid": true }, { "description": "array with two items is invalid", "data": [ 1, "foo" ], "valid": false }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "items and subitems", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$defs": { "item": { "type": "array", "additionalItems": false, "items": [ { "$ref": "#/$defs/sub-item" }, { "$ref": "#/$defs/sub-item" } ] }, "sub-item": { "type": "object", "required": ["foo"] } }, "type": "array", "additionalItems": false, "items": [ { "$ref": "#/$defs/item" }, { "$ref": "#/$defs/item" }, { "$ref": "#/$defs/item" } ] }, "tests": [ { "description": "valid items", "data": [ [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": true }, { "description": "too many items", "data": [ [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "too many sub-items", "data": [ [ {"foo": null}, {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "wrong item", "data": [ {"foo": null}, [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "wrong sub-item", "data": [ [ {}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "fewer items is valid", "data": [ [ {"foo": null} ], [ {"foo": null} ] ], "valid": true } ] }, { "description": "nested items", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "array", "items": { "type": "array", "items": { "type": "array", "items": { "type": "array", "items": { "type": "number" } } } } }, "tests": [ { "description": "valid nested array", "data": [[[[1]], [[2],[3]]], [[[4], [5], [6]]]], "valid": true }, { "description": "nested array with invalid type", "data": [[[["1"]], [[2],[3]]], [[[4], [5], [6]]]], "valid": false }, { "description": "not deep enough", "data": [[[1], [2],[3]], [[4], [5], [6]]], "valid": false } ] }, { "description": "single-form items with null instance elements", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": { "type": "null" } }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] }, { "description": "array-form items with null instance elements", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": [ { "type": "null" } ] }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/maxContains.json0000644000175100001770000000574614653725311024425 0ustar00runnerdocker[ { "description": "maxContains without contains is ignored", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "maxContains": 1 }, "tests": [ { "description": "one item valid against lone maxContains", "data": [ 1 ], "valid": true }, { "description": "two items still valid against lone maxContains", "data": [ 1, 2 ], "valid": true } ] }, { "description": "maxContains with contains", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "contains": {"const": 1}, "maxContains": 1 }, "tests": [ { "description": "empty data", "data": [ ], "valid": false }, { "description": "all elements match, valid maxContains", "data": [ 1 ], "valid": true }, { "description": "all elements match, invalid maxContains", "data": [ 1, 1 ], "valid": false }, { "description": "some elements match, valid maxContains", "data": [ 1, 2 ], "valid": true }, { "description": "some elements match, invalid maxContains", "data": [ 1, 2, 1 ], "valid": false } ] }, { "description": "maxContains with contains, value with a decimal", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "contains": {"const": 1}, "maxContains": 1.0 }, "tests": [ { "description": "one element matches, valid maxContains", "data": [ 1 ], "valid": true }, { "description": "too many elements match, invalid maxContains", "data": [ 1, 1 ], "valid": false } ] }, { "description": "minContains < maxContains", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "contains": {"const": 1}, "minContains": 1, "maxContains": 3 }, "tests": [ { "description": "actual < minContains < maxContains", "data": [ ], "valid": false }, { "description": "minContains < actual < maxContains", "data": [ 1, 1 ], "valid": true }, { "description": "minContains < maxContains < actual", "data": [ 1, 1, 1, 1 ], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/maxItems.json0000644000175100001770000000244714653725311023723 0ustar00runnerdocker[ { "description": "maxItems validation", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "maxItems": 2 }, "tests": [ { "description": "shorter is valid", "data": [1], "valid": true }, { "description": "exact length is valid", "data": [1, 2], "valid": true }, { "description": "too long is invalid", "data": [1, 2, 3], "valid": false }, { "description": "ignores non-arrays", "data": "foobar", "valid": true } ] }, { "description": "maxItems validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "maxItems": 2.0 }, "tests": [ { "description": "shorter is valid", "data": [1], "valid": true }, { "description": "too long is invalid", "data": [1, 2, 3], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/maxLength.json0000644000175100001770000000274314653725311024062 0ustar00runnerdocker[ { "description": "maxLength validation", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "maxLength": 2 }, "tests": [ { "description": "shorter is valid", "data": "f", "valid": true }, { "description": "exact length is valid", "data": "fo", "valid": true }, { "description": "too long is invalid", "data": "foo", "valid": false }, { "description": "ignores non-strings", "data": 100, "valid": true }, { "description": "two supplementary Unicode code points is long enough", "data": "\uD83D\uDCA9\uD83D\uDCA9", "valid": true } ] }, { "description": "maxLength validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "maxLength": 2.0 }, "tests": [ { "description": "shorter is valid", "data": "f", "valid": true }, { "description": "too long is invalid", "data": "foo", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/maxProperties.json0000644000175100001770000000430014653725311024764 0ustar00runnerdocker[ { "description": "maxProperties validation", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "maxProperties": 2 }, "tests": [ { "description": "shorter is valid", "data": {"foo": 1}, "valid": true }, { "description": "exact length is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "too long is invalid", "data": {"foo": 1, "bar": 2, "baz": 3}, "valid": false }, { "description": "ignores arrays", "data": [1, 2, 3], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "maxProperties validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "maxProperties": 2.0 }, "tests": [ { "description": "shorter is valid", "data": {"foo": 1}, "valid": true }, { "description": "too long is invalid", "data": {"foo": 1, "bar": 2, "baz": 3}, "valid": false } ] }, { "description": "maxProperties = 0 means the object is empty", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "maxProperties": 0 }, "tests": [ { "description": "no properties is valid", "data": {}, "valid": true }, { "description": "one property is invalid", "data": { "foo": 1 }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/maximum.json0000644000175100001770000000317614653725311023611 0ustar00runnerdocker[ { "description": "maximum validation", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "maximum": 3.0 }, "tests": [ { "description": "below the maximum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 3.0, "valid": true }, { "description": "above the maximum is invalid", "data": 3.5, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] }, { "description": "maximum validation with unsigned integer", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "maximum": 300 }, "tests": [ { "description": "below the maximum is invalid", "data": 299.97, "valid": true }, { "description": "boundary point integer is valid", "data": 300, "valid": true }, { "description": "boundary point float is valid", "data": 300.00, "valid": true }, { "description": "above the maximum is invalid", "data": 300.5, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/minContains.json0000644000175100001770000001474014653725311024415 0ustar00runnerdocker[ { "description": "minContains without contains is ignored", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "minContains": 1 }, "tests": [ { "description": "one item valid against lone minContains", "data": [ 1 ], "valid": true }, { "description": "zero items still valid against lone minContains", "data": [], "valid": true } ] }, { "description": "minContains=1 with contains", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "contains": {"const": 1}, "minContains": 1 }, "tests": [ { "description": "empty data", "data": [ ], "valid": false }, { "description": "no elements match", "data": [ 2 ], "valid": false }, { "description": "single element matches, valid minContains", "data": [ 1 ], "valid": true }, { "description": "some elements match, valid minContains", "data": [ 1, 2 ], "valid": true }, { "description": "all elements match, valid minContains", "data": [ 1, 1 ], "valid": true } ] }, { "description": "minContains=2 with contains", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "contains": {"const": 1}, "minContains": 2 }, "tests": [ { "description": "empty data", "data": [ ], "valid": false }, { "description": "all elements match, invalid minContains", "data": [ 1 ], "valid": false }, { "description": "some elements match, invalid minContains", "data": [ 1, 2 ], "valid": false }, { "description": "all elements match, valid minContains (exactly as needed)", "data": [ 1, 1 ], "valid": true }, { "description": "all elements match, valid minContains (more than needed)", "data": [ 1, 1, 1 ], "valid": true }, { "description": "some elements match, valid minContains", "data": [ 1, 2, 1 ], "valid": true } ] }, { "description": "minContains=2 with contains with a decimal value", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "contains": {"const": 1}, "minContains": 2.0 }, "tests": [ { "description": "one element matches, invalid minContains", "data": [ 1 ], "valid": false }, { "description": "both elements match, valid minContains", "data": [ 1, 1 ], "valid": true } ] }, { "description": "maxContains = minContains", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "contains": {"const": 1}, "maxContains": 2, "minContains": 2 }, "tests": [ { "description": "empty data", "data": [ ], "valid": false }, { "description": "all elements match, invalid minContains", "data": [ 1 ], "valid": false }, { "description": "all elements match, invalid maxContains", "data": [ 1, 1, 1 ], "valid": false }, { "description": "all elements match, valid maxContains and minContains", "data": [ 1, 1 ], "valid": true } ] }, { "description": "maxContains < minContains", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "contains": {"const": 1}, "maxContains": 1, "minContains": 3 }, "tests": [ { "description": "empty data", "data": [ ], "valid": false }, { "description": "invalid minContains", "data": [ 1 ], "valid": false }, { "description": "invalid maxContains", "data": [ 1, 1, 1 ], "valid": false }, { "description": "invalid maxContains and minContains", "data": [ 1, 1 ], "valid": false } ] }, { "description": "minContains = 0 with no maxContains", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "contains": {"const": 1}, "minContains": 0 }, "tests": [ { "description": "empty data", "data": [ ], "valid": true }, { "description": "minContains = 0 makes contains always pass", "data": [ 2 ], "valid": true } ] }, { "description": "minContains = 0 with maxContains", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "contains": {"const": 1}, "minContains": 0, "maxContains": 1 }, "tests": [ { "description": "empty data", "data": [ ], "valid": true }, { "description": "not more than maxContains", "data": [ 1 ], "valid": true }, { "description": "too many", "data": [ 1, 1 ], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/minItems.json0000644000175100001770000000242614653725311023716 0ustar00runnerdocker[ { "description": "minItems validation", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "minItems": 1 }, "tests": [ { "description": "longer is valid", "data": [1, 2], "valid": true }, { "description": "exact length is valid", "data": [1], "valid": true }, { "description": "too short is invalid", "data": [], "valid": false }, { "description": "ignores non-arrays", "data": "", "valid": true } ] }, { "description": "minItems validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "minItems": 1.0 }, "tests": [ { "description": "longer is valid", "data": [1, 2], "valid": true }, { "description": "too short is invalid", "data": [], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/minLength.json0000644000175100001770000000273114653725311024055 0ustar00runnerdocker[ { "description": "minLength validation", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "minLength": 2 }, "tests": [ { "description": "longer is valid", "data": "foo", "valid": true }, { "description": "exact length is valid", "data": "fo", "valid": true }, { "description": "too short is invalid", "data": "f", "valid": false }, { "description": "ignores non-strings", "data": 1, "valid": true }, { "description": "one supplementary Unicode code point is not long enough", "data": "\uD83D\uDCA9", "valid": false } ] }, { "description": "minLength validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "minLength": 2.0 }, "tests": [ { "description": "longer is valid", "data": "foo", "valid": true }, { "description": "too short is invalid", "data": "f", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/minProperties.json0000644000175100001770000000314514653725311024770 0ustar00runnerdocker[ { "description": "minProperties validation", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "minProperties": 1 }, "tests": [ { "description": "longer is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "exact length is valid", "data": {"foo": 1}, "valid": true }, { "description": "too short is invalid", "data": {}, "valid": false }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "minProperties validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "minProperties": 1.0 }, "tests": [ { "description": "longer is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "too short is invalid", "data": {}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/minimum.json0000644000175100001770000000410414653725311023577 0ustar00runnerdocker[ { "description": "minimum validation", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "minimum": 1.1 }, "tests": [ { "description": "above the minimum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 1.1, "valid": true }, { "description": "below the minimum is invalid", "data": 0.6, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] }, { "description": "minimum validation with signed integer", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "minimum": -2 }, "tests": [ { "description": "negative above the minimum is valid", "data": -1, "valid": true }, { "description": "positive above the minimum is valid", "data": 0, "valid": true }, { "description": "boundary point is valid", "data": -2, "valid": true }, { "description": "boundary point with float is valid", "data": -2.0, "valid": true }, { "description": "float below the minimum is invalid", "data": -2.0001, "valid": false }, { "description": "int below the minimum is invalid", "data": -3, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/multipleOf.json0000644000175100001770000000430614653725311024250 0ustar00runnerdocker[ { "description": "by int", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "multipleOf": 2 }, "tests": [ { "description": "int by int", "data": 10, "valid": true }, { "description": "int by int fail", "data": 7, "valid": false }, { "description": "ignores non-numbers", "data": "foo", "valid": true } ] }, { "description": "by number", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "multipleOf": 1.5 }, "tests": [ { "description": "zero is multiple of anything", "data": 0, "valid": true }, { "description": "4.5 is multiple of 1.5", "data": 4.5, "valid": true }, { "description": "35 is not multiple of 1.5", "data": 35, "valid": false } ] }, { "description": "by small number", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "multipleOf": 0.0001 }, "tests": [ { "description": "0.0075 is multiple of 0.0001", "data": 0.0075, "valid": true }, { "description": "0.00751 is not multiple of 0.0001", "data": 0.00751, "valid": false } ] }, { "description": "float division = inf", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "integer", "multipleOf": 0.123456789 }, "tests": [ { "description": "always invalid, but naive implementations may raise an overflow error", "data": 1e308, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/not.json0000644000175100001770000000632414653725311022732 0ustar00runnerdocker[ { "description": "not", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "not": {"type": "integer"} }, "tests": [ { "description": "allowed", "data": "foo", "valid": true }, { "description": "disallowed", "data": 1, "valid": false } ] }, { "description": "not multiple types", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "not": {"type": ["integer", "boolean"]} }, "tests": [ { "description": "valid", "data": "foo", "valid": true }, { "description": "mismatch", "data": 1, "valid": false }, { "description": "other mismatch", "data": true, "valid": false } ] }, { "description": "not more complex schema", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "not": { "type": "object", "properties": { "foo": { "type": "string" } } } }, "tests": [ { "description": "match", "data": 1, "valid": true }, { "description": "other match", "data": {"foo": 1}, "valid": true }, { "description": "mismatch", "data": {"foo": "bar"}, "valid": false } ] }, { "description": "forbidden property", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": { "foo": { "not": {} } } }, "tests": [ { "description": "property present", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "property absent", "data": {"bar": 1, "baz": 2}, "valid": true } ] }, { "description": "not with boolean schema true", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "not": true }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "not with boolean schema false", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "not": false }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/oneOf.json0000644000175100001770000001767014653725311023206 0ustar00runnerdocker[ { "description": "oneOf", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "oneOf": [ { "type": "integer" }, { "minimum": 2 } ] }, "tests": [ { "description": "first oneOf valid", "data": 1, "valid": true }, { "description": "second oneOf valid", "data": 2.5, "valid": true }, { "description": "both oneOf valid", "data": 3, "valid": false }, { "description": "neither oneOf valid", "data": 1.5, "valid": false } ] }, { "description": "oneOf with base schema", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "string", "oneOf" : [ { "minLength": 2 }, { "maxLength": 4 } ] }, "tests": [ { "description": "mismatch base schema", "data": 3, "valid": false }, { "description": "one oneOf valid", "data": "foobar", "valid": true }, { "description": "both oneOf valid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, all true", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "oneOf": [true, true, true] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, one true", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "oneOf": [true, false, false] }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "oneOf with boolean schemas, more than one true", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "oneOf": [true, true, false] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, all false", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "oneOf": [false, false, false] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf complex types", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "oneOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "first oneOf valid (complex)", "data": {"bar": 2}, "valid": true }, { "description": "second oneOf valid (complex)", "data": {"foo": "baz"}, "valid": true }, { "description": "both oneOf valid (complex)", "data": {"foo": "baz", "bar": 2}, "valid": false }, { "description": "neither oneOf valid (complex)", "data": {"foo": 2, "bar": "quux"}, "valid": false } ] }, { "description": "oneOf with empty schema", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "oneOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "one valid - valid", "data": "foo", "valid": true }, { "description": "both valid - invalid", "data": 123, "valid": false } ] }, { "description": "oneOf with required", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "oneOf": [ { "required": ["foo", "bar"] }, { "required": ["foo", "baz"] } ] }, "tests": [ { "description": "both invalid - invalid", "data": {"bar": 2}, "valid": false }, { "description": "first valid - valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "second valid - valid", "data": {"foo": 1, "baz": 3}, "valid": true }, { "description": "both valid - invalid", "data": {"foo": 1, "bar": 2, "baz" : 3}, "valid": false } ] }, { "description": "oneOf with missing optional property", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "oneOf": [ { "properties": { "bar": true, "baz": true }, "required": ["bar"] }, { "properties": { "foo": true }, "required": ["foo"] } ] }, "tests": [ { "description": "first oneOf valid", "data": {"bar": 8}, "valid": true }, { "description": "second oneOf valid", "data": {"foo": "foo"}, "valid": true }, { "description": "both oneOf valid", "data": {"foo": "foo", "bar": 8}, "valid": false }, { "description": "neither oneOf valid", "data": {"baz": "quux"}, "valid": false } ] }, { "description": "nested oneOf, to check validation semantics", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "oneOf": [ { "oneOf": [ { "type": "null" } ] } ] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "anything non-null is invalid", "data": 123, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0650966 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/0000755000175100001770000000000014653725331023061 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/bignum.json0000644000175100001770000000652614653725311025244 0ustar00runnerdocker[ { "description": "integer", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "integer" }, "tests": [ { "description": "a bignum is an integer", "data": 12345678910111213141516171819202122232425262728293031, "valid": true }, { "description": "a negative bignum is an integer", "data": -12345678910111213141516171819202122232425262728293031, "valid": true } ] }, { "description": "number", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "number" }, "tests": [ { "description": "a bignum is a number", "data": 98249283749234923498293171823948729348710298301928331, "valid": true }, { "description": "a negative bignum is a number", "data": -98249283749234923498293171823948729348710298301928331, "valid": true } ] }, { "description": "string", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "string" }, "tests": [ { "description": "a bignum is not a string", "data": 98249283749234923498293171823948729348710298301928331, "valid": false } ] }, { "description": "maximum integer comparison", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "maximum": 18446744073709551615 }, "tests": [ { "description": "comparison works for high numbers", "data": 18446744073709551600, "valid": true } ] }, { "description": "float comparison with high precision", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "exclusiveMaximum": 972783798187987123879878123.18878137 }, "tests": [ { "description": "comparison works for high numbers", "data": 972783798187987123879878123.188781371, "valid": false } ] }, { "description": "minimum integer comparison", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "minimum": -18446744073709551615 }, "tests": [ { "description": "comparison works for very negative numbers", "data": -18446744073709551600, "valid": true } ] }, { "description": "float comparison with high precision on negative numbers", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "exclusiveMinimum": -972783798187987123879878123.18878137 }, "tests": [ { "description": "comparison works for very negative numbers", "data": -972783798187987123879878123.188781371, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/cross-draft.json0000644000175100001770000000262214653725311026203 0ustar00runnerdocker[ { "description": "refs to future drafts are processed as future drafts", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "array", "$ref": "http://localhost:1234/draft2020-12/prefixItems.json" }, "tests": [ { "description": "first item not a string is invalid", "comment": "if the implementation is not processing the $ref as a 2020-12 schema, this test will fail", "data": [1, 2, 3], "valid": false }, { "description": "first item is a string is valid", "data": ["a string", 1, 2, 3], "valid": true } ] }, { "description": "refs to historic drafts are processed as historic drafts", "schema": { "type": "object", "allOf": [ { "properties": { "foo": true } }, { "$ref": "http://localhost:1234/draft7/ignore-dependentRequired.json" } ] }, "tests": [ { "description": "missing bar is valid", "comment": "if the implementation is not processing the $ref as a draft 7 schema, this test will fail", "data": {"foo": "any value"}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/dependencies-compatibility.json0000644000175100001770000001772014653725311031256 0ustar00runnerdocker[ { "description": "single dependency", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "dependencies": {"bar": ["foo"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependant", "data": {"foo": 1}, "valid": true }, { "description": "with dependency", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "missing dependency", "data": {"bar": 2}, "valid": false }, { "description": "ignores arrays", "data": ["bar"], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "empty dependents", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "dependencies": {"bar": []} }, "tests": [ { "description": "empty object", "data": {}, "valid": true }, { "description": "object with one property", "data": {"bar": 2}, "valid": true }, { "description": "non-object is valid", "data": 1, "valid": true } ] }, { "description": "multiple dependents required", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "dependencies": {"quux": ["foo", "bar"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependants", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "with dependencies", "data": {"foo": 1, "bar": 2, "quux": 3}, "valid": true }, { "description": "missing dependency", "data": {"foo": 1, "quux": 2}, "valid": false }, { "description": "missing other dependency", "data": {"bar": 1, "quux": 2}, "valid": false }, { "description": "missing both dependencies", "data": {"quux": 1}, "valid": false } ] }, { "description": "dependencies with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "dependencies": { "foo\nbar": ["foo\rbar"], "foo\"bar": ["foo'bar"] } }, "tests": [ { "description": "CRLF", "data": { "foo\nbar": 1, "foo\rbar": 2 }, "valid": true }, { "description": "quoted quotes", "data": { "foo'bar": 1, "foo\"bar": 2 }, "valid": true }, { "description": "CRLF missing dependent", "data": { "foo\nbar": 1, "foo": 2 }, "valid": false }, { "description": "quoted quotes missing dependent", "data": { "foo\"bar": 2 }, "valid": false } ] }, { "description": "single schema dependency", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "dependencies": { "bar": { "properties": { "foo": {"type": "integer"}, "bar": {"type": "integer"} } } } }, "tests": [ { "description": "valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "no dependency", "data": {"foo": "quux"}, "valid": true }, { "description": "wrong type", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "wrong type other", "data": {"foo": 2, "bar": "quux"}, "valid": false }, { "description": "wrong type both", "data": {"foo": "quux", "bar": "quux"}, "valid": false }, { "description": "ignores arrays", "data": ["bar"], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "boolean subschemas", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "dependencies": { "foo": true, "bar": false } }, "tests": [ { "description": "object with property having schema true is valid", "data": {"foo": 1}, "valid": true }, { "description": "object with property having schema false is invalid", "data": {"bar": 2}, "valid": false }, { "description": "object with both properties is invalid", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "schema dependencies with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "dependencies": { "foo\tbar": {"minProperties": 4}, "foo'bar": {"required": ["foo\"bar"]} } }, "tests": [ { "description": "quoted tab", "data": { "foo\tbar": 1, "a": 2, "b": 3, "c": 4 }, "valid": true }, { "description": "quoted quote", "data": { "foo'bar": {"foo\"bar": 1} }, "valid": false }, { "description": "quoted tab invalid under dependent schema", "data": { "foo\tbar": 1, "a": 2 }, "valid": false }, { "description": "quoted quote invalid under dependent schema", "data": {"foo'bar": 1}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/ecmascript-regex.json0000644000175100001770000004706114653725311027224 0ustar00runnerdocker[ { "description": "ECMA 262 regex $ does not match trailing newline", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "string", "pattern": "^abc$" }, "tests": [ { "description": "matches in Python, but not in ECMA 262", "data": "abc\\n", "valid": false }, { "description": "matches", "data": "abc", "valid": true } ] }, { "description": "ECMA 262 regex converts \\t to horizontal tab", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "string", "pattern": "^\\t$" }, "tests": [ { "description": "does not match", "data": "\\t", "valid": false }, { "description": "matches", "data": "\u0009", "valid": true } ] }, { "description": "ECMA 262 regex escapes control codes with \\c and upper letter", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "string", "pattern": "^\\cC$" }, "tests": [ { "description": "does not match", "data": "\\cC", "valid": false }, { "description": "matches", "data": "\u0003", "valid": true } ] }, { "description": "ECMA 262 regex escapes control codes with \\c and lower letter", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "string", "pattern": "^\\cc$" }, "tests": [ { "description": "does not match", "data": "\\cc", "valid": false }, { "description": "matches", "data": "\u0003", "valid": true } ] }, { "description": "ECMA 262 \\d matches ascii digits only", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "string", "pattern": "^\\d$" }, "tests": [ { "description": "ASCII zero matches", "data": "0", "valid": true }, { "description": "NKO DIGIT ZERO does not match (unlike e.g. Python)", "data": "߀", "valid": false }, { "description": "NKO DIGIT ZERO (as \\u escape) does not match", "data": "\u07c0", "valid": false } ] }, { "description": "ECMA 262 \\D matches everything but ascii digits", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "string", "pattern": "^\\D$" }, "tests": [ { "description": "ASCII zero does not match", "data": "0", "valid": false }, { "description": "NKO DIGIT ZERO matches (unlike e.g. Python)", "data": "߀", "valid": true }, { "description": "NKO DIGIT ZERO (as \\u escape) matches", "data": "\u07c0", "valid": true } ] }, { "description": "ECMA 262 \\w matches ascii letters only", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "string", "pattern": "^\\w$" }, "tests": [ { "description": "ASCII 'a' matches", "data": "a", "valid": true }, { "description": "latin-1 e-acute does not match (unlike e.g. Python)", "data": "é", "valid": false } ] }, { "description": "ECMA 262 \\W matches everything but ascii letters", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "string", "pattern": "^\\W$" }, "tests": [ { "description": "ASCII 'a' does not match", "data": "a", "valid": false }, { "description": "latin-1 e-acute matches (unlike e.g. Python)", "data": "é", "valid": true } ] }, { "description": "ECMA 262 \\s matches whitespace", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "string", "pattern": "^\\s$" }, "tests": [ { "description": "ASCII space matches", "data": " ", "valid": true }, { "description": "Character tabulation matches", "data": "\t", "valid": true }, { "description": "Line tabulation matches", "data": "\u000b", "valid": true }, { "description": "Form feed matches", "data": "\u000c", "valid": true }, { "description": "latin-1 non-breaking-space matches", "data": "\u00a0", "valid": true }, { "description": "zero-width whitespace matches", "data": "\ufeff", "valid": true }, { "description": "line feed matches (line terminator)", "data": "\u000a", "valid": true }, { "description": "paragraph separator matches (line terminator)", "data": "\u2029", "valid": true }, { "description": "EM SPACE matches (Space_Separator)", "data": "\u2003", "valid": true }, { "description": "Non-whitespace control does not match", "data": "\u0001", "valid": false }, { "description": "Non-whitespace does not match", "data": "\u2013", "valid": false } ] }, { "description": "ECMA 262 \\S matches everything but whitespace", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "string", "pattern": "^\\S$" }, "tests": [ { "description": "ASCII space does not match", "data": " ", "valid": false }, { "description": "Character tabulation does not match", "data": "\t", "valid": false }, { "description": "Line tabulation does not match", "data": "\u000b", "valid": false }, { "description": "Form feed does not match", "data": "\u000c", "valid": false }, { "description": "latin-1 non-breaking-space does not match", "data": "\u00a0", "valid": false }, { "description": "zero-width whitespace does not match", "data": "\ufeff", "valid": false }, { "description": "line feed does not match (line terminator)", "data": "\u000a", "valid": false }, { "description": "paragraph separator does not match (line terminator)", "data": "\u2029", "valid": false }, { "description": "EM SPACE does not match (Space_Separator)", "data": "\u2003", "valid": false }, { "description": "Non-whitespace control matches", "data": "\u0001", "valid": true }, { "description": "Non-whitespace matches", "data": "\u2013", "valid": true } ] }, { "description": "patterns always use unicode semantics with pattern", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "pattern": "\\p{Letter}cole" }, "tests": [ { "description": "ascii character in json string", "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", "valid": true }, { "description": "literal unicode character in json string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": true }, { "description": "unicode character in hex format in string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": true }, { "description": "unicode matching is case-sensitive", "data": "LES HIVERS DE MON ENFANCE ÉTAIENT DES SAISONS LONGUES, LONGUES. NOUS VIVIONS EN TROIS LIEUX: L'ÉCOLE, L'ÉGLISE ET LA PATINOIRE; MAIS LA VRAIE VIE ÉTAIT SUR LA PATINOIRE.", "valid": false } ] }, { "description": "\\w in patterns matches [A-Za-z0-9_], not unicode letters", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "pattern": "\\wcole" }, "tests": [ { "description": "ascii character in json string", "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", "valid": true }, { "description": "literal unicode character in json string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "unicode character in hex format in string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "unicode matching is case-sensitive", "data": "LES HIVERS DE MON ENFANCE ÉTAIENT DES SAISONS LONGUES, LONGUES. NOUS VIVIONS EN TROIS LIEUX: L'ÉCOLE, L'ÉGLISE ET LA PATINOIRE; MAIS LA VRAIE VIE ÉTAIT SUR LA PATINOIRE.", "valid": false } ] }, { "description": "pattern with ASCII ranges", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "pattern": "[a-z]cole" }, "tests": [ { "description": "literal unicode character in json string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "unicode character in hex format in string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "ascii characters match", "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", "valid": true } ] }, { "description": "\\d in pattern matches [0-9], not unicode digits", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "pattern": "^\\d+$" }, "tests": [ { "description": "ascii digits", "data": "42", "valid": true }, { "description": "ascii non-digits", "data": "-%#", "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": "৪২", "valid": false } ] }, { "description": "pattern with non-ASCII digits", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "pattern": "^\\p{digit}+$" }, "tests": [ { "description": "ascii digits", "data": "42", "valid": true }, { "description": "ascii non-digits", "data": "-%#", "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": "৪২", "valid": true } ] }, { "description": "patterns always use unicode semantics with patternProperties", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "patternProperties": { "\\p{Letter}cole": true }, "additionalProperties": false }, "tests": [ { "description": "ascii character in json string", "data": { "l'ecole": "pas de vraie vie" }, "valid": true }, { "description": "literal unicode character in json string", "data": { "l'école": "pas de vraie vie" }, "valid": true }, { "description": "unicode character in hex format in string", "data": { "l'\u00e9cole": "pas de vraie vie" }, "valid": true }, { "description": "unicode matching is case-sensitive", "data": { "L'ÉCOLE": "PAS DE VRAIE VIE" }, "valid": false } ] }, { "description": "\\w in patternProperties matches [A-Za-z0-9_], not unicode letters", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "patternProperties": { "\\wcole": true }, "additionalProperties": false }, "tests": [ { "description": "ascii character in json string", "data": { "l'ecole": "pas de vraie vie" }, "valid": true }, { "description": "literal unicode character in json string", "data": { "l'école": "pas de vraie vie" }, "valid": false }, { "description": "unicode character in hex format in string", "data": { "l'\u00e9cole": "pas de vraie vie" }, "valid": false }, { "description": "unicode matching is case-sensitive", "data": { "L'ÉCOLE": "PAS DE VRAIE VIE" }, "valid": false } ] }, { "description": "patternProperties with ASCII ranges", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "patternProperties": { "[a-z]cole": true }, "additionalProperties": false }, "tests": [ { "description": "literal unicode character in json string", "data": { "l'école": "pas de vraie vie" }, "valid": false }, { "description": "unicode character in hex format in string", "data": { "l'\u00e9cole": "pas de vraie vie" }, "valid": false }, { "description": "ascii characters match", "data": { "l'ecole": "pas de vraie vie" }, "valid": true } ] }, { "description": "\\d in patternProperties matches [0-9], not unicode digits", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "patternProperties": { "^\\d+$": true }, "additionalProperties": false }, "tests": [ { "description": "ascii digits", "data": { "42": "life, the universe, and everything" }, "valid": true }, { "description": "ascii non-digits", "data": { "-%#": "spending the year dead for tax reasons" }, "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": { "৪২": "khajit has wares if you have coin" }, "valid": false } ] }, { "description": "patternProperties with non-ASCII digits", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "patternProperties": { "^\\p{digit}+$": true }, "additionalProperties": false }, "tests": [ { "description": "ascii digits", "data": { "42": "life, the universe, and everything" }, "valid": true }, { "description": "ascii non-digits", "data": { "-%#": "spending the year dead for tax reasons" }, "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": { "৪২": "khajit has wares if you have coin" }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/float-overflow.json0000644000175100001770000000070614653725311026723 0ustar00runnerdocker[ { "description": "all integers are multiples of 0.5, if overflow is handled", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "integer", "multipleOf": 0.5 }, "tests": [ { "description": "valid if optional overflow handling is implemented", "data": 1e308, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0650966 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/format/0000755000175100001770000000000014653725331024351 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/format/date-time.json0000644000175100001770000001121314653725311027111 0ustar00runnerdocker[ { "description": "validation of date-time strings", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "date-time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid date-time string", "data": "1963-06-19T08:30:06.283185Z", "valid": true }, { "description": "a valid date-time string without second fraction", "data": "1963-06-19T08:30:06Z", "valid": true }, { "description": "a valid date-time string with plus offset", "data": "1937-01-01T12:00:27.87+00:20", "valid": true }, { "description": "a valid date-time string with minus offset", "data": "1990-12-31T15:59:50.123-08:00", "valid": true }, { "description": "a valid date-time with a leap second, UTC", "data": "1998-12-31T23:59:60Z", "valid": true }, { "description": "a valid date-time with a leap second, with minus offset", "data": "1998-12-31T15:59:60.123-08:00", "valid": true }, { "description": "an invalid date-time past leap second, UTC", "data": "1998-12-31T23:59:61Z", "valid": false }, { "description": "an invalid date-time with leap second on a wrong minute, UTC", "data": "1998-12-31T23:58:60Z", "valid": false }, { "description": "an invalid date-time with leap second on a wrong hour, UTC", "data": "1998-12-31T22:59:60Z", "valid": false }, { "description": "an invalid day in date-time string", "data": "1990-02-31T15:59:59.123-08:00", "valid": false }, { "description": "an invalid offset in date-time string", "data": "1990-12-31T15:59:59-24:00", "valid": false }, { "description": "an invalid closing Z after time-zone offset", "data": "1963-06-19T08:30:06.28123+01:00Z", "valid": false }, { "description": "an invalid date-time string", "data": "06/19/1963 08:30:06 PST", "valid": false }, { "description": "case-insensitive T and Z", "data": "1963-06-19t08:30:06.283185z", "valid": true }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "2013-350T01:01:01", "valid": false }, { "description": "invalid non-padded month dates", "data": "1963-6-19T08:30:06.283185Z", "valid": false }, { "description": "invalid non-padded day dates", "data": "1963-06-1T08:30:06.283185Z", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4) in date portion", "data": "1963-06-1৪T00:00:00Z", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4) in time portion", "data": "1963-06-11T0৪:00:00Z", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/format/date.json0000644000175100001770000001656314653725311026172 0ustar00runnerdocker[ { "description": "validation of date strings", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "date" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid date string", "data": "1963-06-19", "valid": true }, { "description": "a valid date string with 31 days in January", "data": "2020-01-31", "valid": true }, { "description": "a invalid date string with 32 days in January", "data": "2020-01-32", "valid": false }, { "description": "a valid date string with 28 days in February (normal)", "data": "2021-02-28", "valid": true }, { "description": "a invalid date string with 29 days in February (normal)", "data": "2021-02-29", "valid": false }, { "description": "a valid date string with 29 days in February (leap)", "data": "2020-02-29", "valid": true }, { "description": "a invalid date string with 30 days in February (leap)", "data": "2020-02-30", "valid": false }, { "description": "a valid date string with 31 days in March", "data": "2020-03-31", "valid": true }, { "description": "a invalid date string with 32 days in March", "data": "2020-03-32", "valid": false }, { "description": "a valid date string with 30 days in April", "data": "2020-04-30", "valid": true }, { "description": "a invalid date string with 31 days in April", "data": "2020-04-31", "valid": false }, { "description": "a valid date string with 31 days in May", "data": "2020-05-31", "valid": true }, { "description": "a invalid date string with 32 days in May", "data": "2020-05-32", "valid": false }, { "description": "a valid date string with 30 days in June", "data": "2020-06-30", "valid": true }, { "description": "a invalid date string with 31 days in June", "data": "2020-06-31", "valid": false }, { "description": "a valid date string with 31 days in July", "data": "2020-07-31", "valid": true }, { "description": "a invalid date string with 32 days in July", "data": "2020-07-32", "valid": false }, { "description": "a valid date string with 31 days in August", "data": "2020-08-31", "valid": true }, { "description": "a invalid date string with 32 days in August", "data": "2020-08-32", "valid": false }, { "description": "a valid date string with 30 days in September", "data": "2020-09-30", "valid": true }, { "description": "a invalid date string with 31 days in September", "data": "2020-09-31", "valid": false }, { "description": "a valid date string with 31 days in October", "data": "2020-10-31", "valid": true }, { "description": "a invalid date string with 32 days in October", "data": "2020-10-32", "valid": false }, { "description": "a valid date string with 30 days in November", "data": "2020-11-30", "valid": true }, { "description": "a invalid date string with 31 days in November", "data": "2020-11-31", "valid": false }, { "description": "a valid date string with 31 days in December", "data": "2020-12-31", "valid": true }, { "description": "a invalid date string with 32 days in December", "data": "2020-12-32", "valid": false }, { "description": "a invalid date string with invalid month", "data": "2020-13-01", "valid": false }, { "description": "an invalid date string", "data": "06/19/1963", "valid": false }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "2013-350", "valid": false }, { "description": "non-padded month dates are not valid", "data": "1998-1-20", "valid": false }, { "description": "non-padded day dates are not valid", "data": "1998-01-1", "valid": false }, { "description": "invalid month", "data": "1998-13-01", "valid": false }, { "description": "invalid month-day combination", "data": "1998-04-31", "valid": false }, { "description": "2021 is not a leap year", "data": "2021-02-29", "valid": false }, { "description": "2020 is a leap year", "data": "2020-02-29", "valid": true }, { "description": "invalid non-ASCII '৪' (a Bengali 4)", "data": "1963-06-1৪", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/format/duration.json0000644000175100001770000000772014653725311027075 0ustar00runnerdocker[ { "description": "validation of duration strings", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "duration" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid duration string", "data": "P4DT12H30M5S", "valid": true }, { "description": "an invalid duration string", "data": "PT1D", "valid": false }, { "description": "no elements present", "data": "P", "valid": false }, { "description": "no time elements present", "data": "P1YT", "valid": false }, { "description": "no date or time elements present", "data": "PT", "valid": false }, { "description": "elements out of order", "data": "P2D1Y", "valid": false }, { "description": "missing time separator", "data": "P1D2H", "valid": false }, { "description": "time element in the date position", "data": "P2S", "valid": false }, { "description": "four years duration", "data": "P4Y", "valid": true }, { "description": "zero time, in seconds", "data": "PT0S", "valid": true }, { "description": "zero time, in days", "data": "P0D", "valid": true }, { "description": "one month duration", "data": "P1M", "valid": true }, { "description": "one minute duration", "data": "PT1M", "valid": true }, { "description": "one and a half days, in hours", "data": "PT36H", "valid": true }, { "description": "one and a half days, in days and hours", "data": "P1DT12H", "valid": true }, { "description": "two weeks", "data": "P2W", "valid": true }, { "description": "weeks cannot be combined with other units", "data": "P1Y2W", "valid": false }, { "description": "invalid non-ASCII '২' (a Bengali 2)", "data": "P২Y", "valid": false }, { "description": "element without unit", "data": "P1", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/format/email.json0000644000175100001770000000523714653725311026340 0ustar00runnerdocker[ { "description": "validation of e-mail addresses", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid e-mail address", "data": "joe.bloggs@example.com", "valid": true }, { "description": "an invalid e-mail address", "data": "2962", "valid": false }, { "description": "tilde in local part is valid", "data": "te~st@example.com", "valid": true }, { "description": "tilde before local part is valid", "data": "~test@example.com", "valid": true }, { "description": "tilde after local part is valid", "data": "test~@example.com", "valid": true }, { "description": "dot before local part is not valid", "data": ".test@example.com", "valid": false }, { "description": "dot after local part is not valid", "data": "test.@example.com", "valid": false }, { "description": "two separated dots inside local part are valid", "data": "te.s.t@example.com", "valid": true }, { "description": "two subsequent dots inside local part are not valid", "data": "te..st@example.com", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/format/hostname.json0000644000175100001770000000635714653725311027073 0ustar00runnerdocker[ { "description": "validation of host names", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid host name", "data": "www.example.com", "valid": true }, { "description": "a valid punycoded IDN hostname", "data": "xn--4gbwdl.xn--wgbh1c", "valid": true }, { "description": "a host name starting with an illegal character", "data": "-a-host-name-that-starts-with--", "valid": false }, { "description": "a host name containing illegal characters", "data": "not_a_valid_host_name", "valid": false }, { "description": "a host name with a component too long", "data": "a-vvvvvvvvvvvvvvvveeeeeeeeeeeeeeeerrrrrrrrrrrrrrrryyyyyyyyyyyyyyyy-long-host-name-component", "valid": false }, { "description": "starts with hyphen", "data": "-hostname", "valid": false }, { "description": "ends with hyphen", "data": "hostname-", "valid": false }, { "description": "starts with underscore", "data": "_hostname", "valid": false }, { "description": "ends with underscore", "data": "hostname_", "valid": false }, { "description": "contains underscore", "data": "host_name", "valid": false }, { "description": "maximum label length", "data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.com", "valid": true }, { "description": "exceeds maximum label length", "data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl.com", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/format/idn-email.json0000644000175100001770000000350714653725311027106 0ustar00runnerdocker[ { "description": "validation of an internationalized e-mail addresses", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "idn-email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid idn e-mail (example@example.test in Hangul)", "data": "실례@실례.테스트", "valid": true }, { "description": "an invalid idn e-mail address", "data": "2962", "valid": false }, { "description": "a valid e-mail address", "data": "joe.bloggs@example.com", "valid": true }, { "description": "an invalid e-mail address", "data": "2962", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/format/idn-hostname.json0000644000175100001770000003477414653725311027647 0ustar00runnerdocker[ { "description": "validation of internationalized host names", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "idn-hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid host name (example.test in Hangul)", "data": "실례.테스트", "valid": true }, { "description": "illegal first char U+302E Hangul single dot tone mark", "data": "〮실례.테스트", "valid": false }, { "description": "contains illegal char U+302E Hangul single dot tone mark", "data": "실〮례.테스트", "valid": false }, { "description": "a host name with a component too long", "data": "실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실례례테스트례례례례례례례례례례례례례례례례례테스트례례례례례례례례례례례례례례례례례례례테스트례례례례례례례례례례례례테스트례례실례.테스트", "valid": false }, { "description": "invalid label, correct Punycode", "comment": "https://tools.ietf.org/html/rfc5890#section-2.3.2.1 https://tools.ietf.org/html/rfc5891#section-4.4 https://tools.ietf.org/html/rfc3492#section-7.1", "data": "-> $1.00 <--", "valid": false }, { "description": "valid Chinese Punycode", "comment": "https://tools.ietf.org/html/rfc5890#section-2.3.2.1 https://tools.ietf.org/html/rfc5891#section-4.4", "data": "xn--ihqwcrb4cv8a8dqg056pqjye", "valid": true }, { "description": "invalid Punycode", "comment": "https://tools.ietf.org/html/rfc5891#section-4.4 https://tools.ietf.org/html/rfc5890#section-2.3.2.1", "data": "xn--X", "valid": false }, { "description": "U-label contains \"--\" in the 3rd and 4th position", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1 https://tools.ietf.org/html/rfc5890#section-2.3.2.1", "data": "XN--aa---o47jg78q", "valid": false }, { "description": "U-label starts with a dash", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1", "data": "-hello", "valid": false }, { "description": "U-label ends with a dash", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1", "data": "hello-", "valid": false }, { "description": "U-label starts and ends with a dash", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1", "data": "-hello-", "valid": false }, { "description": "Begins with a Spacing Combining Mark", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2", "data": "\u0903hello", "valid": false }, { "description": "Begins with a Nonspacing Mark", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2", "data": "\u0300hello", "valid": false }, { "description": "Begins with an Enclosing Mark", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2", "data": "\u0488hello", "valid": false }, { "description": "Exceptions that are PVALID, left-to-right chars", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6", "data": "\u00df\u03c2\u0f0b\u3007", "valid": true }, { "description": "Exceptions that are PVALID, right-to-left chars", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6", "data": "\u06fd\u06fe", "valid": true }, { "description": "Exceptions that are DISALLOWED, right-to-left chars", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6", "data": "\u0640\u07fa", "valid": false }, { "description": "Exceptions that are DISALLOWED, left-to-right chars", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6 Note: The two combining marks (U+302E and U+302F) are in the middle and not at the start", "data": "\u3031\u3032\u3033\u3034\u3035\u302e\u302f\u303b", "valid": false }, { "description": "MIDDLE DOT with no preceding 'l'", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "a\u00b7l", "valid": false }, { "description": "MIDDLE DOT with nothing preceding", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "\u00b7l", "valid": false }, { "description": "MIDDLE DOT with no following 'l'", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "l\u00b7a", "valid": false }, { "description": "MIDDLE DOT with nothing following", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "l\u00b7", "valid": false }, { "description": "MIDDLE DOT with surrounding 'l's", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "l\u00b7l", "valid": true }, { "description": "Greek KERAIA not followed by Greek", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4", "data": "\u03b1\u0375S", "valid": false }, { "description": "Greek KERAIA not followed by anything", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4", "data": "\u03b1\u0375", "valid": false }, { "description": "Greek KERAIA followed by Greek", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4", "data": "\u03b1\u0375\u03b2", "valid": true }, { "description": "Hebrew GERESH not preceded by Hebrew", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5", "data": "A\u05f3\u05d1", "valid": false }, { "description": "Hebrew GERESH not preceded by anything", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5", "data": "\u05f3\u05d1", "valid": false }, { "description": "Hebrew GERESH preceded by Hebrew", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5", "data": "\u05d0\u05f3\u05d1", "valid": true }, { "description": "Hebrew GERSHAYIM not preceded by Hebrew", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6", "data": "A\u05f4\u05d1", "valid": false }, { "description": "Hebrew GERSHAYIM not preceded by anything", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6", "data": "\u05f4\u05d1", "valid": false }, { "description": "Hebrew GERSHAYIM preceded by Hebrew", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6", "data": "\u05d0\u05f4\u05d1", "valid": true }, { "description": "KATAKANA MIDDLE DOT with no Hiragana, Katakana, or Han", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "def\u30fbabc", "valid": false }, { "description": "KATAKANA MIDDLE DOT with no other characters", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "\u30fb", "valid": false }, { "description": "KATAKANA MIDDLE DOT with Hiragana", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "\u30fb\u3041", "valid": true }, { "description": "KATAKANA MIDDLE DOT with Katakana", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "\u30fb\u30a1", "valid": true }, { "description": "KATAKANA MIDDLE DOT with Han", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "\u30fb\u4e08", "valid": true }, { "description": "Arabic-Indic digits mixed with Extended Arabic-Indic digits", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.8", "data": "\u0660\u06f0", "valid": false }, { "description": "Arabic-Indic digits not mixed with Extended Arabic-Indic digits", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.8", "data": "\u0628\u0660\u0628", "valid": true }, { "description": "Extended Arabic-Indic digits not mixed with Arabic-Indic digits", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.9", "data": "\u06f00", "valid": true }, { "description": "ZERO WIDTH JOINER not preceded by Virama", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf", "data": "\u0915\u200d\u0937", "valid": false }, { "description": "ZERO WIDTH JOINER not preceded by anything", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf", "data": "\u200d\u0937", "valid": false }, { "description": "ZERO WIDTH JOINER preceded by Virama", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf", "data": "\u0915\u094d\u200d\u0937", "valid": true }, { "description": "ZERO WIDTH NON-JOINER preceded by Virama", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.1", "data": "\u0915\u094d\u200c\u0937", "valid": true }, { "description": "ZERO WIDTH NON-JOINER not preceded by Virama but matches regexp", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.1 https://www.w3.org/TR/alreq/#h_disjoining_enforcement", "data": "\u0628\u064a\u200c\u0628\u064a", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/format/ipv4.json0000644000175100001770000000553714653725311026136 0ustar00runnerdocker[ { "description": "validation of IP addresses", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "ipv4" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IP address", "data": "192.168.0.1", "valid": true }, { "description": "an IP address with too many components", "data": "127.0.0.0.1", "valid": false }, { "description": "an IP address with out-of-range values", "data": "256.256.256.256", "valid": false }, { "description": "an IP address without 4 components", "data": "127.0", "valid": false }, { "description": "an IP address as an integer", "data": "0x7f000001", "valid": false }, { "description": "an IP address as an integer (decimal)", "data": "2130706433", "valid": false }, { "description": "invalid leading zeroes, as they are treated as octals", "comment": "see https://sick.codes/universal-netmask-npm-package-used-by-270000-projects-vulnerable-to-octal-input-data-server-side-request-forgery-remote-file-inclusion-local-file-inclusion-and-more-cve-2021-28918/", "data": "087.10.0.1", "valid": false }, { "description": "value without leading zero is valid", "data": "87.10.0.1", "valid": true }, { "description": "invalid non-ASCII '২' (a Bengali 2)", "data": "1২7.0.0.1", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/format/ipv6.json0000644000175100001770000001557214653725311026140 0ustar00runnerdocker[ { "description": "validation of IPv6 addresses", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "ipv6" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IPv6 address", "data": "::1", "valid": true }, { "description": "an IPv6 address with out-of-range values", "data": "12345::", "valid": false }, { "description": "trailing 4 hex symbols is valid", "data": "::abef", "valid": true }, { "description": "trailing 5 hex symbols is invalid", "data": "::abcef", "valid": false }, { "description": "an IPv6 address with too many components", "data": "1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1", "valid": false }, { "description": "an IPv6 address containing illegal characters", "data": "::laptop", "valid": false }, { "description": "no digits is valid", "data": "::", "valid": true }, { "description": "leading colons is valid", "data": "::42:ff:1", "valid": true }, { "description": "trailing colons is valid", "data": "d6::", "valid": true }, { "description": "missing leading octet is invalid", "data": ":2:3:4:5:6:7:8", "valid": false }, { "description": "missing trailing octet is invalid", "data": "1:2:3:4:5:6:7:", "valid": false }, { "description": "missing leading octet with omitted octets later", "data": ":2:3:4::8", "valid": false }, { "description": "single set of double colons in the middle is valid", "data": "1:d6::42", "valid": true }, { "description": "two sets of double colons is invalid", "data": "1::d6::42", "valid": false }, { "description": "mixed format with the ipv4 section as decimal octets", "data": "1::d6:192.168.0.1", "valid": true }, { "description": "mixed format with double colons between the sections", "data": "1:2::192.168.0.1", "valid": true }, { "description": "mixed format with ipv4 section with octet out of range", "data": "1::2:192.168.256.1", "valid": false }, { "description": "mixed format with ipv4 section with a hex octet", "data": "1::2:192.168.ff.1", "valid": false }, { "description": "mixed format with leading double colons (ipv4-mapped ipv6 address)", "data": "::ffff:192.168.0.1", "valid": true }, { "description": "triple colons is invalid", "data": "1:2:3:4:5:::8", "valid": false }, { "description": "8 octets", "data": "1:2:3:4:5:6:7:8", "valid": true }, { "description": "insufficient octets without double colons", "data": "1:2:3:4:5:6:7", "valid": false }, { "description": "no colons is invalid", "data": "1", "valid": false }, { "description": "ipv4 is not ipv6", "data": "127.0.0.1", "valid": false }, { "description": "ipv4 segment must have 4 octets", "data": "1:2:3:4:1.2.3", "valid": false }, { "description": "leading whitespace is invalid", "data": " ::1", "valid": false }, { "description": "trailing whitespace is invalid", "data": "::1 ", "valid": false }, { "description": "netmask is not a part of ipv6 address", "data": "fe80::/64", "valid": false }, { "description": "zone id is not a part of ipv6 address", "data": "fe80::a%eth1", "valid": false }, { "description": "a long valid ipv6", "data": "1000:1000:1000:1000:1000:1000:255.255.255.255", "valid": true }, { "description": "a long invalid ipv6, below length limit, first", "data": "100:100:100:100:100:100:255.255.255.255.255", "valid": false }, { "description": "a long invalid ipv6, below length limit, second", "data": "100:100:100:100:100:100:100:255.255.255.255", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4)", "data": "1:2:3:4:5:6:7:৪", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4) in the IPv4 portion", "data": "1:2::192.16৪.0.1", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/format/iri-reference.json0000644000175100001770000000444514653725311027770 0ustar00runnerdocker[ { "description": "validation of IRI References", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "iri-reference" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IRI", "data": "http://ƒøø.ßår/?∂éœ=πîx#πîüx", "valid": true }, { "description": "a valid protocol-relative IRI Reference", "data": "//ƒøø.ßår/?∂éœ=πîx#πîüx", "valid": true }, { "description": "a valid relative IRI Reference", "data": "/âππ", "valid": true }, { "description": "an invalid IRI Reference", "data": "\\\\WINDOWS\\filëßåré", "valid": false }, { "description": "a valid IRI Reference", "data": "âππ", "valid": true }, { "description": "a valid IRI fragment", "data": "#Æ’rägmênt", "valid": true }, { "description": "an invalid IRI fragment", "data": "#Æ’räg\\mênt", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/format/iri.json0000644000175100001770000000545714653725311026040 0ustar00runnerdocker[ { "description": "validation of IRIs", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "iri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IRI with anchor tag", "data": "http://ƒøø.ßår/?∂éœ=πîx#πîüx", "valid": true }, { "description": "a valid IRI with anchor tag and parentheses", "data": "http://ƒøø.com/blah_(wîkïpédiÃ¥)_blah#ßité-1", "valid": true }, { "description": "a valid IRI with URL-encoded stuff", "data": "http://ƒøø.ßår/?q=Test%20URL-encoded%20stuff", "valid": true }, { "description": "a valid IRI with many special characters", "data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", "valid": true }, { "description": "a valid IRI based on IPv6", "data": "http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]", "valid": true }, { "description": "an invalid IRI based on IPv6", "data": "http://2001:0db8:85a3:0000:0000:8a2e:0370:7334", "valid": false }, { "description": "an invalid relative IRI Reference", "data": "/abc", "valid": false }, { "description": "an invalid IRI", "data": "\\\\WINDOWS\\filëßåré", "valid": false }, { "description": "an invalid IRI though valid IRI reference", "data": "âππ", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/format/json-pointer.json0000644000175100001770000001521614653725311027676 0ustar00runnerdocker[ { "description": "validation of JSON-pointers (JSON String Representation)", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "json-pointer" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid JSON-pointer", "data": "/foo/bar~0/baz~1/%a", "valid": true }, { "description": "not a valid JSON-pointer (~ not escaped)", "data": "/foo/bar~", "valid": false }, { "description": "valid JSON-pointer with empty segment", "data": "/foo//bar", "valid": true }, { "description": "valid JSON-pointer with the last empty segment", "data": "/foo/bar/", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #1", "data": "", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #2", "data": "/foo", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #3", "data": "/foo/0", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #4", "data": "/", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #5", "data": "/a~1b", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #6", "data": "/c%d", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #7", "data": "/e^f", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #8", "data": "/g|h", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #9", "data": "/i\\j", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #10", "data": "/k\"l", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #11", "data": "/ ", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #12", "data": "/m~0n", "valid": true }, { "description": "valid JSON-pointer used adding to the last array position", "data": "/foo/-", "valid": true }, { "description": "valid JSON-pointer (- used as object member name)", "data": "/foo/-/bar", "valid": true }, { "description": "valid JSON-pointer (multiple escaped characters)", "data": "/~1~0~0~1~1", "valid": true }, { "description": "valid JSON-pointer (escaped with fraction part) #1", "data": "/~1.1", "valid": true }, { "description": "valid JSON-pointer (escaped with fraction part) #2", "data": "/~0.1", "valid": true }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #1", "data": "#", "valid": false }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #2", "data": "#/", "valid": false }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #3", "data": "#a", "valid": false }, { "description": "not a valid JSON-pointer (some escaped, but not all) #1", "data": "/~0~", "valid": false }, { "description": "not a valid JSON-pointer (some escaped, but not all) #2", "data": "/~0/~", "valid": false }, { "description": "not a valid JSON-pointer (wrong escape character) #1", "data": "/~2", "valid": false }, { "description": "not a valid JSON-pointer (wrong escape character) #2", "data": "/~-1", "valid": false }, { "description": "not a valid JSON-pointer (multiple characters not escaped)", "data": "/~~", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #1", "data": "a", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #2", "data": "0", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #3", "data": "a/a", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/format/regex.json0000644000175100001770000000275114653725311026361 0ustar00runnerdocker[ { "description": "validation of regular expressions", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "regex" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid regular expression", "data": "([abc])+\\s+$", "valid": true }, { "description": "a regular expression with unclosed parens is invalid", "data": "^(abc]", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/format/relative-json-pointer.json0000644000175100001770000000607614653725311031513 0ustar00runnerdocker[ { "description": "validation of Relative JSON Pointers (RJP)", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "relative-json-pointer" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid upwards RJP", "data": "1", "valid": true }, { "description": "a valid downwards RJP", "data": "0/foo/bar", "valid": true }, { "description": "a valid up and then down RJP, with array index", "data": "2/0/baz/1/zip", "valid": true }, { "description": "a valid RJP taking the member or index name", "data": "0#", "valid": true }, { "description": "an invalid RJP that is a valid JSON Pointer", "data": "/foo/bar", "valid": false }, { "description": "negative prefix", "data": "-1/foo/bar", "valid": false }, { "description": "explicit positive prefix", "data": "+1/foo/bar", "valid": false }, { "description": "## is not a valid json-pointer", "data": "0##", "valid": false }, { "description": "zero cannot be followed by other digits, plus json-pointer", "data": "01/a", "valid": false }, { "description": "zero cannot be followed by other digits, plus octothorpe", "data": "01#", "valid": false }, { "description": "empty string", "data": "", "valid": false }, { "description": "multi-digit integer prefix", "data": "120/foo/bar", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/format/time.json0000644000175100001770000001632114653725311026203 0ustar00runnerdocker[ { "description": "validation of time strings", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid time string", "data": "08:30:06Z", "valid": true }, { "description": "a valid time string with leap second, Zulu", "data": "23:59:60Z", "valid": true }, { "description": "invalid leap second, Zulu (wrong hour)", "data": "22:59:60Z", "valid": false }, { "description": "invalid leap second, Zulu (wrong minute)", "data": "23:58:60Z", "valid": false }, { "description": "valid leap second, zero time-offset", "data": "23:59:60+00:00", "valid": true }, { "description": "invalid leap second, zero time-offset (wrong hour)", "data": "22:59:60+00:00", "valid": false }, { "description": "invalid leap second, zero time-offset (wrong minute)", "data": "23:58:60+00:00", "valid": false }, { "description": "valid leap second, positive time-offset", "data": "01:29:60+01:30", "valid": true }, { "description": "valid leap second, large positive time-offset", "data": "23:29:60+23:30", "valid": true }, { "description": "invalid leap second, positive time-offset (wrong hour)", "data": "23:59:60+01:00", "valid": false }, { "description": "invalid leap second, positive time-offset (wrong minute)", "data": "23:59:60+00:30", "valid": false }, { "description": "valid leap second, negative time-offset", "data": "15:59:60-08:00", "valid": true }, { "description": "valid leap second, large negative time-offset", "data": "00:29:60-23:30", "valid": true }, { "description": "invalid leap second, negative time-offset (wrong hour)", "data": "23:59:60-01:00", "valid": false }, { "description": "invalid leap second, negative time-offset (wrong minute)", "data": "23:59:60-00:30", "valid": false }, { "description": "a valid time string with second fraction", "data": "23:20:50.52Z", "valid": true }, { "description": "a valid time string with precise second fraction", "data": "08:30:06.283185Z", "valid": true }, { "description": "a valid time string with plus offset", "data": "08:30:06+00:20", "valid": true }, { "description": "a valid time string with minus offset", "data": "08:30:06-08:00", "valid": true }, { "description": "a valid time string with case-insensitive Z", "data": "08:30:06z", "valid": true }, { "description": "an invalid time string with invalid hour", "data": "24:00:00Z", "valid": false }, { "description": "an invalid time string with invalid minute", "data": "00:60:00Z", "valid": false }, { "description": "an invalid time string with invalid second", "data": "00:00:61Z", "valid": false }, { "description": "an invalid time string with invalid leap second (wrong hour)", "data": "22:59:60Z", "valid": false }, { "description": "an invalid time string with invalid leap second (wrong minute)", "data": "23:58:60Z", "valid": false }, { "description": "an invalid time string with invalid time numoffset hour", "data": "01:02:03+24:00", "valid": false }, { "description": "an invalid time string with invalid time numoffset minute", "data": "01:02:03+00:60", "valid": false }, { "description": "an invalid time string with invalid time with both Z and numoffset", "data": "01:02:03Z+00:30", "valid": false }, { "description": "an invalid offset indicator", "data": "08:30:06 PST", "valid": false }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "01:01:01,1111", "valid": false }, { "description": "no time offset", "data": "12:00:00", "valid": false }, { "description": "no time offset with second fraction", "data": "12:00:00.52", "valid": false }, { "description": "invalid non-ASCII '২' (a Bengali 2)", "data": "1২:00:00Z", "valid": false }, { "description": "offset not starting with plus or minus", "data": "08:30:06#00:20", "valid": false }, { "description": "contains letters", "data": "ab:cd:ef", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/format/unknown.json0000644000175100001770000000241614653725311026744 0ustar00runnerdocker[ { "description": "unknown format", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "unknown" }, "tests": [ { "description": "unknown formats ignore integers", "data": 12, "valid": true }, { "description": "unknown formats ignore floats", "data": 13.7, "valid": true }, { "description": "unknown formats ignore objects", "data": {}, "valid": true }, { "description": "unknown formats ignore arrays", "data": [], "valid": true }, { "description": "unknown formats ignore booleans", "data": false, "valid": true }, { "description": "unknown formats ignore nulls", "data": null, "valid": true }, { "description": "unknown formats ignore strings", "data": "string", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/format/uri-reference.json0000644000175100001770000000437214653725311030003 0ustar00runnerdocker[ { "description": "validation of URI References", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "uri-reference" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid URI", "data": "http://foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid protocol-relative URI Reference", "data": "//foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid relative URI Reference", "data": "/abc", "valid": true }, { "description": "an invalid URI Reference", "data": "\\\\WINDOWS\\fileshare", "valid": false }, { "description": "a valid URI Reference", "data": "abc", "valid": true }, { "description": "a valid URI fragment", "data": "#fragment", "valid": true }, { "description": "an invalid URI fragment", "data": "#frag\\ment", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/format/uri-template.json0000644000175100001770000000356414653725311027662 0ustar00runnerdocker[ { "description": "format: uri-template", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "uri-template" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid uri-template", "data": "http://example.com/dictionary/{term:1}/{term}", "valid": true }, { "description": "an invalid uri-template", "data": "http://example.com/dictionary/{term:1}/{term", "valid": false }, { "description": "a valid uri-template without variables", "data": "http://example.com/dictionary", "valid": true }, { "description": "a valid relative uri-template", "data": "dictionary/{term:1}/{term}", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/format/uri.json0000644000175100001770000001116714653725311026047 0ustar00runnerdocker[ { "description": "validation of URIs", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "uri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid URL with anchor tag", "data": "http://foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid URL with anchor tag and parentheses", "data": "http://foo.com/blah_(wikipedia)_blah#cite-1", "valid": true }, { "description": "a valid URL with URL-encoded stuff", "data": "http://foo.bar/?q=Test%20URL-encoded%20stuff", "valid": true }, { "description": "a valid puny-coded URL ", "data": "http://xn--nw2a.xn--j6w193g/", "valid": true }, { "description": "a valid URL with many special characters", "data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", "valid": true }, { "description": "a valid URL based on IPv4", "data": "http://223.255.255.254", "valid": true }, { "description": "a valid URL with ftp scheme", "data": "ftp://ftp.is.co.za/rfc/rfc1808.txt", "valid": true }, { "description": "a valid URL for a simple text file", "data": "http://www.ietf.org/rfc/rfc2396.txt", "valid": true }, { "description": "a valid URL ", "data": "ldap://[2001:db8::7]/c=GB?objectClass?one", "valid": true }, { "description": "a valid mailto URI", "data": "mailto:John.Doe@example.com", "valid": true }, { "description": "a valid newsgroup URI", "data": "news:comp.infosystems.www.servers.unix", "valid": true }, { "description": "a valid tel URI", "data": "tel:+1-816-555-1212", "valid": true }, { "description": "a valid URN", "data": "urn:oasis:names:specification:docbook:dtd:xml:4.1.2", "valid": true }, { "description": "an invalid protocol-relative URI Reference", "data": "//foo.bar/?baz=qux#quux", "valid": false }, { "description": "an invalid relative URI Reference", "data": "/abc", "valid": false }, { "description": "an invalid URI", "data": "\\\\WINDOWS\\fileshare", "valid": false }, { "description": "an invalid URI though valid URI reference", "data": "abc", "valid": false }, { "description": "an invalid URI with spaces", "data": "http:// shouldfail.com", "valid": false }, { "description": "an invalid URI with spaces and missing scheme", "data": ":// should fail", "valid": false }, { "description": "an invalid URI with comma in scheme", "data": "bar,baz:foo", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/format/uuid.json0000644000175100001770000000725714653725311026223 0ustar00runnerdocker[ { "description": "uuid format", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "format": "uuid" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "all upper-case", "data": "2EB8AA08-AA98-11EA-B4AA-73B441D16380", "valid": true }, { "description": "all lower-case", "data": "2eb8aa08-aa98-11ea-b4aa-73b441d16380", "valid": true }, { "description": "mixed case", "data": "2eb8aa08-AA98-11ea-B4Aa-73B441D16380", "valid": true }, { "description": "all zeroes is valid", "data": "00000000-0000-0000-0000-000000000000", "valid": true }, { "description": "wrong length", "data": "2eb8aa08-aa98-11ea-b4aa-73b441d1638", "valid": false }, { "description": "missing section", "data": "2eb8aa08-aa98-11ea-73b441d16380", "valid": false }, { "description": "bad characters (not hex)", "data": "2eb8aa08-aa98-11ea-b4ga-73b441d16380", "valid": false }, { "description": "no dashes", "data": "2eb8aa08aa9811eab4aa73b441d16380", "valid": false }, { "description": "too few dashes", "data": "2eb8aa08aa98-11ea-b4aa73b441d16380", "valid": false }, { "description": "too many dashes", "data": "2eb8-aa08-aa98-11ea-b4aa73b44-1d16380", "valid": false }, { "description": "dashes in the wrong spot", "data": "2eb8aa08aa9811eab4aa73b441d16380----", "valid": false }, { "description": "valid version 4", "data": "98d80576-482e-427f-8434-7f86890ab222", "valid": true }, { "description": "valid version 5", "data": "99c17cbb-656f-564a-940f-1a4568f03487", "valid": true }, { "description": "hypothetical version 6", "data": "99c17cbb-656f-664a-940f-1a4568f03487", "valid": true }, { "description": "hypothetical version 15", "data": "99c17cbb-656f-f64a-940f-1a4568f03487", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/no-schema.json0000644000175100001770000000123614653725311025626 0ustar00runnerdocker[ { "description": "validation without $schema", "comment": "minLength is the same across all drafts", "schema": { "minLength": 2 }, "tests": [ { "description": "a 3-character string is valid", "data": "foo", "valid": true }, { "description": "a 1-character string is not valid", "data": "a", "valid": false }, { "description": "a non-string is valid", "data": 5, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/non-bmp-regex.json0000644000175100001770000000500014653725311026423 0ustar00runnerdocker[ { "description": "Proper UTF-16 surrogate pair handling: pattern", "comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "pattern": "^ðŸ²*$" }, "tests": [ { "description": "matches empty", "data": "", "valid": true }, { "description": "matches single", "data": "ðŸ²", "valid": true }, { "description": "matches two", "data": "ðŸ²ðŸ²", "valid": true }, { "description": "doesn't match one", "data": "ðŸ‰", "valid": false }, { "description": "doesn't match two", "data": "ðŸ‰ðŸ‰", "valid": false }, { "description": "doesn't match one ASCII", "data": "D", "valid": false }, { "description": "doesn't match two ASCII", "data": "DD", "valid": false } ] }, { "description": "Proper UTF-16 surrogate pair handling: patternProperties", "comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "patternProperties": { "^ðŸ²*$": { "type": "integer" } } }, "tests": [ { "description": "matches empty", "data": { "": 1 }, "valid": true }, { "description": "matches single", "data": { "ðŸ²": 1 }, "valid": true }, { "description": "matches two", "data": { "ðŸ²ðŸ²": 1 }, "valid": true }, { "description": "doesn't match one", "data": { "ðŸ²": "hello" }, "valid": false }, { "description": "doesn't match two", "data": { "ðŸ²ðŸ²": "hello" }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/optional/refOfUnknownKeyword.json0000644000175100001770000000243214653725311027741 0ustar00runnerdocker[ { "description": "reference of a root arbitrary keyword ", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "unknown-keyword": {"type": "integer"}, "properties": { "bar": {"$ref": "#/unknown-keyword"} } }, "tests": [ { "description": "match", "data": {"bar": 3}, "valid": true }, { "description": "mismatch", "data": {"bar": true}, "valid": false } ] }, { "description": "reference of an arbitrary keyword of a sub-schema", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": { "foo": {"unknown-keyword": {"type": "integer"}}, "bar": {"$ref": "#/properties/foo/unknown-keyword"} } }, "tests": [ { "description": "match", "data": {"bar": 3}, "valid": true }, { "description": "mismatch", "data": {"bar": true}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/pattern.json0000644000175100001770000000327514653725311023611 0ustar00runnerdocker[ { "description": "pattern validation", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "pattern": "^a*$" }, "tests": [ { "description": "a matching pattern is valid", "data": "aaa", "valid": true }, { "description": "a non-matching pattern is invalid", "data": "abc", "valid": false }, { "description": "ignores booleans", "data": true, "valid": true }, { "description": "ignores integers", "data": 123, "valid": true }, { "description": "ignores floats", "data": 1.0, "valid": true }, { "description": "ignores objects", "data": {}, "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores null", "data": null, "valid": true } ] }, { "description": "pattern is not anchored", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "pattern": "a+" }, "tests": [ { "description": "matches a substring", "data": "xxaayy", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/patternProperties.json0000644000175100001770000001263414653725311025665 0ustar00runnerdocker[ { "description": "patternProperties validates properties matching a regex", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "patternProperties": { "f.*o": {"type": "integer"} } }, "tests": [ { "description": "a single valid match is valid", "data": {"foo": 1}, "valid": true }, { "description": "multiple valid matches is valid", "data": {"foo": 1, "foooooo" : 2}, "valid": true }, { "description": "a single invalid match is invalid", "data": {"foo": "bar", "fooooo": 2}, "valid": false }, { "description": "multiple invalid matches is invalid", "data": {"foo": "bar", "foooooo" : "baz"}, "valid": false }, { "description": "ignores arrays", "data": ["foo"], "valid": true }, { "description": "ignores strings", "data": "foo", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "multiple simultaneous patternProperties are validated", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "patternProperties": { "a*": {"type": "integer"}, "aaa*": {"maximum": 20} } }, "tests": [ { "description": "a single valid match is valid", "data": {"a": 21}, "valid": true }, { "description": "a simultaneous match is valid", "data": {"aaaa": 18}, "valid": true }, { "description": "multiple matches is valid", "data": {"a": 21, "aaaa": 18}, "valid": true }, { "description": "an invalid due to one is invalid", "data": {"a": "bar"}, "valid": false }, { "description": "an invalid due to the other is invalid", "data": {"aaaa": 31}, "valid": false }, { "description": "an invalid due to both is invalid", "data": {"aaa": "foo", "aaaa": 31}, "valid": false } ] }, { "description": "regexes are not anchored by default and are case sensitive", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "patternProperties": { "[0-9]{2,}": { "type": "boolean" }, "X_": { "type": "string" } } }, "tests": [ { "description": "non recognized members are ignored", "data": { "answer 1": "42" }, "valid": true }, { "description": "recognized members are accounted for", "data": { "a31b": null }, "valid": false }, { "description": "regexes are case sensitive", "data": { "a_x_3": 3 }, "valid": true }, { "description": "regexes are case sensitive, 2", "data": { "a_X_3": 3 }, "valid": false } ] }, { "description": "patternProperties with boolean schemas", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "patternProperties": { "f.*": true, "b.*": false } }, "tests": [ { "description": "object with property matching schema true is valid", "data": {"foo": 1}, "valid": true }, { "description": "object with property matching schema false is invalid", "data": {"bar": 2}, "valid": false }, { "description": "object with both properties is invalid", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "object with a property matching both true and false is invalid", "data": {"foobar":1}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "patternProperties with null valued instance properties", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "patternProperties": { "^.*bar$": {"type": "null"} } }, "tests": [ { "description": "allows null values", "data": {"foobar": null}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/properties.json0000644000175100001770000001706314653725311024330 0ustar00runnerdocker[ { "description": "object properties validation", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": { "foo": {"type": "integer"}, "bar": {"type": "string"} } }, "tests": [ { "description": "both properties present and valid is valid", "data": {"foo": 1, "bar": "baz"}, "valid": true }, { "description": "one property invalid is invalid", "data": {"foo": 1, "bar": {}}, "valid": false }, { "description": "both properties invalid is invalid", "data": {"foo": [], "bar": {}}, "valid": false }, { "description": "doesn't invalidate other properties", "data": {"quux": []}, "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "properties, patternProperties, additionalProperties interaction", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": { "foo": {"type": "array", "maxItems": 3}, "bar": {"type": "array"} }, "patternProperties": {"f.o": {"minItems": 2}}, "additionalProperties": {"type": "integer"} }, "tests": [ { "description": "property validates property", "data": {"foo": [1, 2]}, "valid": true }, { "description": "property invalidates property", "data": {"foo": [1, 2, 3, 4]}, "valid": false }, { "description": "patternProperty invalidates property", "data": {"foo": []}, "valid": false }, { "description": "patternProperty validates nonproperty", "data": {"fxo": [1, 2]}, "valid": true }, { "description": "patternProperty invalidates nonproperty", "data": {"fxo": []}, "valid": false }, { "description": "additionalProperty ignores property", "data": {"bar": []}, "valid": true }, { "description": "additionalProperty validates others", "data": {"quux": 3}, "valid": true }, { "description": "additionalProperty invalidates others", "data": {"quux": "foo"}, "valid": false } ] }, { "description": "properties with boolean schema", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": { "foo": true, "bar": false } }, "tests": [ { "description": "no property present is valid", "data": {}, "valid": true }, { "description": "only 'true' property present is valid", "data": {"foo": 1}, "valid": true }, { "description": "only 'false' property present is invalid", "data": {"bar": 2}, "valid": false }, { "description": "both properties present is invalid", "data": {"foo": 1, "bar": 2}, "valid": false } ] }, { "description": "properties with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": { "foo\nbar": {"type": "number"}, "foo\"bar": {"type": "number"}, "foo\\bar": {"type": "number"}, "foo\rbar": {"type": "number"}, "foo\tbar": {"type": "number"}, "foo\fbar": {"type": "number"} } }, "tests": [ { "description": "object with all numbers is valid", "data": { "foo\nbar": 1, "foo\"bar": 1, "foo\\bar": 1, "foo\rbar": 1, "foo\tbar": 1, "foo\fbar": 1 }, "valid": true }, { "description": "object with strings is invalid", "data": { "foo\nbar": "1", "foo\"bar": "1", "foo\\bar": "1", "foo\rbar": "1", "foo\tbar": "1", "foo\fbar": "1" }, "valid": false } ] }, { "description": "properties with null valued instance properties", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": { "foo": {"type": "null"} } }, "tests": [ { "description": "allows null values", "data": {"foo": null}, "valid": true } ] }, { "description": "properties whose names are Javascript object property names", "comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": { "__proto__": {"type": "number"}, "toString": { "properties": { "length": { "type": "string" } } }, "constructor": {"type": "number"} } }, "tests": [ { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "none of the properties mentioned", "data": {}, "valid": true }, { "description": "__proto__ not valid", "data": { "__proto__": "foo" }, "valid": false }, { "description": "toString not valid", "data": { "toString": { "length": 37 } }, "valid": false }, { "description": "constructor not valid", "data": { "constructor": { "length": 37 } }, "valid": false }, { "description": "all present and valid", "data": { "__proto__": 12, "toString": { "length": "foo" }, "constructor": 37 }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/propertyNames.json0000644000175100001770000000630714653725311025003 0ustar00runnerdocker[ { "description": "propertyNames validation", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "propertyNames": {"maxLength": 3} }, "tests": [ { "description": "all property names valid", "data": { "f": {}, "foo": {} }, "valid": true }, { "description": "some property names invalid", "data": { "foo": {}, "foobar": {} }, "valid": false }, { "description": "object without properties is valid", "data": {}, "valid": true }, { "description": "ignores arrays", "data": [1, 2, 3, 4], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "propertyNames validation with pattern", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "propertyNames": { "pattern": "^a+$" } }, "tests": [ { "description": "matching property names valid", "data": { "a": {}, "aa": {}, "aaa": {} }, "valid": true }, { "description": "non-matching property name is invalid", "data": { "aaA": {} }, "valid": false }, { "description": "object without properties is valid", "data": {}, "valid": true } ] }, { "description": "propertyNames with boolean schema true", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "propertyNames": true }, "tests": [ { "description": "object with any properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "propertyNames with boolean schema false", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "propertyNames": false }, "tests": [ { "description": "object with any properties is invalid", "data": {"foo": 1}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/recursiveRef.json0000644000175100001770000003336414653725311024602 0ustar00runnerdocker[ { "description": "$recursiveRef without $recursiveAnchor works like $ref", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": { "foo": { "$recursiveRef": "#" } }, "additionalProperties": false }, "tests": [ { "description": "match", "data": {"foo": false}, "valid": true }, { "description": "recursive match", "data": { "foo": { "foo": false } }, "valid": true }, { "description": "mismatch", "data": { "bar": false }, "valid": false }, { "description": "recursive mismatch", "data": { "foo": { "bar": false } }, "valid": false } ] }, { "description": "$recursiveRef without using nesting", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "http://localhost:4242/draft2019-09/recursiveRef2/schema.json", "$defs": { "myobject": { "$id": "myobject.json", "$recursiveAnchor": true, "anyOf": [ { "type": "string" }, { "type": "object", "additionalProperties": { "$recursiveRef": "#" } } ] } }, "anyOf": [ { "type": "integer" }, { "$ref": "#/$defs/myobject" } ] }, "tests": [ { "description": "integer matches at the outer level", "data": 1, "valid": true }, { "description": "single level match", "data": { "foo": "hi" }, "valid": true }, { "description": "integer does not match as a property value", "data": { "foo": 1 }, "valid": false }, { "description": "two levels, properties match with inner definition", "data": { "foo": { "bar": "hi" } }, "valid": true }, { "description": "two levels, no match", "data": { "foo": { "bar": 1 } }, "valid": false } ] }, { "description": "$recursiveRef with nesting", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "http://localhost:4242/draft2019-09/recursiveRef3/schema.json", "$recursiveAnchor": true, "$defs": { "myobject": { "$id": "myobject.json", "$recursiveAnchor": true, "anyOf": [ { "type": "string" }, { "type": "object", "additionalProperties": { "$recursiveRef": "#" } } ] } }, "anyOf": [ { "type": "integer" }, { "$ref": "#/$defs/myobject" } ] }, "tests": [ { "description": "integer matches at the outer level", "data": 1, "valid": true }, { "description": "single level match", "data": { "foo": "hi" }, "valid": true }, { "description": "integer now matches as a property value", "data": { "foo": 1 }, "valid": true }, { "description": "two levels, properties match with inner definition", "data": { "foo": { "bar": "hi" } }, "valid": true }, { "description": "two levels, properties match with $recursiveRef", "data": { "foo": { "bar": 1 } }, "valid": true } ] }, { "description": "$recursiveRef with $recursiveAnchor: false works like $ref", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "http://localhost:4242/draft2019-09/recursiveRef4/schema.json", "$recursiveAnchor": false, "$defs": { "myobject": { "$id": "myobject.json", "$recursiveAnchor": false, "anyOf": [ { "type": "string" }, { "type": "object", "additionalProperties": { "$recursiveRef": "#" } } ] } }, "anyOf": [ { "type": "integer" }, { "$ref": "#/$defs/myobject" } ] }, "tests": [ { "description": "integer matches at the outer level", "data": 1, "valid": true }, { "description": "single level match", "data": { "foo": "hi" }, "valid": true }, { "description": "integer does not match as a property value", "data": { "foo": 1 }, "valid": false }, { "description": "two levels, properties match with inner definition", "data": { "foo": { "bar": "hi" } }, "valid": true }, { "description": "two levels, integer does not match as a property value", "data": { "foo": { "bar": 1 } }, "valid": false } ] }, { "description": "$recursiveRef with no $recursiveAnchor works like $ref", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "http://localhost:4242/draft2019-09/recursiveRef5/schema.json", "$defs": { "myobject": { "$id": "myobject.json", "$recursiveAnchor": false, "anyOf": [ { "type": "string" }, { "type": "object", "additionalProperties": { "$recursiveRef": "#" } } ] } }, "anyOf": [ { "type": "integer" }, { "$ref": "#/$defs/myobject" } ] }, "tests": [ { "description": "integer matches at the outer level", "data": 1, "valid": true }, { "description": "single level match", "data": { "foo": "hi" }, "valid": true }, { "description": "integer does not match as a property value", "data": { "foo": 1 }, "valid": false }, { "description": "two levels, properties match with inner definition", "data": { "foo": { "bar": "hi" } }, "valid": true }, { "description": "two levels, integer does not match as a property value", "data": { "foo": { "bar": 1 } }, "valid": false } ] }, { "description": "$recursiveRef with no $recursiveAnchor in the initial target schema resource", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "http://localhost:4242/draft2019-09/recursiveRef6/base.json", "$recursiveAnchor": true, "anyOf": [ { "type": "boolean" }, { "type": "object", "additionalProperties": { "$id": "http://localhost:4242/draft2019-09/recursiveRef6/inner.json", "$comment": "there is no $recursiveAnchor: true here, so we do NOT recurse to the base", "anyOf": [ { "type": "integer" }, { "type": "object", "additionalProperties": { "$recursiveRef": "#" } } ] } } ] }, "tests": [ { "description": "leaf node does not match; no recursion", "data": { "foo": true }, "valid": false }, { "description": "leaf node matches: recursion uses the inner schema", "data": { "foo": { "bar": 1 } }, "valid": true }, { "description": "leaf node does not match: recursion uses the inner schema", "data": { "foo": { "bar": true } }, "valid": false } ] }, { "description": "$recursiveRef with no $recursiveAnchor in the outer schema resource", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "http://localhost:4242/draft2019-09/recursiveRef7/base.json", "anyOf": [ { "type": "boolean" }, { "type": "object", "additionalProperties": { "$id": "http://localhost:4242/draft2019-09/recursiveRef7/inner.json", "$recursiveAnchor": true, "anyOf": [ { "type": "integer" }, { "type": "object", "additionalProperties": { "$recursiveRef": "#" } } ] } } ] }, "tests": [ { "description": "leaf node does not match; no recursion", "data": { "foo": true }, "valid": false }, { "description": "leaf node matches: recursion only uses inner schema", "data": { "foo": { "bar": 1 } }, "valid": true }, { "description": "leaf node does not match: recursion only uses inner schema", "data": { "foo": { "bar": true } }, "valid": false } ] }, { "description": "multiple dynamic paths to the $recursiveRef keyword", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "recursiveRef8_main.json", "$defs": { "inner": { "$id": "recursiveRef8_inner.json", "$recursiveAnchor": true, "title": "inner", "additionalProperties": { "$recursiveRef": "#" } } }, "if": { "propertyNames": { "pattern": "^[a-m]" } }, "then": { "title": "any type of node", "$id": "recursiveRef8_anyLeafNode.json", "$recursiveAnchor": true, "$ref": "recursiveRef8_inner.json" }, "else": { "title": "integer node", "$id": "recursiveRef8_integerNode.json", "$recursiveAnchor": true, "type": [ "object", "integer" ], "$ref": "recursiveRef8_inner.json" } }, "tests": [ { "description": "recurse to anyLeafNode - floats are allowed", "data": { "alpha": 1.1 }, "valid": true }, { "description": "recurse to integerNode - floats are not allowed", "data": { "november": 1.1 }, "valid": false } ] }, { "description": "dynamic $recursiveRef destination (not predictable at schema compile time)", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "main.json", "$defs": { "inner": { "$id": "inner.json", "$recursiveAnchor": true, "title": "inner", "additionalProperties": { "$recursiveRef": "#" } } }, "if": { "propertyNames": { "pattern": "^[a-m]" } }, "then": { "title": "any type of node", "$id": "anyLeafNode.json", "$recursiveAnchor": true, "$ref": "main.json#/$defs/inner" }, "else": { "title": "integer node", "$id": "integerNode.json", "$recursiveAnchor": true, "type": [ "object", "integer" ], "$ref": "main.json#/$defs/inner" } }, "tests": [ { "description": "numeric node", "data": { "alpha": 1.1 }, "valid": true }, { "description": "integer node", "data": { "november": 1.1 }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/ref.json0000644000175100001770000006563414653725311022717 0ustar00runnerdocker[ { "description": "root pointer ref", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": { "foo": {"$ref": "#"} }, "additionalProperties": false }, "tests": [ { "description": "match", "data": {"foo": false}, "valid": true }, { "description": "recursive match", "data": {"foo": {"foo": false}}, "valid": true }, { "description": "mismatch", "data": {"bar": false}, "valid": false }, { "description": "recursive mismatch", "data": {"foo": {"bar": false}}, "valid": false } ] }, { "description": "relative pointer ref to object", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": { "foo": {"type": "integer"}, "bar": {"$ref": "#/properties/foo"} } }, "tests": [ { "description": "match", "data": {"bar": 3}, "valid": true }, { "description": "mismatch", "data": {"bar": true}, "valid": false } ] }, { "description": "relative pointer ref to array", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": [ {"type": "integer"}, {"$ref": "#/items/0"} ] }, "tests": [ { "description": "match array", "data": [1, 2], "valid": true }, { "description": "mismatch array", "data": [1, "foo"], "valid": false } ] }, { "description": "escaped pointer ref", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$defs": { "tilde~field": {"type": "integer"}, "slash/field": {"type": "integer"}, "percent%field": {"type": "integer"} }, "properties": { "tilde": {"$ref": "#/$defs/tilde~0field"}, "slash": {"$ref": "#/$defs/slash~1field"}, "percent": {"$ref": "#/$defs/percent%25field"} } }, "tests": [ { "description": "slash invalid", "data": {"slash": "aoeu"}, "valid": false }, { "description": "tilde invalid", "data": {"tilde": "aoeu"}, "valid": false }, { "description": "percent invalid", "data": {"percent": "aoeu"}, "valid": false }, { "description": "slash valid", "data": {"slash": 123}, "valid": true }, { "description": "tilde valid", "data": {"tilde": 123}, "valid": true }, { "description": "percent valid", "data": {"percent": 123}, "valid": true } ] }, { "description": "nested refs", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$defs": { "a": {"type": "integer"}, "b": {"$ref": "#/$defs/a"}, "c": {"$ref": "#/$defs/b"} }, "$ref": "#/$defs/c" }, "tests": [ { "description": "nested ref valid", "data": 5, "valid": true }, { "description": "nested ref invalid", "data": "a", "valid": false } ] }, { "description": "ref applies alongside sibling keywords", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$defs": { "reffed": { "type": "array" } }, "properties": { "foo": { "$ref": "#/$defs/reffed", "maxItems": 2 } } }, "tests": [ { "description": "ref valid, maxItems valid", "data": { "foo": [] }, "valid": true }, { "description": "ref valid, maxItems invalid", "data": { "foo": [1, 2, 3] }, "valid": false }, { "description": "ref invalid", "data": { "foo": "string" }, "valid": false } ] }, { "description": "remote ref, containing refs itself", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$ref": "https://json-schema.org/draft/2019-09/schema" }, "tests": [ { "description": "remote ref valid", "data": {"minLength": 1}, "valid": true }, { "description": "remote ref invalid", "data": {"minLength": -1}, "valid": false } ] }, { "description": "property named $ref that is not a reference", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": { "$ref": {"type": "string"} } }, "tests": [ { "description": "property named $ref valid", "data": {"$ref": "a"}, "valid": true }, { "description": "property named $ref invalid", "data": {"$ref": 2}, "valid": false } ] }, { "description": "property named $ref, containing an actual $ref", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": { "$ref": {"$ref": "#/$defs/is-string"} }, "$defs": { "is-string": { "type": "string" } } }, "tests": [ { "description": "property named $ref valid", "data": {"$ref": "a"}, "valid": true }, { "description": "property named $ref invalid", "data": {"$ref": 2}, "valid": false } ] }, { "description": "$ref to boolean schema true", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$ref": "#/$defs/bool", "$defs": { "bool": true } }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "$ref to boolean schema false", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$ref": "#/$defs/bool", "$defs": { "bool": false } }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "Recursive references between schemas", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "http://localhost:1234/draft2019-09/tree", "description": "tree of nodes", "type": "object", "properties": { "meta": {"type": "string"}, "nodes": { "type": "array", "items": {"$ref": "node"} } }, "required": ["meta", "nodes"], "$defs": { "node": { "$id": "http://localhost:1234/draft2019-09/node", "description": "node", "type": "object", "properties": { "value": {"type": "number"}, "subtree": {"$ref": "tree"} }, "required": ["value"] } } }, "tests": [ { "description": "valid tree", "data": { "meta": "root", "nodes": [ { "value": 1, "subtree": { "meta": "child", "nodes": [ {"value": 1.1}, {"value": 1.2} ] } }, { "value": 2, "subtree": { "meta": "child", "nodes": [ {"value": 2.1}, {"value": 2.2} ] } } ] }, "valid": true }, { "description": "invalid tree", "data": { "meta": "root", "nodes": [ { "value": 1, "subtree": { "meta": "child", "nodes": [ {"value": "string is invalid"}, {"value": 1.2} ] } }, { "value": 2, "subtree": { "meta": "child", "nodes": [ {"value": 2.1}, {"value": 2.2} ] } } ] }, "valid": false } ] }, { "description": "refs with quote", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": { "foo\"bar": {"$ref": "#/$defs/foo%22bar"} }, "$defs": { "foo\"bar": {"type": "number"} } }, "tests": [ { "description": "object with numbers is valid", "data": { "foo\"bar": 1 }, "valid": true }, { "description": "object with strings is invalid", "data": { "foo\"bar": "1" }, "valid": false } ] }, { "description": "ref creates new scope when adjacent to keywords", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$defs": { "A": { "unevaluatedProperties": false } }, "properties": { "prop1": { "type": "string" } }, "$ref": "#/$defs/A" }, "tests": [ { "description": "referenced subschema doesn't see annotations from properties", "data": { "prop1": "match" }, "valid": false } ] }, { "description": "naive replacement of $ref with its destination is not correct", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$defs": { "a_string": { "type": "string" } }, "enum": [ { "$ref": "#/$defs/a_string" } ] }, "tests": [ { "description": "do not evaluate the $ref inside the enum, matching any string", "data": "this is a string", "valid": false }, { "description": "do not evaluate the $ref inside the enum, definition exact match", "data": { "type": "string" }, "valid": false }, { "description": "match the enum exactly", "data": { "$ref": "#/$defs/a_string" }, "valid": true } ] }, { "description": "refs with relative uris and defs", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "http://example.com/schema-relative-uri-defs1.json", "properties": { "foo": { "$id": "schema-relative-uri-defs2.json", "$defs": { "inner": { "properties": { "bar": { "type": "string" } } } }, "$ref": "#/$defs/inner" } }, "$ref": "schema-relative-uri-defs2.json" }, "tests": [ { "description": "invalid on inner field", "data": { "foo": { "bar": 1 }, "bar": "a" }, "valid": false }, { "description": "invalid on outer field", "data": { "foo": { "bar": "a" }, "bar": 1 }, "valid": false }, { "description": "valid on both fields", "data": { "foo": { "bar": "a" }, "bar": "a" }, "valid": true } ] }, { "description": "relative refs with absolute uris and defs", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "http://example.com/schema-refs-absolute-uris-defs1.json", "properties": { "foo": { "$id": "http://example.com/schema-refs-absolute-uris-defs2.json", "$defs": { "inner": { "properties": { "bar": { "type": "string" } } } }, "$ref": "#/$defs/inner" } }, "$ref": "schema-refs-absolute-uris-defs2.json" }, "tests": [ { "description": "invalid on inner field", "data": { "foo": { "bar": 1 }, "bar": "a" }, "valid": false }, { "description": "invalid on outer field", "data": { "foo": { "bar": "a" }, "bar": 1 }, "valid": false }, { "description": "valid on both fields", "data": { "foo": { "bar": "a" }, "bar": "a" }, "valid": true } ] }, { "description": "$id must be resolved against nearest parent, not just immediate parent", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "http://example.com/a.json", "$defs": { "x": { "$id": "http://example.com/b/c.json", "not": { "$defs": { "y": { "$id": "d.json", "type": "number" } } } } }, "allOf": [ { "$ref": "http://example.com/b/d.json" } ] }, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "non-number is invalid", "data": "a", "valid": false } ] }, { "description": "order of evaluation: $id and $ref", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$comment": "$id must be evaluated before $ref to get the proper $ref destination", "$id": "/draft2019-09/ref-and-id1/base.json", "$ref": "int.json", "$defs": { "bigint": { "$comment": "canonical uri: /draft2019-09/ref-and-id1/int.json", "$id": "int.json", "maximum": 10 }, "smallint": { "$comment": "canonical uri: /draft2019-09/ref-and-id1-int.json", "$id": "/draft2019-09/ref-and-id1-int.json", "maximum": 2 } } }, "tests": [ { "description": "data is valid against first definition", "data": 5, "valid": true }, { "description": "data is invalid against first definition", "data": 50, "valid": false } ] }, { "description": "order of evaluation: $id and $anchor and $ref", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$comment": "$id must be evaluated before $ref to get the proper $ref destination", "$id": "/draft2019-09/ref-and-id2/base.json", "$ref": "#bigint", "$defs": { "bigint": { "$comment": "canonical uri: /draft2019-09/ref-and-id2/base.json#/$defs/bigint; another valid uri for this location: /ref-and-id2/base.json#bigint", "$anchor": "bigint", "maximum": 10 }, "smallint": { "$comment": "canonical uri: /draft2019-09/ref-and-id2#/$defs/smallint; another valid uri for this location: /ref-and-id2/#bigint", "$id": "/draft2019-09/ref-and-id2/", "$anchor": "bigint", "maximum": 2 } } }, "tests": [ { "description": "data is valid against first definition", "data": 5, "valid": true }, { "description": "data is invalid against first definition", "data": 50, "valid": false } ] }, { "description": "simple URN base URI with $ref via the URN", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$comment": "URIs do not have to have HTTP(s) schemes", "$id": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed", "minimum": 30, "properties": { "foo": {"$ref": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed"} } }, "tests": [ { "description": "valid under the URN IDed schema", "data": {"foo": 37}, "valid": true }, { "description": "invalid under the URN IDed schema", "data": {"foo": 12}, "valid": false } ] }, { "description": "simple URN base URI with JSON pointer", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$comment": "URIs do not have to have HTTP(s) schemes", "$id": "urn:uuid:deadbeef-1234-00ff-ff00-4321feebdaed", "properties": { "foo": {"$ref": "#/$defs/bar"} }, "$defs": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with NSS", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$comment": "RFC 8141 §2.2", "$id": "urn:example:1/406/47452/2", "properties": { "foo": {"$ref": "#/$defs/bar"} }, "$defs": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with r-component", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$comment": "RFC 8141 §2.3.1", "$id": "urn:example:foo-bar-baz-qux?+CCResolve:cc=uk", "properties": { "foo": {"$ref": "#/$defs/bar"} }, "$defs": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with q-component", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$comment": "RFC 8141 §2.3.2", "$id": "urn:example:weather?=op=map&lat=39.56&lon=-104.85&datetime=1969-07-21T02:56:15Z", "properties": { "foo": {"$ref": "#/$defs/bar"} }, "$defs": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with f-component", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$comment": "RFC 8141 §2.3.3, but we don't allow fragments", "$ref": "https://json-schema.org/draft/2019-09/schema" }, "tests": [ { "description": "is invalid", "data": {"$id": "urn:example:foo-bar-baz-qux#somepart"}, "valid": false } ] }, { "description": "URN base URI with URN and JSON pointer ref", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed", "properties": { "foo": {"$ref": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed#/$defs/bar"} }, "$defs": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with URN and anchor ref", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed", "properties": { "foo": {"$ref": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed#something"} }, "$defs": { "bar": { "$anchor": "something", "type": "string" } } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN ref with nested pointer ref", "schema": { "$ref": "urn:uuid:deadbeef-4321-ffff-ffff-1234feebdaed", "$defs": { "foo": { "$id": "urn:uuid:deadbeef-4321-ffff-ffff-1234feebdaed", "$defs": {"bar": {"type": "string"}}, "$ref": "#/$defs/bar" } } }, "tests": [ { "description": "a string is valid", "data": "bar", "valid": true }, { "description": "a non-string is invalid", "data": 12, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/refRemote.json0000644000175100001770000002122314653725311024055 0ustar00runnerdocker[ { "description": "remote ref", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$ref": "http://localhost:1234/draft2019-09/integer.json" }, "tests": [ { "description": "remote ref valid", "data": 1, "valid": true }, { "description": "remote ref invalid", "data": "a", "valid": false } ] }, { "description": "fragment within remote ref", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$ref": "http://localhost:1234/draft2019-09/subSchemas-defs.json#/$defs/integer" }, "tests": [ { "description": "remote fragment valid", "data": 1, "valid": true }, { "description": "remote fragment invalid", "data": "a", "valid": false } ] }, { "description": "ref within remote ref", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$ref": "http://localhost:1234/draft2019-09/subSchemas-defs.json#/$defs/refToInteger" }, "tests": [ { "description": "ref within ref valid", "data": 1, "valid": true }, { "description": "ref within ref invalid", "data": "a", "valid": false } ] }, { "description": "base URI change", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "http://localhost:1234/draft2019-09/", "items": { "$id": "baseUriChange/", "items": {"$ref": "folderInteger.json"} } }, "tests": [ { "description": "base URI change ref valid", "data": [[1]], "valid": true }, { "description": "base URI change ref invalid", "data": [["a"]], "valid": false } ] }, { "description": "base URI change - change folder", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "http://localhost:1234/draft2019-09/scope_change_defs1.json", "type" : "object", "properties": {"list": {"$ref": "baseUriChangeFolder/"}}, "$defs": { "baz": { "$id": "baseUriChangeFolder/", "type": "array", "items": {"$ref": "folderInteger.json"} } } }, "tests": [ { "description": "number is valid", "data": {"list": [1]}, "valid": true }, { "description": "string is invalid", "data": {"list": ["a"]}, "valid": false } ] }, { "description": "base URI change - change folder in subschema", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "http://localhost:1234/draft2019-09/scope_change_defs2.json", "type" : "object", "properties": {"list": {"$ref": "baseUriChangeFolderInSubschema/#/$defs/bar"}}, "$defs": { "baz": { "$id": "baseUriChangeFolderInSubschema/", "$defs": { "bar": { "type": "array", "items": {"$ref": "folderInteger.json"} } } } } }, "tests": [ { "description": "number is valid", "data": {"list": [1]}, "valid": true }, { "description": "string is invalid", "data": {"list": ["a"]}, "valid": false } ] }, { "description": "root ref in remote ref", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "http://localhost:1234/draft2019-09/object", "type": "object", "properties": { "name": {"$ref": "name-defs.json#/$defs/orNull"} } }, "tests": [ { "description": "string is valid", "data": { "name": "foo" }, "valid": true }, { "description": "null is valid", "data": { "name": null }, "valid": true }, { "description": "object is invalid", "data": { "name": { "name": null } }, "valid": false } ] }, { "description": "remote ref with ref to defs", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "http://localhost:1234/draft2019-09/schema-remote-ref-ref-defs1.json", "$ref": "ref-and-defs.json" }, "tests": [ { "description": "invalid", "data": { "bar": 1 }, "valid": false }, { "description": "valid", "data": { "bar": "a" }, "valid": true } ] }, { "description": "Location-independent identifier in remote ref", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$ref": "http://localhost:1234/draft2019-09/locationIndependentIdentifier.json#/$defs/refToInteger" }, "tests": [ { "description": "integer is valid", "data": 1, "valid": true }, { "description": "string is invalid", "data": "foo", "valid": false } ] }, { "description": "retrieved nested refs resolve relative to their URI not $id", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "http://localhost:1234/draft2019-09/some-id", "properties": { "name": {"$ref": "nested/foo-ref-string.json"} } }, "tests": [ { "description": "number is invalid", "data": { "name": {"foo": 1} }, "valid": false }, { "description": "string is valid", "data": { "name": {"foo": "a"} }, "valid": true } ] }, { "description": "remote HTTP ref with different $id", "schema": {"$ref": "http://localhost:1234/different-id-ref-string.json"}, "tests": [ { "description": "number is invalid", "data": 1, "valid": false }, { "description": "string is valid", "data": "foo", "valid": true } ] }, { "description": "remote HTTP ref with different URN $id", "schema": {"$ref": "http://localhost:1234/urn-ref-string.json"}, "tests": [ { "description": "number is invalid", "data": 1, "valid": false }, { "description": "string is valid", "data": "foo", "valid": true } ] }, { "description": "remote HTTP ref with nested absolute ref", "schema": {"$ref": "http://localhost:1234/nested-absolute-ref-to-string.json"}, "tests": [ { "description": "number is invalid", "data": 1, "valid": false }, { "description": "string is valid", "data": "foo", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/required.json0000644000175100001770000001102314653725311023742 0ustar00runnerdocker[ { "description": "required validation", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": { "foo": {}, "bar": {} }, "required": ["foo"] }, "tests": [ { "description": "present required property is valid", "data": {"foo": 1}, "valid": true }, { "description": "non-present required property is invalid", "data": {"bar": 1}, "valid": false }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "required default validation", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": { "foo": {} } }, "tests": [ { "description": "not required by default", "data": {}, "valid": true } ] }, { "description": "required with empty array", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": { "foo": {} }, "required": [] }, "tests": [ { "description": "property not required", "data": {}, "valid": true } ] }, { "description": "required with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "required": [ "foo\nbar", "foo\"bar", "foo\\bar", "foo\rbar", "foo\tbar", "foo\fbar" ] }, "tests": [ { "description": "object with all properties present is valid", "data": { "foo\nbar": 1, "foo\"bar": 1, "foo\\bar": 1, "foo\rbar": 1, "foo\tbar": 1, "foo\fbar": 1 }, "valid": true }, { "description": "object with some properties missing is invalid", "data": { "foo\nbar": "1", "foo\"bar": "1" }, "valid": false } ] }, { "description": "required properties whose names are Javascript object property names", "comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "required": ["__proto__", "toString", "constructor"] }, "tests": [ { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "none of the properties mentioned", "data": {}, "valid": false }, { "description": "__proto__ present", "data": { "__proto__": "foo" }, "valid": false }, { "description": "toString present", "data": { "toString": { "length": 37 } }, "valid": false }, { "description": "constructor present", "data": { "constructor": { "length": 37 } }, "valid": false }, { "description": "all present", "data": { "__proto__": 12, "toString": { "length": "foo" }, "constructor": 37 }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/type.json0000644000175100001770000003403514653725311023113 0ustar00runnerdocker[ { "description": "integer type matches integers", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "integer" }, "tests": [ { "description": "an integer is an integer", "data": 1, "valid": true }, { "description": "a float with zero fractional part is an integer", "data": 1.0, "valid": true }, { "description": "a float is not an integer", "data": 1.1, "valid": false }, { "description": "a string is not an integer", "data": "foo", "valid": false }, { "description": "a string is still not an integer, even if it looks like one", "data": "1", "valid": false }, { "description": "an object is not an integer", "data": {}, "valid": false }, { "description": "an array is not an integer", "data": [], "valid": false }, { "description": "a boolean is not an integer", "data": true, "valid": false }, { "description": "null is not an integer", "data": null, "valid": false } ] }, { "description": "number type matches numbers", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "number" }, "tests": [ { "description": "an integer is a number", "data": 1, "valid": true }, { "description": "a float with zero fractional part is a number (and an integer)", "data": 1.0, "valid": true }, { "description": "a float is a number", "data": 1.1, "valid": true }, { "description": "a string is not a number", "data": "foo", "valid": false }, { "description": "a string is still not a number, even if it looks like one", "data": "1", "valid": false }, { "description": "an object is not a number", "data": {}, "valid": false }, { "description": "an array is not a number", "data": [], "valid": false }, { "description": "a boolean is not a number", "data": true, "valid": false }, { "description": "null is not a number", "data": null, "valid": false } ] }, { "description": "string type matches strings", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "string" }, "tests": [ { "description": "1 is not a string", "data": 1, "valid": false }, { "description": "a float is not a string", "data": 1.1, "valid": false }, { "description": "a string is a string", "data": "foo", "valid": true }, { "description": "a string is still a string, even if it looks like a number", "data": "1", "valid": true }, { "description": "an empty string is still a string", "data": "", "valid": true }, { "description": "an object is not a string", "data": {}, "valid": false }, { "description": "an array is not a string", "data": [], "valid": false }, { "description": "a boolean is not a string", "data": true, "valid": false }, { "description": "null is not a string", "data": null, "valid": false } ] }, { "description": "object type matches objects", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object" }, "tests": [ { "description": "an integer is not an object", "data": 1, "valid": false }, { "description": "a float is not an object", "data": 1.1, "valid": false }, { "description": "a string is not an object", "data": "foo", "valid": false }, { "description": "an object is an object", "data": {}, "valid": true }, { "description": "an array is not an object", "data": [], "valid": false }, { "description": "a boolean is not an object", "data": true, "valid": false }, { "description": "null is not an object", "data": null, "valid": false } ] }, { "description": "array type matches arrays", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "array" }, "tests": [ { "description": "an integer is not an array", "data": 1, "valid": false }, { "description": "a float is not an array", "data": 1.1, "valid": false }, { "description": "a string is not an array", "data": "foo", "valid": false }, { "description": "an object is not an array", "data": {}, "valid": false }, { "description": "an array is an array", "data": [], "valid": true }, { "description": "a boolean is not an array", "data": true, "valid": false }, { "description": "null is not an array", "data": null, "valid": false } ] }, { "description": "boolean type matches booleans", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "boolean" }, "tests": [ { "description": "an integer is not a boolean", "data": 1, "valid": false }, { "description": "zero is not a boolean", "data": 0, "valid": false }, { "description": "a float is not a boolean", "data": 1.1, "valid": false }, { "description": "a string is not a boolean", "data": "foo", "valid": false }, { "description": "an empty string is not a boolean", "data": "", "valid": false }, { "description": "an object is not a boolean", "data": {}, "valid": false }, { "description": "an array is not a boolean", "data": [], "valid": false }, { "description": "true is a boolean", "data": true, "valid": true }, { "description": "false is a boolean", "data": false, "valid": true }, { "description": "null is not a boolean", "data": null, "valid": false } ] }, { "description": "null type matches only the null object", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "null" }, "tests": [ { "description": "an integer is not null", "data": 1, "valid": false }, { "description": "a float is not null", "data": 1.1, "valid": false }, { "description": "zero is not null", "data": 0, "valid": false }, { "description": "a string is not null", "data": "foo", "valid": false }, { "description": "an empty string is not null", "data": "", "valid": false }, { "description": "an object is not null", "data": {}, "valid": false }, { "description": "an array is not null", "data": [], "valid": false }, { "description": "true is not null", "data": true, "valid": false }, { "description": "false is not null", "data": false, "valid": false }, { "description": "null is null", "data": null, "valid": true } ] }, { "description": "multiple types can be specified in an array", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": ["integer", "string"] }, "tests": [ { "description": "an integer is valid", "data": 1, "valid": true }, { "description": "a string is valid", "data": "foo", "valid": true }, { "description": "a float is invalid", "data": 1.1, "valid": false }, { "description": "an object is invalid", "data": {}, "valid": false }, { "description": "an array is invalid", "data": [], "valid": false }, { "description": "a boolean is invalid", "data": true, "valid": false }, { "description": "null is invalid", "data": null, "valid": false } ] }, { "description": "type as array with one item", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": ["string"] }, "tests": [ { "description": "string is valid", "data": "foo", "valid": true }, { "description": "number is invalid", "data": 123, "valid": false } ] }, { "description": "type: array or object", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": ["array", "object"] }, "tests": [ { "description": "array is valid", "data": [1,2,3], "valid": true }, { "description": "object is valid", "data": {"foo": 123}, "valid": true }, { "description": "number is invalid", "data": 123, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false }, { "description": "null is invalid", "data": null, "valid": false } ] }, { "description": "type: array, object or null", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": ["array", "object", "null"] }, "tests": [ { "description": "array is valid", "data": [1,2,3], "valid": true }, { "description": "object is valid", "data": {"foo": 123}, "valid": true }, { "description": "null is valid", "data": null, "valid": true }, { "description": "number is invalid", "data": 123, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/unevaluatedItems.json0000644000175100001770000003733714653725311025461 0ustar00runnerdocker[ { "description": "unevaluatedItems true", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "unevaluatedItems": true }, "tests": [ { "description": "with no unevaluated items", "data": [], "valid": true }, { "description": "with unevaluated items", "data": ["foo"], "valid": true } ] }, { "description": "unevaluatedItems false", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "unevaluatedItems": false }, "tests": [ { "description": "with no unevaluated items", "data": [], "valid": true }, { "description": "with unevaluated items", "data": ["foo"], "valid": false } ] }, { "description": "unevaluatedItems as schema", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "unevaluatedItems": { "type": "string" } }, "tests": [ { "description": "with no unevaluated items", "data": [], "valid": true }, { "description": "with valid unevaluated items", "data": ["foo"], "valid": true }, { "description": "with invalid unevaluated items", "data": [42], "valid": false } ] }, { "description": "unevaluatedItems with uniform items", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": { "type": "string" }, "unevaluatedItems": false }, "tests": [ { "description": "unevaluatedItems doesn't apply", "data": ["foo", "bar"], "valid": true } ] }, { "description": "unevaluatedItems with tuple", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": [ { "type": "string" } ], "unevaluatedItems": false }, "tests": [ { "description": "with no unevaluated items", "data": ["foo"], "valid": true }, { "description": "with unevaluated items", "data": ["foo", "bar"], "valid": false } ] }, { "description": "unevaluatedItems with additionalItems", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": [ { "type": "string" } ], "additionalItems": true, "unevaluatedItems": false }, "tests": [ { "description": "unevaluatedItems doesn't apply", "data": ["foo", 42], "valid": true } ] }, { "description": "unevaluatedItems with nested tuple", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": [ { "type": "string" } ], "allOf": [ { "items": [ true, { "type": "number" } ] } ], "unevaluatedItems": false }, "tests": [ { "description": "with no unevaluated items", "data": ["foo", 42], "valid": true }, { "description": "with unevaluated items", "data": ["foo", 42, true], "valid": false } ] }, { "description": "unevaluatedItems with nested items", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "unevaluatedItems": {"type": "boolean"}, "anyOf": [ { "items": {"type": "string"} }, true ] }, "tests": [ { "description": "with only (valid) additional items", "data": [true, false], "valid": true }, { "description": "with no additional items", "data": ["yes", "no"], "valid": true }, { "description": "with invalid additional item", "data": ["yes", false], "valid": false } ] }, { "description": "unevaluatedItems with nested items and additionalItems", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "allOf": [ { "items": [ { "type": "string" } ], "additionalItems": true } ], "unevaluatedItems": false }, "tests": [ { "description": "with no additional items", "data": ["foo"], "valid": true }, { "description": "with additional items", "data": ["foo", 42, true], "valid": true } ] }, { "description": "unevaluatedItems with nested unevaluatedItems", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "allOf": [ { "items": [ { "type": "string" } ] }, { "unevaluatedItems": true } ], "unevaluatedItems": false }, "tests": [ { "description": "with no additional items", "data": ["foo"], "valid": true }, { "description": "with additional items", "data": ["foo", 42, true], "valid": true } ] }, { "description": "unevaluatedItems with anyOf", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": [ { "const": "foo" } ], "anyOf": [ { "items": [ true, { "const": "bar" } ] }, { "items": [ true, true, { "const": "baz" } ] } ], "unevaluatedItems": false }, "tests": [ { "description": "when one schema matches and has no unevaluated items", "data": ["foo", "bar"], "valid": true }, { "description": "when one schema matches and has unevaluated items", "data": ["foo", "bar", 42], "valid": false }, { "description": "when two schemas match and has no unevaluated items", "data": ["foo", "bar", "baz"], "valid": true }, { "description": "when two schemas match and has unevaluated items", "data": ["foo", "bar", "baz", 42], "valid": false } ] }, { "description": "unevaluatedItems with oneOf", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": [ { "const": "foo" } ], "oneOf": [ { "items": [ true, { "const": "bar" } ] }, { "items": [ true, { "const": "baz" } ] } ], "unevaluatedItems": false }, "tests": [ { "description": "with no unevaluated items", "data": ["foo", "bar"], "valid": true }, { "description": "with unevaluated items", "data": ["foo", "bar", 42], "valid": false } ] }, { "description": "unevaluatedItems with not", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": [ { "const": "foo" } ], "not": { "not": { "items": [ true, { "const": "bar" } ] } }, "unevaluatedItems": false }, "tests": [ { "description": "with unevaluated items", "data": ["foo", "bar"], "valid": false } ] }, { "description": "unevaluatedItems with if/then/else", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": [ { "const": "foo" } ], "if": { "items": [ true, { "const": "bar" } ] }, "then": { "items": [ true, true, { "const": "then" } ] }, "else": { "items": [ true, true, true, { "const": "else" } ] }, "unevaluatedItems": false }, "tests": [ { "description": "when if matches and it has no unevaluated items", "data": ["foo", "bar", "then"], "valid": true }, { "description": "when if matches and it has unevaluated items", "data": ["foo", "bar", "then", "else"], "valid": false }, { "description": "when if doesn't match and it has no unevaluated items", "data": ["foo", 42, 42, "else"], "valid": true }, { "description": "when if doesn't match and it has unevaluated items", "data": ["foo", 42, 42, "else", 42], "valid": false } ] }, { "description": "unevaluatedItems with boolean schemas", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "allOf": [true], "unevaluatedItems": false }, "tests": [ { "description": "with no unevaluated items", "data": [], "valid": true }, { "description": "with unevaluated items", "data": ["foo"], "valid": false } ] }, { "description": "unevaluatedItems with $ref", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$ref": "#/$defs/bar", "items": [ { "type": "string" } ], "unevaluatedItems": false, "$defs": { "bar": { "items": [ true, { "type": "string" } ] } } }, "tests": [ { "description": "with no unevaluated items", "data": ["foo", "bar"], "valid": true }, { "description": "with unevaluated items", "data": ["foo", "bar", "baz"], "valid": false } ] }, { "description": "unevaluatedItems can't see inside cousins", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "allOf": [ { "items": [ true ] }, { "unevaluatedItems": false } ] }, "tests": [ { "description": "always fails", "data": [ 1 ], "valid": false } ] }, { "description": "item is evaluated in an uncle schema to unevaluatedItems", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "properties": { "foo": { "items": [ { "type": "string" } ], "unevaluatedItems": false } }, "anyOf": [ { "properties": { "foo": { "items": [ true, { "type": "string" } ] } } } ] }, "tests": [ { "description": "no extra items", "data": { "foo": [ "test" ] }, "valid": true }, { "description": "uncle keyword evaluation is not significant", "data": { "foo": [ "test", "test" ] }, "valid": false } ] }, { "description": "non-array instances are valid", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "unevaluatedItems": false }, "tests": [ { "description": "ignores booleans", "data": true, "valid": true }, { "description": "ignores integers", "data": 123, "valid": true }, { "description": "ignores floats", "data": 1.0, "valid": true }, { "description": "ignores objects", "data": {}, "valid": true }, { "description": "ignores strings", "data": "foo", "valid": true }, { "description": "ignores null", "data": null, "valid": true } ] }, { "description": "unevaluatedItems with null instance elements", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "unevaluatedItems": { "type": "null" } }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/unevaluatedProperties.json0000644000175100001770000012243414653725311026525 0ustar00runnerdocker[ { "description": "unevaluatedProperties true", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "unevaluatedProperties": true }, "tests": [ { "description": "with no unevaluated properties", "data": {}, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo" }, "valid": true } ] }, { "description": "unevaluatedProperties schema", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "unevaluatedProperties": { "type": "string", "minLength": 3 } }, "tests": [ { "description": "with no unevaluated properties", "data": {}, "valid": true }, { "description": "with valid unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with invalid unevaluated properties", "data": { "foo": "fo" }, "valid": false } ] }, { "description": "unevaluatedProperties false", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": {}, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo" }, "valid": false } ] }, { "description": "unevaluatedProperties with adjacent properties", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "unevaluatedProperties with adjacent patternProperties", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "patternProperties": { "^foo": { "type": "string" } }, "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "unevaluatedProperties with adjacent additionalProperties", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "additionalProperties": true, "unevaluatedProperties": false }, "tests": [ { "description": "with no additional properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with additional properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true } ] }, { "description": "unevaluatedProperties with nested properties", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "properties": { "bar": { "type": "string" } } } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no additional properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "with additional properties", "data": { "foo": "foo", "bar": "bar", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties with nested patternProperties", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "patternProperties": { "^bar": { "type": "string" } } } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no additional properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "with additional properties", "data": { "foo": "foo", "bar": "bar", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties with nested additionalProperties", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "additionalProperties": true } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no additional properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with additional properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true } ] }, { "description": "unevaluatedProperties with nested unevaluatedProperties", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "unevaluatedProperties": true } ], "unevaluatedProperties": { "type": "string", "maxLength": 2 } }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true } ] }, { "description": "unevaluatedProperties with anyOf", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "anyOf": [ { "properties": { "bar": { "const": "bar" } }, "required": ["bar"] }, { "properties": { "baz": { "const": "baz" } }, "required": ["baz"] }, { "properties": { "quux": { "const": "quux" } }, "required": ["quux"] } ], "unevaluatedProperties": false }, "tests": [ { "description": "when one matches and has no unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "when one matches and has unevaluated properties", "data": { "foo": "foo", "bar": "bar", "baz": "not-baz" }, "valid": false }, { "description": "when two match and has no unevaluated properties", "data": { "foo": "foo", "bar": "bar", "baz": "baz" }, "valid": true }, { "description": "when two match and has unevaluated properties", "data": { "foo": "foo", "bar": "bar", "baz": "baz", "quux": "not-quux" }, "valid": false } ] }, { "description": "unevaluatedProperties with oneOf", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "oneOf": [ { "properties": { "bar": { "const": "bar" } }, "required": ["bar"] }, { "properties": { "baz": { "const": "baz" } }, "required": ["baz"] } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo", "bar": "bar", "quux": "quux" }, "valid": false } ] }, { "description": "unevaluatedProperties with not", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "not": { "not": { "properties": { "bar": { "const": "bar" } }, "required": ["bar"] } }, "unevaluatedProperties": false }, "tests": [ { "description": "with unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "unevaluatedProperties with if/then/else", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "if": { "properties": { "foo": { "const": "then" } }, "required": ["foo"] }, "then": { "properties": { "bar": { "type": "string" } }, "required": ["bar"] }, "else": { "properties": { "baz": { "type": "string" } }, "required": ["baz"] }, "unevaluatedProperties": false }, "tests": [ { "description": "when if is true and has no unevaluated properties", "data": { "foo": "then", "bar": "bar" }, "valid": true }, { "description": "when if is true and has unevaluated properties", "data": { "foo": "then", "bar": "bar", "baz": "baz" }, "valid": false }, { "description": "when if is false and has no unevaluated properties", "data": { "baz": "baz" }, "valid": true }, { "description": "when if is false and has unevaluated properties", "data": { "foo": "else", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties with if/then/else, then not defined", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "if": { "properties": { "foo": { "const": "then" } }, "required": ["foo"] }, "else": { "properties": { "baz": { "type": "string" } }, "required": ["baz"] }, "unevaluatedProperties": false }, "tests": [ { "description": "when if is true and has no unevaluated properties", "data": { "foo": "then", "bar": "bar" }, "valid": false }, { "description": "when if is true and has unevaluated properties", "data": { "foo": "then", "bar": "bar", "baz": "baz" }, "valid": false }, { "description": "when if is false and has no unevaluated properties", "data": { "baz": "baz" }, "valid": true }, { "description": "when if is false and has unevaluated properties", "data": { "foo": "else", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties with if/then/else, else not defined", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "if": { "properties": { "foo": { "const": "then" } }, "required": ["foo"] }, "then": { "properties": { "bar": { "type": "string" } }, "required": ["bar"] }, "unevaluatedProperties": false }, "tests": [ { "description": "when if is true and has no unevaluated properties", "data": { "foo": "then", "bar": "bar" }, "valid": true }, { "description": "when if is true and has unevaluated properties", "data": { "foo": "then", "bar": "bar", "baz": "baz" }, "valid": false }, { "description": "when if is false and has no unevaluated properties", "data": { "baz": "baz" }, "valid": false }, { "description": "when if is false and has unevaluated properties", "data": { "foo": "else", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties with dependentSchemas", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "dependentSchemas": { "foo": { "properties": { "bar": { "const": "bar" } }, "required": ["bar"] } }, "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "with unevaluated properties", "data": { "bar": "bar" }, "valid": false } ] }, { "description": "unevaluatedProperties with boolean schemas", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [true], "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with unevaluated properties", "data": { "bar": "bar" }, "valid": false } ] }, { "description": "unevaluatedProperties with $ref", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "$ref": "#/$defs/bar", "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": false, "$defs": { "bar": { "properties": { "bar": { "type": "string" } } } } }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo", "bar": "bar", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties can't see inside cousins", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "allOf": [ { "properties": { "foo": true } }, { "unevaluatedProperties": false } ] }, "tests": [ { "description": "always fails", "data": { "foo": 1 }, "valid": false } ] }, { "description": "unevaluatedProperties can't see inside cousins (reverse order)", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "allOf": [ { "unevaluatedProperties": false }, { "properties": { "foo": true } } ] }, "tests": [ { "description": "always fails", "data": { "foo": 1 }, "valid": false } ] }, { "description": "nested unevaluatedProperties, outer false, inner true, properties outside", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "unevaluatedProperties": true } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true } ] }, { "description": "nested unevaluatedProperties, outer false, inner true, properties inside", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "allOf": [ { "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": true } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true } ] }, { "description": "nested unevaluatedProperties, outer true, inner false, properties outside", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "unevaluatedProperties": false } ], "unevaluatedProperties": true }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": false }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "nested unevaluatedProperties, outer true, inner false, properties inside", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "allOf": [ { "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": false } ], "unevaluatedProperties": true }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "cousin unevaluatedProperties, true and false, true with properties", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "allOf": [ { "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": true }, { "unevaluatedProperties": false } ] }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": false }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "cousin unevaluatedProperties, true and false, false with properties", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "allOf": [ { "unevaluatedProperties": true }, { "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": false } ] }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "property is evaluated in an uncle schema to unevaluatedProperties", "comment": "see https://stackoverflow.com/questions/66936884/deeply-nested-unevaluatedproperties-and-their-expectations", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "properties": { "foo": { "type": "object", "properties": { "bar": { "type": "string" } }, "unevaluatedProperties": false } }, "anyOf": [ { "properties": { "foo": { "properties": { "faz": { "type": "string" } } } } } ] }, "tests": [ { "description": "no extra properties", "data": { "foo": { "bar": "test" } }, "valid": true }, { "description": "uncle keyword evaluation is not significant", "data": { "foo": { "bar": "test", "faz": "test" } }, "valid": false } ] }, { "description": "in-place applicator siblings, allOf has unevaluated", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "allOf": [ { "properties": { "foo": true }, "unevaluatedProperties": false } ], "anyOf": [ { "properties": { "bar": true } } ] }, "tests": [ { "description": "base case: both properties present", "data": { "foo": 1, "bar": 1 }, "valid": false }, { "description": "in place applicator siblings, bar is missing", "data": { "foo": 1 }, "valid": true }, { "description": "in place applicator siblings, foo is missing", "data": { "bar": 1 }, "valid": false } ] }, { "description": "in-place applicator siblings, anyOf has unevaluated", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "allOf": [ { "properties": { "foo": true } } ], "anyOf": [ { "properties": { "bar": true }, "unevaluatedProperties": false } ] }, "tests": [ { "description": "base case: both properties present", "data": { "foo": 1, "bar": 1 }, "valid": false }, { "description": "in place applicator siblings, bar is missing", "data": { "foo": 1 }, "valid": false }, { "description": "in place applicator siblings, foo is missing", "data": { "bar": 1 }, "valid": true } ] }, { "description": "unevaluatedProperties + single cyclic ref", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "properties": { "x": { "$ref": "#" } }, "unevaluatedProperties": false }, "tests": [ { "description": "Empty is valid", "data": {}, "valid": true }, { "description": "Single is valid", "data": { "x": {} }, "valid": true }, { "description": "Unevaluated on 1st level is invalid", "data": { "x": {}, "y": {} }, "valid": false }, { "description": "Nested is valid", "data": { "x": { "x": {} } }, "valid": true }, { "description": "Unevaluated on 2nd level is invalid", "data": { "x": { "x": {}, "y": {} } }, "valid": false }, { "description": "Deep nested is valid", "data": { "x": { "x": { "x": {} } } }, "valid": true }, { "description": "Unevaluated on 3rd level is invalid", "data": { "x": { "x": { "x": {}, "y": {} } } }, "valid": false } ] }, { "description": "unevaluatedProperties + ref inside allOf / oneOf", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$defs": { "one": { "properties": { "a": true } }, "two": { "required": ["x"], "properties": { "x": true } } }, "allOf": [ { "$ref": "#/$defs/one" }, { "properties": { "b": true } }, { "oneOf": [ { "$ref": "#/$defs/two" }, { "required": ["y"], "properties": { "y": true } } ] } ], "unevaluatedProperties": false }, "tests": [ { "description": "Empty is invalid (no x or y)", "data": {}, "valid": false }, { "description": "a and b are invalid (no x or y)", "data": { "a": 1, "b": 1 }, "valid": false }, { "description": "x and y are invalid", "data": { "x": 1, "y": 1 }, "valid": false }, { "description": "a and x are valid", "data": { "a": 1, "x": 1 }, "valid": true }, { "description": "a and y are valid", "data": { "a": 1, "y": 1 }, "valid": true }, { "description": "a and b and x are valid", "data": { "a": 1, "b": 1, "x": 1 }, "valid": true }, { "description": "a and b and y are valid", "data": { "a": 1, "b": 1, "y": 1 }, "valid": true }, { "description": "a and b and x and y are invalid", "data": { "a": 1, "b": 1, "x": 1, "y": 1 }, "valid": false } ] }, { "description": "dynamic evalation inside nested refs", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$defs": { "one": { "oneOf": [ { "$ref": "#/$defs/two" }, { "required": ["b"], "properties": { "b": true } }, { "required": ["xx"], "patternProperties": { "x": true } }, { "required": ["all"], "unevaluatedProperties": true } ] }, "two": { "oneOf": [ { "required": ["c"], "properties": { "c": true } }, { "required": ["d"], "properties": { "d": true } } ] } }, "oneOf": [ { "$ref": "#/$defs/one" }, { "required": ["a"], "properties": { "a": true } } ], "unevaluatedProperties": false }, "tests": [ { "description": "Empty is invalid", "data": {}, "valid": false }, { "description": "a is valid", "data": { "a": 1 }, "valid": true }, { "description": "b is valid", "data": { "b": 1 }, "valid": true }, { "description": "c is valid", "data": { "c": 1 }, "valid": true }, { "description": "d is valid", "data": { "d": 1 }, "valid": true }, { "description": "a + b is invalid", "data": { "a": 1, "b": 1 }, "valid": false }, { "description": "a + c is invalid", "data": { "a": 1, "c": 1 }, "valid": false }, { "description": "a + d is invalid", "data": { "a": 1, "d": 1 }, "valid": false }, { "description": "b + c is invalid", "data": { "b": 1, "c": 1 }, "valid": false }, { "description": "b + d is invalid", "data": { "b": 1, "d": 1 }, "valid": false }, { "description": "c + d is invalid", "data": { "c": 1, "d": 1 }, "valid": false }, { "description": "xx is valid", "data": { "xx": 1 }, "valid": true }, { "description": "xx + foox is valid", "data": { "xx": 1, "foox": 1 }, "valid": true }, { "description": "xx + foo is invalid", "data": { "xx": 1, "foo": 1 }, "valid": false }, { "description": "xx + a is invalid", "data": { "xx": 1, "a": 1 }, "valid": false }, { "description": "xx + b is invalid", "data": { "xx": 1, "b": 1 }, "valid": false }, { "description": "xx + c is invalid", "data": { "xx": 1, "c": 1 }, "valid": false }, { "description": "xx + d is invalid", "data": { "xx": 1, "d": 1 }, "valid": false }, { "description": "all is valid", "data": { "all": 1 }, "valid": true }, { "description": "all + foo is valid", "data": { "all": 1, "foo": 1 }, "valid": true }, { "description": "all + a is invalid", "data": { "all": 1, "a": 1 }, "valid": false } ] }, { "description": "non-object instances are valid", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "unevaluatedProperties": false }, "tests": [ { "description": "ignores booleans", "data": true, "valid": true }, { "description": "ignores integers", "data": 123, "valid": true }, { "description": "ignores floats", "data": 1.0, "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "foo", "valid": true }, { "description": "ignores null", "data": null, "valid": true } ] }, { "description": "unevaluatedProperties with null valued instance properties", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "unevaluatedProperties": { "type": "null" } }, "tests": [ { "description": "allows null valued properties", "data": {"foo": null}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/uniqueItems.json0000644000175100001770000003366414653725311024451 0ustar00runnerdocker[ { "description": "uniqueItems validation", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "uniqueItems": true }, "tests": [ { "description": "unique array of integers is valid", "data": [1, 2], "valid": true }, { "description": "non-unique array of integers is invalid", "data": [1, 1], "valid": false }, { "description": "non-unique array of more than two integers is invalid", "data": [1, 2, 1], "valid": false }, { "description": "numbers are unique if mathematically unequal", "data": [1.0, 1.00, 1], "valid": false }, { "description": "false is not equal to zero", "data": [0, false], "valid": true }, { "description": "true is not equal to one", "data": [1, true], "valid": true }, { "description": "unique array of strings is valid", "data": ["foo", "bar", "baz"], "valid": true }, { "description": "non-unique array of strings is invalid", "data": ["foo", "bar", "foo"], "valid": false }, { "description": "unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "baz"}], "valid": true }, { "description": "non-unique array of objects is invalid", "data": [{"foo": "bar"}, {"foo": "bar"}], "valid": false }, { "description": "unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : false}}} ], "valid": true }, { "description": "non-unique array of nested objects is invalid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : true}}} ], "valid": false }, { "description": "unique array of arrays is valid", "data": [["foo"], ["bar"]], "valid": true }, { "description": "non-unique array of arrays is invalid", "data": [["foo"], ["foo"]], "valid": false }, { "description": "non-unique array of more than two arrays is invalid", "data": [["foo"], ["bar"], ["foo"]], "valid": false }, { "description": "1 and true are unique", "data": [1, true], "valid": true }, { "description": "0 and false are unique", "data": [0, false], "valid": true }, { "description": "[1] and [true] are unique", "data": [[1], [true]], "valid": true }, { "description": "[0] and [false] are unique", "data": [[0], [false]], "valid": true }, { "description": "nested [1] and [true] are unique", "data": [[[1], "foo"], [[true], "foo"]], "valid": true }, { "description": "nested [0] and [false] are unique", "data": [[[0], "foo"], [[false], "foo"]], "valid": true }, { "description": "unique heterogeneous types are valid", "data": [{}, [1], true, null, 1, "{}"], "valid": true }, { "description": "non-unique heterogeneous types are invalid", "data": [{}, [1], true, null, {}, 1], "valid": false }, { "description": "different objects are unique", "data": [{"a": 1, "b": 2}, {"a": 2, "b": 1}], "valid": true }, { "description": "objects are non-unique despite key order", "data": [{"a": 1, "b": 2}, {"b": 2, "a": 1}], "valid": false }, { "description": "{\"a\": false} and {\"a\": 0} are unique", "data": [{"a": false}, {"a": 0}], "valid": true }, { "description": "{\"a\": true} and {\"a\": 1} are unique", "data": [{"a": true}, {"a": 1}], "valid": true } ] }, { "description": "uniqueItems with an array of items", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": true }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is not valid", "data": [false, false], "valid": false }, { "description": "[true, true] from items array is not valid", "data": [true, true], "valid": false }, { "description": "unique array extended from [false, true] is valid", "data": [false, true, "foo", "bar"], "valid": true }, { "description": "unique array extended from [true, false] is valid", "data": [true, false, "foo", "bar"], "valid": true }, { "description": "non-unique array extended from [false, true] is not valid", "data": [false, true, "foo", "foo"], "valid": false }, { "description": "non-unique array extended from [true, false] is not valid", "data": [true, false, "foo", "foo"], "valid": false } ] }, { "description": "uniqueItems with an array of items and additionalItems=false", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": true, "additionalItems": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is not valid", "data": [false, false], "valid": false }, { "description": "[true, true] from items array is not valid", "data": [true, true], "valid": false }, { "description": "extra items are invalid even if unique", "data": [false, true, null], "valid": false } ] }, { "description": "uniqueItems=false validation", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "uniqueItems": false }, "tests": [ { "description": "unique array of integers is valid", "data": [1, 2], "valid": true }, { "description": "non-unique array of integers is valid", "data": [1, 1], "valid": true }, { "description": "numbers are unique if mathematically unequal", "data": [1.0, 1.00, 1], "valid": true }, { "description": "false is not equal to zero", "data": [0, false], "valid": true }, { "description": "true is not equal to one", "data": [1, true], "valid": true }, { "description": "unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "baz"}], "valid": true }, { "description": "non-unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "bar"}], "valid": true }, { "description": "unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : false}}} ], "valid": true }, { "description": "non-unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : true}}} ], "valid": true }, { "description": "unique array of arrays is valid", "data": [["foo"], ["bar"]], "valid": true }, { "description": "non-unique array of arrays is valid", "data": [["foo"], ["foo"]], "valid": true }, { "description": "1 and true are unique", "data": [1, true], "valid": true }, { "description": "0 and false are unique", "data": [0, false], "valid": true }, { "description": "unique heterogeneous types are valid", "data": [{}, [1], true, null, 1], "valid": true }, { "description": "non-unique heterogeneous types are valid", "data": [{}, [1], true, null, {}, 1], "valid": true } ] }, { "description": "uniqueItems=false with an array of items", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is valid", "data": [false, false], "valid": true }, { "description": "[true, true] from items array is valid", "data": [true, true], "valid": true }, { "description": "unique array extended from [false, true] is valid", "data": [false, true, "foo", "bar"], "valid": true }, { "description": "unique array extended from [true, false] is valid", "data": [true, false, "foo", "bar"], "valid": true }, { "description": "non-unique array extended from [false, true] is valid", "data": [false, true, "foo", "foo"], "valid": true }, { "description": "non-unique array extended from [true, false] is valid", "data": [true, false, "foo", "foo"], "valid": true } ] }, { "description": "uniqueItems=false with an array of items and additionalItems=false", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "items": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": false, "additionalItems": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is valid", "data": [false, false], "valid": true }, { "description": "[true, true] from items array is valid", "data": [true, true], "valid": true }, { "description": "extra items are invalid even if unique", "data": [false, true, null], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/unknownKeyword.json0000644000175100001770000000411314653725311025170 0ustar00runnerdocker[ { "description": "$id inside an unknown keyword is not a real identifier", "comment": "the implementation must not be confused by an $id in locations we do not know how to parse", "schema": { "$schema": "https://json-schema.org/draft/2019-09/schema", "$defs": { "id_in_unknown0": { "not": { "array_of_schemas": [ { "$id": "https://localhost:1234/draft2019-09/unknownKeyword/my_identifier.json", "type": "null" } ] } }, "real_id_in_schema": { "$id": "https://localhost:1234/draft2019-09/unknownKeyword/my_identifier.json", "type": "string" }, "id_in_unknown1": { "not": { "object_of_schemas": { "foo": { "$id": "https://localhost:1234/draft2019-09/unknownKeyword/my_identifier.json", "type": "integer" } } } } }, "anyOf": [ { "$ref": "#/$defs/id_in_unknown0" }, { "$ref": "#/$defs/id_in_unknown1" }, { "$ref": "https://localhost:1234/draft2019-09/unknownKeyword/my_identifier.json" } ] }, "tests": [ { "description": "type matches second anyOf, which has a real schema in it", "data": "a string", "valid": true }, { "description": "type matches non-schema in first anyOf", "data": null, "valid": false }, { "description": "type matches non-schema in third anyOf", "data": 1, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2019-09/vocabulary.json0000644000175100001770000000221714653725311024276 0ustar00runnerdocker[ { "description": "schema that uses custom metaschema with with no validation vocabulary", "schema": { "$id": "https://schema/using/no/validation", "$schema": "http://localhost:1234/draft2019-09/metaschema-no-validation.json", "properties": { "badProperty": false, "numberProperty": { "minimum": 10 } } }, "tests": [ { "description": "applicator vocabulary still works", "data": { "badProperty": "this property should not exist" }, "valid": false }, { "description": "no validation: valid number", "data": { "numberProperty": 20 }, "valid": true }, { "description": "no validation: invalid number, but it still validates", "data": { "numberProperty": 1 }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0730968 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/0000755000175100001770000000000014653725331021216 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/additionalProperties.json0000644000175100001770000001152114653725311026274 0ustar00runnerdocker[ { "description": "additionalProperties being false does not allow other properties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": {"foo": {}, "bar": {}}, "patternProperties": { "^v": {} }, "additionalProperties": false }, "tests": [ { "description": "no additional properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "an additional property is invalid", "data": {"foo" : 1, "bar" : 2, "quux" : "boom"}, "valid": false }, { "description": "ignores arrays", "data": [1, 2, 3], "valid": true }, { "description": "ignores strings", "data": "foobarbaz", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "patternProperties are not additional properties", "data": {"foo":1, "vroom": 2}, "valid": true } ] }, { "description": "non-ASCII pattern with additionalProperties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "patternProperties": {"^á": {}}, "additionalProperties": false }, "tests": [ { "description": "matching the pattern is valid", "data": {"ármányos": 2}, "valid": true }, { "description": "not matching the pattern is invalid", "data": {"élmény": 2}, "valid": false } ] }, { "description": "additionalProperties with schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": {"foo": {}, "bar": {}}, "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "no additional properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "an additional valid property is valid", "data": {"foo" : 1, "bar" : 2, "quux" : true}, "valid": true }, { "description": "an additional invalid property is invalid", "data": {"foo" : 1, "bar" : 2, "quux" : 12}, "valid": false } ] }, { "description": "additionalProperties can exist by itself", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "an additional valid property is valid", "data": {"foo" : true}, "valid": true }, { "description": "an additional invalid property is invalid", "data": {"foo" : 1}, "valid": false } ] }, { "description": "additionalProperties are allowed by default", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": {"foo": {}, "bar": {}} }, "tests": [ { "description": "additional properties are allowed", "data": {"foo": 1, "bar": 2, "quux": true}, "valid": true } ] }, { "description": "additionalProperties does not look in applicators", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ {"properties": {"foo": {}}} ], "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "properties defined in allOf are not examined", "data": {"foo": 1, "bar": true}, "valid": false } ] }, { "description": "additionalProperties with null valued instance properties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": { "type": "null" } }, "tests": [ { "description": "allows null values", "data": {"foo": null}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/allOf.json0000644000175100001770000002077514653725311023157 0ustar00runnerdocker[ { "description": "allOf", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "allOf", "data": {"foo": "baz", "bar": 2}, "valid": true }, { "description": "mismatch second", "data": {"foo": "baz"}, "valid": false }, { "description": "mismatch first", "data": {"bar": 2}, "valid": false }, { "description": "wrong type", "data": {"foo": "baz", "bar": "quux"}, "valid": false } ] }, { "description": "allOf with base schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": {"bar": {"type": "integer"}}, "required": ["bar"], "allOf" : [ { "properties": { "foo": {"type": "string"} }, "required": ["foo"] }, { "properties": { "baz": {"type": "null"} }, "required": ["baz"] } ] }, "tests": [ { "description": "valid", "data": {"foo": "quux", "bar": 2, "baz": null}, "valid": true }, { "description": "mismatch base schema", "data": {"foo": "quux", "baz": null}, "valid": false }, { "description": "mismatch first allOf", "data": {"bar": 2, "baz": null}, "valid": false }, { "description": "mismatch second allOf", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "mismatch both", "data": {"bar": 2}, "valid": false } ] }, { "description": "allOf simple types", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ {"maximum": 30}, {"minimum": 20} ] }, "tests": [ { "description": "valid", "data": 25, "valid": true }, { "description": "mismatch one", "data": 35, "valid": false } ] }, { "description": "allOf with boolean schemas, all true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [true, true] }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "allOf with boolean schemas, some false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [true, false] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "allOf with boolean schemas, all false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [false, false] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "allOf with one empty schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ {} ] }, "tests": [ { "description": "any data is valid", "data": 1, "valid": true } ] }, { "description": "allOf with two empty schemas", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ {}, {} ] }, "tests": [ { "description": "any data is valid", "data": 1, "valid": true } ] }, { "description": "allOf with the first empty schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ {}, { "type": "number" } ] }, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is invalid", "data": "foo", "valid": false } ] }, { "description": "allOf with the last empty schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is invalid", "data": "foo", "valid": false } ] }, { "description": "nested allOf, to check validation semantics", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "allOf": [ { "type": "null" } ] } ] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "anything non-null is invalid", "data": 123, "valid": false } ] }, { "description": "allOf combined with anyOf, oneOf", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "multipleOf": 2 } ], "anyOf": [ { "multipleOf": 3 } ], "oneOf": [ { "multipleOf": 5 } ] }, "tests": [ { "description": "allOf: false, anyOf: false, oneOf: false", "data": 1, "valid": false }, { "description": "allOf: false, anyOf: false, oneOf: true", "data": 5, "valid": false }, { "description": "allOf: false, anyOf: true, oneOf: false", "data": 3, "valid": false }, { "description": "allOf: false, anyOf: true, oneOf: true", "data": 15, "valid": false }, { "description": "allOf: true, anyOf: false, oneOf: false", "data": 2, "valid": false }, { "description": "allOf: true, anyOf: false, oneOf: true", "data": 10, "valid": false }, { "description": "allOf: true, anyOf: true, oneOf: false", "data": 6, "valid": false }, { "description": "allOf: true, anyOf: true, oneOf: true", "data": 30, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/anchor.json0000644000175100001770000001604614653725311023370 0ustar00runnerdocker[ { "description": "Location-independent identifier", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "#foo", "$defs": { "A": { "$anchor": "foo", "type": "integer" } } }, "tests": [ { "data": 1, "description": "match", "valid": true }, { "data": "a", "description": "mismatch", "valid": false } ] }, { "description": "Location-independent identifier with absolute URI", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "http://localhost:1234/draft2020-12/bar#foo", "$defs": { "A": { "$id": "http://localhost:1234/draft2020-12/bar", "$anchor": "foo", "type": "integer" } } }, "tests": [ { "data": 1, "description": "match", "valid": true }, { "data": "a", "description": "mismatch", "valid": false } ] }, { "description": "Location-independent identifier with base URI change in subschema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/root", "$ref": "http://localhost:1234/draft2020-12/nested.json#foo", "$defs": { "A": { "$id": "nested.json", "$defs": { "B": { "$anchor": "foo", "type": "integer" } } } } }, "tests": [ { "data": 1, "description": "match", "valid": true }, { "data": "a", "description": "mismatch", "valid": false } ] }, { "description": "$anchor inside an enum is not a real identifier", "comment": "the implementation must not be confused by an $anchor buried in the enum", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "anchor_in_enum": { "enum": [ { "$anchor": "my_anchor", "type": "null" } ] }, "real_identifier_in_schema": { "$anchor": "my_anchor", "type": "string" }, "zzz_anchor_in_const": { "const": { "$anchor": "my_anchor", "type": "null" } } }, "anyOf": [ { "$ref": "#/$defs/anchor_in_enum" }, { "$ref": "#my_anchor" } ] }, "tests": [ { "description": "exact match to enum, and type matches", "data": { "$anchor": "my_anchor", "type": "null" }, "valid": true }, { "description": "in implementations that strip $anchor, this may match either $def", "data": { "type": "null" }, "valid": false }, { "description": "match $ref to $anchor", "data": "a string to match #/$defs/anchor_in_enum", "valid": true }, { "description": "no match on enum or $ref to $anchor", "data": 1, "valid": false } ] }, { "description": "same $anchor with different base uri", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/foobar", "$defs": { "A": { "$id": "child1", "allOf": [ { "$id": "child2", "$anchor": "my_anchor", "type": "number" }, { "$anchor": "my_anchor", "type": "string" } ] } }, "$ref": "child1#my_anchor" }, "tests": [ { "description": "$ref resolves to /$defs/A/allOf/1", "data": "a", "valid": true }, { "description": "$ref does not resolve to /$defs/A/allOf/0", "data": 1, "valid": false } ] }, { "description": "non-schema object containing an $anchor property", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "const_not_anchor": { "const": { "$anchor": "not_a_real_anchor" } } }, "if": { "const": "skip not_a_real_anchor" }, "then": true, "else" : { "$ref": "#/$defs/const_not_anchor" } }, "tests": [ { "description": "skip traversing definition for a valid result", "data": "skip not_a_real_anchor", "valid": true }, { "description": "const at const_not_anchor does not match", "data": 1, "valid": false } ] }, { "description": "invalid anchors", "comment": "Section 8.2.2", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "https://json-schema.org/draft/2020-12/schema" }, "tests": [ { "description": "MUST start with a letter (and not #)", "data": { "$anchor" : "#foo" }, "valid": false }, { "description": "JSON pointers are not valid", "data": { "$anchor" : "/a/b" }, "valid": false }, { "description": "invalid with valid beginning", "data": { "$anchor" : "foo#something" }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/anyOf.json0000644000175100001770000001252514653725311023170 0ustar00runnerdocker[ { "description": "anyOf", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "anyOf": [ { "type": "integer" }, { "minimum": 2 } ] }, "tests": [ { "description": "first anyOf valid", "data": 1, "valid": true }, { "description": "second anyOf valid", "data": 2.5, "valid": true }, { "description": "both anyOf valid", "data": 3, "valid": true }, { "description": "neither anyOf valid", "data": 1.5, "valid": false } ] }, { "description": "anyOf with base schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "anyOf" : [ { "maxLength": 2 }, { "minLength": 4 } ] }, "tests": [ { "description": "mismatch base schema", "data": 3, "valid": false }, { "description": "one anyOf valid", "data": "foobar", "valid": true }, { "description": "both anyOf invalid", "data": "foo", "valid": false } ] }, { "description": "anyOf with boolean schemas, all true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "anyOf": [true, true] }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "anyOf with boolean schemas, some true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "anyOf": [true, false] }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "anyOf with boolean schemas, all false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "anyOf": [false, false] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "anyOf complex types", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "anyOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "first anyOf valid (complex)", "data": {"bar": 2}, "valid": true }, { "description": "second anyOf valid (complex)", "data": {"foo": "baz"}, "valid": true }, { "description": "both anyOf valid (complex)", "data": {"foo": "baz", "bar": 2}, "valid": true }, { "description": "neither anyOf valid (complex)", "data": {"foo": 2, "bar": "quux"}, "valid": false } ] }, { "description": "anyOf with one empty schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "anyOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "string is valid", "data": "foo", "valid": true }, { "description": "number is valid", "data": 123, "valid": true } ] }, { "description": "nested anyOf, to check validation semantics", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "anyOf": [ { "anyOf": [ { "type": "null" } ] } ] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "anything non-null is invalid", "data": 123, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/boolean_schema.json0000644000175100001770000000540214653725311025047 0ustar00runnerdocker[ { "description": "boolean schema 'true'", "schema": true, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is valid", "data": "foo", "valid": true }, { "description": "boolean true is valid", "data": true, "valid": true }, { "description": "boolean false is valid", "data": false, "valid": true }, { "description": "null is valid", "data": null, "valid": true }, { "description": "object is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "empty object is valid", "data": {}, "valid": true }, { "description": "array is valid", "data": ["foo"], "valid": true }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "boolean schema 'false'", "schema": false, "tests": [ { "description": "number is invalid", "data": 1, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false }, { "description": "boolean true is invalid", "data": true, "valid": false }, { "description": "boolean false is invalid", "data": false, "valid": false }, { "description": "null is invalid", "data": null, "valid": false }, { "description": "object is invalid", "data": {"foo": "bar"}, "valid": false }, { "description": "empty object is invalid", "data": {}, "valid": false }, { "description": "array is invalid", "data": ["foo"], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/const.json0000644000175100001770000002534514653725311023246 0ustar00runnerdocker[ { "description": "const validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": 2 }, "tests": [ { "description": "same value is valid", "data": 2, "valid": true }, { "description": "another value is invalid", "data": 5, "valid": false }, { "description": "another type is invalid", "data": "a", "valid": false } ] }, { "description": "const with object", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": {"foo": "bar", "baz": "bax"} }, "tests": [ { "description": "same object is valid", "data": {"foo": "bar", "baz": "bax"}, "valid": true }, { "description": "same object with different property order is valid", "data": {"baz": "bax", "foo": "bar"}, "valid": true }, { "description": "another object is invalid", "data": {"foo": "bar"}, "valid": false }, { "description": "another type is invalid", "data": [1, 2], "valid": false } ] }, { "description": "const with array", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": [{ "foo": "bar" }] }, "tests": [ { "description": "same array is valid", "data": [{"foo": "bar"}], "valid": true }, { "description": "another array item is invalid", "data": [2], "valid": false }, { "description": "array with additional items is invalid", "data": [1, 2, 3], "valid": false } ] }, { "description": "const with null", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": null }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "not null is invalid", "data": 0, "valid": false } ] }, { "description": "const with false does not match 0", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": false }, "tests": [ { "description": "false is valid", "data": false, "valid": true }, { "description": "integer zero is invalid", "data": 0, "valid": false }, { "description": "float zero is invalid", "data": 0.0, "valid": false } ] }, { "description": "const with true does not match 1", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": true }, "tests": [ { "description": "true is valid", "data": true, "valid": true }, { "description": "integer one is invalid", "data": 1, "valid": false }, { "description": "float one is invalid", "data": 1.0, "valid": false } ] }, { "description": "const with [false] does not match [0]", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": [false] }, "tests": [ { "description": "[false] is valid", "data": [false], "valid": true }, { "description": "[0] is invalid", "data": [0], "valid": false }, { "description": "[0.0] is invalid", "data": [0.0], "valid": false } ] }, { "description": "const with [true] does not match [1]", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": [true] }, "tests": [ { "description": "[true] is valid", "data": [true], "valid": true }, { "description": "[1] is invalid", "data": [1], "valid": false }, { "description": "[1.0] is invalid", "data": [1.0], "valid": false } ] }, { "description": "const with {\"a\": false} does not match {\"a\": 0}", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": {"a": false} }, "tests": [ { "description": "{\"a\": false} is valid", "data": {"a": false}, "valid": true }, { "description": "{\"a\": 0} is invalid", "data": {"a": 0}, "valid": false }, { "description": "{\"a\": 0.0} is invalid", "data": {"a": 0.0}, "valid": false } ] }, { "description": "const with {\"a\": true} does not match {\"a\": 1}", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": {"a": true} }, "tests": [ { "description": "{\"a\": true} is valid", "data": {"a": true}, "valid": true }, { "description": "{\"a\": 1} is invalid", "data": {"a": 1}, "valid": false }, { "description": "{\"a\": 1.0} is invalid", "data": {"a": 1.0}, "valid": false } ] }, { "description": "const with 0 does not match other zero-like types", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": 0 }, "tests": [ { "description": "false is invalid", "data": false, "valid": false }, { "description": "integer zero is valid", "data": 0, "valid": true }, { "description": "float zero is valid", "data": 0.0, "valid": true }, { "description": "empty object is invalid", "data": {}, "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false }, { "description": "empty string is invalid", "data": "", "valid": false } ] }, { "description": "const with 1 does not match true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": 1 }, "tests": [ { "description": "true is invalid", "data": true, "valid": false }, { "description": "integer one is valid", "data": 1, "valid": true }, { "description": "float one is valid", "data": 1.0, "valid": true } ] }, { "description": "const with -2.0 matches integer and float types", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": -2.0 }, "tests": [ { "description": "integer -2 is valid", "data": -2, "valid": true }, { "description": "integer 2 is invalid", "data": 2, "valid": false }, { "description": "float -2.0 is valid", "data": -2.0, "valid": true }, { "description": "float 2.0 is invalid", "data": 2.0, "valid": false }, { "description": "float -2.00001 is invalid", "data": -2.00001, "valid": false } ] }, { "description": "float and integers are equal up to 64-bit representation limits", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": 9007199254740992 }, "tests": [ { "description": "integer is valid", "data": 9007199254740992, "valid": true }, { "description": "integer minus one is invalid", "data": 9007199254740991, "valid": false }, { "description": "float is valid", "data": 9007199254740992.0, "valid": true }, { "description": "float minus one is invalid", "data": 9007199254740991.0, "valid": false } ] }, { "description": "nul characters in strings", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": "hello\u0000there" }, "tests": [ { "description": "match string with nul", "data": "hello\u0000there", "valid": true }, { "description": "do not match string lacking nul", "data": "hellothere", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/contains.json0000644000175100001770000001206614653725311023732 0ustar00runnerdocker[ { "description": "contains keyword validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": {"minimum": 5} }, "tests": [ { "description": "array with item matching schema (5) is valid", "data": [3, 4, 5], "valid": true }, { "description": "array with item matching schema (6) is valid", "data": [3, 4, 6], "valid": true }, { "description": "array with two items matching schema (5, 6) is valid", "data": [3, 4, 5, 6], "valid": true }, { "description": "array without items matching schema is invalid", "data": [2, 3, 4], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false }, { "description": "not array is valid", "data": {}, "valid": true } ] }, { "description": "contains keyword with const keyword", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": { "const": 5 } }, "tests": [ { "description": "array with item 5 is valid", "data": [3, 4, 5], "valid": true }, { "description": "array with two items 5 is valid", "data": [3, 4, 5, 5], "valid": true }, { "description": "array without item 5 is invalid", "data": [1, 2, 3, 4], "valid": false } ] }, { "description": "contains keyword with boolean schema true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": true }, "tests": [ { "description": "any non-empty array is valid", "data": ["foo"], "valid": true }, { "description": "empty array is invalid", "data": [], "valid": false } ] }, { "description": "contains keyword with boolean schema false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": false }, "tests": [ { "description": "any non-empty array is invalid", "data": ["foo"], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false }, { "description": "non-arrays are valid", "data": "contains does not apply to strings", "valid": true } ] }, { "description": "items + contains", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "items": { "multipleOf": 2 }, "contains": { "multipleOf": 3 } }, "tests": [ { "description": "matches items, does not match contains", "data": [ 2, 4, 8 ], "valid": false }, { "description": "does not match items, matches contains", "data": [ 3, 6, 9 ], "valid": false }, { "description": "matches both items and contains", "data": [ 6, 12 ], "valid": true }, { "description": "matches neither items nor contains", "data": [ 1, 5 ], "valid": false } ] }, { "description": "contains with false if subschema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": { "if": false, "else": true } }, "tests": [ { "description": "any non-empty array is valid", "data": ["foo"], "valid": true }, { "description": "empty array is invalid", "data": [], "valid": false } ] }, { "description": "contains with null instance elements", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": { "type": "null" } }, "tests": [ { "description": "allows null items", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/content.json0000644000175100001770000001045514653725311023566 0ustar00runnerdocker[ { "description": "validation of string-encoded content based on media type", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contentMediaType": "application/json" }, "tests": [ { "description": "a valid JSON document", "data": "{\"foo\": \"bar\"}", "valid": true }, { "description": "an invalid JSON document; validates true", "data": "{:}", "valid": true }, { "description": "ignores non-strings", "data": 100, "valid": true } ] }, { "description": "validation of binary string-encoding", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contentEncoding": "base64" }, "tests": [ { "description": "a valid base64 string", "data": "eyJmb28iOiAiYmFyIn0K", "valid": true }, { "description": "an invalid base64 string (% is not a valid character); validates true", "data": "eyJmb28iOi%iYmFyIn0K", "valid": true }, { "description": "ignores non-strings", "data": 100, "valid": true } ] }, { "description": "validation of binary-encoded media type documents", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contentMediaType": "application/json", "contentEncoding": "base64" }, "tests": [ { "description": "a valid base64-encoded JSON document", "data": "eyJmb28iOiAiYmFyIn0K", "valid": true }, { "description": "a validly-encoded invalid JSON document; validates true", "data": "ezp9Cg==", "valid": true }, { "description": "an invalid base64 string that is valid JSON; validates true", "data": "{}", "valid": true }, { "description": "ignores non-strings", "data": 100, "valid": true } ] }, { "description": "validation of binary-encoded media type documents with schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contentMediaType": "application/json", "contentEncoding": "base64", "contentSchema": { "type": "object", "required": ["foo"], "properties": { "foo": { "type": "string" } } } }, "tests": [ { "description": "a valid base64-encoded JSON document", "data": "eyJmb28iOiAiYmFyIn0K", "valid": true }, { "description": "another valid base64-encoded JSON document", "data": "eyJib28iOiAyMCwgImZvbyI6ICJiYXoifQ==", "valid": true }, { "description": "an invalid base64-encoded JSON document; validates true", "data": "eyJib28iOiAyMH0=", "valid": true }, { "description": "an empty object as a base64-encoded JSON document; validates true", "data": "e30=", "valid": true }, { "description": "an empty array as a base64-encoded JSON document", "data": "W10=", "valid": true }, { "description": "a validly-encoded invalid JSON document; validates true", "data": "ezp9Cg==", "valid": true }, { "description": "an invalid base64 string that is valid JSON; validates true", "data": "{}", "valid": true }, { "description": "ignores non-strings", "data": 100, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/default.json0000644000175100001770000000461414653725311023540 0ustar00runnerdocker[ { "description": "invalid type for default", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": { "type": "integer", "default": [] } } }, "tests": [ { "description": "valid when property is specified", "data": {"foo": 13}, "valid": true }, { "description": "still valid when the invalid default is used", "data": {}, "valid": true } ] }, { "description": "invalid string value for default", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "bar": { "type": "string", "minLength": 4, "default": "bad" } } }, "tests": [ { "description": "valid when property is specified", "data": {"bar": "good"}, "valid": true }, { "description": "still valid when the invalid default is used", "data": {}, "valid": true } ] }, { "description": "the default keyword does not do anything if the property is missing", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "alpha": { "type": "number", "maximum": 3, "default": 5 } } }, "tests": [ { "description": "an explicit property value is checked against maximum (passing)", "data": { "alpha": 1 }, "valid": true }, { "description": "an explicit property value is checked against maximum (failing)", "data": { "alpha": 5 }, "valid": false }, { "description": "missing properties are not filled in with the default", "data": {}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/defs.json0000644000175100001770000000117514653725311023034 0ustar00runnerdocker[ { "description": "validate definition against metaschema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "https://json-schema.org/draft/2020-12/schema" }, "tests": [ { "description": "valid definition schema", "data": {"$defs": {"foo": {"type": "integer"}}}, "valid": true }, { "description": "invalid definition schema", "data": {"$defs": {"foo": {"type": 1}}}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/dependentRequired.json0000644000175100001770000001030614653725311025556 0ustar00runnerdocker[ { "description": "single dependency", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependentRequired": {"bar": ["foo"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependant", "data": {"foo": 1}, "valid": true }, { "description": "with dependency", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "missing dependency", "data": {"bar": 2}, "valid": false }, { "description": "ignores arrays", "data": ["bar"], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "empty dependents", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependentRequired": {"bar": []} }, "tests": [ { "description": "empty object", "data": {}, "valid": true }, { "description": "object with one property", "data": {"bar": 2}, "valid": true }, { "description": "non-object is valid", "data": 1, "valid": true } ] }, { "description": "multiple dependents required", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependentRequired": {"quux": ["foo", "bar"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependants", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "with dependencies", "data": {"foo": 1, "bar": 2, "quux": 3}, "valid": true }, { "description": "missing dependency", "data": {"foo": 1, "quux": 2}, "valid": false }, { "description": "missing other dependency", "data": {"bar": 1, "quux": 2}, "valid": false }, { "description": "missing both dependencies", "data": {"quux": 1}, "valid": false } ] }, { "description": "dependencies with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependentRequired": { "foo\nbar": ["foo\rbar"], "foo\"bar": ["foo'bar"] } }, "tests": [ { "description": "CRLF", "data": { "foo\nbar": 1, "foo\rbar": 2 }, "valid": true }, { "description": "quoted quotes", "data": { "foo'bar": 1, "foo\"bar": 2 }, "valid": true }, { "description": "CRLF missing dependent", "data": { "foo\nbar": 1, "foo": 2 }, "valid": false }, { "description": "quoted quotes missing dependent", "data": { "foo\"bar": 2 }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/dependentSchemas.json0000644000175100001770000000743714653725311025374 0ustar00runnerdocker[ { "description": "single dependency", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependentSchemas": { "bar": { "properties": { "foo": {"type": "integer"}, "bar": {"type": "integer"} } } } }, "tests": [ { "description": "valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "no dependency", "data": {"foo": "quux"}, "valid": true }, { "description": "wrong type", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "wrong type other", "data": {"foo": 2, "bar": "quux"}, "valid": false }, { "description": "wrong type both", "data": {"foo": "quux", "bar": "quux"}, "valid": false }, { "description": "ignores arrays", "data": ["bar"], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "boolean subschemas", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependentSchemas": { "foo": true, "bar": false } }, "tests": [ { "description": "object with property having schema true is valid", "data": {"foo": 1}, "valid": true }, { "description": "object with property having schema false is invalid", "data": {"bar": 2}, "valid": false }, { "description": "object with both properties is invalid", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "dependencies with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependentSchemas": { "foo\tbar": {"minProperties": 4}, "foo'bar": {"required": ["foo\"bar"]} } }, "tests": [ { "description": "quoted tab", "data": { "foo\tbar": 1, "a": 2, "b": 3, "c": 4 }, "valid": true }, { "description": "quoted quote", "data": { "foo'bar": {"foo\"bar": 1} }, "valid": false }, { "description": "quoted tab invalid under dependent schema", "data": { "foo\tbar": 1, "a": 2 }, "valid": false }, { "description": "quoted quote invalid under dependent schema", "data": {"foo'bar": 1}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/dynamicRef.json0000644000175100001770000005212414653725311024174 0ustar00runnerdocker[ { "description": "A $dynamicRef to a $dynamicAnchor in the same schema resource behaves like a normal $ref to an $anchor", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/dynamicRef-dynamicAnchor-same-schema/root", "type": "array", "items": { "$dynamicRef": "#items" }, "$defs": { "foo": { "$dynamicAnchor": "items", "type": "string" } } }, "tests": [ { "description": "An array of strings is valid", "data": ["foo", "bar"], "valid": true }, { "description": "An array containing non-strings is invalid", "data": ["foo", 42], "valid": false } ] }, { "description": "A $dynamicRef to an $anchor in the same schema resource behaves like a normal $ref to an $anchor", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/dynamicRef-anchor-same-schema/root", "type": "array", "items": { "$dynamicRef": "#items" }, "$defs": { "foo": { "$anchor": "items", "type": "string" } } }, "tests": [ { "description": "An array of strings is valid", "data": ["foo", "bar"], "valid": true }, { "description": "An array containing non-strings is invalid", "data": ["foo", 42], "valid": false } ] }, { "description": "A $ref to a $dynamicAnchor in the same schema resource behaves like a normal $ref to an $anchor", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/ref-dynamicAnchor-same-schema/root", "type": "array", "items": { "$ref": "#items" }, "$defs": { "foo": { "$dynamicAnchor": "items", "type": "string" } } }, "tests": [ { "description": "An array of strings is valid", "data": ["foo", "bar"], "valid": true }, { "description": "An array containing non-strings is invalid", "data": ["foo", 42], "valid": false } ] }, { "description": "A $dynamicRef resolves to the first $dynamicAnchor still in scope that is encountered when the schema is evaluated", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/typical-dynamic-resolution/root", "$ref": "list", "$defs": { "foo": { "$dynamicAnchor": "items", "type": "string" }, "list": { "$id": "list", "type": "array", "items": { "$dynamicRef": "#items" }, "$defs": { "items": { "$comment": "This is only needed to satisfy the bookending requirement", "$dynamicAnchor": "items" } } } } }, "tests": [ { "description": "An array of strings is valid", "data": ["foo", "bar"], "valid": true }, { "description": "An array containing non-strings is invalid", "data": ["foo", 42], "valid": false } ] }, { "description": "A $dynamicRef with intermediate scopes that don't include a matching $dynamicAnchor does not affect dynamic scope resolution", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/dynamic-resolution-with-intermediate-scopes/root", "$ref": "intermediate-scope", "$defs": { "foo": { "$dynamicAnchor": "items", "type": "string" }, "intermediate-scope": { "$id": "intermediate-scope", "$ref": "list" }, "list": { "$id": "list", "type": "array", "items": { "$dynamicRef": "#items" }, "$defs": { "items": { "$comment": "This is only needed to satisfy the bookending requirement", "$dynamicAnchor": "items" } } } } }, "tests": [ { "description": "An array of strings is valid", "data": ["foo", "bar"], "valid": true }, { "description": "An array containing non-strings is invalid", "data": ["foo", 42], "valid": false } ] }, { "description": "An $anchor with the same name as a $dynamicAnchor is not used for dynamic scope resolution", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/dynamic-resolution-ignores-anchors/root", "$ref": "list", "$defs": { "foo": { "$anchor": "items", "type": "string" }, "list": { "$id": "list", "type": "array", "items": { "$dynamicRef": "#items" }, "$defs": { "items": { "$comment": "This is only needed to satisfy the bookending requirement", "$dynamicAnchor": "items" } } } } }, "tests": [ { "description": "Any array is valid", "data": ["foo", 42], "valid": true } ] }, { "description": "A $dynamicRef without a matching $dynamicAnchor in the same schema resource behaves like a normal $ref to $anchor", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/dynamic-resolution-without-bookend/root", "$ref": "list", "$defs": { "foo": { "$dynamicAnchor": "items", "type": "string" }, "list": { "$id": "list", "type": "array", "items": { "$dynamicRef": "#items" }, "$defs": { "items": { "$comment": "This is only needed to give the reference somewhere to resolve to when it behaves like $ref", "$anchor": "items" } } } } }, "tests": [ { "description": "Any array is valid", "data": ["foo", 42], "valid": true } ] }, { "description": "A $dynamicRef with a non-matching $dynamicAnchor in the same schema resource behaves like a normal $ref to $anchor", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/unmatched-dynamic-anchor/root", "$ref": "list", "$defs": { "foo": { "$dynamicAnchor": "items", "type": "string" }, "list": { "$id": "list", "type": "array", "items": { "$dynamicRef": "#items" }, "$defs": { "items": { "$comment": "This is only needed to give the reference somewhere to resolve to when it behaves like $ref", "$anchor": "items", "$dynamicAnchor": "foo" } } } } }, "tests": [ { "description": "Any array is valid", "data": ["foo", 42], "valid": true } ] }, { "description": "A $dynamicRef that initially resolves to a schema with a matching $dynamicAnchor resolves to the first $dynamicAnchor in the dynamic scope", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/relative-dynamic-reference/root", "$dynamicAnchor": "meta", "type": "object", "properties": { "foo": { "const": "pass" } }, "$ref": "extended", "$defs": { "extended": { "$id": "extended", "$dynamicAnchor": "meta", "type": "object", "properties": { "bar": { "$ref": "bar" } } }, "bar": { "$id": "bar", "type": "object", "properties": { "baz": { "$dynamicRef": "extended#meta" } } } } }, "tests": [ { "description": "The recursive part is valid against the root", "data": { "foo": "pass", "bar": { "baz": { "foo": "pass" } } }, "valid": true }, { "description": "The recursive part is not valid against the root", "data": { "foo": "pass", "bar": { "baz": { "foo": "fail" } } }, "valid": false } ] }, { "description": "A $dynamicRef that initially resolves to a schema without a matching $dynamicAnchor behaves like a normal $ref to $anchor", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/relative-dynamic-reference-without-bookend/root", "$dynamicAnchor": "meta", "type": "object", "properties": { "foo": { "const": "pass" } }, "$ref": "extended", "$defs": { "extended": { "$id": "extended", "$anchor": "meta", "type": "object", "properties": { "bar": { "$ref": "bar" } } }, "bar": { "$id": "bar", "type": "object", "properties": { "baz": { "$dynamicRef": "extended#meta" } } } } }, "tests": [ { "description": "The recursive part doesn't need to validate against the root", "data": { "foo": "pass", "bar": { "baz": { "foo": "fail" } } }, "valid": true } ] }, { "description": "multiple dynamic paths to the $dynamicRef keyword", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/dynamic-ref-with-multiple-paths/main", "$defs": { "inner": { "$id": "inner", "$dynamicAnchor": "foo", "title": "inner", "additionalProperties": { "$dynamicRef": "#foo" } } }, "if": { "propertyNames": { "pattern": "^[a-m]" } }, "then": { "title": "any type of node", "$id": "anyLeafNode", "$dynamicAnchor": "foo", "$ref": "inner" }, "else": { "title": "integer node", "$id": "integerNode", "$dynamicAnchor": "foo", "type": [ "object", "integer" ], "$ref": "inner" } }, "tests": [ { "description": "recurse to anyLeafNode - floats are allowed", "data": { "alpha": 1.1 }, "valid": true }, { "description": "recurse to integerNode - floats are not allowed", "data": { "november": 1.1 }, "valid": false } ] }, { "description": "after leaving a dynamic scope, it is not used by a $dynamicRef", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/dynamic-ref-leaving-dynamic-scope/main", "if": { "$id": "first_scope", "$defs": { "thingy": { "$comment": "this is first_scope#thingy", "$dynamicAnchor": "thingy", "type": "number" } } }, "then": { "$id": "second_scope", "$ref": "start", "$defs": { "thingy": { "$comment": "this is second_scope#thingy, the final destination of the $dynamicRef", "$dynamicAnchor": "thingy", "type": "null" } } }, "$defs": { "start": { "$comment": "this is the landing spot from $ref", "$id": "start", "$dynamicRef": "inner_scope#thingy" }, "thingy": { "$comment": "this is the first stop for the $dynamicRef", "$id": "inner_scope", "$dynamicAnchor": "thingy", "type": "string" } } }, "tests": [ { "description": "string matches /$defs/thingy, but the $dynamicRef does not stop here", "data": "a string", "valid": false }, { "description": "first_scope is not in dynamic scope for the $dynamicRef", "data": 42, "valid": false }, { "description": "/then/$defs/thingy is the final stop for the $dynamicRef", "data": null, "valid": true } ] }, { "description": "strict-tree schema, guards against misspelled properties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/strict-tree.json", "$dynamicAnchor": "node", "$ref": "tree.json", "unevaluatedProperties": false }, "tests": [ { "description": "instance with misspelled field", "data": { "children": [{ "daat": 1 }] }, "valid": false }, { "description": "instance with correct field", "data": { "children": [{ "data": 1 }] }, "valid": true } ] }, { "description": "tests for implementation dynamic anchor and reference link", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/strict-extendible.json", "$ref": "extendible-dynamic-ref.json", "$defs": { "elements": { "$dynamicAnchor": "elements", "properties": { "a": true }, "required": ["a"], "additionalProperties": false } } }, "tests": [ { "description": "incorrect parent schema", "data": { "a": true }, "valid": false }, { "description": "incorrect extended schema", "data": { "elements": [ { "b": 1 } ] }, "valid": false }, { "description": "correct extended schema", "data": { "elements": [ { "a": 1 } ] }, "valid": true } ] }, { "description": "$ref and $dynamicAnchor are independent of order - $defs first", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/strict-extendible-allof-defs-first.json", "allOf": [ { "$ref": "extendible-dynamic-ref.json" }, { "$defs": { "elements": { "$dynamicAnchor": "elements", "properties": { "a": true }, "required": ["a"], "additionalProperties": false } } } ] }, "tests": [ { "description": "incorrect parent schema", "data": { "a": true }, "valid": false }, { "description": "incorrect extended schema", "data": { "elements": [ { "b": 1 } ] }, "valid": false }, { "description": "correct extended schema", "data": { "elements": [ { "a": 1 } ] }, "valid": true } ] }, { "description": "$ref and $dynamicAnchor are independent of order - $ref first", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/strict-extendible-allof-ref-first.json", "allOf": [ { "$defs": { "elements": { "$dynamicAnchor": "elements", "properties": { "a": true }, "required": ["a"], "additionalProperties": false } } }, { "$ref": "extendible-dynamic-ref.json" } ] }, "tests": [ { "description": "incorrect parent schema", "data": { "a": true }, "valid": false }, { "description": "incorrect extended schema", "data": { "elements": [ { "b": 1 } ] }, "valid": false }, { "description": "correct extended schema", "data": { "elements": [ { "a": 1 } ] }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/enum.json0000644000175100001770000001642514653725311023063 0ustar00runnerdocker[ { "description": "simple enum validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "enum": [1, 2, 3] }, "tests": [ { "description": "one of the enum is valid", "data": 1, "valid": true }, { "description": "something else is invalid", "data": 4, "valid": false } ] }, { "description": "heterogeneous enum validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "enum": [6, "foo", [], true, {"foo": 12}] }, "tests": [ { "description": "one of the enum is valid", "data": [], "valid": true }, { "description": "something else is invalid", "data": null, "valid": false }, { "description": "objects are deep compared", "data": {"foo": false}, "valid": false }, { "description": "valid object matches", "data": {"foo": 12}, "valid": true }, { "description": "extra properties in object is invalid", "data": {"foo": 12, "boo": 42}, "valid": false } ] }, { "description": "heterogeneous enum-with-null validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "enum": [6, null] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "number is valid", "data": 6, "valid": true }, { "description": "something else is invalid", "data": "test", "valid": false } ] }, { "description": "enums in properties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type":"object", "properties": { "foo": {"enum":["foo"]}, "bar": {"enum":["bar"]} }, "required": ["bar"] }, "tests": [ { "description": "both properties are valid", "data": {"foo":"foo", "bar":"bar"}, "valid": true }, { "description": "wrong foo value", "data": {"foo":"foot", "bar":"bar"}, "valid": false }, { "description": "wrong bar value", "data": {"foo":"foo", "bar":"bart"}, "valid": false }, { "description": "missing optional property is valid", "data": {"bar":"bar"}, "valid": true }, { "description": "missing required property is invalid", "data": {"foo":"foo"}, "valid": false }, { "description": "missing all properties is invalid", "data": {}, "valid": false } ] }, { "description": "enum with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "enum": ["foo\nbar", "foo\rbar"] }, "tests": [ { "description": "member 1 is valid", "data": "foo\nbar", "valid": true }, { "description": "member 2 is valid", "data": "foo\rbar", "valid": true }, { "description": "another string is invalid", "data": "abc", "valid": false } ] }, { "description": "enum with false does not match 0", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "enum": [false] }, "tests": [ { "description": "false is valid", "data": false, "valid": true }, { "description": "integer zero is invalid", "data": 0, "valid": false }, { "description": "float zero is invalid", "data": 0.0, "valid": false } ] }, { "description": "enum with true does not match 1", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "enum": [true] }, "tests": [ { "description": "true is valid", "data": true, "valid": true }, { "description": "integer one is invalid", "data": 1, "valid": false }, { "description": "float one is invalid", "data": 1.0, "valid": false } ] }, { "description": "enum with 0 does not match false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "enum": [0] }, "tests": [ { "description": "false is invalid", "data": false, "valid": false }, { "description": "integer zero is valid", "data": 0, "valid": true }, { "description": "float zero is valid", "data": 0.0, "valid": true } ] }, { "description": "enum with 1 does not match true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "enum": [1] }, "tests": [ { "description": "true is invalid", "data": true, "valid": false }, { "description": "integer one is valid", "data": 1, "valid": true }, { "description": "float one is valid", "data": 1.0, "valid": true } ] }, { "description": "nul characters in strings", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "enum": [ "hello\u0000there" ] }, "tests": [ { "description": "match string with nul", "data": "hello\u0000there", "valid": true }, { "description": "do not match string lacking nul", "data": "hellothere", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/exclusiveMaximum.json0000644000175100001770000000151614653725311025457 0ustar00runnerdocker[ { "description": "exclusiveMaximum validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "exclusiveMaximum": 3.0 }, "tests": [ { "description": "below the exclusiveMaximum is valid", "data": 2.2, "valid": true }, { "description": "boundary point is invalid", "data": 3.0, "valid": false }, { "description": "above the exclusiveMaximum is invalid", "data": 3.5, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/exclusiveMinimum.json0000644000175100001770000000151614653725311025455 0ustar00runnerdocker[ { "description": "exclusiveMinimum validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "exclusiveMinimum": 1.1 }, "tests": [ { "description": "above the exclusiveMinimum is valid", "data": 1.2, "valid": true }, { "description": "boundary point is invalid", "data": 1.1, "valid": false }, { "description": "below the exclusiveMinimum is invalid", "data": 0.6, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/format.json0000644000175100001770000005263014653725311023405 0ustar00runnerdocker[ { "description": "email format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "idn-email format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "idn-email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "regex format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "regex" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "ipv4 format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "ipv4" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "ipv6 format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "ipv6" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "idn-hostname format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "idn-hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "hostname format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "date format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "date" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "date-time format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "date-time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "time format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "json-pointer format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "json-pointer" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "relative-json-pointer format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "relative-json-pointer" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "iri format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "iri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "iri-reference format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "iri-reference" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uri format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "uri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uri-reference format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "uri-reference" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uri-template format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "uri-template" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uuid format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "uuid" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "duration format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "duration" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/id.json0000644000175100001770000002406614653725311022513 0ustar00runnerdocker[ { "description": "Invalid use of fragments in location-independent $id", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "https://json-schema.org/draft/2020-12/schema" }, "tests": [ { "description": "Identifier name", "data": { "$ref": "#foo", "$defs": { "A": { "$id": "#foo", "type": "integer" } } }, "valid": false }, { "description": "Identifier name and no ref", "data": { "$defs": { "A": { "$id": "#foo" } } }, "valid": false }, { "description": "Identifier path", "data": { "$ref": "#/a/b", "$defs": { "A": { "$id": "#/a/b", "type": "integer" } } }, "valid": false }, { "description": "Identifier name with absolute URI", "data": { "$ref": "http://localhost:1234/draft2020-12/bar#foo", "$defs": { "A": { "$id": "http://localhost:1234/draft2020-12/bar#foo", "type": "integer" } } }, "valid": false }, { "description": "Identifier path with absolute URI", "data": { "$ref": "http://localhost:1234/draft2020-12/bar#/a/b", "$defs": { "A": { "$id": "http://localhost:1234/draft2020-12/bar#/a/b", "type": "integer" } } }, "valid": false }, { "description": "Identifier name with base URI change in subschema", "data": { "$id": "http://localhost:1234/draft2020-12/root", "$ref": "http://localhost:1234/draft2020-12/nested.json#foo", "$defs": { "A": { "$id": "nested.json", "$defs": { "B": { "$id": "#foo", "type": "integer" } } } } }, "valid": false }, { "description": "Identifier path with base URI change in subschema", "data": { "$id": "http://localhost:1234/draft2020-12/root", "$ref": "http://localhost:1234/draft2020-12/nested.json#/a/b", "$defs": { "A": { "$id": "nested.json", "$defs": { "B": { "$id": "#/a/b", "type": "integer" } } } } }, "valid": false } ] }, { "description": "Valid use of empty fragments in location-independent $id", "comment": "These are allowed but discouraged", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "https://json-schema.org/draft/2020-12/schema" }, "tests": [ { "description": "Identifier name with absolute URI", "data": { "$ref": "http://localhost:1234/draft2020-12/bar", "$defs": { "A": { "$id": "http://localhost:1234/draft2020-12/bar#", "type": "integer" } } }, "valid": true }, { "description": "Identifier name with base URI change in subschema", "data": { "$id": "http://localhost:1234/draft2020-12/root", "$ref": "http://localhost:1234/draft2020-12/nested.json#/$defs/B", "$defs": { "A": { "$id": "nested.json", "$defs": { "B": { "$id": "#", "type": "integer" } } } } }, "valid": true } ] }, { "description": "Unnormalized $ids are allowed but discouraged", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "https://json-schema.org/draft/2020-12/schema" }, "tests": [ { "description": "Unnormalized identifier", "data": { "$ref": "http://localhost:1234/draft2020-12/foo/baz", "$defs": { "A": { "$id": "http://localhost:1234/draft2020-12/foo/bar/../baz", "type": "integer" } } }, "valid": true }, { "description": "Unnormalized identifier and no ref", "data": { "$defs": { "A": { "$id": "http://localhost:1234/draft2020-12/foo/bar/../baz", "type": "integer" } } }, "valid": true }, { "description": "Unnormalized identifier with empty fragment", "data": { "$ref": "http://localhost:1234/draft2020-12/foo/baz", "$defs": { "A": { "$id": "http://localhost:1234/draft2020-12/foo/bar/../baz#", "type": "integer" } } }, "valid": true }, { "description": "Unnormalized identifier with empty fragment and no ref", "data": { "$defs": { "A": { "$id": "http://localhost:1234/draft2020-12/foo/bar/../baz#", "type": "integer" } } }, "valid": true } ] }, { "description": "$id inside an enum is not a real identifier", "comment": "the implementation must not be confused by an $id buried in the enum", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "id_in_enum": { "enum": [ { "$id": "https://localhost:1234/draft2020-12/id/my_identifier.json", "type": "null" } ] }, "real_id_in_schema": { "$id": "https://localhost:1234/draft2020-12/id/my_identifier.json", "type": "string" }, "zzz_id_in_const": { "const": { "$id": "https://localhost:1234/draft2020-12/id/my_identifier.json", "type": "null" } } }, "anyOf": [ { "$ref": "#/$defs/id_in_enum" }, { "$ref": "https://localhost:1234/draft2020-12/id/my_identifier.json" } ] }, "tests": [ { "description": "exact match to enum, and type matches", "data": { "$id": "https://localhost:1234/draft2020-12/id/my_identifier.json", "type": "null" }, "valid": true }, { "description": "match $ref to $id", "data": "a string to match #/$defs/id_in_enum", "valid": true }, { "description": "no match on enum or $ref to $id", "data": 1, "valid": false } ] }, { "description": "non-schema object containing an $id property", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "const_not_id": { "const": { "$id": "not_a_real_id" } } }, "if": { "const": "skip not_a_real_id" }, "then": true, "else" : { "$ref": "#/$defs/const_not_id" } }, "tests": [ { "description": "skip traversing definition for a valid result", "data": "skip not_a_real_id", "valid": true }, { "description": "const at const_not_id does not match", "data": 1, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/if-then-else.json0000644000175100001770000001663014653725311024375 0ustar00runnerdocker[ { "description": "ignore if without then or else", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "if": { "const": 0 } }, "tests": [ { "description": "valid when valid against lone if", "data": 0, "valid": true }, { "description": "valid when invalid against lone if", "data": "hello", "valid": true } ] }, { "description": "ignore then without if", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "then": { "const": 0 } }, "tests": [ { "description": "valid when valid against lone then", "data": 0, "valid": true }, { "description": "valid when invalid against lone then", "data": "hello", "valid": true } ] }, { "description": "ignore else without if", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "else": { "const": 0 } }, "tests": [ { "description": "valid when valid against lone else", "data": 0, "valid": true }, { "description": "valid when invalid against lone else", "data": "hello", "valid": true } ] }, { "description": "if and then without else", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "if": { "exclusiveMaximum": 0 }, "then": { "minimum": -10 } }, "tests": [ { "description": "valid through then", "data": -1, "valid": true }, { "description": "invalid through then", "data": -100, "valid": false }, { "description": "valid when if test fails", "data": 3, "valid": true } ] }, { "description": "if and else without then", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "if": { "exclusiveMaximum": 0 }, "else": { "multipleOf": 2 } }, "tests": [ { "description": "valid when if test passes", "data": -1, "valid": true }, { "description": "valid through else", "data": 4, "valid": true }, { "description": "invalid through else", "data": 3, "valid": false } ] }, { "description": "validate against correct branch, then vs else", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "if": { "exclusiveMaximum": 0 }, "then": { "minimum": -10 }, "else": { "multipleOf": 2 } }, "tests": [ { "description": "valid through then", "data": -1, "valid": true }, { "description": "invalid through then", "data": -100, "valid": false }, { "description": "valid through else", "data": 4, "valid": true }, { "description": "invalid through else", "data": 3, "valid": false } ] }, { "description": "non-interference across combined schemas", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "if": { "exclusiveMaximum": 0 } }, { "then": { "minimum": -10 } }, { "else": { "multipleOf": 2 } } ] }, "tests": [ { "description": "valid, but would have been invalid through then", "data": -100, "valid": true }, { "description": "valid, but would have been invalid through else", "data": 3, "valid": true } ] }, { "description": "if with boolean schema true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "if": true, "then": { "const": "then" }, "else": { "const": "else" } }, "tests": [ { "description": "boolean schema true in if always chooses the then path (valid)", "data": "then", "valid": true }, { "description": "boolean schema true in if always chooses the then path (invalid)", "data": "else", "valid": false } ] }, { "description": "if with boolean schema false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "if": false, "then": { "const": "then" }, "else": { "const": "else" } }, "tests": [ { "description": "boolean schema false in if always chooses the else path (invalid)", "data": "then", "valid": false }, { "description": "boolean schema false in if always chooses the else path (valid)", "data": "else", "valid": true } ] }, { "description": "if appears at the end when serialized (keyword processing sequence)", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "then": { "const": "yes" }, "else": { "const": "other" }, "if": { "maxLength": 4 } }, "tests": [ { "description": "yes redirects to then and passes", "data": "yes", "valid": true }, { "description": "other redirects to else and passes", "data": "other", "valid": true }, { "description": "no redirects to then and fails", "data": "no", "valid": false }, { "description": "invalid redirects to else and fails", "data": "invalid", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/infinite-loop-detection.json0000644000175100001770000000203314653725311026635 0ustar00runnerdocker[ { "description": "evaluating the same schema location against the same data location twice is not a sign of an infinite loop", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "int": { "type": "integer" } }, "allOf": [ { "properties": { "foo": { "$ref": "#/$defs/int" } } }, { "additionalProperties": { "$ref": "#/$defs/int" } } ] }, "tests": [ { "description": "passing case", "data": { "foo": 1 }, "valid": true }, { "description": "failing case", "data": { "foo": "a string" }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/items.json0000644000175100001770000002067414653725311023241 0ustar00runnerdocker[ { "description": "a schema given for items", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "items": {"type": "integer"} }, "tests": [ { "description": "valid items", "data": [ 1, 2, 3 ], "valid": true }, { "description": "wrong type of items", "data": [1, "x"], "valid": false }, { "description": "ignores non-arrays", "data": {"foo" : "bar"}, "valid": true }, { "description": "JavaScript pseudo-array is valid", "data": { "0": "invalid", "length": 1 }, "valid": true } ] }, { "description": "items with boolean schema (true)", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "items": true }, "tests": [ { "description": "any array is valid", "data": [ 1, "foo", true ], "valid": true }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "items with boolean schema (false)", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "items": false }, "tests": [ { "description": "any non-empty array is invalid", "data": [ 1, "foo", true ], "valid": false }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "items and subitems", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "item": { "type": "array", "items": false, "prefixItems": [ { "$ref": "#/$defs/sub-item" }, { "$ref": "#/$defs/sub-item" } ] }, "sub-item": { "type": "object", "required": ["foo"] } }, "type": "array", "items": false, "prefixItems": [ { "$ref": "#/$defs/item" }, { "$ref": "#/$defs/item" }, { "$ref": "#/$defs/item" } ] }, "tests": [ { "description": "valid items", "data": [ [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": true }, { "description": "too many items", "data": [ [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "too many sub-items", "data": [ [ {"foo": null}, {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "wrong item", "data": [ {"foo": null}, [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "wrong sub-item", "data": [ [ {}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "fewer items is valid", "data": [ [ {"foo": null} ], [ {"foo": null} ] ], "valid": true } ] }, { "description": "nested items", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "array", "items": { "type": "array", "items": { "type": "array", "items": { "type": "array", "items": { "type": "number" } } } } }, "tests": [ { "description": "valid nested array", "data": [[[[1]], [[2],[3]]], [[[4], [5], [6]]]], "valid": true }, { "description": "nested array with invalid type", "data": [[[["1"]], [[2],[3]]], [[[4], [5], [6]]]], "valid": false }, { "description": "not deep enough", "data": [[[1], [2],[3]], [[4], [5], [6]]], "valid": false } ] }, { "description": "prefixItems with no additional items allowed", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [{}, {}, {}], "items": false }, "tests": [ { "description": "empty array", "data": [ ], "valid": true }, { "description": "fewer number of items present (1)", "data": [ 1 ], "valid": true }, { "description": "fewer number of items present (2)", "data": [ 1, 2 ], "valid": true }, { "description": "equal number of items present", "data": [ 1, 2, 3 ], "valid": true }, { "description": "additional items are not permitted", "data": [ 1, 2, 3, 4 ], "valid": false } ] }, { "description": "items does not look in applicators, valid case", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "prefixItems": [ { "minimum": 3 } ] } ], "items": { "minimum": 5 } }, "tests": [ { "description": "prefixItems in allOf does not constrain items, invalid case", "data": [ 3, 5 ], "valid": false }, { "description": "prefixItems in allOf does not constrain items, valid case", "data": [ 5, 5 ], "valid": true } ] }, { "description": "prefixItems validation adjusts the starting index for items", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [ { "type": "string" } ], "items": { "type": "integer" } }, "tests": [ { "description": "valid items", "data": [ "x", 2, 3 ], "valid": true }, { "description": "wrong type of second item", "data": [ "x", "y" ], "valid": false } ] }, { "description": "items with null instance elements", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "items": { "type": "null" } }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/maxContains.json0000644000175100001770000000574614653725311024407 0ustar00runnerdocker[ { "description": "maxContains without contains is ignored", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "maxContains": 1 }, "tests": [ { "description": "one item valid against lone maxContains", "data": [ 1 ], "valid": true }, { "description": "two items still valid against lone maxContains", "data": [ 1, 2 ], "valid": true } ] }, { "description": "maxContains with contains", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": {"const": 1}, "maxContains": 1 }, "tests": [ { "description": "empty data", "data": [ ], "valid": false }, { "description": "all elements match, valid maxContains", "data": [ 1 ], "valid": true }, { "description": "all elements match, invalid maxContains", "data": [ 1, 1 ], "valid": false }, { "description": "some elements match, valid maxContains", "data": [ 1, 2 ], "valid": true }, { "description": "some elements match, invalid maxContains", "data": [ 1, 2, 1 ], "valid": false } ] }, { "description": "maxContains with contains, value with a decimal", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": {"const": 1}, "maxContains": 1.0 }, "tests": [ { "description": "one element matches, valid maxContains", "data": [ 1 ], "valid": true }, { "description": "too many elements match, invalid maxContains", "data": [ 1, 1 ], "valid": false } ] }, { "description": "minContains < maxContains", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": {"const": 1}, "minContains": 1, "maxContains": 3 }, "tests": [ { "description": "actual < minContains < maxContains", "data": [ ], "valid": false }, { "description": "minContains < actual < maxContains", "data": [ 1, 1 ], "valid": true }, { "description": "minContains < maxContains < actual", "data": [ 1, 1, 1, 1 ], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/maxItems.json0000644000175100001770000000244714653725311023705 0ustar00runnerdocker[ { "description": "maxItems validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "maxItems": 2 }, "tests": [ { "description": "shorter is valid", "data": [1], "valid": true }, { "description": "exact length is valid", "data": [1, 2], "valid": true }, { "description": "too long is invalid", "data": [1, 2, 3], "valid": false }, { "description": "ignores non-arrays", "data": "foobar", "valid": true } ] }, { "description": "maxItems validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "maxItems": 2.0 }, "tests": [ { "description": "shorter is valid", "data": [1], "valid": true }, { "description": "too long is invalid", "data": [1, 2, 3], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/maxLength.json0000644000175100001770000000274314653725311024044 0ustar00runnerdocker[ { "description": "maxLength validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "maxLength": 2 }, "tests": [ { "description": "shorter is valid", "data": "f", "valid": true }, { "description": "exact length is valid", "data": "fo", "valid": true }, { "description": "too long is invalid", "data": "foo", "valid": false }, { "description": "ignores non-strings", "data": 100, "valid": true }, { "description": "two supplementary Unicode code points is long enough", "data": "\uD83D\uDCA9\uD83D\uDCA9", "valid": true } ] }, { "description": "maxLength validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "maxLength": 2.0 }, "tests": [ { "description": "shorter is valid", "data": "f", "valid": true }, { "description": "too long is invalid", "data": "foo", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/maxProperties.json0000644000175100001770000000430014653725311024746 0ustar00runnerdocker[ { "description": "maxProperties validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "maxProperties": 2 }, "tests": [ { "description": "shorter is valid", "data": {"foo": 1}, "valid": true }, { "description": "exact length is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "too long is invalid", "data": {"foo": 1, "bar": 2, "baz": 3}, "valid": false }, { "description": "ignores arrays", "data": [1, 2, 3], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "maxProperties validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "maxProperties": 2.0 }, "tests": [ { "description": "shorter is valid", "data": {"foo": 1}, "valid": true }, { "description": "too long is invalid", "data": {"foo": 1, "bar": 2, "baz": 3}, "valid": false } ] }, { "description": "maxProperties = 0 means the object is empty", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "maxProperties": 0 }, "tests": [ { "description": "no properties is valid", "data": {}, "valid": true }, { "description": "one property is invalid", "data": { "foo": 1 }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/maximum.json0000644000175100001770000000317614653725311023573 0ustar00runnerdocker[ { "description": "maximum validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "maximum": 3.0 }, "tests": [ { "description": "below the maximum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 3.0, "valid": true }, { "description": "above the maximum is invalid", "data": 3.5, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] }, { "description": "maximum validation with unsigned integer", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "maximum": 300 }, "tests": [ { "description": "below the maximum is invalid", "data": 299.97, "valid": true }, { "description": "boundary point integer is valid", "data": 300, "valid": true }, { "description": "boundary point float is valid", "data": 300.00, "valid": true }, { "description": "above the maximum is invalid", "data": 300.5, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/minContains.json0000644000175100001770000001471414653725311024400 0ustar00runnerdocker[ { "description": "minContains without contains is ignored", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "minContains": 1 }, "tests": [ { "description": "one item valid against lone minContains", "data": [ 1 ], "valid": true }, { "description": "zero items still valid against lone minContains", "data": [], "valid": true } ] }, { "description": "minContains=1 with contains", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": {"const": 1}, "minContains": 1 }, "tests": [ { "description": "empty data", "data": [ ], "valid": false }, { "description": "no elements match", "data": [ 2 ], "valid": false }, { "description": "single element matches, valid minContains", "data": [ 1 ], "valid": true }, { "description": "some elements match, valid minContains", "data": [ 1, 2 ], "valid": true }, { "description": "all elements match, valid minContains", "data": [ 1, 1 ], "valid": true } ] }, { "description": "minContains=2 with contains", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": {"const": 1}, "minContains": 2 }, "tests": [ { "description": "empty data", "data": [ ], "valid": false }, { "description": "all elements match, invalid minContains", "data": [ 1 ], "valid": false }, { "description": "some elements match, invalid minContains", "data": [ 1, 2 ], "valid": false }, { "description": "all elements match, valid minContains (exactly as needed)", "data": [ 1, 1 ], "valid": true }, { "description": "all elements match, valid minContains (more than needed)", "data": [ 1, 1, 1 ], "valid": true }, { "description": "some elements match, valid minContains", "data": [ 1, 2, 1 ], "valid": true } ] }, { "description": "minContains=2 with contains with a decimal value", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": {"const": 1}, "minContains": 2.0 }, "tests": [ { "description": "one element matches, invalid minContains", "data": [ 1 ], "valid": false }, { "description": "both elements match, valid minContains", "data": [ 1, 1 ], "valid": true } ] }, { "description": "maxContains = minContains", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": {"const": 1}, "maxContains": 2, "minContains": 2 }, "tests": [ { "description": "empty data", "data": [ ], "valid": false }, { "description": "all elements match, invalid minContains", "data": [ 1 ], "valid": false }, { "description": "all elements match, invalid maxContains", "data": [ 1, 1, 1 ], "valid": false }, { "description": "all elements match, valid maxContains and minContains", "data": [ 1, 1 ], "valid": true } ] }, { "description": "maxContains < minContains", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": {"const": 1}, "maxContains": 1, "minContains": 3 }, "tests": [ { "description": "empty data", "data": [ ], "valid": false }, { "description": "invalid minContains", "data": [ 1 ], "valid": false }, { "description": "invalid maxContains", "data": [ 1, 1, 1 ], "valid": false }, { "description": "invalid maxContains and minContains", "data": [ 1, 1 ], "valid": false } ] }, { "description": "minContains = 0", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": {"const": 1}, "minContains": 0 }, "tests": [ { "description": "empty data", "data": [ ], "valid": true }, { "description": "minContains = 0 makes contains always pass", "data": [ 2 ], "valid": true } ] }, { "description": "minContains = 0 with maxContains", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": {"const": 1}, "minContains": 0, "maxContains": 1 }, "tests": [ { "description": "empty data", "data": [ ], "valid": true }, { "description": "not more than maxContains", "data": [ 1 ], "valid": true }, { "description": "too many", "data": [ 1, 1 ], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/minItems.json0000644000175100001770000000242614653725311023700 0ustar00runnerdocker[ { "description": "minItems validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "minItems": 1 }, "tests": [ { "description": "longer is valid", "data": [1, 2], "valid": true }, { "description": "exact length is valid", "data": [1], "valid": true }, { "description": "too short is invalid", "data": [], "valid": false }, { "description": "ignores non-arrays", "data": "", "valid": true } ] }, { "description": "minItems validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "minItems": 1.0 }, "tests": [ { "description": "longer is valid", "data": [1, 2], "valid": true }, { "description": "too short is invalid", "data": [], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/minLength.json0000644000175100001770000000273114653725311024037 0ustar00runnerdocker[ { "description": "minLength validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "minLength": 2 }, "tests": [ { "description": "longer is valid", "data": "foo", "valid": true }, { "description": "exact length is valid", "data": "fo", "valid": true }, { "description": "too short is invalid", "data": "f", "valid": false }, { "description": "ignores non-strings", "data": 1, "valid": true }, { "description": "one supplementary Unicode code point is not long enough", "data": "\uD83D\uDCA9", "valid": false } ] }, { "description": "minLength validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "minLength": 2.0 }, "tests": [ { "description": "longer is valid", "data": "foo", "valid": true }, { "description": "too short is invalid", "data": "f", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/minProperties.json0000644000175100001770000000314514653725311024752 0ustar00runnerdocker[ { "description": "minProperties validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "minProperties": 1 }, "tests": [ { "description": "longer is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "exact length is valid", "data": {"foo": 1}, "valid": true }, { "description": "too short is invalid", "data": {}, "valid": false }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "minProperties validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "minProperties": 1.0 }, "tests": [ { "description": "longer is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "too short is invalid", "data": {}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/minimum.json0000644000175100001770000000410414653725311023561 0ustar00runnerdocker[ { "description": "minimum validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "minimum": 1.1 }, "tests": [ { "description": "above the minimum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 1.1, "valid": true }, { "description": "below the minimum is invalid", "data": 0.6, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] }, { "description": "minimum validation with signed integer", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "minimum": -2 }, "tests": [ { "description": "negative above the minimum is valid", "data": -1, "valid": true }, { "description": "positive above the minimum is valid", "data": 0, "valid": true }, { "description": "boundary point is valid", "data": -2, "valid": true }, { "description": "boundary point with float is valid", "data": -2.0, "valid": true }, { "description": "float below the minimum is invalid", "data": -2.0001, "valid": false }, { "description": "int below the minimum is invalid", "data": -3, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/multipleOf.json0000644000175100001770000000430614653725311024232 0ustar00runnerdocker[ { "description": "by int", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "multipleOf": 2 }, "tests": [ { "description": "int by int", "data": 10, "valid": true }, { "description": "int by int fail", "data": 7, "valid": false }, { "description": "ignores non-numbers", "data": "foo", "valid": true } ] }, { "description": "by number", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "multipleOf": 1.5 }, "tests": [ { "description": "zero is multiple of anything", "data": 0, "valid": true }, { "description": "4.5 is multiple of 1.5", "data": 4.5, "valid": true }, { "description": "35 is not multiple of 1.5", "data": 35, "valid": false } ] }, { "description": "by small number", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "multipleOf": 0.0001 }, "tests": [ { "description": "0.0075 is multiple of 0.0001", "data": 0.0075, "valid": true }, { "description": "0.00751 is not multiple of 0.0001", "data": 0.00751, "valid": false } ] }, { "description": "float division = inf", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "integer", "multipleOf": 0.123456789 }, "tests": [ { "description": "always invalid, but naive implementations may raise an overflow error", "data": 1e308, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/not.json0000644000175100001770000000632414653725311022714 0ustar00runnerdocker[ { "description": "not", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "not": {"type": "integer"} }, "tests": [ { "description": "allowed", "data": "foo", "valid": true }, { "description": "disallowed", "data": 1, "valid": false } ] }, { "description": "not multiple types", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "not": {"type": ["integer", "boolean"]} }, "tests": [ { "description": "valid", "data": "foo", "valid": true }, { "description": "mismatch", "data": 1, "valid": false }, { "description": "other mismatch", "data": true, "valid": false } ] }, { "description": "not more complex schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "not": { "type": "object", "properties": { "foo": { "type": "string" } } } }, "tests": [ { "description": "match", "data": 1, "valid": true }, { "description": "other match", "data": {"foo": 1}, "valid": true }, { "description": "mismatch", "data": {"foo": "bar"}, "valid": false } ] }, { "description": "forbidden property", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": { "not": {} } } }, "tests": [ { "description": "property present", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "property absent", "data": {"bar": 1, "baz": 2}, "valid": true } ] }, { "description": "not with boolean schema true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "not": true }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "not with boolean schema false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "not": false }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/oneOf.json0000644000175100001770000001767014653725311023170 0ustar00runnerdocker[ { "description": "oneOf", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "type": "integer" }, { "minimum": 2 } ] }, "tests": [ { "description": "first oneOf valid", "data": 1, "valid": true }, { "description": "second oneOf valid", "data": 2.5, "valid": true }, { "description": "both oneOf valid", "data": 3, "valid": false }, { "description": "neither oneOf valid", "data": 1.5, "valid": false } ] }, { "description": "oneOf with base schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "oneOf" : [ { "minLength": 2 }, { "maxLength": 4 } ] }, "tests": [ { "description": "mismatch base schema", "data": 3, "valid": false }, { "description": "one oneOf valid", "data": "foobar", "valid": true }, { "description": "both oneOf valid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, all true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [true, true, true] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, one true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [true, false, false] }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "oneOf with boolean schemas, more than one true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [true, true, false] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, all false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [false, false, false] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf complex types", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "first oneOf valid (complex)", "data": {"bar": 2}, "valid": true }, { "description": "second oneOf valid (complex)", "data": {"foo": "baz"}, "valid": true }, { "description": "both oneOf valid (complex)", "data": {"foo": "baz", "bar": 2}, "valid": false }, { "description": "neither oneOf valid (complex)", "data": {"foo": 2, "bar": "quux"}, "valid": false } ] }, { "description": "oneOf with empty schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "one valid - valid", "data": "foo", "valid": true }, { "description": "both valid - invalid", "data": 123, "valid": false } ] }, { "description": "oneOf with required", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "oneOf": [ { "required": ["foo", "bar"] }, { "required": ["foo", "baz"] } ] }, "tests": [ { "description": "both invalid - invalid", "data": {"bar": 2}, "valid": false }, { "description": "first valid - valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "second valid - valid", "data": {"foo": 1, "baz": 3}, "valid": true }, { "description": "both valid - invalid", "data": {"foo": 1, "bar": 2, "baz" : 3}, "valid": false } ] }, { "description": "oneOf with missing optional property", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "properties": { "bar": true, "baz": true }, "required": ["bar"] }, { "properties": { "foo": true }, "required": ["foo"] } ] }, "tests": [ { "description": "first oneOf valid", "data": {"bar": 8}, "valid": true }, { "description": "second oneOf valid", "data": {"foo": "foo"}, "valid": true }, { "description": "both oneOf valid", "data": {"foo": "foo", "bar": 8}, "valid": false }, { "description": "neither oneOf valid", "data": {"baz": "quux"}, "valid": false } ] }, { "description": "nested oneOf, to check validation semantics", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "oneOf": [ { "type": "null" } ] } ] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "anything non-null is invalid", "data": 123, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0730968 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/0000755000175100001770000000000014653725331023043 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/bignum.json0000644000175100001770000000652614653725311025226 0ustar00runnerdocker[ { "description": "integer", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "integer" }, "tests": [ { "description": "a bignum is an integer", "data": 12345678910111213141516171819202122232425262728293031, "valid": true }, { "description": "a negative bignum is an integer", "data": -12345678910111213141516171819202122232425262728293031, "valid": true } ] }, { "description": "number", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "number" }, "tests": [ { "description": "a bignum is a number", "data": 98249283749234923498293171823948729348710298301928331, "valid": true }, { "description": "a negative bignum is a number", "data": -98249283749234923498293171823948729348710298301928331, "valid": true } ] }, { "description": "string", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string" }, "tests": [ { "description": "a bignum is not a string", "data": 98249283749234923498293171823948729348710298301928331, "valid": false } ] }, { "description": "maximum integer comparison", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "maximum": 18446744073709551615 }, "tests": [ { "description": "comparison works for high numbers", "data": 18446744073709551600, "valid": true } ] }, { "description": "float comparison with high precision", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "exclusiveMaximum": 972783798187987123879878123.18878137 }, "tests": [ { "description": "comparison works for high numbers", "data": 972783798187987123879878123.188781371, "valid": false } ] }, { "description": "minimum integer comparison", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "minimum": -18446744073709551615 }, "tests": [ { "description": "comparison works for very negative numbers", "data": -18446744073709551600, "valid": true } ] }, { "description": "float comparison with high precision on negative numbers", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "exclusiveMinimum": -972783798187987123879878123.18878137 }, "tests": [ { "description": "comparison works for very negative numbers", "data": -972783798187987123879878123.188781371, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/cross-draft.json0000644000175100001770000000115414653725311026164 0ustar00runnerdocker[ { "description": "refs to historic drafts are processed as historic drafts", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "array", "$ref": "http://localhost:1234/draft2019-09/ignore-prefixItems.json" }, "tests": [ { "description": "first item not a string is valid", "comment": "if the implementation is not processing the $ref as a 2019-09 schema, this test will fail", "data": [1, 2, 3], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/dependencies-compatibility.json0000644000175100001770000001772014653725311031240 0ustar00runnerdocker[ { "description": "single dependency", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependencies": {"bar": ["foo"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependant", "data": {"foo": 1}, "valid": true }, { "description": "with dependency", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "missing dependency", "data": {"bar": 2}, "valid": false }, { "description": "ignores arrays", "data": ["bar"], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "empty dependents", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependencies": {"bar": []} }, "tests": [ { "description": "empty object", "data": {}, "valid": true }, { "description": "object with one property", "data": {"bar": 2}, "valid": true }, { "description": "non-object is valid", "data": 1, "valid": true } ] }, { "description": "multiple dependents required", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependencies": {"quux": ["foo", "bar"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependants", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "with dependencies", "data": {"foo": 1, "bar": 2, "quux": 3}, "valid": true }, { "description": "missing dependency", "data": {"foo": 1, "quux": 2}, "valid": false }, { "description": "missing other dependency", "data": {"bar": 1, "quux": 2}, "valid": false }, { "description": "missing both dependencies", "data": {"quux": 1}, "valid": false } ] }, { "description": "dependencies with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependencies": { "foo\nbar": ["foo\rbar"], "foo\"bar": ["foo'bar"] } }, "tests": [ { "description": "CRLF", "data": { "foo\nbar": 1, "foo\rbar": 2 }, "valid": true }, { "description": "quoted quotes", "data": { "foo'bar": 1, "foo\"bar": 2 }, "valid": true }, { "description": "CRLF missing dependent", "data": { "foo\nbar": 1, "foo": 2 }, "valid": false }, { "description": "quoted quotes missing dependent", "data": { "foo\"bar": 2 }, "valid": false } ] }, { "description": "single schema dependency", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependencies": { "bar": { "properties": { "foo": {"type": "integer"}, "bar": {"type": "integer"} } } } }, "tests": [ { "description": "valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "no dependency", "data": {"foo": "quux"}, "valid": true }, { "description": "wrong type", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "wrong type other", "data": {"foo": 2, "bar": "quux"}, "valid": false }, { "description": "wrong type both", "data": {"foo": "quux", "bar": "quux"}, "valid": false }, { "description": "ignores arrays", "data": ["bar"], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "boolean subschemas", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependencies": { "foo": true, "bar": false } }, "tests": [ { "description": "object with property having schema true is valid", "data": {"foo": 1}, "valid": true }, { "description": "object with property having schema false is invalid", "data": {"bar": 2}, "valid": false }, { "description": "object with both properties is invalid", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "schema dependencies with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependencies": { "foo\tbar": {"minProperties": 4}, "foo'bar": {"required": ["foo\"bar"]} } }, "tests": [ { "description": "quoted tab", "data": { "foo\tbar": 1, "a": 2, "b": 3, "c": 4 }, "valid": true }, { "description": "quoted quote", "data": { "foo'bar": {"foo\"bar": 1} }, "valid": false }, { "description": "quoted tab invalid under dependent schema", "data": { "foo\tbar": 1, "a": 2 }, "valid": false }, { "description": "quoted quote invalid under dependent schema", "data": {"foo'bar": 1}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/ecmascript-regex.json0000644000175100001770000004774614653725311027220 0ustar00runnerdocker[ { "description": "ECMA 262 regex $ does not match trailing newline", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "pattern": "^abc$" }, "tests": [ { "description": "matches in Python, but not in ECMA 262", "data": "abc\\n", "valid": false }, { "description": "matches", "data": "abc", "valid": true } ] }, { "description": "ECMA 262 regex converts \\t to horizontal tab", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "pattern": "^\\t$" }, "tests": [ { "description": "does not match", "data": "\\t", "valid": false }, { "description": "matches", "data": "\u0009", "valid": true } ] }, { "description": "ECMA 262 regex escapes control codes with \\c and upper letter", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "pattern": "^\\cC$" }, "tests": [ { "description": "does not match", "data": "\\cC", "valid": false }, { "description": "matches", "data": "\u0003", "valid": true } ] }, { "description": "ECMA 262 regex escapes control codes with \\c and lower letter", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "pattern": "^\\cc$" }, "tests": [ { "description": "does not match", "data": "\\cc", "valid": false }, { "description": "matches", "data": "\u0003", "valid": true } ] }, { "description": "ECMA 262 \\d matches ascii digits only", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "pattern": "^\\d$" }, "tests": [ { "description": "ASCII zero matches", "data": "0", "valid": true }, { "description": "NKO DIGIT ZERO does not match (unlike e.g. Python)", "data": "߀", "valid": false }, { "description": "NKO DIGIT ZERO (as \\u escape) does not match", "data": "\u07c0", "valid": false } ] }, { "description": "ECMA 262 \\D matches everything but ascii digits", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "pattern": "^\\D$" }, "tests": [ { "description": "ASCII zero does not match", "data": "0", "valid": false }, { "description": "NKO DIGIT ZERO matches (unlike e.g. Python)", "data": "߀", "valid": true }, { "description": "NKO DIGIT ZERO (as \\u escape) matches", "data": "\u07c0", "valid": true } ] }, { "description": "ECMA 262 \\w matches ascii letters only", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "pattern": "^\\w$" }, "tests": [ { "description": "ASCII 'a' matches", "data": "a", "valid": true }, { "description": "latin-1 e-acute does not match (unlike e.g. Python)", "data": "é", "valid": false } ] }, { "description": "ECMA 262 \\W matches everything but ascii letters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "pattern": "^\\W$" }, "tests": [ { "description": "ASCII 'a' does not match", "data": "a", "valid": false }, { "description": "latin-1 e-acute matches (unlike e.g. Python)", "data": "é", "valid": true } ] }, { "description": "ECMA 262 \\s matches whitespace", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "pattern": "^\\s$" }, "tests": [ { "description": "ASCII space matches", "data": " ", "valid": true }, { "description": "Character tabulation matches", "data": "\t", "valid": true }, { "description": "Line tabulation matches", "data": "\u000b", "valid": true }, { "description": "Form feed matches", "data": "\u000c", "valid": true }, { "description": "latin-1 non-breaking-space matches", "data": "\u00a0", "valid": true }, { "description": "zero-width whitespace matches", "data": "\ufeff", "valid": true }, { "description": "line feed matches (line terminator)", "data": "\u000a", "valid": true }, { "description": "paragraph separator matches (line terminator)", "data": "\u2029", "valid": true }, { "description": "EM SPACE matches (Space_Separator)", "data": "\u2003", "valid": true }, { "description": "Non-whitespace control does not match", "data": "\u0001", "valid": false }, { "description": "Non-whitespace does not match", "data": "\u2013", "valid": false } ] }, { "description": "ECMA 262 \\S matches everything but whitespace", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "pattern": "^\\S$" }, "tests": [ { "description": "ASCII space does not match", "data": " ", "valid": false }, { "description": "Character tabulation does not match", "data": "\t", "valid": false }, { "description": "Line tabulation does not match", "data": "\u000b", "valid": false }, { "description": "Form feed does not match", "data": "\u000c", "valid": false }, { "description": "latin-1 non-breaking-space does not match", "data": "\u00a0", "valid": false }, { "description": "zero-width whitespace does not match", "data": "\ufeff", "valid": false }, { "description": "line feed does not match (line terminator)", "data": "\u000a", "valid": false }, { "description": "paragraph separator does not match (line terminator)", "data": "\u2029", "valid": false }, { "description": "EM SPACE does not match (Space_Separator)", "data": "\u2003", "valid": false }, { "description": "Non-whitespace control matches", "data": "\u0001", "valid": true }, { "description": "Non-whitespace matches", "data": "\u2013", "valid": true } ] }, { "description": "patterns always use unicode semantics with pattern", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "pattern": "\\p{Letter}cole" }, "tests": [ { "description": "ascii character in json string", "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", "valid": true }, { "description": "literal unicode character in json string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": true }, { "description": "unicode character in hex format in string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": true }, { "description": "unicode matching is case-sensitive", "data": "LES HIVERS DE MON ENFANCE ÉTAIENT DES SAISONS LONGUES, LONGUES. NOUS VIVIONS EN TROIS LIEUX: L'ÉCOLE, L'ÉGLISE ET LA PATINOIRE; MAIS LA VRAIE VIE ÉTAIT SUR LA PATINOIRE.", "valid": false } ] }, { "description": "\\w in patterns matches [A-Za-z0-9_], not unicode letters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "pattern": "\\wcole" }, "tests": [ { "description": "ascii character in json string", "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", "valid": true }, { "description": "literal unicode character in json string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "unicode character in hex format in string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "unicode matching is case-sensitive", "data": "LES HIVERS DE MON ENFANCE ÉTAIENT DES SAISONS LONGUES, LONGUES. NOUS VIVIONS EN TROIS LIEUX: L'ÉCOLE, L'ÉGLISE ET LA PATINOIRE; MAIS LA VRAIE VIE ÉTAIT SUR LA PATINOIRE.", "valid": false } ] }, { "description": "pattern with ASCII ranges", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "pattern": "[a-z]cole" }, "tests": [ { "description": "literal unicode character in json string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "unicode character in hex format in string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "ascii characters match", "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", "valid": true } ] }, { "description": "\\d in pattern matches [0-9], not unicode digits", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "pattern": "^\\d+$" }, "tests": [ { "description": "ascii digits", "data": "42", "valid": true }, { "description": "ascii non-digits", "data": "-%#", "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": "৪২", "valid": false } ] }, { "description": "\\a is not an ECMA 262 control escape", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "https://json-schema.org/draft/2020-12/schema" }, "tests": [ { "description": "when used as a pattern", "data": { "pattern": "\\a" }, "valid": false } ] }, { "description": "pattern with non-ASCII digits", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "pattern": "^\\p{digit}+$" }, "tests": [ { "description": "ascii digits", "data": "42", "valid": true }, { "description": "ascii non-digits", "data": "-%#", "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": "৪২", "valid": true } ] }, { "description": "patterns always use unicode semantics with patternProperties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "patternProperties": { "\\p{Letter}cole": true }, "additionalProperties": false }, "tests": [ { "description": "ascii character in json string", "data": { "l'ecole": "pas de vraie vie" }, "valid": true }, { "description": "literal unicode character in json string", "data": { "l'école": "pas de vraie vie" }, "valid": true }, { "description": "unicode character in hex format in string", "data": { "l'\u00e9cole": "pas de vraie vie" }, "valid": true }, { "description": "unicode matching is case-sensitive", "data": { "L'ÉCOLE": "PAS DE VRAIE VIE" }, "valid": false } ] }, { "description": "\\w in patternProperties matches [A-Za-z0-9_], not unicode letters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "patternProperties": { "\\wcole": true }, "additionalProperties": false }, "tests": [ { "description": "ascii character in json string", "data": { "l'ecole": "pas de vraie vie" }, "valid": true }, { "description": "literal unicode character in json string", "data": { "l'école": "pas de vraie vie" }, "valid": false }, { "description": "unicode character in hex format in string", "data": { "l'\u00e9cole": "pas de vraie vie" }, "valid": false }, { "description": "unicode matching is case-sensitive", "data": { "L'ÉCOLE": "PAS DE VRAIE VIE" }, "valid": false } ] }, { "description": "patternProperties with ASCII ranges", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "patternProperties": { "[a-z]cole": true }, "additionalProperties": false }, "tests": [ { "description": "literal unicode character in json string", "data": { "l'école": "pas de vraie vie" }, "valid": false }, { "description": "unicode character in hex format in string", "data": { "l'\u00e9cole": "pas de vraie vie" }, "valid": false }, { "description": "ascii characters match", "data": { "l'ecole": "pas de vraie vie" }, "valid": true } ] }, { "description": "\\d in patternProperties matches [0-9], not unicode digits", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "patternProperties": { "^\\d+$": true }, "additionalProperties": false }, "tests": [ { "description": "ascii digits", "data": { "42": "life, the universe, and everything" }, "valid": true }, { "description": "ascii non-digits", "data": { "-%#": "spending the year dead for tax reasons" }, "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": { "৪২": "khajit has wares if you have coin" }, "valid": false } ] }, { "description": "patternProperties with non-ASCII digits", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "patternProperties": { "^\\p{digit}+$": true }, "additionalProperties": false }, "tests": [ { "description": "ascii digits", "data": { "42": "life, the universe, and everything" }, "valid": true }, { "description": "ascii non-digits", "data": { "-%#": "spending the year dead for tax reasons" }, "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": { "৪২": "khajit has wares if you have coin" }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/float-overflow.json0000644000175100001770000000072214653725311026703 0ustar00runnerdocker[ { "description": "all integers are multiples of 0.5, if overflow is handled", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "integer", "multipleOf": 0.5 }, "tests": [ { "description": "valid if optional overflow handling is implemented", "data": 1e308, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.077097 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/format/0000755000175100001770000000000014653725331024333 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/format/date-time.json0000644000175100001770000001121314653725311027073 0ustar00runnerdocker[ { "description": "validation of date-time strings", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "date-time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid date-time string", "data": "1963-06-19T08:30:06.283185Z", "valid": true }, { "description": "a valid date-time string without second fraction", "data": "1963-06-19T08:30:06Z", "valid": true }, { "description": "a valid date-time string with plus offset", "data": "1937-01-01T12:00:27.87+00:20", "valid": true }, { "description": "a valid date-time string with minus offset", "data": "1990-12-31T15:59:50.123-08:00", "valid": true }, { "description": "a valid date-time with a leap second, UTC", "data": "1998-12-31T23:59:60Z", "valid": true }, { "description": "a valid date-time with a leap second, with minus offset", "data": "1998-12-31T15:59:60.123-08:00", "valid": true }, { "description": "an invalid date-time past leap second, UTC", "data": "1998-12-31T23:59:61Z", "valid": false }, { "description": "an invalid date-time with leap second on a wrong minute, UTC", "data": "1998-12-31T23:58:60Z", "valid": false }, { "description": "an invalid date-time with leap second on a wrong hour, UTC", "data": "1998-12-31T22:59:60Z", "valid": false }, { "description": "an invalid day in date-time string", "data": "1990-02-31T15:59:59.123-08:00", "valid": false }, { "description": "an invalid offset in date-time string", "data": "1990-12-31T15:59:59-24:00", "valid": false }, { "description": "an invalid closing Z after time-zone offset", "data": "1963-06-19T08:30:06.28123+01:00Z", "valid": false }, { "description": "an invalid date-time string", "data": "06/19/1963 08:30:06 PST", "valid": false }, { "description": "case-insensitive T and Z", "data": "1963-06-19t08:30:06.283185z", "valid": true }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "2013-350T01:01:01", "valid": false }, { "description": "invalid non-padded month dates", "data": "1963-6-19T08:30:06.283185Z", "valid": false }, { "description": "invalid non-padded day dates", "data": "1963-06-1T08:30:06.283185Z", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4) in date portion", "data": "1963-06-1৪T00:00:00Z", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4) in time portion", "data": "1963-06-11T0৪:00:00Z", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/format/date.json0000644000175100001770000001656314653725311026154 0ustar00runnerdocker[ { "description": "validation of date strings", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "date" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid date string", "data": "1963-06-19", "valid": true }, { "description": "a valid date string with 31 days in January", "data": "2020-01-31", "valid": true }, { "description": "a invalid date string with 32 days in January", "data": "2020-01-32", "valid": false }, { "description": "a valid date string with 28 days in February (normal)", "data": "2021-02-28", "valid": true }, { "description": "a invalid date string with 29 days in February (normal)", "data": "2021-02-29", "valid": false }, { "description": "a valid date string with 29 days in February (leap)", "data": "2020-02-29", "valid": true }, { "description": "a invalid date string with 30 days in February (leap)", "data": "2020-02-30", "valid": false }, { "description": "a valid date string with 31 days in March", "data": "2020-03-31", "valid": true }, { "description": "a invalid date string with 32 days in March", "data": "2020-03-32", "valid": false }, { "description": "a valid date string with 30 days in April", "data": "2020-04-30", "valid": true }, { "description": "a invalid date string with 31 days in April", "data": "2020-04-31", "valid": false }, { "description": "a valid date string with 31 days in May", "data": "2020-05-31", "valid": true }, { "description": "a invalid date string with 32 days in May", "data": "2020-05-32", "valid": false }, { "description": "a valid date string with 30 days in June", "data": "2020-06-30", "valid": true }, { "description": "a invalid date string with 31 days in June", "data": "2020-06-31", "valid": false }, { "description": "a valid date string with 31 days in July", "data": "2020-07-31", "valid": true }, { "description": "a invalid date string with 32 days in July", "data": "2020-07-32", "valid": false }, { "description": "a valid date string with 31 days in August", "data": "2020-08-31", "valid": true }, { "description": "a invalid date string with 32 days in August", "data": "2020-08-32", "valid": false }, { "description": "a valid date string with 30 days in September", "data": "2020-09-30", "valid": true }, { "description": "a invalid date string with 31 days in September", "data": "2020-09-31", "valid": false }, { "description": "a valid date string with 31 days in October", "data": "2020-10-31", "valid": true }, { "description": "a invalid date string with 32 days in October", "data": "2020-10-32", "valid": false }, { "description": "a valid date string with 30 days in November", "data": "2020-11-30", "valid": true }, { "description": "a invalid date string with 31 days in November", "data": "2020-11-31", "valid": false }, { "description": "a valid date string with 31 days in December", "data": "2020-12-31", "valid": true }, { "description": "a invalid date string with 32 days in December", "data": "2020-12-32", "valid": false }, { "description": "a invalid date string with invalid month", "data": "2020-13-01", "valid": false }, { "description": "an invalid date string", "data": "06/19/1963", "valid": false }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "2013-350", "valid": false }, { "description": "non-padded month dates are not valid", "data": "1998-1-20", "valid": false }, { "description": "non-padded day dates are not valid", "data": "1998-01-1", "valid": false }, { "description": "invalid month", "data": "1998-13-01", "valid": false }, { "description": "invalid month-day combination", "data": "1998-04-31", "valid": false }, { "description": "2021 is not a leap year", "data": "2021-02-29", "valid": false }, { "description": "2020 is a leap year", "data": "2020-02-29", "valid": true }, { "description": "invalid non-ASCII '৪' (a Bengali 4)", "data": "1963-06-1৪", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/format/duration.json0000644000175100001770000000772014653725311027057 0ustar00runnerdocker[ { "description": "validation of duration strings", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "duration" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid duration string", "data": "P4DT12H30M5S", "valid": true }, { "description": "an invalid duration string", "data": "PT1D", "valid": false }, { "description": "no elements present", "data": "P", "valid": false }, { "description": "no time elements present", "data": "P1YT", "valid": false }, { "description": "no date or time elements present", "data": "PT", "valid": false }, { "description": "elements out of order", "data": "P2D1Y", "valid": false }, { "description": "missing time separator", "data": "P1D2H", "valid": false }, { "description": "time element in the date position", "data": "P2S", "valid": false }, { "description": "four years duration", "data": "P4Y", "valid": true }, { "description": "zero time, in seconds", "data": "PT0S", "valid": true }, { "description": "zero time, in days", "data": "P0D", "valid": true }, { "description": "one month duration", "data": "P1M", "valid": true }, { "description": "one minute duration", "data": "PT1M", "valid": true }, { "description": "one and a half days, in hours", "data": "PT36H", "valid": true }, { "description": "one and a half days, in days and hours", "data": "P1DT12H", "valid": true }, { "description": "two weeks", "data": "P2W", "valid": true }, { "description": "weeks cannot be combined with other units", "data": "P1Y2W", "valid": false }, { "description": "invalid non-ASCII '২' (a Bengali 2)", "data": "P২Y", "valid": false }, { "description": "element without unit", "data": "P1", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/format/email.json0000644000175100001770000000772414653725311026325 0ustar00runnerdocker[ { "description": "validation of e-mail addresses", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid e-mail address", "data": "joe.bloggs@example.com", "valid": true }, { "description": "an invalid e-mail address", "data": "2962", "valid": false }, { "description": "tilde in local part is valid", "data": "te~st@example.com", "valid": true }, { "description": "tilde before local part is valid", "data": "~test@example.com", "valid": true }, { "description": "tilde after local part is valid", "data": "test~@example.com", "valid": true }, { "description": "a quoted string with a space in the local part is valid", "data": "\"joe bloggs\"@example.com", "valid": true }, { "description": "a quoted string with a double dot in the local part is valid", "data": "\"joe..bloggs\"@example.com", "valid": true }, { "description": "a quoted string with a @ in the local part is valid", "data": "\"joe@bloggs\"@example.com", "valid": true }, { "description": "an IPv4-address-literal after the @ is valid", "data": "joe.bloggs@[127.0.0.1]", "valid": true }, { "description": "an IPv6-address-literal after the @ is valid", "data": "joe.bloggs@[IPv6:::1]", "valid": true }, { "description": "dot before local part is not valid", "data": ".test@example.com", "valid": false }, { "description": "dot after local part is not valid", "data": "test.@example.com", "valid": false }, { "description": "two separated dots inside local part are valid", "data": "te.s.t@example.com", "valid": true }, { "description": "two subsequent dots inside local part are not valid", "data": "te..st@example.com", "valid": false }, { "description": "an invalid domain", "data": "joe.bloggs@invalid=domain.com", "valid": false }, { "description": "an invalid IPv4-address-literal", "data": "joe.bloggs@[127.0.0.300]", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/format/hostname.json0000644000175100001770000000635714653725311027055 0ustar00runnerdocker[ { "description": "validation of host names", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid host name", "data": "www.example.com", "valid": true }, { "description": "a valid punycoded IDN hostname", "data": "xn--4gbwdl.xn--wgbh1c", "valid": true }, { "description": "a host name starting with an illegal character", "data": "-a-host-name-that-starts-with--", "valid": false }, { "description": "a host name containing illegal characters", "data": "not_a_valid_host_name", "valid": false }, { "description": "a host name with a component too long", "data": "a-vvvvvvvvvvvvvvvveeeeeeeeeeeeeeeerrrrrrrrrrrrrrrryyyyyyyyyyyyyyyy-long-host-name-component", "valid": false }, { "description": "starts with hyphen", "data": "-hostname", "valid": false }, { "description": "ends with hyphen", "data": "hostname-", "valid": false }, { "description": "starts with underscore", "data": "_hostname", "valid": false }, { "description": "ends with underscore", "data": "hostname_", "valid": false }, { "description": "contains underscore", "data": "host_name", "valid": false }, { "description": "maximum label length", "data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.com", "valid": true }, { "description": "exceeds maximum label length", "data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl.com", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/format/idn-email.json0000644000175100001770000000350714653725311027070 0ustar00runnerdocker[ { "description": "validation of an internationalized e-mail addresses", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "idn-email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid idn e-mail (example@example.test in Hangul)", "data": "실례@실례.테스트", "valid": true }, { "description": "an invalid idn e-mail address", "data": "2962", "valid": false }, { "description": "a valid e-mail address", "data": "joe.bloggs@example.com", "valid": true }, { "description": "an invalid e-mail address", "data": "2962", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/format/idn-hostname.json0000644000175100001770000003477414653725311027631 0ustar00runnerdocker[ { "description": "validation of internationalized host names", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "idn-hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid host name (example.test in Hangul)", "data": "실례.테스트", "valid": true }, { "description": "illegal first char U+302E Hangul single dot tone mark", "data": "〮실례.테스트", "valid": false }, { "description": "contains illegal char U+302E Hangul single dot tone mark", "data": "실〮례.테스트", "valid": false }, { "description": "a host name with a component too long", "data": "실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실례례테스트례례례례례례례례례례례례례례례례례테스트례례례례례례례례례례례례례례례례례례례테스트례례례례례례례례례례례례테스트례례실례.테스트", "valid": false }, { "description": "invalid label, correct Punycode", "comment": "https://tools.ietf.org/html/rfc5890#section-2.3.2.1 https://tools.ietf.org/html/rfc5891#section-4.4 https://tools.ietf.org/html/rfc3492#section-7.1", "data": "-> $1.00 <--", "valid": false }, { "description": "valid Chinese Punycode", "comment": "https://tools.ietf.org/html/rfc5890#section-2.3.2.1 https://tools.ietf.org/html/rfc5891#section-4.4", "data": "xn--ihqwcrb4cv8a8dqg056pqjye", "valid": true }, { "description": "invalid Punycode", "comment": "https://tools.ietf.org/html/rfc5891#section-4.4 https://tools.ietf.org/html/rfc5890#section-2.3.2.1", "data": "xn--X", "valid": false }, { "description": "U-label contains \"--\" in the 3rd and 4th position", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1 https://tools.ietf.org/html/rfc5890#section-2.3.2.1", "data": "XN--aa---o47jg78q", "valid": false }, { "description": "U-label starts with a dash", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1", "data": "-hello", "valid": false }, { "description": "U-label ends with a dash", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1", "data": "hello-", "valid": false }, { "description": "U-label starts and ends with a dash", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1", "data": "-hello-", "valid": false }, { "description": "Begins with a Spacing Combining Mark", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2", "data": "\u0903hello", "valid": false }, { "description": "Begins with a Nonspacing Mark", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2", "data": "\u0300hello", "valid": false }, { "description": "Begins with an Enclosing Mark", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2", "data": "\u0488hello", "valid": false }, { "description": "Exceptions that are PVALID, left-to-right chars", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6", "data": "\u00df\u03c2\u0f0b\u3007", "valid": true }, { "description": "Exceptions that are PVALID, right-to-left chars", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6", "data": "\u06fd\u06fe", "valid": true }, { "description": "Exceptions that are DISALLOWED, right-to-left chars", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6", "data": "\u0640\u07fa", "valid": false }, { "description": "Exceptions that are DISALLOWED, left-to-right chars", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6 Note: The two combining marks (U+302E and U+302F) are in the middle and not at the start", "data": "\u3031\u3032\u3033\u3034\u3035\u302e\u302f\u303b", "valid": false }, { "description": "MIDDLE DOT with no preceding 'l'", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "a\u00b7l", "valid": false }, { "description": "MIDDLE DOT with nothing preceding", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "\u00b7l", "valid": false }, { "description": "MIDDLE DOT with no following 'l'", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "l\u00b7a", "valid": false }, { "description": "MIDDLE DOT with nothing following", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "l\u00b7", "valid": false }, { "description": "MIDDLE DOT with surrounding 'l's", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "l\u00b7l", "valid": true }, { "description": "Greek KERAIA not followed by Greek", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4", "data": "\u03b1\u0375S", "valid": false }, { "description": "Greek KERAIA not followed by anything", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4", "data": "\u03b1\u0375", "valid": false }, { "description": "Greek KERAIA followed by Greek", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4", "data": "\u03b1\u0375\u03b2", "valid": true }, { "description": "Hebrew GERESH not preceded by Hebrew", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5", "data": "A\u05f3\u05d1", "valid": false }, { "description": "Hebrew GERESH not preceded by anything", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5", "data": "\u05f3\u05d1", "valid": false }, { "description": "Hebrew GERESH preceded by Hebrew", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5", "data": "\u05d0\u05f3\u05d1", "valid": true }, { "description": "Hebrew GERSHAYIM not preceded by Hebrew", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6", "data": "A\u05f4\u05d1", "valid": false }, { "description": "Hebrew GERSHAYIM not preceded by anything", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6", "data": "\u05f4\u05d1", "valid": false }, { "description": "Hebrew GERSHAYIM preceded by Hebrew", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6", "data": "\u05d0\u05f4\u05d1", "valid": true }, { "description": "KATAKANA MIDDLE DOT with no Hiragana, Katakana, or Han", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "def\u30fbabc", "valid": false }, { "description": "KATAKANA MIDDLE DOT with no other characters", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "\u30fb", "valid": false }, { "description": "KATAKANA MIDDLE DOT with Hiragana", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "\u30fb\u3041", "valid": true }, { "description": "KATAKANA MIDDLE DOT with Katakana", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "\u30fb\u30a1", "valid": true }, { "description": "KATAKANA MIDDLE DOT with Han", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "\u30fb\u4e08", "valid": true }, { "description": "Arabic-Indic digits mixed with Extended Arabic-Indic digits", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.8", "data": "\u0660\u06f0", "valid": false }, { "description": "Arabic-Indic digits not mixed with Extended Arabic-Indic digits", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.8", "data": "\u0628\u0660\u0628", "valid": true }, { "description": "Extended Arabic-Indic digits not mixed with Arabic-Indic digits", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.9", "data": "\u06f00", "valid": true }, { "description": "ZERO WIDTH JOINER not preceded by Virama", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf", "data": "\u0915\u200d\u0937", "valid": false }, { "description": "ZERO WIDTH JOINER not preceded by anything", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf", "data": "\u200d\u0937", "valid": false }, { "description": "ZERO WIDTH JOINER preceded by Virama", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf", "data": "\u0915\u094d\u200d\u0937", "valid": true }, { "description": "ZERO WIDTH NON-JOINER preceded by Virama", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.1", "data": "\u0915\u094d\u200c\u0937", "valid": true }, { "description": "ZERO WIDTH NON-JOINER not preceded by Virama but matches regexp", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.1 https://www.w3.org/TR/alreq/#h_disjoining_enforcement", "data": "\u0628\u064a\u200c\u0628\u064a", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/format/ipv4.json0000644000175100001770000000553714653725311026120 0ustar00runnerdocker[ { "description": "validation of IP addresses", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "ipv4" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IP address", "data": "192.168.0.1", "valid": true }, { "description": "an IP address with too many components", "data": "127.0.0.0.1", "valid": false }, { "description": "an IP address with out-of-range values", "data": "256.256.256.256", "valid": false }, { "description": "an IP address without 4 components", "data": "127.0", "valid": false }, { "description": "an IP address as an integer", "data": "0x7f000001", "valid": false }, { "description": "an IP address as an integer (decimal)", "data": "2130706433", "valid": false }, { "description": "invalid leading zeroes, as they are treated as octals", "comment": "see https://sick.codes/universal-netmask-npm-package-used-by-270000-projects-vulnerable-to-octal-input-data-server-side-request-forgery-remote-file-inclusion-local-file-inclusion-and-more-cve-2021-28918/", "data": "087.10.0.1", "valid": false }, { "description": "value without leading zero is valid", "data": "87.10.0.1", "valid": true }, { "description": "invalid non-ASCII '২' (a Bengali 2)", "data": "1২7.0.0.1", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/format/ipv6.json0000644000175100001770000001557214653725311026122 0ustar00runnerdocker[ { "description": "validation of IPv6 addresses", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "ipv6" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IPv6 address", "data": "::1", "valid": true }, { "description": "an IPv6 address with out-of-range values", "data": "12345::", "valid": false }, { "description": "trailing 4 hex symbols is valid", "data": "::abef", "valid": true }, { "description": "trailing 5 hex symbols is invalid", "data": "::abcef", "valid": false }, { "description": "an IPv6 address with too many components", "data": "1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1", "valid": false }, { "description": "an IPv6 address containing illegal characters", "data": "::laptop", "valid": false }, { "description": "no digits is valid", "data": "::", "valid": true }, { "description": "leading colons is valid", "data": "::42:ff:1", "valid": true }, { "description": "trailing colons is valid", "data": "d6::", "valid": true }, { "description": "missing leading octet is invalid", "data": ":2:3:4:5:6:7:8", "valid": false }, { "description": "missing trailing octet is invalid", "data": "1:2:3:4:5:6:7:", "valid": false }, { "description": "missing leading octet with omitted octets later", "data": ":2:3:4::8", "valid": false }, { "description": "single set of double colons in the middle is valid", "data": "1:d6::42", "valid": true }, { "description": "two sets of double colons is invalid", "data": "1::d6::42", "valid": false }, { "description": "mixed format with the ipv4 section as decimal octets", "data": "1::d6:192.168.0.1", "valid": true }, { "description": "mixed format with double colons between the sections", "data": "1:2::192.168.0.1", "valid": true }, { "description": "mixed format with ipv4 section with octet out of range", "data": "1::2:192.168.256.1", "valid": false }, { "description": "mixed format with ipv4 section with a hex octet", "data": "1::2:192.168.ff.1", "valid": false }, { "description": "mixed format with leading double colons (ipv4-mapped ipv6 address)", "data": "::ffff:192.168.0.1", "valid": true }, { "description": "triple colons is invalid", "data": "1:2:3:4:5:::8", "valid": false }, { "description": "8 octets", "data": "1:2:3:4:5:6:7:8", "valid": true }, { "description": "insufficient octets without double colons", "data": "1:2:3:4:5:6:7", "valid": false }, { "description": "no colons is invalid", "data": "1", "valid": false }, { "description": "ipv4 is not ipv6", "data": "127.0.0.1", "valid": false }, { "description": "ipv4 segment must have 4 octets", "data": "1:2:3:4:1.2.3", "valid": false }, { "description": "leading whitespace is invalid", "data": " ::1", "valid": false }, { "description": "trailing whitespace is invalid", "data": "::1 ", "valid": false }, { "description": "netmask is not a part of ipv6 address", "data": "fe80::/64", "valid": false }, { "description": "zone id is not a part of ipv6 address", "data": "fe80::a%eth1", "valid": false }, { "description": "a long valid ipv6", "data": "1000:1000:1000:1000:1000:1000:255.255.255.255", "valid": true }, { "description": "a long invalid ipv6, below length limit, first", "data": "100:100:100:100:100:100:255.255.255.255.255", "valid": false }, { "description": "a long invalid ipv6, below length limit, second", "data": "100:100:100:100:100:100:100:255.255.255.255", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4)", "data": "1:2:3:4:5:6:7:৪", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4) in the IPv4 portion", "data": "1:2::192.16৪.0.1", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/format/iri-reference.json0000644000175100001770000000444514653725311027752 0ustar00runnerdocker[ { "description": "validation of IRI References", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "iri-reference" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IRI", "data": "http://ƒøø.ßår/?∂éœ=πîx#πîüx", "valid": true }, { "description": "a valid protocol-relative IRI Reference", "data": "//ƒøø.ßår/?∂éœ=πîx#πîüx", "valid": true }, { "description": "a valid relative IRI Reference", "data": "/âππ", "valid": true }, { "description": "an invalid IRI Reference", "data": "\\\\WINDOWS\\filëßåré", "valid": false }, { "description": "a valid IRI Reference", "data": "âππ", "valid": true }, { "description": "a valid IRI fragment", "data": "#Æ’rägmênt", "valid": true }, { "description": "an invalid IRI fragment", "data": "#Æ’räg\\mênt", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/format/iri.json0000644000175100001770000000545714653725311026022 0ustar00runnerdocker[ { "description": "validation of IRIs", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "iri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IRI with anchor tag", "data": "http://ƒøø.ßår/?∂éœ=πîx#πîüx", "valid": true }, { "description": "a valid IRI with anchor tag and parentheses", "data": "http://ƒøø.com/blah_(wîkïpédiÃ¥)_blah#ßité-1", "valid": true }, { "description": "a valid IRI with URL-encoded stuff", "data": "http://ƒøø.ßår/?q=Test%20URL-encoded%20stuff", "valid": true }, { "description": "a valid IRI with many special characters", "data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", "valid": true }, { "description": "a valid IRI based on IPv6", "data": "http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]", "valid": true }, { "description": "an invalid IRI based on IPv6", "data": "http://2001:0db8:85a3:0000:0000:8a2e:0370:7334", "valid": false }, { "description": "an invalid relative IRI Reference", "data": "/abc", "valid": false }, { "description": "an invalid IRI", "data": "\\\\WINDOWS\\filëßåré", "valid": false }, { "description": "an invalid IRI though valid IRI reference", "data": "âππ", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/format/json-pointer.json0000644000175100001770000001521614653725311027660 0ustar00runnerdocker[ { "description": "validation of JSON-pointers (JSON String Representation)", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "json-pointer" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid JSON-pointer", "data": "/foo/bar~0/baz~1/%a", "valid": true }, { "description": "not a valid JSON-pointer (~ not escaped)", "data": "/foo/bar~", "valid": false }, { "description": "valid JSON-pointer with empty segment", "data": "/foo//bar", "valid": true }, { "description": "valid JSON-pointer with the last empty segment", "data": "/foo/bar/", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #1", "data": "", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #2", "data": "/foo", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #3", "data": "/foo/0", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #4", "data": "/", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #5", "data": "/a~1b", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #6", "data": "/c%d", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #7", "data": "/e^f", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #8", "data": "/g|h", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #9", "data": "/i\\j", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #10", "data": "/k\"l", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #11", "data": "/ ", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #12", "data": "/m~0n", "valid": true }, { "description": "valid JSON-pointer used adding to the last array position", "data": "/foo/-", "valid": true }, { "description": "valid JSON-pointer (- used as object member name)", "data": "/foo/-/bar", "valid": true }, { "description": "valid JSON-pointer (multiple escaped characters)", "data": "/~1~0~0~1~1", "valid": true }, { "description": "valid JSON-pointer (escaped with fraction part) #1", "data": "/~1.1", "valid": true }, { "description": "valid JSON-pointer (escaped with fraction part) #2", "data": "/~0.1", "valid": true }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #1", "data": "#", "valid": false }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #2", "data": "#/", "valid": false }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #3", "data": "#a", "valid": false }, { "description": "not a valid JSON-pointer (some escaped, but not all) #1", "data": "/~0~", "valid": false }, { "description": "not a valid JSON-pointer (some escaped, but not all) #2", "data": "/~0/~", "valid": false }, { "description": "not a valid JSON-pointer (wrong escape character) #1", "data": "/~2", "valid": false }, { "description": "not a valid JSON-pointer (wrong escape character) #2", "data": "/~-1", "valid": false }, { "description": "not a valid JSON-pointer (multiple characters not escaped)", "data": "/~~", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #1", "data": "a", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #2", "data": "0", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #3", "data": "a/a", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/format/regex.json0000644000175100001770000000275114653725311026343 0ustar00runnerdocker[ { "description": "validation of regular expressions", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "regex" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid regular expression", "data": "([abc])+\\s+$", "valid": true }, { "description": "a regular expression with unclosed parens is invalid", "data": "^(abc]", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/format/relative-json-pointer.json0000644000175100001770000000607614653725311031475 0ustar00runnerdocker[ { "description": "validation of Relative JSON Pointers (RJP)", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "relative-json-pointer" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid upwards RJP", "data": "1", "valid": true }, { "description": "a valid downwards RJP", "data": "0/foo/bar", "valid": true }, { "description": "a valid up and then down RJP, with array index", "data": "2/0/baz/1/zip", "valid": true }, { "description": "a valid RJP taking the member or index name", "data": "0#", "valid": true }, { "description": "an invalid RJP that is a valid JSON Pointer", "data": "/foo/bar", "valid": false }, { "description": "negative prefix", "data": "-1/foo/bar", "valid": false }, { "description": "explicit positive prefix", "data": "+1/foo/bar", "valid": false }, { "description": "## is not a valid json-pointer", "data": "0##", "valid": false }, { "description": "zero cannot be followed by other digits, plus json-pointer", "data": "01/a", "valid": false }, { "description": "zero cannot be followed by other digits, plus octothorpe", "data": "01#", "valid": false }, { "description": "empty string", "data": "", "valid": false }, { "description": "multi-digit integer prefix", "data": "120/foo/bar", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/format/time.json0000644000175100001770000001632114653725311026165 0ustar00runnerdocker[ { "description": "validation of time strings", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid time string", "data": "08:30:06Z", "valid": true }, { "description": "a valid time string with leap second, Zulu", "data": "23:59:60Z", "valid": true }, { "description": "invalid leap second, Zulu (wrong hour)", "data": "22:59:60Z", "valid": false }, { "description": "invalid leap second, Zulu (wrong minute)", "data": "23:58:60Z", "valid": false }, { "description": "valid leap second, zero time-offset", "data": "23:59:60+00:00", "valid": true }, { "description": "invalid leap second, zero time-offset (wrong hour)", "data": "22:59:60+00:00", "valid": false }, { "description": "invalid leap second, zero time-offset (wrong minute)", "data": "23:58:60+00:00", "valid": false }, { "description": "valid leap second, positive time-offset", "data": "01:29:60+01:30", "valid": true }, { "description": "valid leap second, large positive time-offset", "data": "23:29:60+23:30", "valid": true }, { "description": "invalid leap second, positive time-offset (wrong hour)", "data": "23:59:60+01:00", "valid": false }, { "description": "invalid leap second, positive time-offset (wrong minute)", "data": "23:59:60+00:30", "valid": false }, { "description": "valid leap second, negative time-offset", "data": "15:59:60-08:00", "valid": true }, { "description": "valid leap second, large negative time-offset", "data": "00:29:60-23:30", "valid": true }, { "description": "invalid leap second, negative time-offset (wrong hour)", "data": "23:59:60-01:00", "valid": false }, { "description": "invalid leap second, negative time-offset (wrong minute)", "data": "23:59:60-00:30", "valid": false }, { "description": "a valid time string with second fraction", "data": "23:20:50.52Z", "valid": true }, { "description": "a valid time string with precise second fraction", "data": "08:30:06.283185Z", "valid": true }, { "description": "a valid time string with plus offset", "data": "08:30:06+00:20", "valid": true }, { "description": "a valid time string with minus offset", "data": "08:30:06-08:00", "valid": true }, { "description": "a valid time string with case-insensitive Z", "data": "08:30:06z", "valid": true }, { "description": "an invalid time string with invalid hour", "data": "24:00:00Z", "valid": false }, { "description": "an invalid time string with invalid minute", "data": "00:60:00Z", "valid": false }, { "description": "an invalid time string with invalid second", "data": "00:00:61Z", "valid": false }, { "description": "an invalid time string with invalid leap second (wrong hour)", "data": "22:59:60Z", "valid": false }, { "description": "an invalid time string with invalid leap second (wrong minute)", "data": "23:58:60Z", "valid": false }, { "description": "an invalid time string with invalid time numoffset hour", "data": "01:02:03+24:00", "valid": false }, { "description": "an invalid time string with invalid time numoffset minute", "data": "01:02:03+00:60", "valid": false }, { "description": "an invalid time string with invalid time with both Z and numoffset", "data": "01:02:03Z+00:30", "valid": false }, { "description": "an invalid offset indicator", "data": "08:30:06 PST", "valid": false }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "01:01:01,1111", "valid": false }, { "description": "no time offset", "data": "12:00:00", "valid": false }, { "description": "no time offset with second fraction", "data": "12:00:00.52", "valid": false }, { "description": "invalid non-ASCII '২' (a Bengali 2)", "data": "1২:00:00Z", "valid": false }, { "description": "offset not starting with plus or minus", "data": "08:30:06#00:20", "valid": false }, { "description": "contains letters", "data": "ab:cd:ef", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/format/unknown.json0000644000175100001770000000241614653725311026726 0ustar00runnerdocker[ { "description": "unknown format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "unknown" }, "tests": [ { "description": "unknown formats ignore integers", "data": 12, "valid": true }, { "description": "unknown formats ignore floats", "data": 13.7, "valid": true }, { "description": "unknown formats ignore objects", "data": {}, "valid": true }, { "description": "unknown formats ignore arrays", "data": [], "valid": true }, { "description": "unknown formats ignore booleans", "data": false, "valid": true }, { "description": "unknown formats ignore nulls", "data": null, "valid": true }, { "description": "unknown formats ignore strings", "data": "string", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/format/uri-reference.json0000644000175100001770000000437214653725311027765 0ustar00runnerdocker[ { "description": "validation of URI References", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "uri-reference" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid URI", "data": "http://foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid protocol-relative URI Reference", "data": "//foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid relative URI Reference", "data": "/abc", "valid": true }, { "description": "an invalid URI Reference", "data": "\\\\WINDOWS\\fileshare", "valid": false }, { "description": "a valid URI Reference", "data": "abc", "valid": true }, { "description": "a valid URI fragment", "data": "#fragment", "valid": true }, { "description": "an invalid URI fragment", "data": "#frag\\ment", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/format/uri-template.json0000644000175100001770000000356414653725311027644 0ustar00runnerdocker[ { "description": "format: uri-template", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "uri-template" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid uri-template", "data": "http://example.com/dictionary/{term:1}/{term}", "valid": true }, { "description": "an invalid uri-template", "data": "http://example.com/dictionary/{term:1}/{term", "valid": false }, { "description": "a valid uri-template without variables", "data": "http://example.com/dictionary", "valid": true }, { "description": "a valid relative uri-template", "data": "dictionary/{term:1}/{term}", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/format/uri.json0000644000175100001770000001116714653725311026031 0ustar00runnerdocker[ { "description": "validation of URIs", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "uri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid URL with anchor tag", "data": "http://foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid URL with anchor tag and parentheses", "data": "http://foo.com/blah_(wikipedia)_blah#cite-1", "valid": true }, { "description": "a valid URL with URL-encoded stuff", "data": "http://foo.bar/?q=Test%20URL-encoded%20stuff", "valid": true }, { "description": "a valid puny-coded URL ", "data": "http://xn--nw2a.xn--j6w193g/", "valid": true }, { "description": "a valid URL with many special characters", "data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", "valid": true }, { "description": "a valid URL based on IPv4", "data": "http://223.255.255.254", "valid": true }, { "description": "a valid URL with ftp scheme", "data": "ftp://ftp.is.co.za/rfc/rfc1808.txt", "valid": true }, { "description": "a valid URL for a simple text file", "data": "http://www.ietf.org/rfc/rfc2396.txt", "valid": true }, { "description": "a valid URL ", "data": "ldap://[2001:db8::7]/c=GB?objectClass?one", "valid": true }, { "description": "a valid mailto URI", "data": "mailto:John.Doe@example.com", "valid": true }, { "description": "a valid newsgroup URI", "data": "news:comp.infosystems.www.servers.unix", "valid": true }, { "description": "a valid tel URI", "data": "tel:+1-816-555-1212", "valid": true }, { "description": "a valid URN", "data": "urn:oasis:names:specification:docbook:dtd:xml:4.1.2", "valid": true }, { "description": "an invalid protocol-relative URI Reference", "data": "//foo.bar/?baz=qux#quux", "valid": false }, { "description": "an invalid relative URI Reference", "data": "/abc", "valid": false }, { "description": "an invalid URI", "data": "\\\\WINDOWS\\fileshare", "valid": false }, { "description": "an invalid URI though valid URI reference", "data": "abc", "valid": false }, { "description": "an invalid URI with spaces", "data": "http:// shouldfail.com", "valid": false }, { "description": "an invalid URI with spaces and missing scheme", "data": ":// should fail", "valid": false }, { "description": "an invalid URI with comma in scheme", "data": "bar,baz:foo", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/format/uuid.json0000644000175100001770000000725714653725311026205 0ustar00runnerdocker[ { "description": "uuid format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "uuid" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "all upper-case", "data": "2EB8AA08-AA98-11EA-B4AA-73B441D16380", "valid": true }, { "description": "all lower-case", "data": "2eb8aa08-aa98-11ea-b4aa-73b441d16380", "valid": true }, { "description": "mixed case", "data": "2eb8aa08-AA98-11ea-B4Aa-73B441D16380", "valid": true }, { "description": "all zeroes is valid", "data": "00000000-0000-0000-0000-000000000000", "valid": true }, { "description": "wrong length", "data": "2eb8aa08-aa98-11ea-b4aa-73b441d1638", "valid": false }, { "description": "missing section", "data": "2eb8aa08-aa98-11ea-73b441d16380", "valid": false }, { "description": "bad characters (not hex)", "data": "2eb8aa08-aa98-11ea-b4ga-73b441d16380", "valid": false }, { "description": "no dashes", "data": "2eb8aa08aa9811eab4aa73b441d16380", "valid": false }, { "description": "too few dashes", "data": "2eb8aa08aa98-11ea-b4aa73b441d16380", "valid": false }, { "description": "too many dashes", "data": "2eb8-aa08-aa98-11ea-b4aa73b44-1d16380", "valid": false }, { "description": "dashes in the wrong spot", "data": "2eb8aa08aa9811eab4aa73b441d16380----", "valid": false }, { "description": "valid version 4", "data": "98d80576-482e-427f-8434-7f86890ab222", "valid": true }, { "description": "valid version 5", "data": "99c17cbb-656f-564a-940f-1a4568f03487", "valid": true }, { "description": "hypothetical version 6", "data": "99c17cbb-656f-664a-940f-1a4568f03487", "valid": true }, { "description": "hypothetical version 15", "data": "99c17cbb-656f-f64a-940f-1a4568f03487", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/format-assertion.json0000644000175100001770000000253414653725311027235 0ustar00runnerdocker[ { "description": "schema that uses custom metaschema with format-assertion: false", "schema": { "$id": "https://schema/using/format-assertion/false", "$schema": "http://localhost:1234/draft2020-12/format-assertion-false.json", "format": "ipv4" }, "tests": [ { "description": "format-assertion: false: valid string", "data": "127.0.0.1", "valid": true }, { "description": "format-assertion: false: invalid string", "data": "not-an-ipv4", "valid": false } ] }, { "description": "schema that uses custom metaschema with format-assertion: true", "schema": { "$id": "https://schema/using/format-assertion/true", "$schema": "http://localhost:1234/draft2020-12/format-assertion-true.json", "format": "ipv4" }, "tests": [ { "description": "format-assertion: true: valid string", "data": "127.0.0.1", "valid": true }, { "description": "format-assertion: true: invalid string", "data": "not-an-ipv4", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/no-schema.json0000644000175100001770000000123614653725311025610 0ustar00runnerdocker[ { "description": "validation without $schema", "comment": "minLength is the same across all drafts", "schema": { "minLength": 2 }, "tests": [ { "description": "a 3-character string is valid", "data": "foo", "valid": true }, { "description": "a 1-character string is not valid", "data": "a", "valid": false }, { "description": "a non-string is valid", "data": 5, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/non-bmp-regex.json0000644000175100001770000000500014653725311026405 0ustar00runnerdocker[ { "description": "Proper UTF-16 surrogate pair handling: pattern", "comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "pattern": "^ðŸ²*$" }, "tests": [ { "description": "matches empty", "data": "", "valid": true }, { "description": "matches single", "data": "ðŸ²", "valid": true }, { "description": "matches two", "data": "ðŸ²ðŸ²", "valid": true }, { "description": "doesn't match one", "data": "ðŸ‰", "valid": false }, { "description": "doesn't match two", "data": "ðŸ‰ðŸ‰", "valid": false }, { "description": "doesn't match one ASCII", "data": "D", "valid": false }, { "description": "doesn't match two ASCII", "data": "DD", "valid": false } ] }, { "description": "Proper UTF-16 surrogate pair handling: patternProperties", "comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "patternProperties": { "^ðŸ²*$": { "type": "integer" } } }, "tests": [ { "description": "matches empty", "data": { "": 1 }, "valid": true }, { "description": "matches single", "data": { "ðŸ²": 1 }, "valid": true }, { "description": "matches two", "data": { "ðŸ²ðŸ²": 1 }, "valid": true }, { "description": "doesn't match one", "data": { "ðŸ²": "hello" }, "valid": false }, { "description": "doesn't match two", "data": { "ðŸ²ðŸ²": "hello" }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/optional/refOfUnknownKeyword.json0000644000175100001770000000243214653725311027723 0ustar00runnerdocker[ { "description": "reference of a root arbitrary keyword ", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "unknown-keyword": {"type": "integer"}, "properties": { "bar": {"$ref": "#/unknown-keyword"} } }, "tests": [ { "description": "match", "data": {"bar": 3}, "valid": true }, { "description": "mismatch", "data": {"bar": true}, "valid": false } ] }, { "description": "reference of an arbitrary keyword of a sub-schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": {"unknown-keyword": {"type": "integer"}}, "bar": {"$ref": "#/properties/foo/unknown-keyword"} } }, "tests": [ { "description": "match", "data": {"bar": 3}, "valid": true }, { "description": "mismatch", "data": {"bar": true}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/pattern.json0000644000175100001770000000327514653725311023573 0ustar00runnerdocker[ { "description": "pattern validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "pattern": "^a*$" }, "tests": [ { "description": "a matching pattern is valid", "data": "aaa", "valid": true }, { "description": "a non-matching pattern is invalid", "data": "abc", "valid": false }, { "description": "ignores booleans", "data": true, "valid": true }, { "description": "ignores integers", "data": 123, "valid": true }, { "description": "ignores floats", "data": 1.0, "valid": true }, { "description": "ignores objects", "data": {}, "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores null", "data": null, "valid": true } ] }, { "description": "pattern is not anchored", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "pattern": "a+" }, "tests": [ { "description": "matches a substring", "data": "xxaayy", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/patternProperties.json0000644000175100001770000001263414653725311025647 0ustar00runnerdocker[ { "description": "patternProperties validates properties matching a regex", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "patternProperties": { "f.*o": {"type": "integer"} } }, "tests": [ { "description": "a single valid match is valid", "data": {"foo": 1}, "valid": true }, { "description": "multiple valid matches is valid", "data": {"foo": 1, "foooooo" : 2}, "valid": true }, { "description": "a single invalid match is invalid", "data": {"foo": "bar", "fooooo": 2}, "valid": false }, { "description": "multiple invalid matches is invalid", "data": {"foo": "bar", "foooooo" : "baz"}, "valid": false }, { "description": "ignores arrays", "data": ["foo"], "valid": true }, { "description": "ignores strings", "data": "foo", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "multiple simultaneous patternProperties are validated", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "patternProperties": { "a*": {"type": "integer"}, "aaa*": {"maximum": 20} } }, "tests": [ { "description": "a single valid match is valid", "data": {"a": 21}, "valid": true }, { "description": "a simultaneous match is valid", "data": {"aaaa": 18}, "valid": true }, { "description": "multiple matches is valid", "data": {"a": 21, "aaaa": 18}, "valid": true }, { "description": "an invalid due to one is invalid", "data": {"a": "bar"}, "valid": false }, { "description": "an invalid due to the other is invalid", "data": {"aaaa": 31}, "valid": false }, { "description": "an invalid due to both is invalid", "data": {"aaa": "foo", "aaaa": 31}, "valid": false } ] }, { "description": "regexes are not anchored by default and are case sensitive", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "patternProperties": { "[0-9]{2,}": { "type": "boolean" }, "X_": { "type": "string" } } }, "tests": [ { "description": "non recognized members are ignored", "data": { "answer 1": "42" }, "valid": true }, { "description": "recognized members are accounted for", "data": { "a31b": null }, "valid": false }, { "description": "regexes are case sensitive", "data": { "a_x_3": 3 }, "valid": true }, { "description": "regexes are case sensitive, 2", "data": { "a_X_3": 3 }, "valid": false } ] }, { "description": "patternProperties with boolean schemas", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "patternProperties": { "f.*": true, "b.*": false } }, "tests": [ { "description": "object with property matching schema true is valid", "data": {"foo": 1}, "valid": true }, { "description": "object with property matching schema false is invalid", "data": {"bar": 2}, "valid": false }, { "description": "object with both properties is invalid", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "object with a property matching both true and false is invalid", "data": {"foobar":1}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "patternProperties with null valued instance properties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "patternProperties": { "^.*bar$": {"type": "null"} } }, "tests": [ { "description": "allows null values", "data": {"foobar": null}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/prefixItems.json0000644000175100001770000000556114653725311024415 0ustar00runnerdocker[ { "description": "a schema given for prefixItems", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [ {"type": "integer"}, {"type": "string"} ] }, "tests": [ { "description": "correct types", "data": [ 1, "foo" ], "valid": true }, { "description": "wrong types", "data": [ "foo", 1 ], "valid": false }, { "description": "incomplete array of items", "data": [ 1 ], "valid": true }, { "description": "array with additional items", "data": [ 1, "foo", true ], "valid": true }, { "description": "empty array", "data": [ ], "valid": true }, { "description": "JavaScript pseudo-array is valid", "data": { "0": "invalid", "1": "valid", "length": 2 }, "valid": true } ] }, { "description": "prefixItems with boolean schemas", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [true, false] }, "tests": [ { "description": "array with one item is valid", "data": [ 1 ], "valid": true }, { "description": "array with two items is invalid", "data": [ 1, "foo" ], "valid": false }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "additional items are allowed by default", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [{"type": "integer"}] }, "tests": [ { "description": "only the first item is validated", "data": [1, "foo", false], "valid": true } ] }, { "description": "prefixItems with null instance elements", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [ { "type": "null" } ] }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/properties.json0000644000175100001770000001706314653725311024312 0ustar00runnerdocker[ { "description": "object properties validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": {"type": "integer"}, "bar": {"type": "string"} } }, "tests": [ { "description": "both properties present and valid is valid", "data": {"foo": 1, "bar": "baz"}, "valid": true }, { "description": "one property invalid is invalid", "data": {"foo": 1, "bar": {}}, "valid": false }, { "description": "both properties invalid is invalid", "data": {"foo": [], "bar": {}}, "valid": false }, { "description": "doesn't invalidate other properties", "data": {"quux": []}, "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "properties, patternProperties, additionalProperties interaction", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": {"type": "array", "maxItems": 3}, "bar": {"type": "array"} }, "patternProperties": {"f.o": {"minItems": 2}}, "additionalProperties": {"type": "integer"} }, "tests": [ { "description": "property validates property", "data": {"foo": [1, 2]}, "valid": true }, { "description": "property invalidates property", "data": {"foo": [1, 2, 3, 4]}, "valid": false }, { "description": "patternProperty invalidates property", "data": {"foo": []}, "valid": false }, { "description": "patternProperty validates nonproperty", "data": {"fxo": [1, 2]}, "valid": true }, { "description": "patternProperty invalidates nonproperty", "data": {"fxo": []}, "valid": false }, { "description": "additionalProperty ignores property", "data": {"bar": []}, "valid": true }, { "description": "additionalProperty validates others", "data": {"quux": 3}, "valid": true }, { "description": "additionalProperty invalidates others", "data": {"quux": "foo"}, "valid": false } ] }, { "description": "properties with boolean schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": true, "bar": false } }, "tests": [ { "description": "no property present is valid", "data": {}, "valid": true }, { "description": "only 'true' property present is valid", "data": {"foo": 1}, "valid": true }, { "description": "only 'false' property present is invalid", "data": {"bar": 2}, "valid": false }, { "description": "both properties present is invalid", "data": {"foo": 1, "bar": 2}, "valid": false } ] }, { "description": "properties with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo\nbar": {"type": "number"}, "foo\"bar": {"type": "number"}, "foo\\bar": {"type": "number"}, "foo\rbar": {"type": "number"}, "foo\tbar": {"type": "number"}, "foo\fbar": {"type": "number"} } }, "tests": [ { "description": "object with all numbers is valid", "data": { "foo\nbar": 1, "foo\"bar": 1, "foo\\bar": 1, "foo\rbar": 1, "foo\tbar": 1, "foo\fbar": 1 }, "valid": true }, { "description": "object with strings is invalid", "data": { "foo\nbar": "1", "foo\"bar": "1", "foo\\bar": "1", "foo\rbar": "1", "foo\tbar": "1", "foo\fbar": "1" }, "valid": false } ] }, { "description": "properties with null valued instance properties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": {"type": "null"} } }, "tests": [ { "description": "allows null values", "data": {"foo": null}, "valid": true } ] }, { "description": "properties whose names are Javascript object property names", "comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "__proto__": {"type": "number"}, "toString": { "properties": { "length": { "type": "string" } } }, "constructor": {"type": "number"} } }, "tests": [ { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "none of the properties mentioned", "data": {}, "valid": true }, { "description": "__proto__ not valid", "data": { "__proto__": "foo" }, "valid": false }, { "description": "toString not valid", "data": { "toString": { "length": 37 } }, "valid": false }, { "description": "constructor not valid", "data": { "constructor": { "length": 37 } }, "valid": false }, { "description": "all present and valid", "data": { "__proto__": 12, "toString": { "length": "foo" }, "constructor": 37 }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/propertyNames.json0000644000175100001770000000453114653725311024762 0ustar00runnerdocker[ { "description": "propertyNames validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "propertyNames": {"maxLength": 3} }, "tests": [ { "description": "all property names valid", "data": { "f": {}, "foo": {} }, "valid": true }, { "description": "some property names invalid", "data": { "foo": {}, "foobar": {} }, "valid": false }, { "description": "object without properties is valid", "data": {}, "valid": true }, { "description": "ignores arrays", "data": [1, 2, 3, 4], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "propertyNames with boolean schema true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "propertyNames": true }, "tests": [ { "description": "object with any properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "propertyNames with boolean schema false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "propertyNames": false }, "tests": [ { "description": "object with any properties is invalid", "data": {"foo": 1}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/ref.json0000644000175100001770000006556414653725311022703 0ustar00runnerdocker[ { "description": "root pointer ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": {"$ref": "#"} }, "additionalProperties": false }, "tests": [ { "description": "match", "data": {"foo": false}, "valid": true }, { "description": "recursive match", "data": {"foo": {"foo": false}}, "valid": true }, { "description": "mismatch", "data": {"bar": false}, "valid": false }, { "description": "recursive mismatch", "data": {"foo": {"bar": false}}, "valid": false } ] }, { "description": "relative pointer ref to object", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": {"type": "integer"}, "bar": {"$ref": "#/properties/foo"} } }, "tests": [ { "description": "match", "data": {"bar": 3}, "valid": true }, { "description": "mismatch", "data": {"bar": true}, "valid": false } ] }, { "description": "relative pointer ref to array", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [ {"type": "integer"}, {"$ref": "#/prefixItems/0"} ] }, "tests": [ { "description": "match array", "data": [1, 2], "valid": true }, { "description": "mismatch array", "data": [1, "foo"], "valid": false } ] }, { "description": "escaped pointer ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "tilde~field": {"type": "integer"}, "slash/field": {"type": "integer"}, "percent%field": {"type": "integer"} }, "properties": { "tilde": {"$ref": "#/$defs/tilde~0field"}, "slash": {"$ref": "#/$defs/slash~1field"}, "percent": {"$ref": "#/$defs/percent%25field"} } }, "tests": [ { "description": "slash invalid", "data": {"slash": "aoeu"}, "valid": false }, { "description": "tilde invalid", "data": {"tilde": "aoeu"}, "valid": false }, { "description": "percent invalid", "data": {"percent": "aoeu"}, "valid": false }, { "description": "slash valid", "data": {"slash": 123}, "valid": true }, { "description": "tilde valid", "data": {"tilde": 123}, "valid": true }, { "description": "percent valid", "data": {"percent": 123}, "valid": true } ] }, { "description": "nested refs", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "a": {"type": "integer"}, "b": {"$ref": "#/$defs/a"}, "c": {"$ref": "#/$defs/b"} }, "$ref": "#/$defs/c" }, "tests": [ { "description": "nested ref valid", "data": 5, "valid": true }, { "description": "nested ref invalid", "data": "a", "valid": false } ] }, { "description": "ref applies alongside sibling keywords", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "reffed": { "type": "array" } }, "properties": { "foo": { "$ref": "#/$defs/reffed", "maxItems": 2 } } }, "tests": [ { "description": "ref valid, maxItems valid", "data": { "foo": [] }, "valid": true }, { "description": "ref valid, maxItems invalid", "data": { "foo": [1, 2, 3] }, "valid": false }, { "description": "ref invalid", "data": { "foo": "string" }, "valid": false } ] }, { "description": "remote ref, containing refs itself", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "https://json-schema.org/draft/2020-12/schema" }, "tests": [ { "description": "remote ref valid", "data": {"minLength": 1}, "valid": true }, { "description": "remote ref invalid", "data": {"minLength": -1}, "valid": false } ] }, { "description": "property named $ref that is not a reference", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "$ref": {"type": "string"} } }, "tests": [ { "description": "property named $ref valid", "data": {"$ref": "a"}, "valid": true }, { "description": "property named $ref invalid", "data": {"$ref": 2}, "valid": false } ] }, { "description": "property named $ref, containing an actual $ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "$ref": {"$ref": "#/$defs/is-string"} }, "$defs": { "is-string": { "type": "string" } } }, "tests": [ { "description": "property named $ref valid", "data": {"$ref": "a"}, "valid": true }, { "description": "property named $ref invalid", "data": {"$ref": 2}, "valid": false } ] }, { "description": "$ref to boolean schema true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "#/$defs/bool", "$defs": { "bool": true } }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "$ref to boolean schema false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "#/$defs/bool", "$defs": { "bool": false } }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "Recursive references between schemas", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/tree", "description": "tree of nodes", "type": "object", "properties": { "meta": {"type": "string"}, "nodes": { "type": "array", "items": {"$ref": "node"} } }, "required": ["meta", "nodes"], "$defs": { "node": { "$id": "http://localhost:1234/draft2020-12/node", "description": "node", "type": "object", "properties": { "value": {"type": "number"}, "subtree": {"$ref": "tree"} }, "required": ["value"] } } }, "tests": [ { "description": "valid tree", "data": { "meta": "root", "nodes": [ { "value": 1, "subtree": { "meta": "child", "nodes": [ {"value": 1.1}, {"value": 1.2} ] } }, { "value": 2, "subtree": { "meta": "child", "nodes": [ {"value": 2.1}, {"value": 2.2} ] } } ] }, "valid": true }, { "description": "invalid tree", "data": { "meta": "root", "nodes": [ { "value": 1, "subtree": { "meta": "child", "nodes": [ {"value": "string is invalid"}, {"value": 1.2} ] } }, { "value": 2, "subtree": { "meta": "child", "nodes": [ {"value": 2.1}, {"value": 2.2} ] } } ] }, "valid": false } ] }, { "description": "refs with quote", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo\"bar": {"$ref": "#/$defs/foo%22bar"} }, "$defs": { "foo\"bar": {"type": "number"} } }, "tests": [ { "description": "object with numbers is valid", "data": { "foo\"bar": 1 }, "valid": true }, { "description": "object with strings is invalid", "data": { "foo\"bar": "1" }, "valid": false } ] }, { "description": "ref creates new scope when adjacent to keywords", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "A": { "unevaluatedProperties": false } }, "properties": { "prop1": { "type": "string" } }, "$ref": "#/$defs/A" }, "tests": [ { "description": "referenced subschema doesn't see annotations from properties", "data": { "prop1": "match" }, "valid": false } ] }, { "description": "naive replacement of $ref with its destination is not correct", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "a_string": { "type": "string" } }, "enum": [ { "$ref": "#/$defs/a_string" } ] }, "tests": [ { "description": "do not evaluate the $ref inside the enum, matching any string", "data": "this is a string", "valid": false }, { "description": "do not evaluate the $ref inside the enum, definition exact match", "data": { "type": "string" }, "valid": false }, { "description": "match the enum exactly", "data": { "$ref": "#/$defs/a_string" }, "valid": true } ] }, { "description": "refs with relative uris and defs", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://example.com/schema-relative-uri-defs1.json", "properties": { "foo": { "$id": "schema-relative-uri-defs2.json", "$defs": { "inner": { "properties": { "bar": { "type": "string" } } } }, "$ref": "#/$defs/inner" } }, "$ref": "schema-relative-uri-defs2.json" }, "tests": [ { "description": "invalid on inner field", "data": { "foo": { "bar": 1 }, "bar": "a" }, "valid": false }, { "description": "invalid on outer field", "data": { "foo": { "bar": "a" }, "bar": 1 }, "valid": false }, { "description": "valid on both fields", "data": { "foo": { "bar": "a" }, "bar": "a" }, "valid": true } ] }, { "description": "relative refs with absolute uris and defs", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://example.com/schema-refs-absolute-uris-defs1.json", "properties": { "foo": { "$id": "http://example.com/schema-refs-absolute-uris-defs2.json", "$defs": { "inner": { "properties": { "bar": { "type": "string" } } } }, "$ref": "#/$defs/inner" } }, "$ref": "schema-refs-absolute-uris-defs2.json" }, "tests": [ { "description": "invalid on inner field", "data": { "foo": { "bar": 1 }, "bar": "a" }, "valid": false }, { "description": "invalid on outer field", "data": { "foo": { "bar": "a" }, "bar": 1 }, "valid": false }, { "description": "valid on both fields", "data": { "foo": { "bar": "a" }, "bar": "a" }, "valid": true } ] }, { "description": "$id must be resolved against nearest parent, not just immediate parent", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://example.com/a.json", "$defs": { "x": { "$id": "http://example.com/b/c.json", "not": { "$defs": { "y": { "$id": "d.json", "type": "number" } } } } }, "allOf": [ { "$ref": "http://example.com/b/d.json" } ] }, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "non-number is invalid", "data": "a", "valid": false } ] }, { "description": "order of evaluation: $id and $ref", "schema": { "$comment": "$id must be evaluated before $ref to get the proper $ref destination", "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "/draft2020-12/ref-and-id1/base.json", "$ref": "int.json", "$defs": { "bigint": { "$comment": "canonical uri: /ref-and-id1/int.json", "$id": "int.json", "maximum": 10 }, "smallint": { "$comment": "canonical uri: /ref-and-id1-int.json", "$id": "/draft2020-12/ref-and-id1-int.json", "maximum": 2 } } }, "tests": [ { "description": "data is valid against first definition", "data": 5, "valid": true }, { "description": "data is invalid against first definition", "data": 50, "valid": false } ] }, { "description": "order of evaluation: $id and $anchor and $ref", "schema": { "$comment": "$id must be evaluated before $ref to get the proper $ref destination", "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "/draft2020-12/ref-and-id2/base.json", "$ref": "#bigint", "$defs": { "bigint": { "$comment": "canonical uri: /ref-and-id2/base.json#/$defs/bigint; another valid uri for this location: /ref-and-id2/base.json#bigint", "$anchor": "bigint", "maximum": 10 }, "smallint": { "$comment": "canonical uri: /ref-and-id2#/$defs/smallint; another valid uri for this location: /ref-and-id2/#bigint", "$id": "/draft2020-12/ref-and-id2/", "$anchor": "bigint", "maximum": 2 } } }, "tests": [ { "description": "data is valid against first definition", "data": 5, "valid": true }, { "description": "data is invalid against first definition", "data": 50, "valid": false } ] }, { "description": "simple URN base URI with $ref via the URN", "schema": { "$comment": "URIs do not have to have HTTP(s) schemes", "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed", "minimum": 30, "properties": { "foo": {"$ref": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed"} } }, "tests": [ { "description": "valid under the URN IDed schema", "data": {"foo": 37}, "valid": true }, { "description": "invalid under the URN IDed schema", "data": {"foo": 12}, "valid": false } ] }, { "description": "simple URN base URI with JSON pointer", "schema": { "$comment": "URIs do not have to have HTTP(s) schemes", "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "urn:uuid:deadbeef-1234-00ff-ff00-4321feebdaed", "properties": { "foo": {"$ref": "#/$defs/bar"} }, "$defs": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with NSS", "schema": { "$comment": "RFC 8141 §2.2", "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "urn:example:1/406/47452/2", "properties": { "foo": {"$ref": "#/$defs/bar"} }, "$defs": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with r-component", "schema": { "$comment": "RFC 8141 §2.3.1", "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "urn:example:foo-bar-baz-qux?+CCResolve:cc=uk", "properties": { "foo": {"$ref": "#/$defs/bar"} }, "$defs": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with q-component", "schema": { "$comment": "RFC 8141 §2.3.2", "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "urn:example:weather?=op=map&lat=39.56&lon=-104.85&datetime=1969-07-21T02:56:15Z", "properties": { "foo": {"$ref": "#/$defs/bar"} }, "$defs": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with f-component", "schema": { "$comment": "RFC 8141 §2.3.3, but we don't allow fragments", "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "https://json-schema.org/draft/2020-12/schema" }, "tests": [ { "description": "is invalid", "data": {"$id": "urn:example:foo-bar-baz-qux#somepart"}, "valid": false } ] }, { "description": "URN base URI with URN and JSON pointer ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed", "properties": { "foo": {"$ref": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed#/$defs/bar"} }, "$defs": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with URN and anchor ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed", "properties": { "foo": {"$ref": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed#something"} }, "$defs": { "bar": { "$anchor": "something", "type": "string" } } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN ref with nested pointer ref", "schema": { "$ref": "urn:uuid:deadbeef-4321-ffff-ffff-1234feebdaed", "$defs": { "foo": { "$id": "urn:uuid:deadbeef-4321-ffff-ffff-1234feebdaed", "$defs": {"bar": {"type": "string"}}, "$ref": "#/$defs/bar" } } }, "tests": [ { "description": "a string is valid", "data": "bar", "valid": true }, { "description": "a non-string is invalid", "data": 12, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/refRemote.json0000644000175100001770000002122314653725311024037 0ustar00runnerdocker[ { "description": "remote ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "http://localhost:1234/draft2020-12/integer.json" }, "tests": [ { "description": "remote ref valid", "data": 1, "valid": true }, { "description": "remote ref invalid", "data": "a", "valid": false } ] }, { "description": "fragment within remote ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "http://localhost:1234/draft2020-12/subSchemas-defs.json#/$defs/integer" }, "tests": [ { "description": "remote fragment valid", "data": 1, "valid": true }, { "description": "remote fragment invalid", "data": "a", "valid": false } ] }, { "description": "ref within remote ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "http://localhost:1234/draft2020-12/subSchemas-defs.json#/$defs/refToInteger" }, "tests": [ { "description": "ref within ref valid", "data": 1, "valid": true }, { "description": "ref within ref invalid", "data": "a", "valid": false } ] }, { "description": "base URI change", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/", "items": { "$id": "baseUriChange/", "items": {"$ref": "folderInteger.json"} } }, "tests": [ { "description": "base URI change ref valid", "data": [[1]], "valid": true }, { "description": "base URI change ref invalid", "data": [["a"]], "valid": false } ] }, { "description": "base URI change - change folder", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/scope_change_defs1.json", "type" : "object", "properties": {"list": {"$ref": "baseUriChangeFolder/"}}, "$defs": { "baz": { "$id": "baseUriChangeFolder/", "type": "array", "items": {"$ref": "folderInteger.json"} } } }, "tests": [ { "description": "number is valid", "data": {"list": [1]}, "valid": true }, { "description": "string is invalid", "data": {"list": ["a"]}, "valid": false } ] }, { "description": "base URI change - change folder in subschema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/scope_change_defs2.json", "type" : "object", "properties": {"list": {"$ref": "baseUriChangeFolderInSubschema/#/$defs/bar"}}, "$defs": { "baz": { "$id": "baseUriChangeFolderInSubschema/", "$defs": { "bar": { "type": "array", "items": {"$ref": "folderInteger.json"} } } } } }, "tests": [ { "description": "number is valid", "data": {"list": [1]}, "valid": true }, { "description": "string is invalid", "data": {"list": ["a"]}, "valid": false } ] }, { "description": "root ref in remote ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/object", "type": "object", "properties": { "name": {"$ref": "name-defs.json#/$defs/orNull"} } }, "tests": [ { "description": "string is valid", "data": { "name": "foo" }, "valid": true }, { "description": "null is valid", "data": { "name": null }, "valid": true }, { "description": "object is invalid", "data": { "name": { "name": null } }, "valid": false } ] }, { "description": "remote ref with ref to defs", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/schema-remote-ref-ref-defs1.json", "$ref": "ref-and-defs.json" }, "tests": [ { "description": "invalid", "data": { "bar": 1 }, "valid": false }, { "description": "valid", "data": { "bar": "a" }, "valid": true } ] }, { "description": "Location-independent identifier in remote ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "http://localhost:1234/draft2020-12/locationIndependentIdentifier.json#/$defs/refToInteger" }, "tests": [ { "description": "integer is valid", "data": 1, "valid": true }, { "description": "string is invalid", "data": "foo", "valid": false } ] }, { "description": "retrieved nested refs resolve relative to their URI not $id", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/some-id", "properties": { "name": {"$ref": "nested/foo-ref-string.json"} } }, "tests": [ { "description": "number is invalid", "data": { "name": {"foo": 1} }, "valid": false }, { "description": "string is valid", "data": { "name": {"foo": "a"} }, "valid": true } ] }, { "description": "remote HTTP ref with different $id", "schema": {"$ref": "http://localhost:1234/different-id-ref-string.json"}, "tests": [ { "description": "number is invalid", "data": 1, "valid": false }, { "description": "string is valid", "data": "foo", "valid": true } ] }, { "description": "remote HTTP ref with different URN $id", "schema": {"$ref": "http://localhost:1234/urn-ref-string.json"}, "tests": [ { "description": "number is invalid", "data": 1, "valid": false }, { "description": "string is valid", "data": "foo", "valid": true } ] }, { "description": "remote HTTP ref with nested absolute ref", "schema": {"$ref": "http://localhost:1234/nested-absolute-ref-to-string.json"}, "tests": [ { "description": "number is invalid", "data": 1, "valid": false }, { "description": "string is valid", "data": "foo", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/required.json0000644000175100001770000001102314653725311023724 0ustar00runnerdocker[ { "description": "required validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": {}, "bar": {} }, "required": ["foo"] }, "tests": [ { "description": "present required property is valid", "data": {"foo": 1}, "valid": true }, { "description": "non-present required property is invalid", "data": {"bar": 1}, "valid": false }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "required default validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": {} } }, "tests": [ { "description": "not required by default", "data": {}, "valid": true } ] }, { "description": "required with empty array", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": {} }, "required": [] }, "tests": [ { "description": "property not required", "data": {}, "valid": true } ] }, { "description": "required with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "required": [ "foo\nbar", "foo\"bar", "foo\\bar", "foo\rbar", "foo\tbar", "foo\fbar" ] }, "tests": [ { "description": "object with all properties present is valid", "data": { "foo\nbar": 1, "foo\"bar": 1, "foo\\bar": 1, "foo\rbar": 1, "foo\tbar": 1, "foo\fbar": 1 }, "valid": true }, { "description": "object with some properties missing is invalid", "data": { "foo\nbar": "1", "foo\"bar": "1" }, "valid": false } ] }, { "description": "required properties whose names are Javascript object property names", "comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "required": ["__proto__", "toString", "constructor"] }, "tests": [ { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "none of the properties mentioned", "data": {}, "valid": false }, { "description": "__proto__ present", "data": { "__proto__": "foo" }, "valid": false }, { "description": "toString present", "data": { "toString": { "length": 37 } }, "valid": false }, { "description": "constructor present", "data": { "constructor": { "length": 37 } }, "valid": false }, { "description": "all present", "data": { "__proto__": 12, "toString": { "length": "foo" }, "constructor": 37 }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/type.json0000644000175100001770000003403514653725311023075 0ustar00runnerdocker[ { "description": "integer type matches integers", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "integer" }, "tests": [ { "description": "an integer is an integer", "data": 1, "valid": true }, { "description": "a float with zero fractional part is an integer", "data": 1.0, "valid": true }, { "description": "a float is not an integer", "data": 1.1, "valid": false }, { "description": "a string is not an integer", "data": "foo", "valid": false }, { "description": "a string is still not an integer, even if it looks like one", "data": "1", "valid": false }, { "description": "an object is not an integer", "data": {}, "valid": false }, { "description": "an array is not an integer", "data": [], "valid": false }, { "description": "a boolean is not an integer", "data": true, "valid": false }, { "description": "null is not an integer", "data": null, "valid": false } ] }, { "description": "number type matches numbers", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "number" }, "tests": [ { "description": "an integer is a number", "data": 1, "valid": true }, { "description": "a float with zero fractional part is a number (and an integer)", "data": 1.0, "valid": true }, { "description": "a float is a number", "data": 1.1, "valid": true }, { "description": "a string is not a number", "data": "foo", "valid": false }, { "description": "a string is still not a number, even if it looks like one", "data": "1", "valid": false }, { "description": "an object is not a number", "data": {}, "valid": false }, { "description": "an array is not a number", "data": [], "valid": false }, { "description": "a boolean is not a number", "data": true, "valid": false }, { "description": "null is not a number", "data": null, "valid": false } ] }, { "description": "string type matches strings", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string" }, "tests": [ { "description": "1 is not a string", "data": 1, "valid": false }, { "description": "a float is not a string", "data": 1.1, "valid": false }, { "description": "a string is a string", "data": "foo", "valid": true }, { "description": "a string is still a string, even if it looks like a number", "data": "1", "valid": true }, { "description": "an empty string is still a string", "data": "", "valid": true }, { "description": "an object is not a string", "data": {}, "valid": false }, { "description": "an array is not a string", "data": [], "valid": false }, { "description": "a boolean is not a string", "data": true, "valid": false }, { "description": "null is not a string", "data": null, "valid": false } ] }, { "description": "object type matches objects", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object" }, "tests": [ { "description": "an integer is not an object", "data": 1, "valid": false }, { "description": "a float is not an object", "data": 1.1, "valid": false }, { "description": "a string is not an object", "data": "foo", "valid": false }, { "description": "an object is an object", "data": {}, "valid": true }, { "description": "an array is not an object", "data": [], "valid": false }, { "description": "a boolean is not an object", "data": true, "valid": false }, { "description": "null is not an object", "data": null, "valid": false } ] }, { "description": "array type matches arrays", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "array" }, "tests": [ { "description": "an integer is not an array", "data": 1, "valid": false }, { "description": "a float is not an array", "data": 1.1, "valid": false }, { "description": "a string is not an array", "data": "foo", "valid": false }, { "description": "an object is not an array", "data": {}, "valid": false }, { "description": "an array is an array", "data": [], "valid": true }, { "description": "a boolean is not an array", "data": true, "valid": false }, { "description": "null is not an array", "data": null, "valid": false } ] }, { "description": "boolean type matches booleans", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "boolean" }, "tests": [ { "description": "an integer is not a boolean", "data": 1, "valid": false }, { "description": "zero is not a boolean", "data": 0, "valid": false }, { "description": "a float is not a boolean", "data": 1.1, "valid": false }, { "description": "a string is not a boolean", "data": "foo", "valid": false }, { "description": "an empty string is not a boolean", "data": "", "valid": false }, { "description": "an object is not a boolean", "data": {}, "valid": false }, { "description": "an array is not a boolean", "data": [], "valid": false }, { "description": "true is a boolean", "data": true, "valid": true }, { "description": "false is a boolean", "data": false, "valid": true }, { "description": "null is not a boolean", "data": null, "valid": false } ] }, { "description": "null type matches only the null object", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "null" }, "tests": [ { "description": "an integer is not null", "data": 1, "valid": false }, { "description": "a float is not null", "data": 1.1, "valid": false }, { "description": "zero is not null", "data": 0, "valid": false }, { "description": "a string is not null", "data": "foo", "valid": false }, { "description": "an empty string is not null", "data": "", "valid": false }, { "description": "an object is not null", "data": {}, "valid": false }, { "description": "an array is not null", "data": [], "valid": false }, { "description": "true is not null", "data": true, "valid": false }, { "description": "false is not null", "data": false, "valid": false }, { "description": "null is null", "data": null, "valid": true } ] }, { "description": "multiple types can be specified in an array", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": ["integer", "string"] }, "tests": [ { "description": "an integer is valid", "data": 1, "valid": true }, { "description": "a string is valid", "data": "foo", "valid": true }, { "description": "a float is invalid", "data": 1.1, "valid": false }, { "description": "an object is invalid", "data": {}, "valid": false }, { "description": "an array is invalid", "data": [], "valid": false }, { "description": "a boolean is invalid", "data": true, "valid": false }, { "description": "null is invalid", "data": null, "valid": false } ] }, { "description": "type as array with one item", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": ["string"] }, "tests": [ { "description": "string is valid", "data": "foo", "valid": true }, { "description": "number is invalid", "data": 123, "valid": false } ] }, { "description": "type: array or object", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": ["array", "object"] }, "tests": [ { "description": "array is valid", "data": [1,2,3], "valid": true }, { "description": "object is valid", "data": {"foo": 123}, "valid": true }, { "description": "number is invalid", "data": 123, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false }, { "description": "null is invalid", "data": null, "valid": false } ] }, { "description": "type: array, object or null", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": ["array", "object", "null"] }, "tests": [ { "description": "array is valid", "data": [1,2,3], "valid": true }, { "description": "object is valid", "data": {"foo": 123}, "valid": true }, { "description": "null is valid", "data": null, "valid": true }, { "description": "number is invalid", "data": 123, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/unevaluatedItems.json0000644000175100001770000004651014653725311025434 0ustar00runnerdocker[ { "description": "unevaluatedItems true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "unevaluatedItems": true }, "tests": [ { "description": "with no unevaluated items", "data": [], "valid": true }, { "description": "with unevaluated items", "data": ["foo"], "valid": true } ] }, { "description": "unevaluatedItems false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "unevaluatedItems": false }, "tests": [ { "description": "with no unevaluated items", "data": [], "valid": true }, { "description": "with unevaluated items", "data": ["foo"], "valid": false } ] }, { "description": "unevaluatedItems as schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "unevaluatedItems": { "type": "string" } }, "tests": [ { "description": "with no unevaluated items", "data": [], "valid": true }, { "description": "with valid unevaluated items", "data": ["foo"], "valid": true }, { "description": "with invalid unevaluated items", "data": [42], "valid": false } ] }, { "description": "unevaluatedItems with uniform items", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "items": { "type": "string" }, "unevaluatedItems": false }, "tests": [ { "description": "unevaluatedItems doesn't apply", "data": ["foo", "bar"], "valid": true } ] }, { "description": "unevaluatedItems with tuple", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [ { "type": "string" } ], "unevaluatedItems": false }, "tests": [ { "description": "with no unevaluated items", "data": ["foo"], "valid": true }, { "description": "with unevaluated items", "data": ["foo", "bar"], "valid": false } ] }, { "description": "unevaluatedItems with items", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [ { "type": "string" } ], "items": true, "unevaluatedItems": false }, "tests": [ { "description": "unevaluatedItems doesn't apply", "data": ["foo", 42], "valid": true } ] }, { "description": "unevaluatedItems with nested tuple", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [ { "type": "string" } ], "allOf": [ { "prefixItems": [ true, { "type": "number" } ] } ], "unevaluatedItems": false }, "tests": [ { "description": "with no unevaluated items", "data": ["foo", 42], "valid": true }, { "description": "with unevaluated items", "data": ["foo", 42, true], "valid": false } ] }, { "description": "unevaluatedItems with nested items", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "unevaluatedItems": {"type": "boolean"}, "anyOf": [ { "items": {"type": "string"} }, true ] }, "tests": [ { "description": "with only (valid) additional items", "data": [true, false], "valid": true }, { "description": "with no additional items", "data": ["yes", "no"], "valid": true }, { "description": "with invalid additional item", "data": ["yes", false], "valid": false } ] }, { "description": "unevaluatedItems with nested prefixItems and items", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "prefixItems": [ { "type": "string" } ], "items": true } ], "unevaluatedItems": false }, "tests": [ { "description": "with no additional items", "data": ["foo"], "valid": true }, { "description": "with additional items", "data": ["foo", 42, true], "valid": true } ] }, { "description": "unevaluatedItems with nested unevaluatedItems", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "prefixItems": [ { "type": "string" } ] }, { "unevaluatedItems": true } ], "unevaluatedItems": false }, "tests": [ { "description": "with no additional items", "data": ["foo"], "valid": true }, { "description": "with additional items", "data": ["foo", 42, true], "valid": true } ] }, { "description": "unevaluatedItems with anyOf", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [ { "const": "foo" } ], "anyOf": [ { "prefixItems": [ true, { "const": "bar" } ] }, { "prefixItems": [ true, true, { "const": "baz" } ] } ], "unevaluatedItems": false }, "tests": [ { "description": "when one schema matches and has no unevaluated items", "data": ["foo", "bar"], "valid": true }, { "description": "when one schema matches and has unevaluated items", "data": ["foo", "bar", 42], "valid": false }, { "description": "when two schemas match and has no unevaluated items", "data": ["foo", "bar", "baz"], "valid": true }, { "description": "when two schemas match and has unevaluated items", "data": ["foo", "bar", "baz", 42], "valid": false } ] }, { "description": "unevaluatedItems with oneOf", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [ { "const": "foo" } ], "oneOf": [ { "prefixItems": [ true, { "const": "bar" } ] }, { "prefixItems": [ true, { "const": "baz" } ] } ], "unevaluatedItems": false }, "tests": [ { "description": "with no unevaluated items", "data": ["foo", "bar"], "valid": true }, { "description": "with unevaluated items", "data": ["foo", "bar", 42], "valid": false } ] }, { "description": "unevaluatedItems with not", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [ { "const": "foo" } ], "not": { "not": { "prefixItems": [ true, { "const": "bar" } ] } }, "unevaluatedItems": false }, "tests": [ { "description": "with unevaluated items", "data": ["foo", "bar"], "valid": false } ] }, { "description": "unevaluatedItems with if/then/else", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [ { "const": "foo" } ], "if": { "prefixItems": [ true, { "const": "bar" } ] }, "then": { "prefixItems": [ true, true, { "const": "then" } ] }, "else": { "prefixItems": [ true, true, true, { "const": "else" } ] }, "unevaluatedItems": false }, "tests": [ { "description": "when if matches and it has no unevaluated items", "data": ["foo", "bar", "then"], "valid": true }, { "description": "when if matches and it has unevaluated items", "data": ["foo", "bar", "then", "else"], "valid": false }, { "description": "when if doesn't match and it has no unevaluated items", "data": ["foo", 42, 42, "else"], "valid": true }, { "description": "when if doesn't match and it has unevaluated items", "data": ["foo", 42, 42, "else", 42], "valid": false } ] }, { "description": "unevaluatedItems with boolean schemas", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [true], "unevaluatedItems": false }, "tests": [ { "description": "with no unevaluated items", "data": [], "valid": true }, { "description": "with unevaluated items", "data": ["foo"], "valid": false } ] }, { "description": "unevaluatedItems with $ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "#/$defs/bar", "prefixItems": [ { "type": "string" } ], "unevaluatedItems": false, "$defs": { "bar": { "prefixItems": [ true, { "type": "string" } ] } } }, "tests": [ { "description": "with no unevaluated items", "data": ["foo", "bar"], "valid": true }, { "description": "with unevaluated items", "data": ["foo", "bar", "baz"], "valid": false } ] }, { "description": "unevaluatedItems can't see inside cousins", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "prefixItems": [ true ] }, { "unevaluatedItems": false } ] }, "tests": [ { "description": "always fails", "data": [ 1 ], "valid": false } ] }, { "description": "item is evaluated in an uncle schema to unevaluatedItems", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": { "prefixItems": [ { "type": "string" } ], "unevaluatedItems": false } }, "anyOf": [ { "properties": { "foo": { "prefixItems": [ true, { "type": "string" } ] } } } ] }, "tests": [ { "description": "no extra items", "data": { "foo": [ "test" ] }, "valid": true }, { "description": "uncle keyword evaluation is not significant", "data": { "foo": [ "test", "test" ] }, "valid": false } ] }, { "description": "unevaluatedItems depends on adjacent contains", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [true], "contains": {"type": "string"}, "unevaluatedItems": false }, "tests": [ { "description": "second item is evaluated by contains", "data": [ 1, "foo" ], "valid": true }, { "description": "contains fails, second item is not evaluated", "data": [ 1, 2 ], "valid": false }, { "description": "contains passes, second item is not evaluated", "data": [ 1, 2, "foo" ], "valid": false } ] }, { "description": "unevaluatedItems depends on multiple nested contains", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "contains": { "multipleOf": 2 } }, { "contains": { "multipleOf": 3 } } ], "unevaluatedItems": { "multipleOf": 5 } }, "tests": [ { "description": "5 not evaluated, passes unevaluatedItems", "data": [ 2, 3, 4, 5, 6 ], "valid": true }, { "description": "7 not evaluated, fails unevaluatedItems", "data": [ 2, 3, 4, 7, 8 ], "valid": false } ] }, { "description": "unevaluatedItems and contains interact to control item dependency relationship", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "if": { "contains": {"const": "a"} }, "then": { "if": { "contains": {"const": "b"} }, "then": { "if": { "contains": {"const": "c"} } } }, "unevaluatedItems": false }, "tests": [ { "description": "empty array is valid", "data": [], "valid": true }, { "description": "only a's are valid", "data": [ "a", "a" ], "valid": true }, { "description": "a's and b's are valid", "data": [ "a", "b", "a", "b", "a" ], "valid": true }, { "description": "a's, b's and c's are valid", "data": [ "c", "a", "c", "c", "b", "a" ], "valid": true }, { "description": "only b's are invalid", "data": [ "b", "b" ], "valid": false }, { "description": "only c's are invalid", "data": [ "c", "c" ], "valid": false }, { "description": "only b's and c's are invalid", "data": [ "c", "b", "c", "b", "c" ], "valid": false }, { "description": "only a's and c's are invalid", "data": [ "c", "a", "c", "a", "c" ], "valid": false } ] }, { "description": "non-array instances are valid", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "unevaluatedItems": false }, "tests": [ { "description": "ignores booleans", "data": true, "valid": true }, { "description": "ignores integers", "data": 123, "valid": true }, { "description": "ignores floats", "data": 1.0, "valid": true }, { "description": "ignores objects", "data": {}, "valid": true }, { "description": "ignores strings", "data": "foo", "valid": true }, { "description": "ignores null", "data": null, "valid": true } ] }, { "description": "unevaluatedItems with null instance elements", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "unevaluatedItems": { "type": "null" } }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/unevaluatedProperties.json0000644000175100001770000012243414653725311026507 0ustar00runnerdocker[ { "description": "unevaluatedProperties true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "unevaluatedProperties": true }, "tests": [ { "description": "with no unevaluated properties", "data": {}, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo" }, "valid": true } ] }, { "description": "unevaluatedProperties schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "unevaluatedProperties": { "type": "string", "minLength": 3 } }, "tests": [ { "description": "with no unevaluated properties", "data": {}, "valid": true }, { "description": "with valid unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with invalid unevaluated properties", "data": { "foo": "fo" }, "valid": false } ] }, { "description": "unevaluatedProperties false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": {}, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo" }, "valid": false } ] }, { "description": "unevaluatedProperties with adjacent properties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "unevaluatedProperties with adjacent patternProperties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "patternProperties": { "^foo": { "type": "string" } }, "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "unevaluatedProperties with adjacent additionalProperties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "additionalProperties": true, "unevaluatedProperties": false }, "tests": [ { "description": "with no additional properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with additional properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true } ] }, { "description": "unevaluatedProperties with nested properties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "properties": { "bar": { "type": "string" } } } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no additional properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "with additional properties", "data": { "foo": "foo", "bar": "bar", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties with nested patternProperties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "patternProperties": { "^bar": { "type": "string" } } } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no additional properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "with additional properties", "data": { "foo": "foo", "bar": "bar", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties with nested additionalProperties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "additionalProperties": true } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no additional properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with additional properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true } ] }, { "description": "unevaluatedProperties with nested unevaluatedProperties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "unevaluatedProperties": true } ], "unevaluatedProperties": { "type": "string", "maxLength": 2 } }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true } ] }, { "description": "unevaluatedProperties with anyOf", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "anyOf": [ { "properties": { "bar": { "const": "bar" } }, "required": ["bar"] }, { "properties": { "baz": { "const": "baz" } }, "required": ["baz"] }, { "properties": { "quux": { "const": "quux" } }, "required": ["quux"] } ], "unevaluatedProperties": false }, "tests": [ { "description": "when one matches and has no unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "when one matches and has unevaluated properties", "data": { "foo": "foo", "bar": "bar", "baz": "not-baz" }, "valid": false }, { "description": "when two match and has no unevaluated properties", "data": { "foo": "foo", "bar": "bar", "baz": "baz" }, "valid": true }, { "description": "when two match and has unevaluated properties", "data": { "foo": "foo", "bar": "bar", "baz": "baz", "quux": "not-quux" }, "valid": false } ] }, { "description": "unevaluatedProperties with oneOf", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "oneOf": [ { "properties": { "bar": { "const": "bar" } }, "required": ["bar"] }, { "properties": { "baz": { "const": "baz" } }, "required": ["baz"] } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo", "bar": "bar", "quux": "quux" }, "valid": false } ] }, { "description": "unevaluatedProperties with not", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "not": { "not": { "properties": { "bar": { "const": "bar" } }, "required": ["bar"] } }, "unevaluatedProperties": false }, "tests": [ { "description": "with unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "unevaluatedProperties with if/then/else", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "if": { "properties": { "foo": { "const": "then" } }, "required": ["foo"] }, "then": { "properties": { "bar": { "type": "string" } }, "required": ["bar"] }, "else": { "properties": { "baz": { "type": "string" } }, "required": ["baz"] }, "unevaluatedProperties": false }, "tests": [ { "description": "when if is true and has no unevaluated properties", "data": { "foo": "then", "bar": "bar" }, "valid": true }, { "description": "when if is true and has unevaluated properties", "data": { "foo": "then", "bar": "bar", "baz": "baz" }, "valid": false }, { "description": "when if is false and has no unevaluated properties", "data": { "baz": "baz" }, "valid": true }, { "description": "when if is false and has unevaluated properties", "data": { "foo": "else", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties with if/then/else, then not defined", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "if": { "properties": { "foo": { "const": "then" } }, "required": ["foo"] }, "else": { "properties": { "baz": { "type": "string" } }, "required": ["baz"] }, "unevaluatedProperties": false }, "tests": [ { "description": "when if is true and has no unevaluated properties", "data": { "foo": "then", "bar": "bar" }, "valid": false }, { "description": "when if is true and has unevaluated properties", "data": { "foo": "then", "bar": "bar", "baz": "baz" }, "valid": false }, { "description": "when if is false and has no unevaluated properties", "data": { "baz": "baz" }, "valid": true }, { "description": "when if is false and has unevaluated properties", "data": { "foo": "else", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties with if/then/else, else not defined", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "if": { "properties": { "foo": { "const": "then" } }, "required": ["foo"] }, "then": { "properties": { "bar": { "type": "string" } }, "required": ["bar"] }, "unevaluatedProperties": false }, "tests": [ { "description": "when if is true and has no unevaluated properties", "data": { "foo": "then", "bar": "bar" }, "valid": true }, { "description": "when if is true and has unevaluated properties", "data": { "foo": "then", "bar": "bar", "baz": "baz" }, "valid": false }, { "description": "when if is false and has no unevaluated properties", "data": { "baz": "baz" }, "valid": false }, { "description": "when if is false and has unevaluated properties", "data": { "foo": "else", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties with dependentSchemas", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "dependentSchemas": { "foo": { "properties": { "bar": { "const": "bar" } }, "required": ["bar"] } }, "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "with unevaluated properties", "data": { "bar": "bar" }, "valid": false } ] }, { "description": "unevaluatedProperties with boolean schemas", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [true], "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with unevaluated properties", "data": { "bar": "bar" }, "valid": false } ] }, { "description": "unevaluatedProperties with $ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "$ref": "#/$defs/bar", "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": false, "$defs": { "bar": { "properties": { "bar": { "type": "string" } } } } }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo", "bar": "bar", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties can't see inside cousins", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "properties": { "foo": true } }, { "unevaluatedProperties": false } ] }, "tests": [ { "description": "always fails", "data": { "foo": 1 }, "valid": false } ] }, { "description": "unevaluatedProperties can't see inside cousins (reverse order)", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "unevaluatedProperties": false }, { "properties": { "foo": true } } ] }, "tests": [ { "description": "always fails", "data": { "foo": 1 }, "valid": false } ] }, { "description": "nested unevaluatedProperties, outer false, inner true, properties outside", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "unevaluatedProperties": true } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true } ] }, { "description": "nested unevaluatedProperties, outer false, inner true, properties inside", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "allOf": [ { "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": true } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true } ] }, { "description": "nested unevaluatedProperties, outer true, inner false, properties outside", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "unevaluatedProperties": false } ], "unevaluatedProperties": true }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": false }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "nested unevaluatedProperties, outer true, inner false, properties inside", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "allOf": [ { "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": false } ], "unevaluatedProperties": true }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "cousin unevaluatedProperties, true and false, true with properties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "allOf": [ { "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": true }, { "unevaluatedProperties": false } ] }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": false }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "cousin unevaluatedProperties, true and false, false with properties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "allOf": [ { "unevaluatedProperties": true }, { "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": false } ] }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "property is evaluated in an uncle schema to unevaluatedProperties", "comment": "see https://stackoverflow.com/questions/66936884/deeply-nested-unevaluatedproperties-and-their-expectations", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "object", "properties": { "bar": { "type": "string" } }, "unevaluatedProperties": false } }, "anyOf": [ { "properties": { "foo": { "properties": { "faz": { "type": "string" } } } } } ] }, "tests": [ { "description": "no extra properties", "data": { "foo": { "bar": "test" } }, "valid": true }, { "description": "uncle keyword evaluation is not significant", "data": { "foo": { "bar": "test", "faz": "test" } }, "valid": false } ] }, { "description": "in-place applicator siblings, allOf has unevaluated", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "allOf": [ { "properties": { "foo": true }, "unevaluatedProperties": false } ], "anyOf": [ { "properties": { "bar": true } } ] }, "tests": [ { "description": "base case: both properties present", "data": { "foo": 1, "bar": 1 }, "valid": false }, { "description": "in place applicator siblings, bar is missing", "data": { "foo": 1 }, "valid": true }, { "description": "in place applicator siblings, foo is missing", "data": { "bar": 1 }, "valid": false } ] }, { "description": "in-place applicator siblings, anyOf has unevaluated", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "allOf": [ { "properties": { "foo": true } } ], "anyOf": [ { "properties": { "bar": true }, "unevaluatedProperties": false } ] }, "tests": [ { "description": "base case: both properties present", "data": { "foo": 1, "bar": 1 }, "valid": false }, { "description": "in place applicator siblings, bar is missing", "data": { "foo": 1 }, "valid": false }, { "description": "in place applicator siblings, foo is missing", "data": { "bar": 1 }, "valid": true } ] }, { "description": "unevaluatedProperties + single cyclic ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "x": { "$ref": "#" } }, "unevaluatedProperties": false }, "tests": [ { "description": "Empty is valid", "data": {}, "valid": true }, { "description": "Single is valid", "data": { "x": {} }, "valid": true }, { "description": "Unevaluated on 1st level is invalid", "data": { "x": {}, "y": {} }, "valid": false }, { "description": "Nested is valid", "data": { "x": { "x": {} } }, "valid": true }, { "description": "Unevaluated on 2nd level is invalid", "data": { "x": { "x": {}, "y": {} } }, "valid": false }, { "description": "Deep nested is valid", "data": { "x": { "x": { "x": {} } } }, "valid": true }, { "description": "Unevaluated on 3rd level is invalid", "data": { "x": { "x": { "x": {}, "y": {} } } }, "valid": false } ] }, { "description": "unevaluatedProperties + ref inside allOf / oneOf", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "one": { "properties": { "a": true } }, "two": { "required": ["x"], "properties": { "x": true } } }, "allOf": [ { "$ref": "#/$defs/one" }, { "properties": { "b": true } }, { "oneOf": [ { "$ref": "#/$defs/two" }, { "required": ["y"], "properties": { "y": true } } ] } ], "unevaluatedProperties": false }, "tests": [ { "description": "Empty is invalid (no x or y)", "data": {}, "valid": false }, { "description": "a and b are invalid (no x or y)", "data": { "a": 1, "b": 1 }, "valid": false }, { "description": "x and y are invalid", "data": { "x": 1, "y": 1 }, "valid": false }, { "description": "a and x are valid", "data": { "a": 1, "x": 1 }, "valid": true }, { "description": "a and y are valid", "data": { "a": 1, "y": 1 }, "valid": true }, { "description": "a and b and x are valid", "data": { "a": 1, "b": 1, "x": 1 }, "valid": true }, { "description": "a and b and y are valid", "data": { "a": 1, "b": 1, "y": 1 }, "valid": true }, { "description": "a and b and x and y are invalid", "data": { "a": 1, "b": 1, "x": 1, "y": 1 }, "valid": false } ] }, { "description": "dynamic evalation inside nested refs", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "one": { "oneOf": [ { "$ref": "#/$defs/two" }, { "required": ["b"], "properties": { "b": true } }, { "required": ["xx"], "patternProperties": { "x": true } }, { "required": ["all"], "unevaluatedProperties": true } ] }, "two": { "oneOf": [ { "required": ["c"], "properties": { "c": true } }, { "required": ["d"], "properties": { "d": true } } ] } }, "oneOf": [ { "$ref": "#/$defs/one" }, { "required": ["a"], "properties": { "a": true } } ], "unevaluatedProperties": false }, "tests": [ { "description": "Empty is invalid", "data": {}, "valid": false }, { "description": "a is valid", "data": { "a": 1 }, "valid": true }, { "description": "b is valid", "data": { "b": 1 }, "valid": true }, { "description": "c is valid", "data": { "c": 1 }, "valid": true }, { "description": "d is valid", "data": { "d": 1 }, "valid": true }, { "description": "a + b is invalid", "data": { "a": 1, "b": 1 }, "valid": false }, { "description": "a + c is invalid", "data": { "a": 1, "c": 1 }, "valid": false }, { "description": "a + d is invalid", "data": { "a": 1, "d": 1 }, "valid": false }, { "description": "b + c is invalid", "data": { "b": 1, "c": 1 }, "valid": false }, { "description": "b + d is invalid", "data": { "b": 1, "d": 1 }, "valid": false }, { "description": "c + d is invalid", "data": { "c": 1, "d": 1 }, "valid": false }, { "description": "xx is valid", "data": { "xx": 1 }, "valid": true }, { "description": "xx + foox is valid", "data": { "xx": 1, "foox": 1 }, "valid": true }, { "description": "xx + foo is invalid", "data": { "xx": 1, "foo": 1 }, "valid": false }, { "description": "xx + a is invalid", "data": { "xx": 1, "a": 1 }, "valid": false }, { "description": "xx + b is invalid", "data": { "xx": 1, "b": 1 }, "valid": false }, { "description": "xx + c is invalid", "data": { "xx": 1, "c": 1 }, "valid": false }, { "description": "xx + d is invalid", "data": { "xx": 1, "d": 1 }, "valid": false }, { "description": "all is valid", "data": { "all": 1 }, "valid": true }, { "description": "all + foo is valid", "data": { "all": 1, "foo": 1 }, "valid": true }, { "description": "all + a is invalid", "data": { "all": 1, "a": 1 }, "valid": false } ] }, { "description": "non-object instances are valid", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "unevaluatedProperties": false }, "tests": [ { "description": "ignores booleans", "data": true, "valid": true }, { "description": "ignores integers", "data": 123, "valid": true }, { "description": "ignores floats", "data": 1.0, "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "foo", "valid": true }, { "description": "ignores null", "data": null, "valid": true } ] }, { "description": "unevaluatedProperties with null valued instance properties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "unevaluatedProperties": { "type": "null" } }, "tests": [ { "description": "allows null valued properties", "data": {"foo": null}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/uniqueItems.json0000644000175100001770000003367014653725311024430 0ustar00runnerdocker[ { "description": "uniqueItems validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "uniqueItems": true }, "tests": [ { "description": "unique array of integers is valid", "data": [1, 2], "valid": true }, { "description": "non-unique array of integers is invalid", "data": [1, 1], "valid": false }, { "description": "non-unique array of more than two integers is invalid", "data": [1, 2, 1], "valid": false }, { "description": "numbers are unique if mathematically unequal", "data": [1.0, 1.00, 1], "valid": false }, { "description": "false is not equal to zero", "data": [0, false], "valid": true }, { "description": "true is not equal to one", "data": [1, true], "valid": true }, { "description": "unique array of strings is valid", "data": ["foo", "bar", "baz"], "valid": true }, { "description": "non-unique array of strings is invalid", "data": ["foo", "bar", "foo"], "valid": false }, { "description": "unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "baz"}], "valid": true }, { "description": "non-unique array of objects is invalid", "data": [{"foo": "bar"}, {"foo": "bar"}], "valid": false }, { "description": "unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : false}}} ], "valid": true }, { "description": "non-unique array of nested objects is invalid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : true}}} ], "valid": false }, { "description": "unique array of arrays is valid", "data": [["foo"], ["bar"]], "valid": true }, { "description": "non-unique array of arrays is invalid", "data": [["foo"], ["foo"]], "valid": false }, { "description": "non-unique array of more than two arrays is invalid", "data": [["foo"], ["bar"], ["foo"]], "valid": false }, { "description": "1 and true are unique", "data": [1, true], "valid": true }, { "description": "0 and false are unique", "data": [0, false], "valid": true }, { "description": "[1] and [true] are unique", "data": [[1], [true]], "valid": true }, { "description": "[0] and [false] are unique", "data": [[0], [false]], "valid": true }, { "description": "nested [1] and [true] are unique", "data": [[[1], "foo"], [[true], "foo"]], "valid": true }, { "description": "nested [0] and [false] are unique", "data": [[[0], "foo"], [[false], "foo"]], "valid": true }, { "description": "unique heterogeneous types are valid", "data": [{}, [1], true, null, 1, "{}"], "valid": true }, { "description": "non-unique heterogeneous types are invalid", "data": [{}, [1], true, null, {}, 1], "valid": false }, { "description": "different objects are unique", "data": [{"a": 1, "b": 2}, {"a": 2, "b": 1}], "valid": true }, { "description": "objects are non-unique despite key order", "data": [{"a": 1, "b": 2}, {"b": 2, "a": 1}], "valid": false }, { "description": "{\"a\": false} and {\"a\": 0} are unique", "data": [{"a": false}, {"a": 0}], "valid": true }, { "description": "{\"a\": true} and {\"a\": 1} are unique", "data": [{"a": true}, {"a": 1}], "valid": true } ] }, { "description": "uniqueItems with an array of items", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": true }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is not valid", "data": [false, false], "valid": false }, { "description": "[true, true] from items array is not valid", "data": [true, true], "valid": false }, { "description": "unique array extended from [false, true] is valid", "data": [false, true, "foo", "bar"], "valid": true }, { "description": "unique array extended from [true, false] is valid", "data": [true, false, "foo", "bar"], "valid": true }, { "description": "non-unique array extended from [false, true] is not valid", "data": [false, true, "foo", "foo"], "valid": false }, { "description": "non-unique array extended from [true, false] is not valid", "data": [true, false, "foo", "foo"], "valid": false } ] }, { "description": "uniqueItems with an array of items and additionalItems=false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": true, "items": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is not valid", "data": [false, false], "valid": false }, { "description": "[true, true] from items array is not valid", "data": [true, true], "valid": false }, { "description": "extra items are invalid even if unique", "data": [false, true, null], "valid": false } ] }, { "description": "uniqueItems=false validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "uniqueItems": false }, "tests": [ { "description": "unique array of integers is valid", "data": [1, 2], "valid": true }, { "description": "non-unique array of integers is valid", "data": [1, 1], "valid": true }, { "description": "numbers are unique if mathematically unequal", "data": [1.0, 1.00, 1], "valid": true }, { "description": "false is not equal to zero", "data": [0, false], "valid": true }, { "description": "true is not equal to one", "data": [1, true], "valid": true }, { "description": "unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "baz"}], "valid": true }, { "description": "non-unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "bar"}], "valid": true }, { "description": "unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : false}}} ], "valid": true }, { "description": "non-unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : true}}} ], "valid": true }, { "description": "unique array of arrays is valid", "data": [["foo"], ["bar"]], "valid": true }, { "description": "non-unique array of arrays is valid", "data": [["foo"], ["foo"]], "valid": true }, { "description": "1 and true are unique", "data": [1, true], "valid": true }, { "description": "0 and false are unique", "data": [0, false], "valid": true }, { "description": "unique heterogeneous types are valid", "data": [{}, [1], true, null, 1], "valid": true }, { "description": "non-unique heterogeneous types are valid", "data": [{}, [1], true, null, {}, 1], "valid": true } ] }, { "description": "uniqueItems=false with an array of items", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is valid", "data": [false, false], "valid": true }, { "description": "[true, true] from items array is valid", "data": [true, true], "valid": true }, { "description": "unique array extended from [false, true] is valid", "data": [false, true, "foo", "bar"], "valid": true }, { "description": "unique array extended from [true, false] is valid", "data": [true, false, "foo", "bar"], "valid": true }, { "description": "non-unique array extended from [false, true] is valid", "data": [false, true, "foo", "foo"], "valid": true }, { "description": "non-unique array extended from [true, false] is valid", "data": [true, false, "foo", "foo"], "valid": true } ] }, { "description": "uniqueItems=false with an array of items and additionalItems=false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": false, "items": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is valid", "data": [false, false], "valid": true }, { "description": "[true, true] from items array is valid", "data": [true, true], "valid": true }, { "description": "extra items are invalid even if unique", "data": [false, true, null], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/unknownKeyword.json0000644000175100001770000000411314653725311025152 0ustar00runnerdocker[ { "description": "$id inside an unknown keyword is not a real identifier", "comment": "the implementation must not be confused by an $id in locations we do not know how to parse", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "id_in_unknown0": { "not": { "array_of_schemas": [ { "$id": "https://localhost:1234/draft2020-12/unknownKeyword/my_identifier.json", "type": "null" } ] } }, "real_id_in_schema": { "$id": "https://localhost:1234/draft2020-12/unknownKeyword/my_identifier.json", "type": "string" }, "id_in_unknown1": { "not": { "object_of_schemas": { "foo": { "$id": "https://localhost:1234/draft2020-12/unknownKeyword/my_identifier.json", "type": "integer" } } } } }, "anyOf": [ { "$ref": "#/$defs/id_in_unknown0" }, { "$ref": "#/$defs/id_in_unknown1" }, { "$ref": "https://localhost:1234/draft2020-12/unknownKeyword/my_identifier.json" } ] }, "tests": [ { "description": "type matches second anyOf, which has a real schema in it", "data": "a string", "valid": true }, { "description": "type matches non-schema in first anyOf", "data": null, "valid": false }, { "description": "type matches non-schema in third anyOf", "data": 1, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft2020-12/vocabulary.json0000644000175100001770000000221714653725311024260 0ustar00runnerdocker[ { "description": "schema that uses custom metaschema with with no validation vocabulary", "schema": { "$id": "https://schema/using/no/validation", "$schema": "http://localhost:1234/draft2020-12/metaschema-no-validation.json", "properties": { "badProperty": false, "numberProperty": { "minimum": 10 } } }, "tests": [ { "description": "applicator vocabulary still works", "data": { "badProperty": "this property should not exist" }, "valid": false }, { "description": "no validation: valid number", "data": { "numberProperty": 20 }, "valid": true }, { "description": "no validation: invalid number, but it still validates", "data": { "numberProperty": 1 }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.081097 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/0000755000175100001770000000000014653725331020555 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/additionalItems.json0000644000175100001770000000700114653725311024556 0ustar00runnerdocker[ { "description": "additionalItems as schema", "schema": { "items": [], "additionalItems": {"type": "integer"} }, "tests": [ { "description": "additional items match schema", "data": [ 1, 2, 3, 4 ], "valid": true }, { "description": "additional items do not match schema", "data": [ 1, 2, 3, "foo" ], "valid": false } ] }, { "description": "when items is schema, additionalItems does nothing", "schema": { "items": {}, "additionalItems": false }, "tests": [ { "description": "all items match schema", "data": [ 1, 2, 3, 4, 5 ], "valid": true } ] }, { "description": "array of items with no additionalItems permitted", "schema": { "items": [{}, {}, {}], "additionalItems": false }, "tests": [ { "description": "empty array", "data": [ ], "valid": true }, { "description": "fewer number of items present (1)", "data": [ 1 ], "valid": true }, { "description": "fewer number of items present (2)", "data": [ 1, 2 ], "valid": true }, { "description": "equal number of items present", "data": [ 1, 2, 3 ], "valid": true }, { "description": "additional items are not permitted", "data": [ 1, 2, 3, 4 ], "valid": false } ] }, { "description": "additionalItems as false without items", "schema": {"additionalItems": false}, "tests": [ { "description": "items defaults to empty schema so everything is valid", "data": [ 1, 2, 3, 4, 5 ], "valid": true }, { "description": "ignores non-arrays", "data": {"foo" : "bar"}, "valid": true } ] }, { "description": "additionalItems are allowed by default", "schema": {"items": [{"type": "integer"}]}, "tests": [ { "description": "only the first item is validated", "data": [1, "foo", false], "valid": true } ] }, { "description": "additionalItems does not look in applicators", "schema": { "extends": [ { "items": [ { "type": "integer" } ] } ], "additionalItems": { "type": "boolean" } }, "tests": [ { "description": "items defined in extends are not examined", "data": [ 1, null ], "valid": true } ] }, { "description": "additionalItems with null instance elements", "schema": { "additionalItems": { "type": "null" } }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/additionalProperties.json0000644000175100001770000001051614653725311025636 0ustar00runnerdocker[ { "description": "additionalProperties being false does not allow other properties", "schema": { "properties": {"foo": {}, "bar": {}}, "patternProperties": { "^v": {} }, "additionalProperties": false }, "tests": [ { "description": "no additional properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "an additional property is invalid", "data": {"foo" : 1, "bar" : 2, "quux" : "boom"}, "valid": false }, { "description": "ignores arrays", "data": [1, 2, 3], "valid": true }, { "description": "ignores strings", "data": "foobarbaz", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "patternProperties are not additional properties", "data": {"foo":1, "vroom": 2}, "valid": true } ] }, { "description": "non-ASCII pattern with additionalProperties", "schema": { "patternProperties": {"^á": {}}, "additionalProperties": false }, "tests": [ { "description": "matching the pattern is valid", "data": {"ármányos": 2}, "valid": true }, { "description": "not matching the pattern is invalid", "data": {"élmény": 2}, "valid": false } ] }, { "description": "additionalProperties with schema", "schema": { "properties": {"foo": {}, "bar": {}}, "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "no additional properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "an additional valid property is valid", "data": {"foo" : 1, "bar" : 2, "quux" : true}, "valid": true }, { "description": "an additional invalid property is invalid", "data": {"foo" : 1, "bar" : 2, "quux" : 12}, "valid": false } ] }, { "description": "additionalProperties can exist by itself", "schema": { "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "an additional valid property is valid", "data": {"foo" : true}, "valid": true }, { "description": "an additional invalid property is invalid", "data": {"foo" : 1}, "valid": false } ] }, { "description": "additionalProperties are allowed by default", "schema": {"properties": {"foo": {}, "bar": {}}}, "tests": [ { "description": "additional properties are allowed", "data": {"foo": 1, "bar": 2, "quux": true}, "valid": true } ] }, { "description": "additionalProperties does not look in applicators", "schema": { "extends": [ {"properties": {"foo": {}}} ], "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "properties defined in extends are not examined", "data": {"foo": 1, "bar": true}, "valid": false } ] }, { "description": "additionalProperties with null valued instance properties", "schema": { "additionalProperties": { "type": "null" } }, "tests": [ { "description": "allows null values", "data": {"foo": null}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/default.json0000644000175100001770000000426714653725311023103 0ustar00runnerdocker[ { "description": "invalid type for default", "schema": { "properties": { "foo": { "type": "integer", "default": [] } } }, "tests": [ { "description": "valid when property is specified", "data": {"foo": 13}, "valid": true }, { "description": "still valid when the invalid default is used", "data": {}, "valid": true } ] }, { "description": "invalid string value for default", "schema": { "properties": { "bar": { "type": "string", "minLength": 4, "default": "bad" } } }, "tests": [ { "description": "valid when property is specified", "data": {"bar": "good"}, "valid": true }, { "description": "still valid when the invalid default is used", "data": {}, "valid": true } ] }, { "description": "the default keyword does not do anything if the property is missing", "schema": { "type": "object", "properties": { "alpha": { "type": "number", "maximum": 3, "default": 5 } } }, "tests": [ { "description": "an explicit property value is checked against maximum (passing)", "data": { "alpha": 1 }, "valid": true }, { "description": "an explicit property value is checked against maximum (failing)", "data": { "alpha": 5 }, "valid": false }, { "description": "missing properties are not filled in with the default", "data": {}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/dependencies.json0000644000175100001770000000654014653725311024101 0ustar00runnerdocker[ { "description": "dependencies", "schema": { "dependencies": {"bar": "foo"} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependant", "data": {"foo": 1}, "valid": true }, { "description": "with dependency", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "missing dependency", "data": {"bar": 2}, "valid": false }, { "description": "ignores arrays", "data": ["bar"], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "multiple dependencies", "schema": { "dependencies": {"quux": ["foo", "bar"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependants", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "with dependencies", "data": {"foo": 1, "bar": 2, "quux": 3}, "valid": true }, { "description": "missing dependency", "data": {"foo": 1, "quux": 2}, "valid": false }, { "description": "missing other dependency", "data": {"bar": 1, "quux": 2}, "valid": false }, { "description": "missing both dependencies", "data": {"quux": 1}, "valid": false } ] }, { "description": "multiple dependencies subschema", "schema": { "dependencies": { "bar": { "properties": { "foo": {"type": "integer"}, "bar": {"type": "integer"} } } } }, "tests": [ { "description": "valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "no dependency", "data": {"foo": "quux"}, "valid": true }, { "description": "wrong type", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "wrong type other", "data": {"foo": 2, "bar": "quux"}, "valid": false }, { "description": "wrong type both", "data": {"foo": "quux", "bar": "quux"}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/disallow.json0000644000175100001770000000362014653725311023265 0ustar00runnerdocker[ { "description": "disallow", "schema": { "disallow": "integer" }, "tests": [ { "description": "allowed", "data": "foo", "valid": true }, { "description": "disallowed", "data": 1, "valid": false } ] }, { "description": "multiple disallow", "schema": { "disallow": ["integer", "boolean"] }, "tests": [ { "description": "valid", "data": "foo", "valid": true }, { "description": "mismatch", "data": 1, "valid": false }, { "description": "other mismatch", "data": true, "valid": false } ] }, { "description": "multiple disallow subschema", "schema": { "disallow": ["string", { "type": "object", "properties": { "foo": { "type": "string" } } }] }, "tests": [ { "description": "match", "data": 1, "valid": true }, { "description": "other match", "data": {"foo": 1}, "valid": true }, { "description": "mismatch", "data": "foo", "valid": false }, { "description": "other mismatch", "data": {"foo": "bar"}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/divisibleBy.json0000644000175100001770000000301014653725311023705 0ustar00runnerdocker[ { "description": "by int", "schema": {"divisibleBy": 2}, "tests": [ { "description": "int by int", "data": 10, "valid": true }, { "description": "int by int fail", "data": 7, "valid": false }, { "description": "ignores non-numbers", "data": "foo", "valid": true } ] }, { "description": "by number", "schema": {"divisibleBy": 1.5}, "tests": [ { "description": "zero is divisible by anything (except 0)", "data": 0, "valid": true }, { "description": "4.5 is divisible by 1.5", "data": 4.5, "valid": true }, { "description": "35 is not divisible by 1.5", "data": 35, "valid": false } ] }, { "description": "by small number", "schema": {"divisibleBy": 0.0001}, "tests": [ { "description": "0.0075 is divisible by 0.0001", "data": 0.0075, "valid": true }, { "description": "0.00751 is not divisible by 0.0001", "data": 0.00751, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/enum.json0000644000175100001770000000644014653725311022416 0ustar00runnerdocker[ { "description": "simple enum validation", "schema": {"enum": [1, 2, 3]}, "tests": [ { "description": "one of the enum is valid", "data": 1, "valid": true }, { "description": "something else is invalid", "data": 4, "valid": false } ] }, { "description": "heterogeneous enum validation", "schema": {"enum": [6, "foo", [], true, {"foo": 12}]}, "tests": [ { "description": "one of the enum is valid", "data": [], "valid": true }, { "description": "something else is invalid", "data": null, "valid": false }, { "description": "objects are deep compared", "data": {"foo": false}, "valid": false } ] }, { "description": "heterogeneous enum-with-null validation", "schema": { "enum": [6, null] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "number is valid", "data": 6, "valid": true }, { "description": "something else is invalid", "data": "test", "valid": false } ] }, { "description": "enums in properties", "schema": { "type":"object", "properties": { "foo": {"enum":["foo"]}, "bar": {"enum":["bar"], "required":true} } }, "tests": [ { "description": "both properties are valid", "data": {"foo":"foo", "bar":"bar"}, "valid": true }, { "description": "wrong foo value", "data": {"foo":"foot", "bar":"bar"}, "valid": false }, { "description": "wrong bar value", "data": {"foo":"foo", "bar":"bart"}, "valid": false }, { "description": "missing optional property is valid", "data": {"bar":"bar"}, "valid": true }, { "description": "missing required property is invalid", "data": {"foo":"foo"}, "valid": false }, { "description": "missing all properties is invalid", "data": {}, "valid": false } ] }, { "description": "nul characters in strings", "schema": { "enum": [ "hello\u0000there" ] }, "tests": [ { "description": "match string with nul", "data": "hello\u0000there", "valid": true }, { "description": "do not match string lacking nul", "data": "hellothere", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/extends.json0000644000175100001770000000503714653725311023125 0ustar00runnerdocker[ { "description": "extends", "schema": { "properties": {"bar": {"type": "integer", "required": true}}, "extends": { "properties": { "foo": {"type": "string", "required": true} } } }, "tests": [ { "description": "extends", "data": {"foo": "baz", "bar": 2}, "valid": true }, { "description": "mismatch extends", "data": {"foo": "baz"}, "valid": false }, { "description": "mismatch extended", "data": {"bar": 2}, "valid": false }, { "description": "wrong type", "data": {"foo": "baz", "bar": "quux"}, "valid": false } ] }, { "description": "multiple extends", "schema": { "properties": {"bar": {"type": "integer", "required": true}}, "extends" : [ { "properties": { "foo": {"type": "string", "required": true} } }, { "properties": { "baz": {"type": "null", "required": true} } } ] }, "tests": [ { "description": "valid", "data": {"foo": "quux", "bar": 2, "baz": null}, "valid": true }, { "description": "mismatch first extends", "data": {"bar": 2, "baz": null}, "valid": false }, { "description": "mismatch second extends", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "mismatch both", "data": {"bar": 2}, "valid": false } ] }, { "description": "extends simple types", "schema": { "minimum": 20, "extends": {"maximum": 30} }, "tests": [ { "description": "valid", "data": 25, "valid": true }, { "description": "mismatch extends", "data": 35, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/format.json0000644000175100001770000002452314653725311022744 0ustar00runnerdocker[ { "description": "email format", "schema": { "format": "email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "ip-address format", "schema": { "format": "ip-address" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "ipv6 format", "schema": { "format": "ipv6" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "host-name format", "schema": { "format": "host-name" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "date-time format", "schema": { "format": "date-time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "regex format", "schema": { "format": "regex" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "date format", "schema": { "format": "date" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "time format", "schema": { "format": "time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "color format", "schema": { "format": "color" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uri format", "schema": { "format": "uri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/infinite-loop-detection.json0000644000175100001770000000155414653725311026203 0ustar00runnerdocker[ { "description": "evaluating the same schema location against the same data location twice is not a sign of an infinite loop", "schema": { "definitions": { "int": { "type": "integer" } }, "properties": { "foo": { "$ref": "#/definitions/int" } }, "extends": { "additionalProperties": { "$ref": "#/definitions/int" } } }, "tests": [ { "description": "passing case", "data": { "foo": 1 }, "valid": true }, { "description": "failing case", "data": { "foo": "a string" }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/items.json0000644000175100001770000000353314653725311022573 0ustar00runnerdocker[ { "description": "a schema given for items", "schema": { "items": {"type": "integer"} }, "tests": [ { "description": "valid items", "data": [ 1, 2, 3 ], "valid": true }, { "description": "wrong type of items", "data": [1, "x"], "valid": false }, { "description": "ignores non-arrays", "data": {"foo" : "bar"}, "valid": true } ] }, { "description": "an array of schemas for items", "schema": { "items": [ {"type": "integer"}, {"type": "string"} ] }, "tests": [ { "description": "correct types", "data": [ 1, "foo" ], "valid": true }, { "description": "wrong types", "data": [ "foo", 1 ], "valid": false } ] }, { "description": "items with null instance elements", "schema": { "items": { "type": "null" } }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] }, { "description": "array-form items with null instance elements", "schema": { "items": [ { "type": "null" } ] }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/maxItems.json0000644000175100001770000000130214653725311023231 0ustar00runnerdocker[ { "description": "maxItems validation", "schema": {"maxItems": 2}, "tests": [ { "description": "shorter is valid", "data": [1], "valid": true }, { "description": "exact length is valid", "data": [1, 2], "valid": true }, { "description": "too long is invalid", "data": [1, 2, 3], "valid": false }, { "description": "ignores non-arrays", "data": "foobar", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/maxLength.json0000644000175100001770000000157714653725311023407 0ustar00runnerdocker[ { "description": "maxLength validation", "schema": {"maxLength": 2}, "tests": [ { "description": "shorter is valid", "data": "f", "valid": true }, { "description": "exact length is valid", "data": "fo", "valid": true }, { "description": "too long is invalid", "data": "foo", "valid": false }, { "description": "ignores non-strings", "data": 10, "valid": true }, { "description": "two supplementary Unicode code points is long enough", "data": "\uD83D\uDCA9\uD83D\uDCA9", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/maximum.json0000644000175100001770000000526214653725311023130 0ustar00runnerdocker[ { "description": "maximum validation", "schema": {"maximum": 3.0}, "tests": [ { "description": "below the maximum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 3.0, "valid": true }, { "description": "above the maximum is invalid", "data": 3.5, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] }, { "description": "maximum validation with unsigned integer", "schema": {"maximum": 300}, "tests": [ { "description": "below the maximum is invalid", "data": 299.97, "valid": true }, { "description": "boundary point integer is valid", "data": 300, "valid": true }, { "description": "boundary point float is valid", "data": 300.00, "valid": true }, { "description": "above the maximum is invalid", "data": 300.5, "valid": false } ] }, { "description": "maximum validation (explicit false exclusivity)", "schema": {"maximum": 3.0, "exclusiveMaximum": false}, "tests": [ { "description": "below the maximum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 3.0, "valid": true }, { "description": "above the maximum is invalid", "data": 3.5, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] }, { "description": "exclusiveMaximum validation", "schema": { "maximum": 3.0, "exclusiveMaximum": true }, "tests": [ { "description": "below the maximum is still valid", "data": 2.2, "valid": true }, { "description": "boundary point is invalid", "data": 3.0, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/minItems.json0000644000175100001770000000126514653725311023237 0ustar00runnerdocker[ { "description": "minItems validation", "schema": {"minItems": 1}, "tests": [ { "description": "longer is valid", "data": [1, 2], "valid": true }, { "description": "exact length is valid", "data": [1], "valid": true }, { "description": "too short is invalid", "data": [], "valid": false }, { "description": "ignores non-arrays", "data": "", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/minLength.json0000644000175100001770000000156614653725311023403 0ustar00runnerdocker[ { "description": "minLength validation", "schema": {"minLength": 2}, "tests": [ { "description": "longer is valid", "data": "foo", "valid": true }, { "description": "exact length is valid", "data": "fo", "valid": true }, { "description": "too short is invalid", "data": "f", "valid": false }, { "description": "ignores non-strings", "data": 1, "valid": true }, { "description": "one supplementary Unicode code point is not long enough", "data": "\uD83D\uDCA9", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/minimum.json0000644000175100001770000000457114653725311023130 0ustar00runnerdocker[ { "description": "minimum validation", "schema": {"minimum": 1.1}, "tests": [ { "description": "above the minimum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 1.1, "valid": true }, { "description": "below the minimum is invalid", "data": 0.6, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] }, { "description": "exclusiveMinimum validation", "schema": { "minimum": 1.1, "exclusiveMinimum": true }, "tests": [ { "description": "above the minimum is still valid", "data": 1.2, "valid": true }, { "description": "boundary point is invalid", "data": 1.1, "valid": false } ] }, { "description": "minimum validation with signed integer", "schema": {"minimum": -2}, "tests": [ { "description": "negative above the minimum is valid", "data": -1, "valid": true }, { "description": "positive above the minimum is valid", "data": 0, "valid": true }, { "description": "boundary point is valid", "data": -2, "valid": true }, { "description": "boundary point with float is valid", "data": -2.0, "valid": true }, { "description": "float below the minimum is invalid", "data": -2.0001, "valid": false }, { "description": "int below the minimum is invalid", "data": -3, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.081097 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/optional/0000755000175100001770000000000014653725331022402 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/optional/bignum.json0000644000175100001770000000547314653725311024565 0ustar00runnerdocker[ { "description": "integer", "schema": { "type": "integer" }, "tests": [ { "description": "a bignum is an integer", "data": 12345678910111213141516171819202122232425262728293031, "valid": true }, { "description": "a negative bignum is an integer", "data": -12345678910111213141516171819202122232425262728293031, "valid": true } ] }, { "description": "number", "schema": { "type": "number" }, "tests": [ { "description": "a bignum is a number", "data": 98249283749234923498293171823948729348710298301928331, "valid": true }, { "description": "a negative bignum is a number", "data": -98249283749234923498293171823948729348710298301928331, "valid": true } ] }, { "description": "string", "schema": { "type": "string" }, "tests": [ { "description": "a bignum is not a string", "data": 98249283749234923498293171823948729348710298301928331, "valid": false } ] }, { "description": "maximum integer comparison", "schema": { "maximum": 18446744073709551615 }, "tests": [ { "description": "comparison works for high numbers", "data": 18446744073709551600, "valid": true } ] }, { "description": "float comparison with high precision", "schema": { "maximum": 972783798187987123879878123.18878137, "exclusiveMaximum": true }, "tests": [ { "description": "comparison works for high numbers", "data": 972783798187987123879878123.188781371, "valid": false } ] }, { "description": "minimum integer comparison", "schema": { "minimum": -18446744073709551615 }, "tests": [ { "description": "comparison works for very negative numbers", "data": -18446744073709551600, "valid": true } ] }, { "description": "float comparison with high precision on negative numbers", "schema": { "minimum": -972783798187987123879878123.18878137, "exclusiveMinimum": true }, "tests": [ { "description": "comparison works for very negative numbers", "data": -972783798187987123879878123.188781371, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/optional/ecmascript-regex.json0000644000175100001770000000071714653725311026542 0ustar00runnerdocker[ { "description": "ECMA 262 regex dialect recognition", "schema": { "format": "regex" }, "tests": [ { "description": "[^] is a valid regex", "data": "[^]", "valid": true }, { "description": "ECMA 262 has no support for lookbehind", "data": "(?<=foo)bar", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.085097 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/optional/format/0000755000175100001770000000000014653725331023672 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/optional/format/color.json0000644000175100001770000000212614653725311025702 0ustar00runnerdocker[ { "description": "validation of CSS colors", "schema": { "format": "color" }, "tests": [ { "description": "a valid CSS color name", "data": "fuchsia", "valid": true }, { "description": "a valid six-digit CSS color code", "data": "#CC8899", "valid": true }, { "description": "a valid three-digit CSS color code", "data": "#C89", "valid": true }, { "description": "an invalid CSS color code", "data": "#00332520", "valid": false }, { "description": "an invalid CSS color name", "data": "puce", "valid": false }, { "description": "a CSS color name containing invalid characters", "data": "light_grayish_red-violet", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/optional/format/date-time.json0000644000175100001770000000226414653725311026440 0ustar00runnerdocker[ { "description": "validation of date-time strings", "schema": { "format": "date-time" }, "tests": [ { "description": "a valid date-time string", "data": "1963-06-19T08:30:06.283185Z", "valid": true }, { "description": "an invalid date-time string", "data": "06/19/1963 08:30:06 PST", "valid": false }, { "description": "case-insensitive T and Z", "data": "1963-06-19t08:30:06.283185z", "valid": true }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "2013-350T01:01:01", "valid": false }, { "description": "invalid non-padded month dates", "data": "1963-6-19T08:30:06.283185Z", "valid": false }, { "description": "invalid non-padded day dates", "data": "1963-06-1T08:30:06.283185Z", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/optional/format/date.json0000644000175100001770000001313214653725311025500 0ustar00runnerdocker[ { "description": "validation of date strings", "schema": { "format": "date" }, "tests": [ { "description": "a valid date string", "data": "1963-06-19", "valid": true }, { "description": "a valid date string with 31 days in January", "data": "2020-01-31", "valid": true }, { "description": "a invalid date string with 32 days in January", "data": "2020-01-32", "valid": false }, { "description": "a valid date string with 28 days in February (normal)", "data": "2021-02-28", "valid": true }, { "description": "a invalid date string with 29 days in February (normal)", "data": "2021-02-29", "valid": false }, { "description": "a valid date string with 29 days in February (leap)", "data": "2020-02-29", "valid": true }, { "description": "a invalid date string with 30 days in February (leap)", "data": "2020-02-30", "valid": false }, { "description": "a valid date string with 31 days in March", "data": "2020-03-31", "valid": true }, { "description": "a invalid date string with 32 days in March", "data": "2020-03-32", "valid": false }, { "description": "a valid date string with 30 days in April", "data": "2020-04-30", "valid": true }, { "description": "a invalid date string with 31 days in April", "data": "2020-04-31", "valid": false }, { "description": "a valid date string with 31 days in May", "data": "2020-05-31", "valid": true }, { "description": "a invalid date string with 32 days in May", "data": "2020-05-32", "valid": false }, { "description": "a valid date string with 30 days in June", "data": "2020-06-30", "valid": true }, { "description": "a invalid date string with 31 days in June", "data": "2020-06-31", "valid": false }, { "description": "a valid date string with 31 days in July", "data": "2020-07-31", "valid": true }, { "description": "a invalid date string with 32 days in July", "data": "2020-07-32", "valid": false }, { "description": "a valid date string with 31 days in August", "data": "2020-08-31", "valid": true }, { "description": "a invalid date string with 32 days in August", "data": "2020-08-32", "valid": false }, { "description": "a valid date string with 30 days in September", "data": "2020-09-30", "valid": true }, { "description": "a invalid date string with 31 days in September", "data": "2020-09-31", "valid": false }, { "description": "a valid date string with 31 days in October", "data": "2020-10-31", "valid": true }, { "description": "a invalid date string with 32 days in October", "data": "2020-10-32", "valid": false }, { "description": "a valid date string with 30 days in November", "data": "2020-11-30", "valid": true }, { "description": "a invalid date string with 31 days in November", "data": "2020-11-31", "valid": false }, { "description": "a valid date string with 31 days in December", "data": "2020-12-31", "valid": true }, { "description": "a invalid date string with 32 days in December", "data": "2020-12-32", "valid": false }, { "description": "a invalid date string with invalid month", "data": "2020-13-01", "valid": false }, { "description": "an invalid date string", "data": "06/19/1963", "valid": false }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "2013-350", "valid": false }, { "description": "invalidates non-padded month dates", "data": "1998-1-20", "valid": false }, { "description": "invalidates non-padded day dates", "data": "1998-01-1", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/optional/format/email.json0000644000175100001770000000323514653725311025655 0ustar00runnerdocker[ { "description": "validation of e-mail addresses", "schema": { "format": "email" }, "tests": [ { "description": "a valid e-mail address", "data": "joe.bloggs@example.com", "valid": true }, { "description": "an invalid e-mail address", "data": "2962", "valid": false }, { "description": "tilde in local part is valid", "data": "te~st@example.com", "valid": true }, { "description": "tilde before local part is valid", "data": "~test@example.com", "valid": true }, { "description": "tilde after local part is valid", "data": "test~@example.com", "valid": true }, { "description": "dot before local part is not valid", "data": ".test@example.com", "valid": false }, { "description": "dot after local part is not valid", "data": "test.@example.com", "valid": false }, { "description": "two separated dots inside local part are valid", "data": "te.s.t@example.com", "valid": true }, { "description": "two subsequent dots inside local part are not valid", "data": "te..st@example.com", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/optional/format/host-name.json0000644000175100001770000000410114653725311026452 0ustar00runnerdocker[ { "description": "validation of host names", "schema": { "format": "host-name" }, "tests": [ { "description": "a valid host name", "data": "www.example.com", "valid": true }, { "description": "a host name starting with an illegal character", "data": "-a-host-name-that-starts-with--", "valid": false }, { "description": "a host name containing illegal characters", "data": "not_a_valid_host_name", "valid": false }, { "description": "a host name with a component too long", "data": "a-vvvvvvvvvvvvvvvveeeeeeeeeeeeeeeerrrrrrrrrrrrrrrryyyyyyyyyyyyyyyy-long-host-name-component", "valid": false }, { "description": "starts with hyphen", "data": "-hostname", "valid": false }, { "description": "ends with hyphen", "data": "hostname-", "valid": false }, { "description": "starts with underscore", "data": "_hostname", "valid": false }, { "description": "ends with underscore", "data": "hostname_", "valid": false }, { "description": "contains underscore", "data": "host_name", "valid": false }, { "description": "maximum label length", "data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.com", "valid": true }, { "description": "exceeds maximum label length", "data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl.com", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/optional/format/ip-address.json0000644000175100001770000000120214653725311026611 0ustar00runnerdocker[ { "description": "validation of IP addresses", "schema": { "format": "ip-address" }, "tests": [ { "description": "a valid IP address", "data": "192.168.0.1", "valid": true }, { "description": "an IP address with too many components", "data": "127.0.0.0.1", "valid": false }, { "description": "an IP address with out-of-range values", "data": "256.256.256.256", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/optional/format/ipv6.json0000644000175100001770000000422314653725311025450 0ustar00runnerdocker[ { "description": "validation of IPv6 addresses", "schema": { "format": "ipv6" }, "tests": [ { "description": "a valid IPv6 address", "data": "::1", "valid": true }, { "description": "an IPv6 address with out-of-range values", "data": "12345::", "valid": false }, { "description": "an IPv6 address with too many components", "data": "1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1", "valid": false }, { "description": "an IPv6 address containing illegal characters", "data": "::laptop", "valid": false }, { "description": "no digits is valid", "data": "::", "valid": true }, { "description": "leading colons is valid", "data": "::1", "valid": true }, { "description": "trailing colons is valid", "data": "d6::", "valid": true }, { "description": "two sets of double colons is invalid", "data": "1::d6::42", "valid": false }, { "description": "mixed format with the ipv4 section as decimal octets", "data": "1::d6:192.168.0.1", "valid": true }, { "description": "mixed format with double colons between the sections", "data": "1:2::192.168.0.1", "valid": true }, { "description": "mixed format with ipv4 section with octet out of range", "data": "1::2:192.168.256.1", "valid": false }, { "description": "mixed format with ipv4 section with a hex octet", "data": "1::2:192.168.ff.1", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/optional/format/regex.json0000644000175100001770000000074714653725311025705 0ustar00runnerdocker[ { "description": "validation of regular expressions", "schema": { "format": "regex" }, "tests": [ { "description": "a valid regular expression", "data": "([abc])+\\s+$", "valid": true }, { "description": "a regular expression with unclosed parens is invalid", "data": "^(abc]", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/optional/format/time.json0000644000175100001770000000066614653725311025531 0ustar00runnerdocker[ { "description": "validation of time strings", "schema": { "format": "time" }, "tests": [ { "description": "a valid time string", "data": "08:30:06", "valid": true }, { "description": "an invalid time string", "data": "8:30 AM", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/optional/format/uri.json0000644000175100001770000000144314653725311025364 0ustar00runnerdocker[ { "description": "validation of URIs", "schema": { "format": "uri" }, "tests": [ { "description": "a valid URI", "data": "http://foo.bar/?baz=qux#quux", "valid": true }, { "description": "an invalid protocol-relative URI Reference", "data": "//foo.bar/?baz=qux#quux", "valid": false }, { "description": "an invalid URI", "data": "\\\\WINDOWS\\fileshare", "valid": false }, { "description": "an invalid URI though valid URI reference", "data": "abc", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/optional/non-bmp-regex.json0000644000175100001770000000453614653725311025761 0ustar00runnerdocker[ { "description": "Proper UTF-16 surrogate pair handling: pattern", "comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters", "schema": { "pattern": "^ðŸ²*$" }, "tests": [ { "description": "matches empty", "data": "", "valid": true }, { "description": "matches single", "data": "ðŸ²", "valid": true }, { "description": "matches two", "data": "ðŸ²ðŸ²", "valid": true }, { "description": "doesn't match one", "data": "ðŸ‰", "valid": false }, { "description": "doesn't match two", "data": "ðŸ‰ðŸ‰", "valid": false }, { "description": "doesn't match one ASCII", "data": "D", "valid": false }, { "description": "doesn't match two ASCII", "data": "DD", "valid": false } ] }, { "description": "Proper UTF-16 surrogate pair handling: patternProperties", "comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters", "schema": { "patternProperties": { "^ðŸ²*$": { "type": "integer" } } }, "tests": [ { "description": "matches empty", "data": { "": 1 }, "valid": true }, { "description": "matches single", "data": { "ðŸ²": 1 }, "valid": true }, { "description": "matches two", "data": { "ðŸ²ðŸ²": 1 }, "valid": true }, { "description": "doesn't match one", "data": { "ðŸ²": "hello" }, "valid": false }, { "description": "doesn't match two", "data": { "ðŸ²ðŸ²": "hello" }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/optional/zeroTerminatedFloats.json0000644000175100001770000000060014653725311027434 0ustar00runnerdocker[ { "description": "some languages do not distinguish between different types of numeric value", "schema": { "type": "integer" }, "tests": [ { "description": "a float is not an integer even without fractional part", "data": 1.0, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/pattern.json0000644000175100001770000000300314653725311023117 0ustar00runnerdocker[ { "description": "pattern validation", "schema": {"pattern": "^a*$"}, "tests": [ { "description": "a matching pattern is valid", "data": "aaa", "valid": true }, { "description": "a non-matching pattern is invalid", "data": "abc", "valid": false }, { "description": "ignores booleans", "data": true, "valid": true }, { "description": "ignores integers", "data": 123, "valid": true }, { "description": "ignores floats", "data": 1.0, "valid": true }, { "description": "ignores objects", "data": {}, "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores null", "data": null, "valid": true } ] }, { "description": "pattern is not anchored", "schema": {"pattern": "a+"}, "tests": [ { "description": "matches a substring", "data": "xxaayy", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/patternProperties.json0000644000175100001770000000750314653725311025205 0ustar00runnerdocker[ { "description": "patternProperties validates properties matching a regex", "schema": { "patternProperties": { "f.*o": {"type": "integer"} } }, "tests": [ { "description": "a single valid match is valid", "data": {"foo": 1}, "valid": true }, { "description": "multiple valid matches is valid", "data": {"foo": 1, "foooooo" : 2}, "valid": true }, { "description": "a single invalid match is invalid", "data": {"foo": "bar", "fooooo": 2}, "valid": false }, { "description": "multiple invalid matches is invalid", "data": {"foo": "bar", "foooooo" : "baz"}, "valid": false }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "multiple simultaneous patternProperties are validated", "schema": { "patternProperties": { "a*": {"type": "integer"}, "aaa*": {"maximum": 20} } }, "tests": [ { "description": "a single valid match is valid", "data": {"a": 21}, "valid": true }, { "description": "a simultaneous match is valid", "data": {"aaaa": 18}, "valid": true }, { "description": "multiple matches is valid", "data": {"a": 21, "aaaa": 18}, "valid": true }, { "description": "an invalid due to one is invalid", "data": {"a": "bar"}, "valid": false }, { "description": "an invalid due to the other is invalid", "data": {"aaaa": 31}, "valid": false }, { "description": "an invalid due to both is invalid", "data": {"aaa": "foo", "aaaa": 31}, "valid": false } ] }, { "description": "regexes are not anchored by default and are case sensitive", "schema": { "patternProperties": { "[0-9]{2,}": { "type": "boolean" }, "X_": { "type": "string" } } }, "tests": [ { "description": "non recognized members are ignored", "data": { "answer 1": "42" }, "valid": true }, { "description": "recognized members are accounted for", "data": { "a31b": null }, "valid": false }, { "description": "regexes are case sensitive", "data": { "a_x_3": 3 }, "valid": true }, { "description": "regexes are case sensitive, 2", "data": { "a_X_3": 3 }, "valid": false } ] }, { "description": "patternProperties with null valued instance properties", "schema": { "patternProperties": { "^.*bar$": {"type": "null"} } }, "tests": [ { "description": "allows null values", "data": {"foobar": null}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/properties.json0000644000175100001770000000651214653725311023646 0ustar00runnerdocker[ { "description": "object properties validation", "schema": { "properties": { "foo": {"type": "integer"}, "bar": {"type": "string"} } }, "tests": [ { "description": "both properties present and valid is valid", "data": {"foo": 1, "bar": "baz"}, "valid": true }, { "description": "one property invalid is invalid", "data": {"foo": 1, "bar": {}}, "valid": false }, { "description": "both properties invalid is invalid", "data": {"foo": [], "bar": {}}, "valid": false }, { "description": "doesn't invalidate other properties", "data": {"quux": []}, "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "properties, patternProperties, additionalProperties interaction", "schema": { "properties": { "foo": {"type": "array", "maxItems": 3}, "bar": {"type": "array"} }, "patternProperties": {"f.o": {"minItems": 2}}, "additionalProperties": {"type": "integer"} }, "tests": [ { "description": "property validates property", "data": {"foo": [1, 2]}, "valid": true }, { "description": "property invalidates property", "data": {"foo": [1, 2, 3, 4]}, "valid": false }, { "description": "patternProperty invalidates property", "data": {"foo": []}, "valid": false }, { "description": "patternProperty validates nonproperty", "data": {"fxo": [1, 2]}, "valid": true }, { "description": "patternProperty invalidates nonproperty", "data": {"fxo": []}, "valid": false }, { "description": "additionalProperty ignores property", "data": {"bar": []}, "valid": true }, { "description": "additionalProperty validates others", "data": {"quux": 3}, "valid": true }, { "description": "additionalProperty invalidates others", "data": {"quux": "foo"}, "valid": false } ] }, { "description": "properties with null valued instance properties", "schema": { "properties": { "foo": {"type": "null"} } }, "tests": [ { "description": "allows null values", "data": {"foo": null}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/ref.json0000644000175100001770000001766014653725311022234 0ustar00runnerdocker[ { "description": "root pointer ref", "schema": { "properties": { "foo": {"$ref": "#"} }, "additionalProperties": false }, "tests": [ { "description": "match", "data": {"foo": false}, "valid": true }, { "description": "recursive match", "data": {"foo": {"foo": false}}, "valid": true }, { "description": "mismatch", "data": {"bar": false}, "valid": false }, { "description": "recursive mismatch", "data": {"foo": {"bar": false}}, "valid": false } ] }, { "description": "relative pointer ref to object", "schema": { "properties": { "foo": {"type": "integer"}, "bar": {"$ref": "#/properties/foo"} } }, "tests": [ { "description": "match", "data": {"bar": 3}, "valid": true }, { "description": "mismatch", "data": {"bar": true}, "valid": false } ] }, { "description": "relative pointer ref to array", "schema": { "items": [ {"type": "integer"}, {"$ref": "#/items/0"} ] }, "tests": [ { "description": "match array", "data": [1, 2], "valid": true }, { "description": "mismatch array", "data": [1, "foo"], "valid": false } ] }, { "description": "escaped pointer ref", "schema": { "definitions": { "tilde~field": {"type": "integer"}, "slash/field": {"type": "integer"}, "percent%field": {"type": "integer"} }, "properties": { "tilde": {"$ref": "#/definitions/tilde~0field"}, "slash": {"$ref": "#/definitions/slash~1field"}, "percent": {"$ref": "#/definitions/percent%25field"} } }, "tests": [ { "description": "slash invalid", "data": {"slash": "aoeu"}, "valid": false }, { "description": "tilde invalid", "data": {"tilde": "aoeu"}, "valid": false }, { "description": "percent invalid", "data": {"percent": "aoeu"}, "valid": false }, { "description": "slash valid", "data": {"slash": 123}, "valid": true }, { "description": "tilde valid", "data": {"tilde": 123}, "valid": true }, { "description": "percent valid", "data": {"percent": 123}, "valid": true } ] }, { "description": "nested refs", "schema": { "definitions": { "a": {"type": "integer"}, "b": {"$ref": "#/definitions/a"}, "c": {"$ref": "#/definitions/b"} }, "$ref": "#/definitions/c" }, "tests": [ { "description": "nested ref valid", "data": 5, "valid": true }, { "description": "nested ref invalid", "data": "a", "valid": false } ] }, { "description": "ref overrides any sibling keywords", "schema": { "definitions": { "reffed": { "type": "array" } }, "properties": { "foo": { "$ref": "#/definitions/reffed", "maxItems": 2 } } }, "tests": [ { "description": "remote ref valid", "data": { "foo": [] }, "valid": true }, { "description": "remote ref valid, maxItems ignored", "data": { "foo": [ 1, 2, 3] }, "valid": true }, { "description": "ref invalid", "data": { "foo": "string" }, "valid": false } ] }, { "description": "property named $ref, containing an actual $ref", "schema": { "properties": { "$ref": {"$ref": "#/definitions/is-string"} }, "definitions": { "is-string": { "type": "string" } } }, "tests": [ { "description": "property named $ref valid", "data": {"$ref": "a"}, "valid": true }, { "description": "property named $ref invalid", "data": {"$ref": 2}, "valid": false } ] }, { "description": "$ref prevents a sibling id from changing the base uri", "schema": { "id": "http://localhost:1234/sibling_id/base/", "definitions": { "foo": { "id": "http://localhost:1234/sibling_id/foo.json", "type": "string" }, "base_foo": { "$comment": "this canonical uri is http://localhost:1234/sibling_id/base/foo.json", "id": "foo.json", "type": "number" } }, "allOf": [ { "$comment": "$ref resolves to http://localhost:1234/sibling_id/base/foo.json, not http://localhost:1234/sibling_id/foo.json", "id": "http://localhost:1234/sibling_id/", "$ref": "foo.json" } ] }, "tests": [ { "description": "$ref resolves to /definitions/base_foo, data does not validate", "data": "a", "valid": false }, { "description": "$ref resolves to /definitions/base_foo, data validates", "data": 1, "valid": true } ] }, { "description": "remote ref, containing refs itself", "schema": {"$ref": "http://json-schema.org/draft-03/schema#"}, "tests": [ { "description": "remote ref valid", "data": {"items": {"type": "integer"}}, "valid": true }, { "description": "remote ref invalid", "data": {"items": {"type": 1}}, "valid": false } ] }, { "description": "naive replacement of $ref with its destination is not correct", "schema": { "definitions": { "a_string": { "type": "string" } }, "enum": [ { "$ref": "#/definitions/a_string" } ] }, "tests": [ { "description": "do not evaluate the $ref inside the enum, matching any string", "data": "this is a string", "valid": false }, { "description": "match the enum exactly", "data": { "$ref": "#/definitions/a_string" }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/refRemote.json0000644000175100001770000000366014653725311023403 0ustar00runnerdocker[ { "description": "remote ref", "schema": {"$ref": "http://localhost:1234/integer.json"}, "tests": [ { "description": "remote ref valid", "data": 1, "valid": true }, { "description": "remote ref invalid", "data": "a", "valid": false } ] }, { "description": "fragment within remote ref", "schema": {"$ref": "http://localhost:1234/subSchemas.json#/integer"}, "tests": [ { "description": "remote fragment valid", "data": 1, "valid": true }, { "description": "remote fragment invalid", "data": "a", "valid": false } ] }, { "description": "ref within remote ref", "schema": { "$ref": "http://localhost:1234/subSchemas.json#/refToInteger" }, "tests": [ { "description": "ref within ref valid", "data": 1, "valid": true }, { "description": "ref within ref invalid", "data": "a", "valid": false } ] }, { "description": "change resolution scope", "schema": { "id": "http://localhost:1234/", "items": { "id": "baseUriChange/", "items": {"$ref": "folderInteger.json"} } }, "tests": [ { "description": "changed scope ref valid", "data": [[1]], "valid": true }, { "description": "changed scope ref invalid", "data": [["a"]], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/required.json0000644000175100001770000000240214653725311023264 0ustar00runnerdocker[ { "description": "required validation", "schema": { "properties": { "foo": {"required" : true}, "bar": {} } }, "tests": [ { "description": "present required property is valid", "data": {"foo": 1}, "valid": true }, { "description": "non-present required property is invalid", "data": {"bar": 1}, "valid": false } ] }, { "description": "required default validation", "schema": { "properties": { "foo": {} } }, "tests": [ { "description": "not required by default", "data": {}, "valid": true } ] }, { "description": "required explicitly false validation", "schema": { "properties": { "foo": {"required": false} } }, "tests": [ { "description": "not required if required is false", "data": {}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/type.json0000644000175100001770000003306414653725311022435 0ustar00runnerdocker[ { "description": "integer type matches integers", "schema": {"type": "integer"}, "tests": [ { "description": "an integer is an integer", "data": 1, "valid": true }, { "description": "a float is not an integer", "data": 1.1, "valid": false }, { "description": "a string is not an integer", "data": "foo", "valid": false }, { "description": "a string is still not an integer, even if it looks like one", "data": "1", "valid": false }, { "description": "an object is not an integer", "data": {}, "valid": false }, { "description": "an array is not an integer", "data": [], "valid": false }, { "description": "a boolean is not an integer", "data": true, "valid": false }, { "description": "null is not an integer", "data": null, "valid": false } ] }, { "description": "number type matches numbers", "schema": {"type": "number"}, "tests": [ { "description": "an integer is a number", "data": 1, "valid": true }, { "description": "a float with zero fractional part is a number", "data": 1.0, "valid": true }, { "description": "a float is a number", "data": 1.1, "valid": true }, { "description": "a string is not a number", "data": "foo", "valid": false }, { "description": "a string is still not a number, even if it looks like one", "data": "1", "valid": false }, { "description": "an object is not a number", "data": {}, "valid": false }, { "description": "an array is not a number", "data": [], "valid": false }, { "description": "a boolean is not a number", "data": true, "valid": false }, { "description": "null is not a number", "data": null, "valid": false } ] }, { "description": "string type matches strings", "schema": {"type": "string"}, "tests": [ { "description": "1 is not a string", "data": 1, "valid": false }, { "description": "a float is not a string", "data": 1.1, "valid": false }, { "description": "a string is a string", "data": "foo", "valid": true }, { "description": "a string is still a string, even if it looks like a number", "data": "1", "valid": true }, { "description": "an object is not a string", "data": {}, "valid": false }, { "description": "an array is not a string", "data": [], "valid": false }, { "description": "a boolean is not a string", "data": true, "valid": false }, { "description": "null is not a string", "data": null, "valid": false } ] }, { "description": "object type matches objects", "schema": {"type": "object"}, "tests": [ { "description": "an integer is not an object", "data": 1, "valid": false }, { "description": "a float is not an object", "data": 1.1, "valid": false }, { "description": "a string is not an object", "data": "foo", "valid": false }, { "description": "an object is an object", "data": {}, "valid": true }, { "description": "an array is not an object", "data": [], "valid": false }, { "description": "a boolean is not an object", "data": true, "valid": false }, { "description": "null is not an object", "data": null, "valid": false } ] }, { "description": "array type matches arrays", "schema": {"type": "array"}, "tests": [ { "description": "an integer is not an array", "data": 1, "valid": false }, { "description": "a float is not an array", "data": 1.1, "valid": false }, { "description": "a string is not an array", "data": "foo", "valid": false }, { "description": "an object is not an array", "data": {}, "valid": false }, { "description": "an array is an array", "data": [], "valid": true }, { "description": "a boolean is not an array", "data": true, "valid": false }, { "description": "null is not an array", "data": null, "valid": false } ] }, { "description": "boolean type matches booleans", "schema": {"type": "boolean"}, "tests": [ { "description": "an integer is not a boolean", "data": 1, "valid": false }, { "description": "a float is not a boolean", "data": 1.1, "valid": false }, { "description": "a string is not a boolean", "data": "foo", "valid": false }, { "description": "an object is not a boolean", "data": {}, "valid": false }, { "description": "an array is not a boolean", "data": [], "valid": false }, { "description": "a boolean is a boolean", "data": true, "valid": true }, { "description": "null is not a boolean", "data": null, "valid": false } ] }, { "description": "null type matches only the null object", "schema": {"type": "null"}, "tests": [ { "description": "an integer is not null", "data": 1, "valid": false }, { "description": "a float is not null", "data": 1.1, "valid": false }, { "description": "a string is not null", "data": "foo", "valid": false }, { "description": "an object is not null", "data": {}, "valid": false }, { "description": "an array is not null", "data": [], "valid": false }, { "description": "a boolean is not null", "data": true, "valid": false }, { "description": "null is null", "data": null, "valid": true } ] }, { "description": "any type matches any type", "schema": {"type": "any"}, "tests": [ { "description": "any type includes integers", "data": 1, "valid": true }, { "description": "any type includes float", "data": 1.1, "valid": true }, { "description": "any type includes string", "data": "foo", "valid": true }, { "description": "any type includes object", "data": {}, "valid": true }, { "description": "any type includes array", "data": [], "valid": true }, { "description": "any type includes boolean", "data": true, "valid": true }, { "description": "any type includes null", "data": null, "valid": true } ] }, { "description": "multiple types can be specified in an array", "schema": {"type": ["integer", "string"]}, "tests": [ { "description": "an integer is valid", "data": 1, "valid": true }, { "description": "a string is valid", "data": "foo", "valid": true }, { "description": "a float is invalid", "data": 1.1, "valid": false }, { "description": "an object is invalid", "data": {}, "valid": false }, { "description": "an array is invalid", "data": [], "valid": false }, { "description": "a boolean is invalid", "data": true, "valid": false }, { "description": "null is invalid", "data": null, "valid": false } ] }, { "description": "types can include schemas", "schema": { "type": [ "array", {"type": "object"} ] }, "tests": [ { "description": "an integer is invalid", "data": 1, "valid": false }, { "description": "a string is invalid", "data": "foo", "valid": false }, { "description": "a float is invalid", "data": 1.1, "valid": false }, { "description": "an object is valid", "data": {}, "valid": true }, { "description": "an array is valid", "data": [], "valid": true }, { "description": "a boolean is invalid", "data": true, "valid": false }, { "description": "null is invalid", "data": null, "valid": false } ] }, { "description": "applies a nested schema", "schema": { "type": [ "integer", { "properties": { "foo": {"type": "null"} } } ] }, "tests": [ { "description": "an integer is valid", "data": 1, "valid": true }, { "description": "an object is valid only if it is fully valid", "data": {"foo": null}, "valid": true }, { "description": "an object is invalid otherwise", "data": {"foo": "bar"}, "valid": false } ] }, { "description": "types from separate schemas are merged", "schema": { "type": [ {"type": ["string"]}, {"type": ["array", "null"]} ] }, "tests": [ { "description": "an integer is invalid", "data": 1, "valid": false }, { "description": "a string is valid", "data": "foo", "valid": true }, { "description": "an array is valid", "data": [1, 2, 3], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft3/uniqueItems.json0000644000175100001770000003076314653725311023767 0ustar00runnerdocker[ { "description": "uniqueItems validation", "schema": {"uniqueItems": true}, "tests": [ { "description": "unique array of integers is valid", "data": [1, 2], "valid": true }, { "description": "non-unique array of integers is invalid", "data": [1, 1], "valid": false }, { "description": "non-unique array of more than two integers is invalid", "data": [1, 2, 1], "valid": false }, { "description": "numbers are unique if mathematically unequal", "data": [1.0, 1.00, 1], "valid": false }, { "description": "unique array of strings is valid", "data": ["foo", "bar", "baz"], "valid": true }, { "description": "non-unique array of strings is invalid", "data": ["foo", "bar", "foo"], "valid": false }, { "description": "unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "baz"}], "valid": true }, { "description": "non-unique array of objects is invalid", "data": [{"foo": "bar"}, {"foo": "bar"}], "valid": false }, { "description": "unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : false}}} ], "valid": true }, { "description": "non-unique array of nested objects is invalid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : true}}} ], "valid": false }, { "description": "unique array of arrays is valid", "data": [["foo"], ["bar"]], "valid": true }, { "description": "non-unique array of arrays is invalid", "data": [["foo"], ["foo"]], "valid": false }, { "description": "non-unique array of more than two arrays is invalid", "data": [["foo"], ["bar"], ["foo"]], "valid": false }, { "description": "1 and true are unique", "data": [1, true], "valid": true }, { "description": "0 and false are unique", "data": [0, false], "valid": true }, { "description": "[1] and [true] are unique", "data": [[1], [true]], "valid": true }, { "description": "[0] and [false] are unique", "data": [[0], [false]], "valid": true }, { "description": "nested [1] and [true] are unique", "data": [[[1], "foo"], [[true], "foo"]], "valid": true }, { "description": "nested [0] and [false] are unique", "data": [[[0], "foo"], [[false], "foo"]], "valid": true }, { "description": "unique heterogeneous types are valid", "data": [{}, [1], true, null, 1], "valid": true }, { "description": "non-unique heterogeneous types are invalid", "data": [{}, [1], true, null, {}, 1], "valid": false }, { "description": "{\"a\": false} and {\"a\": 0} are unique", "data": [{"a": false}, {"a": 0}], "valid": true }, { "description": "{\"a\": true} and {\"a\": 1} are unique", "data": [{"a": true}, {"a": 1}], "valid": true } ] }, { "description": "uniqueItems with an array of items", "schema": { "items": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": true }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is not valid", "data": [false, false], "valid": false }, { "description": "[true, true] from items array is not valid", "data": [true, true], "valid": false }, { "description": "unique array extended from [false, true] is valid", "data": [false, true, "foo", "bar"], "valid": true }, { "description": "unique array extended from [true, false] is valid", "data": [true, false, "foo", "bar"], "valid": true }, { "description": "non-unique array extended from [false, true] is not valid", "data": [false, true, "foo", "foo"], "valid": false }, { "description": "non-unique array extended from [true, false] is not valid", "data": [true, false, "foo", "foo"], "valid": false } ] }, { "description": "uniqueItems with an array of items and additionalItems=false", "schema": { "items": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": true, "additionalItems": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is not valid", "data": [false, false], "valid": false }, { "description": "[true, true] from items array is not valid", "data": [true, true], "valid": false }, { "description": "extra items are invalid even if unique", "data": [false, true, null], "valid": false } ] }, { "description": "uniqueItems=false validation", "schema": { "uniqueItems": false }, "tests": [ { "description": "unique array of integers is valid", "data": [1, 2], "valid": true }, { "description": "non-unique array of integers is valid", "data": [1, 1], "valid": true }, { "description": "numbers are unique if mathematically unequal", "data": [1.0, 1.00, 1], "valid": true }, { "description": "unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "baz"}], "valid": true }, { "description": "non-unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "bar"}], "valid": true }, { "description": "unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : false}}} ], "valid": true }, { "description": "non-unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : true}}} ], "valid": true }, { "description": "unique array of arrays is valid", "data": [["foo"], ["bar"]], "valid": true }, { "description": "non-unique array of arrays is valid", "data": [["foo"], ["foo"]], "valid": true }, { "description": "1 and true are unique", "data": [1, true], "valid": true }, { "description": "0 and false are unique", "data": [0, false], "valid": true }, { "description": "unique heterogeneous types are valid", "data": [{}, [1], true, null, 1], "valid": true }, { "description": "non-unique heterogeneous types are valid", "data": [{}, [1], true, null, {}, 1], "valid": true } ] }, { "description": "uniqueItems=false with an array of items", "schema": { "items": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is valid", "data": [false, false], "valid": true }, { "description": "[true, true] from items array is valid", "data": [true, true], "valid": true }, { "description": "unique array extended from [false, true] is valid", "data": [false, true, "foo", "bar"], "valid": true }, { "description": "unique array extended from [true, false] is valid", "data": [true, false, "foo", "bar"], "valid": true }, { "description": "non-unique array extended from [false, true] is valid", "data": [false, true, "foo", "foo"], "valid": true }, { "description": "non-unique array extended from [true, false] is valid", "data": [true, false, "foo", "foo"], "valid": true } ] }, { "description": "uniqueItems=false with an array of items and additionalItems=false", "schema": { "items": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": false, "additionalItems": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is valid", "data": [false, false], "valid": true }, { "description": "[true, true] from items array is valid", "data": [true, true], "valid": true }, { "description": "extra items are invalid even if unique", "data": [false, true, null], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.089097 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/0000755000175100001770000000000014653725331020556 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/additionalItems.json0000644000175100001770000001114714653725311024565 0ustar00runnerdocker[ { "description": "additionalItems as schema", "schema": { "items": [{}], "additionalItems": {"type": "integer"} }, "tests": [ { "description": "additional items match schema", "data": [ null, 2, 3, 4 ], "valid": true }, { "description": "additional items do not match schema", "data": [ null, 2, 3, "foo" ], "valid": false } ] }, { "description": "when items is schema, additionalItems does nothing", "schema": { "items": {}, "additionalItems": false }, "tests": [ { "description": "all items match schema", "data": [ 1, 2, 3, 4, 5 ], "valid": true } ] }, { "description": "array of items with no additionalItems permitted", "schema": { "items": [{}, {}, {}], "additionalItems": false }, "tests": [ { "description": "empty array", "data": [ ], "valid": true }, { "description": "fewer number of items present (1)", "data": [ 1 ], "valid": true }, { "description": "fewer number of items present (2)", "data": [ 1, 2 ], "valid": true }, { "description": "equal number of items present", "data": [ 1, 2, 3 ], "valid": true }, { "description": "additional items are not permitted", "data": [ 1, 2, 3, 4 ], "valid": false } ] }, { "description": "additionalItems as false without items", "schema": {"additionalItems": false}, "tests": [ { "description": "items defaults to empty schema so everything is valid", "data": [ 1, 2, 3, 4, 5 ], "valid": true }, { "description": "ignores non-arrays", "data": {"foo" : "bar"}, "valid": true } ] }, { "description": "additionalItems are allowed by default", "schema": {"items": [{"type": "integer"}]}, "tests": [ { "description": "only the first item is validated", "data": [1, "foo", false], "valid": true } ] }, { "description": "additionalItems does not look in applicators, valid case", "schema": { "allOf": [ { "items": [ { "type": "integer" } ] } ], "additionalItems": { "type": "boolean" } }, "tests": [ { "description": "items defined in allOf are not examined", "data": [ 1, null ], "valid": true } ] }, { "description": "additionalItems does not look in applicators, invalid case", "schema": { "allOf": [ { "items": [ { "type": "integer" }, { "type": "string" } ] } ], "items": [ {"type": "integer" } ], "additionalItems": { "type": "boolean" } }, "tests": [ { "description": "items defined in allOf are not examined", "data": [ 1, "hello" ], "valid": false } ] }, { "description": "items validation adjusts the starting index for additionalItems", "schema": { "items": [ { "type": "string" } ], "additionalItems": { "type": "integer" } }, "tests": [ { "description": "valid items", "data": [ "x", 2, 3 ], "valid": true }, { "description": "wrong type of second item", "data": [ "x", "y" ], "valid": false } ] }, { "description": "additionalItems with null instance elements", "schema": { "additionalItems": { "type": "null" } }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/additionalProperties.json0000644000175100001770000001051214653725311025633 0ustar00runnerdocker[ { "description": "additionalProperties being false does not allow other properties", "schema": { "properties": {"foo": {}, "bar": {}}, "patternProperties": { "^v": {} }, "additionalProperties": false }, "tests": [ { "description": "no additional properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "an additional property is invalid", "data": {"foo" : 1, "bar" : 2, "quux" : "boom"}, "valid": false }, { "description": "ignores arrays", "data": [1, 2, 3], "valid": true }, { "description": "ignores strings", "data": "foobarbaz", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "patternProperties are not additional properties", "data": {"foo":1, "vroom": 2}, "valid": true } ] }, { "description": "non-ASCII pattern with additionalProperties", "schema": { "patternProperties": {"^á": {}}, "additionalProperties": false }, "tests": [ { "description": "matching the pattern is valid", "data": {"ármányos": 2}, "valid": true }, { "description": "not matching the pattern is invalid", "data": {"élmény": 2}, "valid": false } ] }, { "description": "additionalProperties with schema", "schema": { "properties": {"foo": {}, "bar": {}}, "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "no additional properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "an additional valid property is valid", "data": {"foo" : 1, "bar" : 2, "quux" : true}, "valid": true }, { "description": "an additional invalid property is invalid", "data": {"foo" : 1, "bar" : 2, "quux" : 12}, "valid": false } ] }, { "description": "additionalProperties can exist by itself", "schema": { "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "an additional valid property is valid", "data": {"foo" : true}, "valid": true }, { "description": "an additional invalid property is invalid", "data": {"foo" : 1}, "valid": false } ] }, { "description": "additionalProperties are allowed by default", "schema": {"properties": {"foo": {}, "bar": {}}}, "tests": [ { "description": "additional properties are allowed", "data": {"foo": 1, "bar": 2, "quux": true}, "valid": true } ] }, { "description": "additionalProperties does not look in applicators", "schema": { "allOf": [ {"properties": {"foo": {}}} ], "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "properties defined in allOf are not examined", "data": {"foo": 1, "bar": true}, "valid": false } ] }, { "description": "additionalProperties with null valued instance properties", "schema": { "additionalProperties": { "type": "null" } }, "tests": [ { "description": "allows null values", "data": {"foo": null}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/allOf.json0000644000175100001770000001536514653725311022516 0ustar00runnerdocker[ { "description": "allOf", "schema": { "allOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "allOf", "data": {"foo": "baz", "bar": 2}, "valid": true }, { "description": "mismatch second", "data": {"foo": "baz"}, "valid": false }, { "description": "mismatch first", "data": {"bar": 2}, "valid": false }, { "description": "wrong type", "data": {"foo": "baz", "bar": "quux"}, "valid": false } ] }, { "description": "allOf with base schema", "schema": { "properties": {"bar": {"type": "integer"}}, "required": ["bar"], "allOf" : [ { "properties": { "foo": {"type": "string"} }, "required": ["foo"] }, { "properties": { "baz": {"type": "null"} }, "required": ["baz"] } ] }, "tests": [ { "description": "valid", "data": {"foo": "quux", "bar": 2, "baz": null}, "valid": true }, { "description": "mismatch base schema", "data": {"foo": "quux", "baz": null}, "valid": false }, { "description": "mismatch first allOf", "data": {"bar": 2, "baz": null}, "valid": false }, { "description": "mismatch second allOf", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "mismatch both", "data": {"bar": 2}, "valid": false } ] }, { "description": "allOf simple types", "schema": { "allOf": [ {"maximum": 30}, {"minimum": 20} ] }, "tests": [ { "description": "valid", "data": 25, "valid": true }, { "description": "mismatch one", "data": 35, "valid": false } ] }, { "description": "allOf with one empty schema", "schema": { "allOf": [ {} ] }, "tests": [ { "description": "any data is valid", "data": 1, "valid": true } ] }, { "description": "allOf with two empty schemas", "schema": { "allOf": [ {}, {} ] }, "tests": [ { "description": "any data is valid", "data": 1, "valid": true } ] }, { "description": "allOf with the first empty schema", "schema": { "allOf": [ {}, { "type": "number" } ] }, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is invalid", "data": "foo", "valid": false } ] }, { "description": "allOf with the last empty schema", "schema": { "allOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is invalid", "data": "foo", "valid": false } ] }, { "description": "nested allOf, to check validation semantics", "schema": { "allOf": [ { "allOf": [ { "type": "null" } ] } ] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "anything non-null is invalid", "data": 123, "valid": false } ] }, { "description": "allOf combined with anyOf, oneOf", "schema": { "allOf": [ { "multipleOf": 2 } ], "anyOf": [ { "multipleOf": 3 } ], "oneOf": [ { "multipleOf": 5 } ] }, "tests": [ { "description": "allOf: false, anyOf: false, oneOf: false", "data": 1, "valid": false }, { "description": "allOf: false, anyOf: false, oneOf: true", "data": 5, "valid": false }, { "description": "allOf: false, anyOf: true, oneOf: false", "data": 3, "valid": false }, { "description": "allOf: false, anyOf: true, oneOf: true", "data": 15, "valid": false }, { "description": "allOf: true, anyOf: false, oneOf: false", "data": 2, "valid": false }, { "description": "allOf: true, anyOf: false, oneOf: true", "data": 10, "valid": false }, { "description": "allOf: true, anyOf: true, oneOf: false", "data": 6, "valid": false }, { "description": "allOf: true, anyOf: true, oneOf: true", "data": 30, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/anyOf.json0000644000175100001770000000755514653725311022537 0ustar00runnerdocker[ { "description": "anyOf", "schema": { "anyOf": [ { "type": "integer" }, { "minimum": 2 } ] }, "tests": [ { "description": "first anyOf valid", "data": 1, "valid": true }, { "description": "second anyOf valid", "data": 2.5, "valid": true }, { "description": "both anyOf valid", "data": 3, "valid": true }, { "description": "neither anyOf valid", "data": 1.5, "valid": false } ] }, { "description": "anyOf with base schema", "schema": { "type": "string", "anyOf" : [ { "maxLength": 2 }, { "minLength": 4 } ] }, "tests": [ { "description": "mismatch base schema", "data": 3, "valid": false }, { "description": "one anyOf valid", "data": "foobar", "valid": true }, { "description": "both anyOf invalid", "data": "foo", "valid": false } ] }, { "description": "anyOf complex types", "schema": { "anyOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "first anyOf valid (complex)", "data": {"bar": 2}, "valid": true }, { "description": "second anyOf valid (complex)", "data": {"foo": "baz"}, "valid": true }, { "description": "both anyOf valid (complex)", "data": {"foo": "baz", "bar": 2}, "valid": true }, { "description": "neither anyOf valid (complex)", "data": {"foo": 2, "bar": "quux"}, "valid": false } ] }, { "description": "anyOf with one empty schema", "schema": { "anyOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "string is valid", "data": "foo", "valid": true }, { "description": "number is valid", "data": 123, "valid": true } ] }, { "description": "nested anyOf, to check validation semantics", "schema": { "anyOf": [ { "anyOf": [ { "type": "null" } ] } ] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "anything non-null is invalid", "data": 123, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/default.json0000644000175100001770000000426714653725311023104 0ustar00runnerdocker[ { "description": "invalid type for default", "schema": { "properties": { "foo": { "type": "integer", "default": [] } } }, "tests": [ { "description": "valid when property is specified", "data": {"foo": 13}, "valid": true }, { "description": "still valid when the invalid default is used", "data": {}, "valid": true } ] }, { "description": "invalid string value for default", "schema": { "properties": { "bar": { "type": "string", "minLength": 4, "default": "bad" } } }, "tests": [ { "description": "valid when property is specified", "data": {"bar": "good"}, "valid": true }, { "description": "still valid when the invalid default is used", "data": {}, "valid": true } ] }, { "description": "the default keyword does not do anything if the property is missing", "schema": { "type": "object", "properties": { "alpha": { "type": "number", "maximum": 3, "default": 5 } } }, "tests": [ { "description": "an explicit property value is checked against maximum (passing)", "data": { "alpha": 1 }, "valid": true }, { "description": "an explicit property value is checked against maximum (failing)", "data": { "alpha": 5 }, "valid": false }, { "description": "missing properties are not filled in with the default", "data": {}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/definitions.json0000644000175100001770000000131714653725311023764 0ustar00runnerdocker[ { "description": "validate definition against metaschema", "schema": {"$ref": "http://json-schema.org/draft-04/schema#"}, "tests": [ { "description": "valid definition schema", "data": { "definitions": { "foo": {"type": "integer"} } }, "valid": true }, { "description": "invalid definition schema", "data": { "definitions": { "foo": {"type": 1} } }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/dependencies.json0000644000175100001770000001236114653725311024100 0ustar00runnerdocker[ { "description": "dependencies", "schema": { "dependencies": {"bar": ["foo"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependant", "data": {"foo": 1}, "valid": true }, { "description": "with dependency", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "missing dependency", "data": {"bar": 2}, "valid": false }, { "description": "ignores arrays", "data": ["bar"], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "multiple dependencies", "schema": { "dependencies": {"quux": ["foo", "bar"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependants", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "with dependencies", "data": {"foo": 1, "bar": 2, "quux": 3}, "valid": true }, { "description": "missing dependency", "data": {"foo": 1, "quux": 2}, "valid": false }, { "description": "missing other dependency", "data": {"bar": 1, "quux": 2}, "valid": false }, { "description": "missing both dependencies", "data": {"quux": 1}, "valid": false } ] }, { "description": "multiple dependencies subschema", "schema": { "dependencies": { "bar": { "properties": { "foo": {"type": "integer"}, "bar": {"type": "integer"} } } } }, "tests": [ { "description": "valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "no dependency", "data": {"foo": "quux"}, "valid": true }, { "description": "wrong type", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "wrong type other", "data": {"foo": 2, "bar": "quux"}, "valid": false }, { "description": "wrong type both", "data": {"foo": "quux", "bar": "quux"}, "valid": false } ] }, { "description": "dependencies with escaped characters", "schema": { "dependencies": { "foo\nbar": ["foo\rbar"], "foo\tbar": { "minProperties": 4 }, "foo'bar": {"required": ["foo\"bar"]}, "foo\"bar": ["foo'bar"] } }, "tests": [ { "description": "valid object 1", "data": { "foo\nbar": 1, "foo\rbar": 2 }, "valid": true }, { "description": "valid object 2", "data": { "foo\tbar": 1, "a": 2, "b": 3, "c": 4 }, "valid": true }, { "description": "valid object 3", "data": { "foo'bar": 1, "foo\"bar": 2 }, "valid": true }, { "description": "invalid object 1", "data": { "foo\nbar": 1, "foo": 2 }, "valid": false }, { "description": "invalid object 2", "data": { "foo\tbar": 1, "a": 2 }, "valid": false }, { "description": "invalid object 3", "data": { "foo'bar": 1 }, "valid": false }, { "description": "invalid object 4", "data": { "foo\"bar": 2 }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/enum.json0000644000175100001770000001464314653725311022423 0ustar00runnerdocker[ { "description": "simple enum validation", "schema": {"enum": [1, 2, 3]}, "tests": [ { "description": "one of the enum is valid", "data": 1, "valid": true }, { "description": "something else is invalid", "data": 4, "valid": false } ] }, { "description": "heterogeneous enum validation", "schema": {"enum": [6, "foo", [], true, {"foo": 12}]}, "tests": [ { "description": "one of the enum is valid", "data": [], "valid": true }, { "description": "something else is invalid", "data": null, "valid": false }, { "description": "objects are deep compared", "data": {"foo": false}, "valid": false }, { "description": "valid object matches", "data": {"foo": 12}, "valid": true }, { "description": "extra properties in object is invalid", "data": {"foo": 12, "boo": 42}, "valid": false } ] }, { "description": "heterogeneous enum-with-null validation", "schema": { "enum": [6, null] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "number is valid", "data": 6, "valid": true }, { "description": "something else is invalid", "data": "test", "valid": false } ] }, { "description": "enums in properties", "schema": { "type":"object", "properties": { "foo": {"enum":["foo"]}, "bar": {"enum":["bar"]} }, "required": ["bar"] }, "tests": [ { "description": "both properties are valid", "data": {"foo":"foo", "bar":"bar"}, "valid": true }, { "description": "wrong foo value", "data": {"foo":"foot", "bar":"bar"}, "valid": false }, { "description": "wrong bar value", "data": {"foo":"foo", "bar":"bart"}, "valid": false }, { "description": "missing optional property is valid", "data": {"bar":"bar"}, "valid": true }, { "description": "missing required property is invalid", "data": {"foo":"foo"}, "valid": false }, { "description": "missing all properties is invalid", "data": {}, "valid": false } ] }, { "description": "enum with escaped characters", "schema": { "enum": ["foo\nbar", "foo\rbar"] }, "tests": [ { "description": "member 1 is valid", "data": "foo\nbar", "valid": true }, { "description": "member 2 is valid", "data": "foo\rbar", "valid": true }, { "description": "another string is invalid", "data": "abc", "valid": false } ] }, { "description": "enum with false does not match 0", "schema": {"enum": [false]}, "tests": [ { "description": "false is valid", "data": false, "valid": true }, { "description": "integer zero is invalid", "data": 0, "valid": false }, { "description": "float zero is invalid", "data": 0.0, "valid": false } ] }, { "description": "enum with true does not match 1", "schema": {"enum": [true]}, "tests": [ { "description": "true is valid", "data": true, "valid": true }, { "description": "integer one is invalid", "data": 1, "valid": false }, { "description": "float one is invalid", "data": 1.0, "valid": false } ] }, { "description": "enum with 0 does not match false", "schema": {"enum": [0]}, "tests": [ { "description": "false is invalid", "data": false, "valid": false }, { "description": "integer zero is valid", "data": 0, "valid": true }, { "description": "float zero is valid", "data": 0.0, "valid": true } ] }, { "description": "enum with 1 does not match true", "schema": {"enum": [1]}, "tests": [ { "description": "true is invalid", "data": true, "valid": false }, { "description": "integer one is valid", "data": 1, "valid": true }, { "description": "float one is valid", "data": 1.0, "valid": true } ] }, { "description": "nul characters in strings", "schema": { "enum": [ "hello\u0000there" ] }, "tests": [ { "description": "match string with nul", "data": "hello\u0000there", "valid": true }, { "description": "do not match string lacking nul", "data": "hellothere", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/format.json0000644000175100001770000001431114653725311022737 0ustar00runnerdocker[ { "description": "email format", "schema": { "format": "email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "ipv4 format", "schema": { "format": "ipv4" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "ipv6 format", "schema": { "format": "ipv6" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "hostname format", "schema": { "format": "hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "date-time format", "schema": { "format": "date-time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uri format", "schema": { "format": "uri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/id.json0000644000175100001770000000326714653725311022053 0ustar00runnerdocker[ { "description": "id inside an enum is not a real identifier", "comment": "the implementation must not be confused by an id buried in the enum", "schema": { "definitions": { "id_in_enum": { "enum": [ { "id": "https://localhost:1234/my_identifier.json", "type": "null" } ] }, "real_id_in_schema": { "id": "https://localhost:1234/my_identifier.json", "type": "string" }, "zzz_id_in_const": { "const": { "id": "https://localhost:1234/my_identifier.json", "type": "null" } } }, "anyOf": [ { "$ref": "#/definitions/id_in_enum" }, { "$ref": "https://localhost:1234/my_identifier.json" } ] }, "tests": [ { "description": "exact match to enum, and type matches", "data": { "id": "https://localhost:1234/my_identifier.json", "type": "null" }, "valid": true }, { "description": "match $ref to id", "data": "a string to match #/definitions/id_in_enum", "valid": true }, { "description": "no match on enum or $ref to id", "data": 1, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/infinite-loop-detection.json0000644000175100001770000000174614653725311026207 0ustar00runnerdocker[ { "description": "evaluating the same schema location against the same data location twice is not a sign of an infinite loop", "schema": { "definitions": { "int": { "type": "integer" } }, "allOf": [ { "properties": { "foo": { "$ref": "#/definitions/int" } } }, { "additionalProperties": { "$ref": "#/definitions/int" } } ] }, "tests": [ { "description": "passing case", "data": { "foo": 1 }, "valid": true }, { "description": "failing case", "data": { "foo": "a string" }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/items.json0000644000175100001770000001464414653725311022601 0ustar00runnerdocker[ { "description": "a schema given for items", "schema": { "items": {"type": "integer"} }, "tests": [ { "description": "valid items", "data": [ 1, 2, 3 ], "valid": true }, { "description": "wrong type of items", "data": [1, "x"], "valid": false }, { "description": "ignores non-arrays", "data": {"foo" : "bar"}, "valid": true }, { "description": "JavaScript pseudo-array is valid", "data": { "0": "invalid", "length": 1 }, "valid": true } ] }, { "description": "an array of schemas for items", "schema": { "items": [ {"type": "integer"}, {"type": "string"} ] }, "tests": [ { "description": "correct types", "data": [ 1, "foo" ], "valid": true }, { "description": "wrong types", "data": [ "foo", 1 ], "valid": false }, { "description": "incomplete array of items", "data": [ 1 ], "valid": true }, { "description": "array with additional items", "data": [ 1, "foo", true ], "valid": true }, { "description": "empty array", "data": [ ], "valid": true }, { "description": "JavaScript pseudo-array is valid", "data": { "0": "invalid", "1": "valid", "length": 2 }, "valid": true } ] }, { "description": "items and subitems", "schema": { "definitions": { "item": { "type": "array", "additionalItems": false, "items": [ { "$ref": "#/definitions/sub-item" }, { "$ref": "#/definitions/sub-item" } ] }, "sub-item": { "type": "object", "required": ["foo"] } }, "type": "array", "additionalItems": false, "items": [ { "$ref": "#/definitions/item" }, { "$ref": "#/definitions/item" }, { "$ref": "#/definitions/item" } ] }, "tests": [ { "description": "valid items", "data": [ [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": true }, { "description": "too many items", "data": [ [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "too many sub-items", "data": [ [ {"foo": null}, {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "wrong item", "data": [ {"foo": null}, [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "wrong sub-item", "data": [ [ {}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "fewer items is valid", "data": [ [ {"foo": null} ], [ {"foo": null} ] ], "valid": true } ] }, { "description": "nested items", "schema": { "type": "array", "items": { "type": "array", "items": { "type": "array", "items": { "type": "array", "items": { "type": "number" } } } } }, "tests": [ { "description": "valid nested array", "data": [[[[1]], [[2],[3]]], [[[4], [5], [6]]]], "valid": true }, { "description": "nested array with invalid type", "data": [[[["1"]], [[2],[3]]], [[[4], [5], [6]]]], "valid": false }, { "description": "not deep enough", "data": [[[1], [2],[3]], [[4], [5], [6]]], "valid": false } ] }, { "description": "items with null instance elements", "schema": { "items": { "type": "null" } }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] }, { "description": "array-form items with null instance elements", "schema": { "items": [ { "type": "null" } ] }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/maxItems.json0000644000175100001770000000130214653725311023232 0ustar00runnerdocker[ { "description": "maxItems validation", "schema": {"maxItems": 2}, "tests": [ { "description": "shorter is valid", "data": [1], "valid": true }, { "description": "exact length is valid", "data": [1, 2], "valid": true }, { "description": "too long is invalid", "data": [1, 2, 3], "valid": false }, { "description": "ignores non-arrays", "data": "foobar", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/maxLength.json0000644000175100001770000000160014653725311023373 0ustar00runnerdocker[ { "description": "maxLength validation", "schema": {"maxLength": 2}, "tests": [ { "description": "shorter is valid", "data": "f", "valid": true }, { "description": "exact length is valid", "data": "fo", "valid": true }, { "description": "too long is invalid", "data": "foo", "valid": false }, { "description": "ignores non-strings", "data": 100, "valid": true }, { "description": "two supplementary Unicode code points is long enough", "data": "\uD83D\uDCA9\uD83D\uDCA9", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/maxProperties.json0000644000175100001770000000273214653725311024315 0ustar00runnerdocker[ { "description": "maxProperties validation", "schema": {"maxProperties": 2}, "tests": [ { "description": "shorter is valid", "data": {"foo": 1}, "valid": true }, { "description": "exact length is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "too long is invalid", "data": {"foo": 1, "bar": 2, "baz": 3}, "valid": false }, { "description": "ignores arrays", "data": [1, 2, 3], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "maxProperties = 0 means the object is empty", "schema": { "maxProperties": 0 }, "tests": [ { "description": "no properties is valid", "data": {}, "valid": true }, { "description": "one property is invalid", "data": { "foo": 1 }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/maximum.json0000644000175100001770000000526214653725311023131 0ustar00runnerdocker[ { "description": "maximum validation", "schema": {"maximum": 3.0}, "tests": [ { "description": "below the maximum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 3.0, "valid": true }, { "description": "above the maximum is invalid", "data": 3.5, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] }, { "description": "maximum validation with unsigned integer", "schema": {"maximum": 300}, "tests": [ { "description": "below the maximum is invalid", "data": 299.97, "valid": true }, { "description": "boundary point integer is valid", "data": 300, "valid": true }, { "description": "boundary point float is valid", "data": 300.00, "valid": true }, { "description": "above the maximum is invalid", "data": 300.5, "valid": false } ] }, { "description": "maximum validation (explicit false exclusivity)", "schema": {"maximum": 3.0, "exclusiveMaximum": false}, "tests": [ { "description": "below the maximum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 3.0, "valid": true }, { "description": "above the maximum is invalid", "data": 3.5, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] }, { "description": "exclusiveMaximum validation", "schema": { "maximum": 3.0, "exclusiveMaximum": true }, "tests": [ { "description": "below the maximum is still valid", "data": 2.2, "valid": true }, { "description": "boundary point is invalid", "data": 3.0, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/minItems.json0000644000175100001770000000126514653725311023240 0ustar00runnerdocker[ { "description": "minItems validation", "schema": {"minItems": 1}, "tests": [ { "description": "longer is valid", "data": [1, 2], "valid": true }, { "description": "exact length is valid", "data": [1], "valid": true }, { "description": "too short is invalid", "data": [], "valid": false }, { "description": "ignores non-arrays", "data": "", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/minLength.json0000644000175100001770000000156614653725311023404 0ustar00runnerdocker[ { "description": "minLength validation", "schema": {"minLength": 2}, "tests": [ { "description": "longer is valid", "data": "foo", "valid": true }, { "description": "exact length is valid", "data": "fo", "valid": true }, { "description": "too short is invalid", "data": "f", "valid": false }, { "description": "ignores non-strings", "data": 1, "valid": true }, { "description": "one supplementary Unicode code point is not long enough", "data": "\uD83D\uDCA9", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/minProperties.json0000644000175100001770000000175414653725311024316 0ustar00runnerdocker[ { "description": "minProperties validation", "schema": {"minProperties": 1}, "tests": [ { "description": "longer is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "exact length is valid", "data": {"foo": 1}, "valid": true }, { "description": "too short is invalid", "data": {}, "valid": false }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/minimum.json0000644000175100001770000000617014653725311023126 0ustar00runnerdocker[ { "description": "minimum validation", "schema": {"minimum": 1.1}, "tests": [ { "description": "above the minimum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 1.1, "valid": true }, { "description": "below the minimum is invalid", "data": 0.6, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] }, { "description": "minimum validation (explicit false exclusivity)", "schema": {"minimum": 1.1, "exclusiveMinimum": false}, "tests": [ { "description": "above the minimum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 1.1, "valid": true }, { "description": "below the minimum is invalid", "data": 0.6, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] }, { "description": "exclusiveMinimum validation", "schema": { "minimum": 1.1, "exclusiveMinimum": true }, "tests": [ { "description": "above the minimum is still valid", "data": 1.2, "valid": true }, { "description": "boundary point is invalid", "data": 1.1, "valid": false } ] }, { "description": "minimum validation with signed integer", "schema": {"minimum": -2}, "tests": [ { "description": "negative above the minimum is valid", "data": -1, "valid": true }, { "description": "positive above the minimum is valid", "data": 0, "valid": true }, { "description": "boundary point is valid", "data": -2, "valid": true }, { "description": "boundary point with float is valid", "data": -2.0, "valid": true }, { "description": "float below the minimum is invalid", "data": -2.0001, "valid": false }, { "description": "int below the minimum is invalid", "data": -3, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/multipleOf.json0000644000175100001770000000351314653725311023571 0ustar00runnerdocker[ { "description": "by int", "schema": {"multipleOf": 2}, "tests": [ { "description": "int by int", "data": 10, "valid": true }, { "description": "int by int fail", "data": 7, "valid": false }, { "description": "ignores non-numbers", "data": "foo", "valid": true } ] }, { "description": "by number", "schema": {"multipleOf": 1.5}, "tests": [ { "description": "zero is multiple of anything", "data": 0, "valid": true }, { "description": "4.5 is multiple of 1.5", "data": 4.5, "valid": true }, { "description": "35 is not multiple of 1.5", "data": 35, "valid": false } ] }, { "description": "by small number", "schema": {"multipleOf": 0.0001}, "tests": [ { "description": "0.0075 is multiple of 0.0001", "data": 0.0075, "valid": true }, { "description": "0.00751 is not multiple of 0.0001", "data": 0.00751, "valid": false } ] }, { "description": "float division = inf", "schema": {"type": "integer", "multipleOf": 0.123456789}, "tests": [ { "description": "invalid, but naive implementations may raise an overflow error", "data": 1e308, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/not.json0000644000175100001770000000433214653725311022251 0ustar00runnerdocker[ { "description": "not", "schema": { "not": {"type": "integer"} }, "tests": [ { "description": "allowed", "data": "foo", "valid": true }, { "description": "disallowed", "data": 1, "valid": false } ] }, { "description": "not multiple types", "schema": { "not": {"type": ["integer", "boolean"]} }, "tests": [ { "description": "valid", "data": "foo", "valid": true }, { "description": "mismatch", "data": 1, "valid": false }, { "description": "other mismatch", "data": true, "valid": false } ] }, { "description": "not more complex schema", "schema": { "not": { "type": "object", "properties": { "foo": { "type": "string" } } } }, "tests": [ { "description": "match", "data": 1, "valid": true }, { "description": "other match", "data": {"foo": 1}, "valid": true }, { "description": "mismatch", "data": {"foo": "bar"}, "valid": false } ] }, { "description": "forbidden property", "schema": { "properties": { "foo": { "not": {} } } }, "tests": [ { "description": "property present", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "property absent", "data": {"bar": 1, "baz": 2}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/oneOf.json0000644000175100001770000001362314653725311022522 0ustar00runnerdocker[ { "description": "oneOf", "schema": { "oneOf": [ { "type": "integer" }, { "minimum": 2 } ] }, "tests": [ { "description": "first oneOf valid", "data": 1, "valid": true }, { "description": "second oneOf valid", "data": 2.5, "valid": true }, { "description": "both oneOf valid", "data": 3, "valid": false }, { "description": "neither oneOf valid", "data": 1.5, "valid": false } ] }, { "description": "oneOf with base schema", "schema": { "type": "string", "oneOf" : [ { "minLength": 2 }, { "maxLength": 4 } ] }, "tests": [ { "description": "mismatch base schema", "data": 3, "valid": false }, { "description": "one oneOf valid", "data": "foobar", "valid": true }, { "description": "both oneOf valid", "data": "foo", "valid": false } ] }, { "description": "oneOf complex types", "schema": { "oneOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "first oneOf valid (complex)", "data": {"bar": 2}, "valid": true }, { "description": "second oneOf valid (complex)", "data": {"foo": "baz"}, "valid": true }, { "description": "both oneOf valid (complex)", "data": {"foo": "baz", "bar": 2}, "valid": false }, { "description": "neither oneOf valid (complex)", "data": {"foo": 2, "bar": "quux"}, "valid": false } ] }, { "description": "oneOf with empty schema", "schema": { "oneOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "one valid - valid", "data": "foo", "valid": true }, { "description": "both valid - invalid", "data": 123, "valid": false } ] }, { "description": "oneOf with required", "schema": { "type": "object", "oneOf": [ { "required": ["foo", "bar"] }, { "required": ["foo", "baz"] } ] }, "tests": [ { "description": "both invalid - invalid", "data": {"bar": 2}, "valid": false }, { "description": "first valid - valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "second valid - valid", "data": {"foo": 1, "baz": 3}, "valid": true }, { "description": "both valid - invalid", "data": {"foo": 1, "bar": 2, "baz" : 3}, "valid": false } ] }, { "description": "oneOf with missing optional property", "schema": { "oneOf": [ { "properties": { "bar": {}, "baz": {} }, "required": ["bar"] }, { "properties": { "foo": {} }, "required": ["foo"] } ] }, "tests": [ { "description": "first oneOf valid", "data": {"bar": 8}, "valid": true }, { "description": "second oneOf valid", "data": {"foo": "foo"}, "valid": true }, { "description": "both oneOf valid", "data": {"foo": "foo", "bar": 8}, "valid": false }, { "description": "neither oneOf valid", "data": {"baz": "quux"}, "valid": false } ] }, { "description": "nested oneOf, to check validation semantics", "schema": { "oneOf": [ { "oneOf": [ { "type": "null" } ] } ] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "anything non-null is invalid", "data": 123, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.089097 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/optional/0000755000175100001770000000000014653725331022403 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/optional/bignum.json0000644000175100001770000000547314653725311024566 0ustar00runnerdocker[ { "description": "integer", "schema": { "type": "integer" }, "tests": [ { "description": "a bignum is an integer", "data": 12345678910111213141516171819202122232425262728293031, "valid": true }, { "description": "a negative bignum is an integer", "data": -12345678910111213141516171819202122232425262728293031, "valid": true } ] }, { "description": "number", "schema": { "type": "number" }, "tests": [ { "description": "a bignum is a number", "data": 98249283749234923498293171823948729348710298301928331, "valid": true }, { "description": "a negative bignum is a number", "data": -98249283749234923498293171823948729348710298301928331, "valid": true } ] }, { "description": "string", "schema": { "type": "string" }, "tests": [ { "description": "a bignum is not a string", "data": 98249283749234923498293171823948729348710298301928331, "valid": false } ] }, { "description": "maximum integer comparison", "schema": { "maximum": 18446744073709551615 }, "tests": [ { "description": "comparison works for high numbers", "data": 18446744073709551600, "valid": true } ] }, { "description": "float comparison with high precision", "schema": { "maximum": 972783798187987123879878123.18878137, "exclusiveMaximum": true }, "tests": [ { "description": "comparison works for high numbers", "data": 972783798187987123879878123.188781371, "valid": false } ] }, { "description": "minimum integer comparison", "schema": { "minimum": -18446744073709551615 }, "tests": [ { "description": "comparison works for very negative numbers", "data": -18446744073709551600, "valid": true } ] }, { "description": "float comparison with high precision on negative numbers", "schema": { "minimum": -972783798187987123879878123.18878137, "exclusiveMinimum": true }, "tests": [ { "description": "comparison works for very negative numbers", "data": -972783798187987123879878123.188781371, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/optional/ecmascript-regex.json0000644000175100001770000004406714653725311026551 0ustar00runnerdocker[ { "description": "ECMA 262 regex $ does not match trailing newline", "schema": { "type": "string", "pattern": "^abc$" }, "tests": [ { "description": "matches in Python, but not in ECMA 262", "data": "abc\\n", "valid": false }, { "description": "matches", "data": "abc", "valid": true } ] }, { "description": "ECMA 262 regex converts \\t to horizontal tab", "schema": { "type": "string", "pattern": "^\\t$" }, "tests": [ { "description": "does not match", "data": "\\t", "valid": false }, { "description": "matches", "data": "\u0009", "valid": true } ] }, { "description": "ECMA 262 regex escapes control codes with \\c and upper letter", "schema": { "type": "string", "pattern": "^\\cC$" }, "tests": [ { "description": "does not match", "data": "\\cC", "valid": false }, { "description": "matches", "data": "\u0003", "valid": true } ] }, { "description": "ECMA 262 regex escapes control codes with \\c and lower letter", "schema": { "type": "string", "pattern": "^\\cc$" }, "tests": [ { "description": "does not match", "data": "\\cc", "valid": false }, { "description": "matches", "data": "\u0003", "valid": true } ] }, { "description": "ECMA 262 \\d matches ascii digits only", "schema": { "type": "string", "pattern": "^\\d$" }, "tests": [ { "description": "ASCII zero matches", "data": "0", "valid": true }, { "description": "NKO DIGIT ZERO does not match (unlike e.g. Python)", "data": "߀", "valid": false }, { "description": "NKO DIGIT ZERO (as \\u escape) does not match", "data": "\u07c0", "valid": false } ] }, { "description": "ECMA 262 \\D matches everything but ascii digits", "schema": { "type": "string", "pattern": "^\\D$" }, "tests": [ { "description": "ASCII zero does not match", "data": "0", "valid": false }, { "description": "NKO DIGIT ZERO matches (unlike e.g. Python)", "data": "߀", "valid": true }, { "description": "NKO DIGIT ZERO (as \\u escape) matches", "data": "\u07c0", "valid": true } ] }, { "description": "ECMA 262 \\w matches ascii letters only", "schema": { "type": "string", "pattern": "^\\w$" }, "tests": [ { "description": "ASCII 'a' matches", "data": "a", "valid": true }, { "description": "latin-1 e-acute does not match (unlike e.g. Python)", "data": "é", "valid": false } ] }, { "description": "ECMA 262 \\W matches everything but ascii letters", "schema": { "type": "string", "pattern": "^\\W$" }, "tests": [ { "description": "ASCII 'a' does not match", "data": "a", "valid": false }, { "description": "latin-1 e-acute matches (unlike e.g. Python)", "data": "é", "valid": true } ] }, { "description": "ECMA 262 \\s matches whitespace", "schema": { "type": "string", "pattern": "^\\s$" }, "tests": [ { "description": "ASCII space matches", "data": " ", "valid": true }, { "description": "Character tabulation matches", "data": "\t", "valid": true }, { "description": "Line tabulation matches", "data": "\u000b", "valid": true }, { "description": "Form feed matches", "data": "\u000c", "valid": true }, { "description": "latin-1 non-breaking-space matches", "data": "\u00a0", "valid": true }, { "description": "zero-width whitespace matches", "data": "\ufeff", "valid": true }, { "description": "line feed matches (line terminator)", "data": "\u000a", "valid": true }, { "description": "paragraph separator matches (line terminator)", "data": "\u2029", "valid": true }, { "description": "EM SPACE matches (Space_Separator)", "data": "\u2003", "valid": true }, { "description": "Non-whitespace control does not match", "data": "\u0001", "valid": false }, { "description": "Non-whitespace does not match", "data": "\u2013", "valid": false } ] }, { "description": "ECMA 262 \\S matches everything but whitespace", "schema": { "type": "string", "pattern": "^\\S$" }, "tests": [ { "description": "ASCII space does not match", "data": " ", "valid": false }, { "description": "Character tabulation does not match", "data": "\t", "valid": false }, { "description": "Line tabulation does not match", "data": "\u000b", "valid": false }, { "description": "Form feed does not match", "data": "\u000c", "valid": false }, { "description": "latin-1 non-breaking-space does not match", "data": "\u00a0", "valid": false }, { "description": "zero-width whitespace does not match", "data": "\ufeff", "valid": false }, { "description": "line feed does not match (line terminator)", "data": "\u000a", "valid": false }, { "description": "paragraph separator does not match (line terminator)", "data": "\u2029", "valid": false }, { "description": "EM SPACE does not match (Space_Separator)", "data": "\u2003", "valid": false }, { "description": "Non-whitespace control matches", "data": "\u0001", "valid": true }, { "description": "Non-whitespace matches", "data": "\u2013", "valid": true } ] }, { "description": "patterns always use unicode semantics with pattern", "schema": { "pattern": "\\p{Letter}cole" }, "tests": [ { "description": "ascii character in json string", "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", "valid": true }, { "description": "literal unicode character in json string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": true }, { "description": "unicode character in hex format in string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": true }, { "description": "unicode matching is case-sensitive", "data": "LES HIVERS DE MON ENFANCE ÉTAIENT DES SAISONS LONGUES, LONGUES. NOUS VIVIONS EN TROIS LIEUX: L'ÉCOLE, L'ÉGLISE ET LA PATINOIRE; MAIS LA VRAIE VIE ÉTAIT SUR LA PATINOIRE.", "valid": false } ] }, { "description": "\\w in patterns matches [A-Za-z0-9_], not unicode letters", "schema": { "pattern": "\\wcole" }, "tests": [ { "description": "ascii character in json string", "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", "valid": true }, { "description": "literal unicode character in json string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "unicode character in hex format in string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "unicode matching is case-sensitive", "data": "LES HIVERS DE MON ENFANCE ÉTAIENT DES SAISONS LONGUES, LONGUES. NOUS VIVIONS EN TROIS LIEUX: L'ÉCOLE, L'ÉGLISE ET LA PATINOIRE; MAIS LA VRAIE VIE ÉTAIT SUR LA PATINOIRE.", "valid": false } ] }, { "description": "pattern with ASCII ranges", "schema": { "pattern": "[a-z]cole" }, "tests": [ { "description": "literal unicode character in json string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "unicode character in hex format in string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "ascii characters match", "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", "valid": true } ] }, { "description": "\\d in pattern matches [0-9], not unicode digits", "schema": { "pattern": "^\\d+$" }, "tests": [ { "description": "ascii digits", "data": "42", "valid": true }, { "description": "ascii non-digits", "data": "-%#", "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": "৪২", "valid": false } ] }, { "description": "pattern with non-ASCII digits", "schema": { "pattern": "^\\p{digit}+$" }, "tests": [ { "description": "ascii digits", "data": "42", "valid": true }, { "description": "ascii non-digits", "data": "-%#", "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": "৪২", "valid": true } ] }, { "description": "patterns always use unicode semantics with patternProperties", "schema": { "type": "object", "patternProperties": { "\\p{Letter}cole": {} }, "additionalProperties": false }, "tests": [ { "description": "ascii character in json string", "data": { "l'ecole": "pas de vraie vie" }, "valid": true }, { "description": "literal unicode character in json string", "data": { "l'école": "pas de vraie vie" }, "valid": true }, { "description": "unicode character in hex format in string", "data": { "l'\u00e9cole": "pas de vraie vie" }, "valid": true }, { "description": "unicode matching is case-sensitive", "data": { "L'ÉCOLE": "PAS DE VRAIE VIE" }, "valid": false } ] }, { "description": "\\w in patternProperties matches [A-Za-z0-9_], not unicode letters", "schema": { "type": "object", "patternProperties": { "\\wcole": {} }, "additionalProperties": false }, "tests": [ { "description": "ascii character in json string", "data": { "l'ecole": "pas de vraie vie" }, "valid": true }, { "description": "literal unicode character in json string", "data": { "l'école": "pas de vraie vie" }, "valid": false }, { "description": "unicode character in hex format in string", "data": { "l'\u00e9cole": "pas de vraie vie" }, "valid": false }, { "description": "unicode matching is case-sensitive", "data": { "L'ÉCOLE": "PAS DE VRAIE VIE" }, "valid": false } ] }, { "description": "patternProperties with ASCII ranges", "schema": { "type": "object", "patternProperties": { "[a-z]cole": {} }, "additionalProperties": false }, "tests": [ { "description": "literal unicode character in json string", "data": { "l'école": "pas de vraie vie" }, "valid": false }, { "description": "unicode character in hex format in string", "data": { "l'\u00e9cole": "pas de vraie vie" }, "valid": false }, { "description": "ascii characters match", "data": { "l'ecole": "pas de vraie vie" }, "valid": true } ] }, { "description": "\\d in patternProperties matches [0-9], not unicode digits", "schema": { "type": "object", "patternProperties": { "^\\d+$": {} }, "additionalProperties": false }, "tests": [ { "description": "ascii digits", "data": { "42": "life, the universe, and everything" }, "valid": true }, { "description": "ascii non-digits", "data": { "-%#": "spending the year dead for tax reasons" }, "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": { "৪২": "khajit has wares if you have coin" }, "valid": false } ] }, { "description": "patternProperties with non-ASCII digits", "schema": { "type": "object", "patternProperties": { "^\\p{digit}+$": {} }, "additionalProperties": false }, "tests": [ { "description": "ascii digits", "data": { "42": "life, the universe, and everything" }, "valid": true }, { "description": "ascii non-digits", "data": { "-%#": "spending the year dead for tax reasons" }, "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": { "৪২": "khajit has wares if you have coin" }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/optional/float-overflow.json0000644000175100001770000000055014653725311026242 0ustar00runnerdocker[ { "description": "all integers are multiples of 0.5, if overflow is handled", "schema": {"type": "number", "multipleOf": 0.5}, "tests": [ { "description": "valid if optional overflow handling is implemented", "data": 1e308, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0930972 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/optional/format/0000755000175100001770000000000014653725331023673 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/optional/format/date-time.json0000644000175100001770000001106014653725311026433 0ustar00runnerdocker[ { "description": "validation of date-time strings", "schema": { "format": "date-time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid date-time string", "data": "1963-06-19T08:30:06.283185Z", "valid": true }, { "description": "a valid date-time string without second fraction", "data": "1963-06-19T08:30:06Z", "valid": true }, { "description": "a valid date-time string with plus offset", "data": "1937-01-01T12:00:27.87+00:20", "valid": true }, { "description": "a valid date-time string with minus offset", "data": "1990-12-31T15:59:50.123-08:00", "valid": true }, { "description": "a valid date-time with a leap second, UTC", "data": "1998-12-31T23:59:60Z", "valid": true }, { "description": "a valid date-time with a leap second, with minus offset", "data": "1998-12-31T15:59:60.123-08:00", "valid": true }, { "description": "an invalid date-time past leap second, UTC", "data": "1998-12-31T23:59:61Z", "valid": false }, { "description": "an invalid date-time with leap second on a wrong minute, UTC", "data": "1998-12-31T23:58:60Z", "valid": false }, { "description": "an invalid date-time with leap second on a wrong hour, UTC", "data": "1998-12-31T22:59:60Z", "valid": false }, { "description": "an invalid day in date-time string", "data": "1990-02-31T15:59:59.123-08:00", "valid": false }, { "description": "an invalid offset in date-time string", "data": "1990-12-31T15:59:59-24:00", "valid": false }, { "description": "an invalid closing Z after time-zone offset", "data": "1963-06-19T08:30:06.28123+01:00Z", "valid": false }, { "description": "an invalid date-time string", "data": "06/19/1963 08:30:06 PST", "valid": false }, { "description": "case-insensitive T and Z", "data": "1963-06-19t08:30:06.283185z", "valid": true }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "2013-350T01:01:01", "valid": false }, { "description": "invalid non-padded month dates", "data": "1963-6-19T08:30:06.283185Z", "valid": false }, { "description": "invalid non-padded day dates", "data": "1963-06-1T08:30:06.283185Z", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4) in date portion", "data": "1963-06-1৪T00:00:00Z", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4) in time portion", "data": "1963-06-11T0৪:00:00Z", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/optional/format/email.json0000644000175100001770000000510414653725311025653 0ustar00runnerdocker[ { "description": "validation of e-mail addresses", "schema": { "format": "email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid e-mail address", "data": "joe.bloggs@example.com", "valid": true }, { "description": "an invalid e-mail address", "data": "2962", "valid": false }, { "description": "tilde in local part is valid", "data": "te~st@example.com", "valid": true }, { "description": "tilde before local part is valid", "data": "~test@example.com", "valid": true }, { "description": "tilde after local part is valid", "data": "test~@example.com", "valid": true }, { "description": "dot before local part is not valid", "data": ".test@example.com", "valid": false }, { "description": "dot after local part is not valid", "data": "test.@example.com", "valid": false }, { "description": "two separated dots inside local part are valid", "data": "te.s.t@example.com", "valid": true }, { "description": "two subsequent dots inside local part are not valid", "data": "te..st@example.com", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/optional/format/hostname.json0000644000175100001770000000622414653725311026406 0ustar00runnerdocker[ { "description": "validation of host names", "schema": { "format": "hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid host name", "data": "www.example.com", "valid": true }, { "description": "a valid punycoded IDN hostname", "data": "xn--4gbwdl.xn--wgbh1c", "valid": true }, { "description": "a host name starting with an illegal character", "data": "-a-host-name-that-starts-with--", "valid": false }, { "description": "a host name containing illegal characters", "data": "not_a_valid_host_name", "valid": false }, { "description": "a host name with a component too long", "data": "a-vvvvvvvvvvvvvvvveeeeeeeeeeeeeeeerrrrrrrrrrrrrrrryyyyyyyyyyyyyyyy-long-host-name-component", "valid": false }, { "description": "starts with hyphen", "data": "-hostname", "valid": false }, { "description": "ends with hyphen", "data": "hostname-", "valid": false }, { "description": "starts with underscore", "data": "_hostname", "valid": false }, { "description": "ends with underscore", "data": "hostname_", "valid": false }, { "description": "contains underscore", "data": "host_name", "valid": false }, { "description": "maximum label length", "data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.com", "valid": true }, { "description": "exceeds maximum label length", "data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl.com", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/optional/format/ipv4.json0000644000175100001770000000540414653725311025451 0ustar00runnerdocker[ { "description": "validation of IP addresses", "schema": { "format": "ipv4" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IP address", "data": "192.168.0.1", "valid": true }, { "description": "an IP address with too many components", "data": "127.0.0.0.1", "valid": false }, { "description": "an IP address with out-of-range values", "data": "256.256.256.256", "valid": false }, { "description": "an IP address without 4 components", "data": "127.0", "valid": false }, { "description": "an IP address as an integer", "data": "0x7f000001", "valid": false }, { "description": "an IP address as an integer (decimal)", "data": "2130706433", "valid": false }, { "description": "invalid leading zeroes, as they are treated as octals", "comment": "see https://sick.codes/universal-netmask-npm-package-used-by-270000-projects-vulnerable-to-octal-input-data-server-side-request-forgery-remote-file-inclusion-local-file-inclusion-and-more-cve-2021-28918/", "data": "087.10.0.1", "valid": false }, { "description": "value without leading zero is valid", "data": "87.10.0.1", "valid": true }, { "description": "invalid non-ASCII '২' (a Bengali 2)", "data": "1২7.0.0.1", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/optional/format/ipv6.json0000644000175100001770000001543714653725311025462 0ustar00runnerdocker[ { "description": "validation of IPv6 addresses", "schema": { "format": "ipv6" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IPv6 address", "data": "::1", "valid": true }, { "description": "an IPv6 address with out-of-range values", "data": "12345::", "valid": false }, { "description": "trailing 4 hex symbols is valid", "data": "::abef", "valid": true }, { "description": "trailing 5 hex symbols is invalid", "data": "::abcef", "valid": false }, { "description": "an IPv6 address with too many components", "data": "1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1", "valid": false }, { "description": "an IPv6 address containing illegal characters", "data": "::laptop", "valid": false }, { "description": "no digits is valid", "data": "::", "valid": true }, { "description": "leading colons is valid", "data": "::42:ff:1", "valid": true }, { "description": "trailing colons is valid", "data": "d6::", "valid": true }, { "description": "missing leading octet is invalid", "data": ":2:3:4:5:6:7:8", "valid": false }, { "description": "missing trailing octet is invalid", "data": "1:2:3:4:5:6:7:", "valid": false }, { "description": "missing leading octet with omitted octets later", "data": ":2:3:4::8", "valid": false }, { "description": "single set of double colons in the middle is valid", "data": "1:d6::42", "valid": true }, { "description": "two sets of double colons is invalid", "data": "1::d6::42", "valid": false }, { "description": "mixed format with the ipv4 section as decimal octets", "data": "1::d6:192.168.0.1", "valid": true }, { "description": "mixed format with double colons between the sections", "data": "1:2::192.168.0.1", "valid": true }, { "description": "mixed format with ipv4 section with octet out of range", "data": "1::2:192.168.256.1", "valid": false }, { "description": "mixed format with ipv4 section with a hex octet", "data": "1::2:192.168.ff.1", "valid": false }, { "description": "mixed format with leading double colons (ipv4-mapped ipv6 address)", "data": "::ffff:192.168.0.1", "valid": true }, { "description": "triple colons is invalid", "data": "1:2:3:4:5:::8", "valid": false }, { "description": "8 octets", "data": "1:2:3:4:5:6:7:8", "valid": true }, { "description": "insufficient octets without double colons", "data": "1:2:3:4:5:6:7", "valid": false }, { "description": "no colons is invalid", "data": "1", "valid": false }, { "description": "ipv4 is not ipv6", "data": "127.0.0.1", "valid": false }, { "description": "ipv4 segment must have 4 octets", "data": "1:2:3:4:1.2.3", "valid": false }, { "description": "leading whitespace is invalid", "data": " ::1", "valid": false }, { "description": "trailing whitespace is invalid", "data": "::1 ", "valid": false }, { "description": "netmask is not a part of ipv6 address", "data": "fe80::/64", "valid": false }, { "description": "zone id is not a part of ipv6 address", "data": "fe80::a%eth1", "valid": false }, { "description": "a long valid ipv6", "data": "1000:1000:1000:1000:1000:1000:255.255.255.255", "valid": true }, { "description": "a long invalid ipv6, below length limit, first", "data": "100:100:100:100:100:100:255.255.255.255.255", "valid": false }, { "description": "a long invalid ipv6, below length limit, second", "data": "100:100:100:100:100:100:100:255.255.255.255", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4)", "data": "1:2:3:4:5:6:7:৪", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4) in the IPv4 portion", "data": "1:2::192.16৪.0.1", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/optional/format/unknown.json0000644000175100001770000000226314653725311026266 0ustar00runnerdocker[ { "description": "unknown format", "schema": { "format": "unknown" }, "tests": [ { "description": "unknown formats ignore integers", "data": 12, "valid": true }, { "description": "unknown formats ignore floats", "data": 13.7, "valid": true }, { "description": "unknown formats ignore objects", "data": {}, "valid": true }, { "description": "unknown formats ignore arrays", "data": [], "valid": true }, { "description": "unknown formats ignore booleans", "data": false, "valid": true }, { "description": "unknown formats ignore nulls", "data": null, "valid": true }, { "description": "unknown formats ignore strings", "data": "string", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/optional/format/uri.json0000644000175100001770000001103414653725311025362 0ustar00runnerdocker[ { "description": "validation of URIs", "schema": { "format": "uri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid URL with anchor tag", "data": "http://foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid URL with anchor tag and parentheses", "data": "http://foo.com/blah_(wikipedia)_blah#cite-1", "valid": true }, { "description": "a valid URL with URL-encoded stuff", "data": "http://foo.bar/?q=Test%20URL-encoded%20stuff", "valid": true }, { "description": "a valid puny-coded URL ", "data": "http://xn--nw2a.xn--j6w193g/", "valid": true }, { "description": "a valid URL with many special characters", "data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", "valid": true }, { "description": "a valid URL based on IPv4", "data": "http://223.255.255.254", "valid": true }, { "description": "a valid URL with ftp scheme", "data": "ftp://ftp.is.co.za/rfc/rfc1808.txt", "valid": true }, { "description": "a valid URL for a simple text file", "data": "http://www.ietf.org/rfc/rfc2396.txt", "valid": true }, { "description": "a valid URL ", "data": "ldap://[2001:db8::7]/c=GB?objectClass?one", "valid": true }, { "description": "a valid mailto URI", "data": "mailto:John.Doe@example.com", "valid": true }, { "description": "a valid newsgroup URI", "data": "news:comp.infosystems.www.servers.unix", "valid": true }, { "description": "a valid tel URI", "data": "tel:+1-816-555-1212", "valid": true }, { "description": "a valid URN", "data": "urn:oasis:names:specification:docbook:dtd:xml:4.1.2", "valid": true }, { "description": "an invalid protocol-relative URI Reference", "data": "//foo.bar/?baz=qux#quux", "valid": false }, { "description": "an invalid relative URI Reference", "data": "/abc", "valid": false }, { "description": "an invalid URI", "data": "\\\\WINDOWS\\fileshare", "valid": false }, { "description": "an invalid URI though valid URI reference", "data": "abc", "valid": false }, { "description": "an invalid URI with spaces", "data": "http:// shouldfail.com", "valid": false }, { "description": "an invalid URI with spaces and missing scheme", "data": ":// should fail", "valid": false }, { "description": "an invalid URI with comma in scheme", "data": "bar,baz:foo", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/optional/non-bmp-regex.json0000644000175100001770000000453614653725311025762 0ustar00runnerdocker[ { "description": "Proper UTF-16 surrogate pair handling: pattern", "comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters", "schema": { "pattern": "^ðŸ²*$" }, "tests": [ { "description": "matches empty", "data": "", "valid": true }, { "description": "matches single", "data": "ðŸ²", "valid": true }, { "description": "matches two", "data": "ðŸ²ðŸ²", "valid": true }, { "description": "doesn't match one", "data": "ðŸ‰", "valid": false }, { "description": "doesn't match two", "data": "ðŸ‰ðŸ‰", "valid": false }, { "description": "doesn't match one ASCII", "data": "D", "valid": false }, { "description": "doesn't match two ASCII", "data": "DD", "valid": false } ] }, { "description": "Proper UTF-16 surrogate pair handling: patternProperties", "comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters", "schema": { "patternProperties": { "^ðŸ²*$": { "type": "integer" } } }, "tests": [ { "description": "matches empty", "data": { "": 1 }, "valid": true }, { "description": "matches single", "data": { "ðŸ²": 1 }, "valid": true }, { "description": "matches two", "data": { "ðŸ²ðŸ²": 1 }, "valid": true }, { "description": "doesn't match one", "data": { "ðŸ²": "hello" }, "valid": false }, { "description": "doesn't match two", "data": { "ðŸ²ðŸ²": "hello" }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/optional/zeroTerminatedFloats.json0000644000175100001770000000060014653725311027435 0ustar00runnerdocker[ { "description": "some languages do not distinguish between different types of numeric value", "schema": { "type": "integer" }, "tests": [ { "description": "a float is not an integer even without fractional part", "data": 1.0, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/pattern.json0000644000175100001770000000300314653725311023120 0ustar00runnerdocker[ { "description": "pattern validation", "schema": {"pattern": "^a*$"}, "tests": [ { "description": "a matching pattern is valid", "data": "aaa", "valid": true }, { "description": "a non-matching pattern is invalid", "data": "abc", "valid": false }, { "description": "ignores booleans", "data": true, "valid": true }, { "description": "ignores integers", "data": 123, "valid": true }, { "description": "ignores floats", "data": 1.0, "valid": true }, { "description": "ignores objects", "data": {}, "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores null", "data": null, "valid": true } ] }, { "description": "pattern is not anchored", "schema": {"pattern": "a+"}, "tests": [ { "description": "matches a substring", "data": "xxaayy", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/patternProperties.json0000644000175100001770000000771414653725311025212 0ustar00runnerdocker[ { "description": "patternProperties validates properties matching a regex", "schema": { "patternProperties": { "f.*o": {"type": "integer"} } }, "tests": [ { "description": "a single valid match is valid", "data": {"foo": 1}, "valid": true }, { "description": "multiple valid matches is valid", "data": {"foo": 1, "foooooo" : 2}, "valid": true }, { "description": "a single invalid match is invalid", "data": {"foo": "bar", "fooooo": 2}, "valid": false }, { "description": "multiple invalid matches is invalid", "data": {"foo": "bar", "foooooo" : "baz"}, "valid": false }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "multiple simultaneous patternProperties are validated", "schema": { "patternProperties": { "a*": {"type": "integer"}, "aaa*": {"maximum": 20} } }, "tests": [ { "description": "a single valid match is valid", "data": {"a": 21}, "valid": true }, { "description": "a simultaneous match is valid", "data": {"aaaa": 18}, "valid": true }, { "description": "multiple matches is valid", "data": {"a": 21, "aaaa": 18}, "valid": true }, { "description": "an invalid due to one is invalid", "data": {"a": "bar"}, "valid": false }, { "description": "an invalid due to the other is invalid", "data": {"aaaa": 31}, "valid": false }, { "description": "an invalid due to both is invalid", "data": {"aaa": "foo", "aaaa": 31}, "valid": false } ] }, { "description": "regexes are not anchored by default and are case sensitive", "schema": { "patternProperties": { "[0-9]{2,}": { "type": "boolean" }, "X_": { "type": "string" } } }, "tests": [ { "description": "non recognized members are ignored", "data": { "answer 1": "42" }, "valid": true }, { "description": "recognized members are accounted for", "data": { "a31b": null }, "valid": false }, { "description": "regexes are case sensitive", "data": { "a_x_3": 3 }, "valid": true }, { "description": "regexes are case sensitive, 2", "data": { "a_X_3": 3 }, "valid": false } ] }, { "description": "patternProperties with null valued instance properties", "schema": { "patternProperties": { "^.*bar$": {"type": "null"} } }, "tests": [ { "description": "allows null values", "data": {"foobar": null}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/properties.json0000644000175100001770000001441514653725311023650 0ustar00runnerdocker[ { "description": "object properties validation", "schema": { "properties": { "foo": {"type": "integer"}, "bar": {"type": "string"} } }, "tests": [ { "description": "both properties present and valid is valid", "data": {"foo": 1, "bar": "baz"}, "valid": true }, { "description": "one property invalid is invalid", "data": {"foo": 1, "bar": {}}, "valid": false }, { "description": "both properties invalid is invalid", "data": {"foo": [], "bar": {}}, "valid": false }, { "description": "doesn't invalidate other properties", "data": {"quux": []}, "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "properties, patternProperties, additionalProperties interaction", "schema": { "properties": { "foo": {"type": "array", "maxItems": 3}, "bar": {"type": "array"} }, "patternProperties": {"f.o": {"minItems": 2}}, "additionalProperties": {"type": "integer"} }, "tests": [ { "description": "property validates property", "data": {"foo": [1, 2]}, "valid": true }, { "description": "property invalidates property", "data": {"foo": [1, 2, 3, 4]}, "valid": false }, { "description": "patternProperty invalidates property", "data": {"foo": []}, "valid": false }, { "description": "patternProperty validates nonproperty", "data": {"fxo": [1, 2]}, "valid": true }, { "description": "patternProperty invalidates nonproperty", "data": {"fxo": []}, "valid": false }, { "description": "additionalProperty ignores property", "data": {"bar": []}, "valid": true }, { "description": "additionalProperty validates others", "data": {"quux": 3}, "valid": true }, { "description": "additionalProperty invalidates others", "data": {"quux": "foo"}, "valid": false } ] }, { "description": "properties with escaped characters", "schema": { "properties": { "foo\nbar": {"type": "number"}, "foo\"bar": {"type": "number"}, "foo\\bar": {"type": "number"}, "foo\rbar": {"type": "number"}, "foo\tbar": {"type": "number"}, "foo\fbar": {"type": "number"} } }, "tests": [ { "description": "object with all numbers is valid", "data": { "foo\nbar": 1, "foo\"bar": 1, "foo\\bar": 1, "foo\rbar": 1, "foo\tbar": 1, "foo\fbar": 1 }, "valid": true }, { "description": "object with strings is invalid", "data": { "foo\nbar": "1", "foo\"bar": "1", "foo\\bar": "1", "foo\rbar": "1", "foo\tbar": "1", "foo\fbar": "1" }, "valid": false } ] }, { "description": "properties with null valued instance properties", "schema": { "properties": { "foo": {"type": "null"} } }, "tests": [ { "description": "allows null values", "data": {"foo": null}, "valid": true } ] }, { "description": "properties whose names are Javascript object property names", "comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.", "schema": { "properties": { "__proto__": {"type": "number"}, "toString": { "properties": { "length": { "type": "string" } } }, "constructor": {"type": "number"} } }, "tests": [ { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "none of the properties mentioned", "data": {}, "valid": true }, { "description": "__proto__ not valid", "data": { "__proto__": "foo" }, "valid": false }, { "description": "toString not valid", "data": { "toString": { "length": 37 } }, "valid": false }, { "description": "constructor not valid", "data": { "constructor": { "length": 37 } }, "valid": false }, { "description": "all present and valid", "data": { "__proto__": 12, "toString": { "length": "foo" }, "constructor": 37 }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/ref.json0000644000175100001770000003512714653725311022233 0ustar00runnerdocker[ { "description": "root pointer ref", "schema": { "properties": { "foo": {"$ref": "#"} }, "additionalProperties": false }, "tests": [ { "description": "match", "data": {"foo": false}, "valid": true }, { "description": "recursive match", "data": {"foo": {"foo": false}}, "valid": true }, { "description": "mismatch", "data": {"bar": false}, "valid": false }, { "description": "recursive mismatch", "data": {"foo": {"bar": false}}, "valid": false } ] }, { "description": "relative pointer ref to object", "schema": { "properties": { "foo": {"type": "integer"}, "bar": {"$ref": "#/properties/foo"} } }, "tests": [ { "description": "match", "data": {"bar": 3}, "valid": true }, { "description": "mismatch", "data": {"bar": true}, "valid": false } ] }, { "description": "relative pointer ref to array", "schema": { "items": [ {"type": "integer"}, {"$ref": "#/items/0"} ] }, "tests": [ { "description": "match array", "data": [1, 2], "valid": true }, { "description": "mismatch array", "data": [1, "foo"], "valid": false } ] }, { "description": "escaped pointer ref", "schema": { "definitions": { "tilde~field": {"type": "integer"}, "slash/field": {"type": "integer"}, "percent%field": {"type": "integer"} }, "properties": { "tilde": {"$ref": "#/definitions/tilde~0field"}, "slash": {"$ref": "#/definitions/slash~1field"}, "percent": {"$ref": "#/definitions/percent%25field"} } }, "tests": [ { "description": "slash invalid", "data": {"slash": "aoeu"}, "valid": false }, { "description": "tilde invalid", "data": {"tilde": "aoeu"}, "valid": false }, { "description": "percent invalid", "data": {"percent": "aoeu"}, "valid": false }, { "description": "slash valid", "data": {"slash": 123}, "valid": true }, { "description": "tilde valid", "data": {"tilde": 123}, "valid": true }, { "description": "percent valid", "data": {"percent": 123}, "valid": true } ] }, { "description": "nested refs", "schema": { "definitions": { "a": {"type": "integer"}, "b": {"$ref": "#/definitions/a"}, "c": {"$ref": "#/definitions/b"} }, "allOf": [{ "$ref": "#/definitions/c" }] }, "tests": [ { "description": "nested ref valid", "data": 5, "valid": true }, { "description": "nested ref invalid", "data": "a", "valid": false } ] }, { "description": "ref overrides any sibling keywords", "schema": { "definitions": { "reffed": { "type": "array" } }, "properties": { "foo": { "$ref": "#/definitions/reffed", "maxItems": 2 } } }, "tests": [ { "description": "ref valid", "data": { "foo": [] }, "valid": true }, { "description": "ref valid, maxItems ignored", "data": { "foo": [ 1, 2, 3] }, "valid": true }, { "description": "ref invalid", "data": { "foo": "string" }, "valid": false } ] }, { "description": "$ref prevents a sibling id from changing the base uri", "schema": { "id": "http://localhost:1234/sibling_id/base/", "definitions": { "foo": { "id": "http://localhost:1234/sibling_id/foo.json", "type": "string" }, "base_foo": { "$comment": "this canonical uri is http://localhost:1234/sibling_id/base/foo.json", "id": "foo.json", "type": "number" } }, "allOf": [ { "$comment": "$ref resolves to http://localhost:1234/sibling_id/base/foo.json, not http://localhost:1234/sibling_id/foo.json", "id": "http://localhost:1234/sibling_id/", "$ref": "foo.json" } ] }, "tests": [ { "description": "$ref resolves to /definitions/base_foo, data does not validate", "data": "a", "valid": false }, { "description": "$ref resolves to /definitions/base_foo, data validates", "data": 1, "valid": true } ] }, { "description": "remote ref, containing refs itself", "schema": {"$ref": "http://json-schema.org/draft-04/schema#"}, "tests": [ { "description": "remote ref valid", "data": {"minLength": 1}, "valid": true }, { "description": "remote ref invalid", "data": {"minLength": -1}, "valid": false } ] }, { "description": "property named $ref that is not a reference", "schema": { "properties": { "$ref": {"type": "string"} } }, "tests": [ { "description": "property named $ref valid", "data": {"$ref": "a"}, "valid": true }, { "description": "property named $ref invalid", "data": {"$ref": 2}, "valid": false } ] }, { "description": "property named $ref, containing an actual $ref", "schema": { "properties": { "$ref": {"$ref": "#/definitions/is-string"} }, "definitions": { "is-string": { "type": "string" } } }, "tests": [ { "description": "property named $ref valid", "data": {"$ref": "a"}, "valid": true }, { "description": "property named $ref invalid", "data": {"$ref": 2}, "valid": false } ] }, { "description": "Recursive references between schemas", "schema": { "id": "http://localhost:1234/tree", "description": "tree of nodes", "type": "object", "properties": { "meta": {"type": "string"}, "nodes": { "type": "array", "items": {"$ref": "node"} } }, "required": ["meta", "nodes"], "definitions": { "node": { "id": "http://localhost:1234/node", "description": "node", "type": "object", "properties": { "value": {"type": "number"}, "subtree": {"$ref": "tree"} }, "required": ["value"] } } }, "tests": [ { "description": "valid tree", "data": { "meta": "root", "nodes": [ { "value": 1, "subtree": { "meta": "child", "nodes": [ {"value": 1.1}, {"value": 1.2} ] } }, { "value": 2, "subtree": { "meta": "child", "nodes": [ {"value": 2.1}, {"value": 2.2} ] } } ] }, "valid": true }, { "description": "invalid tree", "data": { "meta": "root", "nodes": [ { "value": 1, "subtree": { "meta": "child", "nodes": [ {"value": "string is invalid"}, {"value": 1.2} ] } }, { "value": 2, "subtree": { "meta": "child", "nodes": [ {"value": 2.1}, {"value": 2.2} ] } } ] }, "valid": false } ] }, { "description": "refs with quote", "schema": { "properties": { "foo\"bar": {"$ref": "#/definitions/foo%22bar"} }, "definitions": { "foo\"bar": {"type": "number"} } }, "tests": [ { "description": "object with numbers is valid", "data": { "foo\"bar": 1 }, "valid": true }, { "description": "object with strings is invalid", "data": { "foo\"bar": "1" }, "valid": false } ] }, { "description": "Location-independent identifier", "schema": { "allOf": [{ "$ref": "#foo" }], "definitions": { "A": { "id": "#foo", "type": "integer" } } }, "tests": [ { "data": 1, "description": "match", "valid": true }, { "data": "a", "description": "mismatch", "valid": false } ] }, { "description": "Location-independent identifier with base URI change in subschema", "schema": { "id": "http://localhost:1234/root", "allOf": [{ "$ref": "http://localhost:1234/nested.json#foo" }], "definitions": { "A": { "id": "nested.json", "definitions": { "B": { "id": "#foo", "type": "integer" } } } } }, "tests": [ { "data": 1, "description": "match", "valid": true }, { "data": "a", "description": "mismatch", "valid": false } ] }, { "description": "naive replacement of $ref with its destination is not correct", "schema": { "definitions": { "a_string": { "type": "string" } }, "enum": [ { "$ref": "#/definitions/a_string" } ] }, "tests": [ { "description": "do not evaluate the $ref inside the enum, matching any string", "data": "this is a string", "valid": false }, { "description": "match the enum exactly", "data": { "$ref": "#/definitions/a_string" }, "valid": true } ] }, { "description": "id must be resolved against nearest parent, not just immediate parent", "schema": { "id": "http://example.com/a.json", "definitions": { "x": { "id": "http://example.com/b/c.json", "not": { "definitions": { "y": { "id": "d.json", "type": "number" } } } } }, "allOf": [ { "$ref": "http://example.com/b/d.json" } ] }, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "non-number is invalid", "data": "a", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/refRemote.json0000644000175100001770000001230714653725311023402 0ustar00runnerdocker[ { "description": "remote ref", "schema": {"$ref": "http://localhost:1234/integer.json"}, "tests": [ { "description": "remote ref valid", "data": 1, "valid": true }, { "description": "remote ref invalid", "data": "a", "valid": false } ] }, { "description": "fragment within remote ref", "schema": {"$ref": "http://localhost:1234/subSchemas.json#/integer"}, "tests": [ { "description": "remote fragment valid", "data": 1, "valid": true }, { "description": "remote fragment invalid", "data": "a", "valid": false } ] }, { "description": "ref within remote ref", "schema": { "$ref": "http://localhost:1234/subSchemas.json#/refToInteger" }, "tests": [ { "description": "ref within ref valid", "data": 1, "valid": true }, { "description": "ref within ref invalid", "data": "a", "valid": false } ] }, { "description": "base URI change", "schema": { "id": "http://localhost:1234/", "items": { "id": "baseUriChange/", "items": {"$ref": "folderInteger.json"} } }, "tests": [ { "description": "base URI change ref valid", "data": [[1]], "valid": true }, { "description": "base URI change ref invalid", "data": [["a"]], "valid": false } ] }, { "description": "base URI change - change folder", "schema": { "id": "http://localhost:1234/scope_change_defs1.json", "type" : "object", "properties": { "list": {"$ref": "#/definitions/baz"} }, "definitions": { "baz": { "id": "baseUriChangeFolder/", "type": "array", "items": {"$ref": "folderInteger.json"} } } }, "tests": [ { "description": "number is valid", "data": {"list": [1]}, "valid": true }, { "description": "string is invalid", "data": {"list": ["a"]}, "valid": false } ] }, { "description": "base URI change - change folder in subschema", "schema": { "id": "http://localhost:1234/scope_change_defs2.json", "type" : "object", "properties": { "list": {"$ref": "#/definitions/baz/definitions/bar"} }, "definitions": { "baz": { "id": "baseUriChangeFolderInSubschema/", "definitions": { "bar": { "type": "array", "items": {"$ref": "folderInteger.json"} } } } } }, "tests": [ { "description": "number is valid", "data": {"list": [1]}, "valid": true }, { "description": "string is invalid", "data": {"list": ["a"]}, "valid": false } ] }, { "description": "root ref in remote ref", "schema": { "id": "http://localhost:1234/object", "type": "object", "properties": { "name": {"$ref": "name.json#/definitions/orNull"} } }, "tests": [ { "description": "string is valid", "data": { "name": "foo" }, "valid": true }, { "description": "null is valid", "data": { "name": null }, "valid": true }, { "description": "object is invalid", "data": { "name": { "name": null } }, "valid": false } ] }, { "description": "Location-independent identifier in remote ref", "schema": { "$ref": "http://localhost:1234/locationIndependentIdentifierDraft4.json#/definitions/refToInteger" }, "tests": [ { "description": "integer is valid", "data": 1, "valid": true }, { "description": "string is invalid", "data": "foo", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/required.json0000644000175100001770000000746114653725311023277 0ustar00runnerdocker[ { "description": "required validation", "schema": { "properties": { "foo": {}, "bar": {} }, "required": ["foo"] }, "tests": [ { "description": "present required property is valid", "data": {"foo": 1}, "valid": true }, { "description": "non-present required property is invalid", "data": {"bar": 1}, "valid": false }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "required default validation", "schema": { "properties": { "foo": {} } }, "tests": [ { "description": "not required by default", "data": {}, "valid": true } ] }, { "description": "required with escaped characters", "schema": { "required": [ "foo\nbar", "foo\"bar", "foo\\bar", "foo\rbar", "foo\tbar", "foo\fbar" ] }, "tests": [ { "description": "object with all properties present is valid", "data": { "foo\nbar": 1, "foo\"bar": 1, "foo\\bar": 1, "foo\rbar": 1, "foo\tbar": 1, "foo\fbar": 1 }, "valid": true }, { "description": "object with some properties missing is invalid", "data": { "foo\nbar": "1", "foo\"bar": "1" }, "valid": false } ] }, { "description": "required properties whose names are Javascript object property names", "comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.", "schema": { "required": ["__proto__", "toString", "constructor"] }, "tests": [ { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "none of the properties mentioned", "data": {}, "valid": false }, { "description": "__proto__ present", "data": { "__proto__": "foo" }, "valid": false }, { "description": "toString present", "data": { "toString": { "length": 37 } }, "valid": false }, { "description": "constructor present", "data": { "constructor": { "length": 37 } }, "valid": false }, { "description": "all present", "data": { "__proto__": 12, "toString": { "length": "foo" }, "constructor": 37 }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/type.json0000644000175100001770000003164514653725311022441 0ustar00runnerdocker[ { "description": "integer type matches integers", "schema": {"type": "integer"}, "tests": [ { "description": "an integer is an integer", "data": 1, "valid": true }, { "description": "a float is not an integer", "data": 1.1, "valid": false }, { "description": "a string is not an integer", "data": "foo", "valid": false }, { "description": "a string is still not an integer, even if it looks like one", "data": "1", "valid": false }, { "description": "an object is not an integer", "data": {}, "valid": false }, { "description": "an array is not an integer", "data": [], "valid": false }, { "description": "a boolean is not an integer", "data": true, "valid": false }, { "description": "null is not an integer", "data": null, "valid": false } ] }, { "description": "number type matches numbers", "schema": {"type": "number"}, "tests": [ { "description": "an integer is a number", "data": 1, "valid": true }, { "description": "a float with zero fractional part is a number", "data": 1.0, "valid": true }, { "description": "a float is a number", "data": 1.1, "valid": true }, { "description": "a string is not a number", "data": "foo", "valid": false }, { "description": "a string is still not a number, even if it looks like one", "data": "1", "valid": false }, { "description": "an object is not a number", "data": {}, "valid": false }, { "description": "an array is not a number", "data": [], "valid": false }, { "description": "a boolean is not a number", "data": true, "valid": false }, { "description": "null is not a number", "data": null, "valid": false } ] }, { "description": "string type matches strings", "schema": {"type": "string"}, "tests": [ { "description": "1 is not a string", "data": 1, "valid": false }, { "description": "a float is not a string", "data": 1.1, "valid": false }, { "description": "a string is a string", "data": "foo", "valid": true }, { "description": "a string is still a string, even if it looks like a number", "data": "1", "valid": true }, { "description": "an empty string is still a string", "data": "", "valid": true }, { "description": "an object is not a string", "data": {}, "valid": false }, { "description": "an array is not a string", "data": [], "valid": false }, { "description": "a boolean is not a string", "data": true, "valid": false }, { "description": "null is not a string", "data": null, "valid": false } ] }, { "description": "object type matches objects", "schema": {"type": "object"}, "tests": [ { "description": "an integer is not an object", "data": 1, "valid": false }, { "description": "a float is not an object", "data": 1.1, "valid": false }, { "description": "a string is not an object", "data": "foo", "valid": false }, { "description": "an object is an object", "data": {}, "valid": true }, { "description": "an array is not an object", "data": [], "valid": false }, { "description": "a boolean is not an object", "data": true, "valid": false }, { "description": "null is not an object", "data": null, "valid": false } ] }, { "description": "array type matches arrays", "schema": {"type": "array"}, "tests": [ { "description": "an integer is not an array", "data": 1, "valid": false }, { "description": "a float is not an array", "data": 1.1, "valid": false }, { "description": "a string is not an array", "data": "foo", "valid": false }, { "description": "an object is not an array", "data": {}, "valid": false }, { "description": "an array is an array", "data": [], "valid": true }, { "description": "a boolean is not an array", "data": true, "valid": false }, { "description": "null is not an array", "data": null, "valid": false } ] }, { "description": "boolean type matches booleans", "schema": {"type": "boolean"}, "tests": [ { "description": "an integer is not a boolean", "data": 1, "valid": false }, { "description": "zero is not a boolean", "data": 0, "valid": false }, { "description": "a float is not a boolean", "data": 1.1, "valid": false }, { "description": "a string is not a boolean", "data": "foo", "valid": false }, { "description": "an empty string is not a boolean", "data": "", "valid": false }, { "description": "an object is not a boolean", "data": {}, "valid": false }, { "description": "an array is not a boolean", "data": [], "valid": false }, { "description": "true is a boolean", "data": true, "valid": true }, { "description": "false is a boolean", "data": false, "valid": true }, { "description": "null is not a boolean", "data": null, "valid": false } ] }, { "description": "null type matches only the null object", "schema": {"type": "null"}, "tests": [ { "description": "an integer is not null", "data": 1, "valid": false }, { "description": "a float is not null", "data": 1.1, "valid": false }, { "description": "zero is not null", "data": 0, "valid": false }, { "description": "a string is not null", "data": "foo", "valid": false }, { "description": "an empty string is not null", "data": "", "valid": false }, { "description": "an object is not null", "data": {}, "valid": false }, { "description": "an array is not null", "data": [], "valid": false }, { "description": "true is not null", "data": true, "valid": false }, { "description": "false is not null", "data": false, "valid": false }, { "description": "null is null", "data": null, "valid": true } ] }, { "description": "multiple types can be specified in an array", "schema": {"type": ["integer", "string"]}, "tests": [ { "description": "an integer is valid", "data": 1, "valid": true }, { "description": "a string is valid", "data": "foo", "valid": true }, { "description": "a float is invalid", "data": 1.1, "valid": false }, { "description": "an object is invalid", "data": {}, "valid": false }, { "description": "an array is invalid", "data": [], "valid": false }, { "description": "a boolean is invalid", "data": true, "valid": false }, { "description": "null is invalid", "data": null, "valid": false } ] }, { "description": "type as array with one item", "schema": { "type": ["string"] }, "tests": [ { "description": "string is valid", "data": "foo", "valid": true }, { "description": "number is invalid", "data": 123, "valid": false } ] }, { "description": "type: array or object", "schema": { "type": ["array", "object"] }, "tests": [ { "description": "array is valid", "data": [1,2,3], "valid": true }, { "description": "object is valid", "data": {"foo": 123}, "valid": true }, { "description": "number is invalid", "data": 123, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false }, { "description": "null is invalid", "data": null, "valid": false } ] }, { "description": "type: array, object or null", "schema": { "type": ["array", "object", "null"] }, "tests": [ { "description": "array is valid", "data": [1,2,3], "valid": true }, { "description": "object is valid", "data": {"foo": 123}, "valid": true }, { "description": "null is valid", "data": null, "valid": true }, { "description": "number is invalid", "data": 123, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft4/uniqueItems.json0000644000175100001770000003274014653725311023765 0ustar00runnerdocker[ { "description": "uniqueItems validation", "schema": {"uniqueItems": true}, "tests": [ { "description": "unique array of integers is valid", "data": [1, 2], "valid": true }, { "description": "non-unique array of integers is invalid", "data": [1, 1], "valid": false }, { "description": "non-unique array of more than two integers is invalid", "data": [1, 2, 1], "valid": false }, { "description": "numbers are unique if mathematically unequal", "data": [1.0, 1.00, 1], "valid": false }, { "description": "false is not equal to zero", "data": [0, false], "valid": true }, { "description": "true is not equal to one", "data": [1, true], "valid": true }, { "description": "unique array of strings is valid", "data": ["foo", "bar", "baz"], "valid": true }, { "description": "non-unique array of strings is invalid", "data": ["foo", "bar", "foo"], "valid": false }, { "description": "unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "baz"}], "valid": true }, { "description": "non-unique array of objects is invalid", "data": [{"foo": "bar"}, {"foo": "bar"}], "valid": false }, { "description": "unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : false}}} ], "valid": true }, { "description": "non-unique array of nested objects is invalid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : true}}} ], "valid": false }, { "description": "unique array of arrays is valid", "data": [["foo"], ["bar"]], "valid": true }, { "description": "non-unique array of arrays is invalid", "data": [["foo"], ["foo"]], "valid": false }, { "description": "non-unique array of more than two arrays is invalid", "data": [["foo"], ["bar"], ["foo"]], "valid": false }, { "description": "1 and true are unique", "data": [1, true], "valid": true }, { "description": "0 and false are unique", "data": [0, false], "valid": true }, { "description": "[1] and [true] are unique", "data": [[1], [true]], "valid": true }, { "description": "[0] and [false] are unique", "data": [[0], [false]], "valid": true }, { "description": "nested [1] and [true] are unique", "data": [[[1], "foo"], [[true], "foo"]], "valid": true }, { "description": "nested [0] and [false] are unique", "data": [[[0], "foo"], [[false], "foo"]], "valid": true }, { "description": "unique heterogeneous types are valid", "data": [{}, [1], true, null, 1, "{}"], "valid": true }, { "description": "non-unique heterogeneous types are invalid", "data": [{}, [1], true, null, {}, 1], "valid": false }, { "description": "different objects are unique", "data": [{"a": 1, "b": 2}, {"a": 2, "b": 1}], "valid": true }, { "description": "objects are non-unique despite key order", "data": [{"a": 1, "b": 2}, {"b": 2, "a": 1}], "valid": false }, { "description": "{\"a\": false} and {\"a\": 0} are unique", "data": [{"a": false}, {"a": 0}], "valid": true }, { "description": "{\"a\": true} and {\"a\": 1} are unique", "data": [{"a": true}, {"a": 1}], "valid": true } ] }, { "description": "uniqueItems with an array of items", "schema": { "items": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": true }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is not valid", "data": [false, false], "valid": false }, { "description": "[true, true] from items array is not valid", "data": [true, true], "valid": false }, { "description": "unique array extended from [false, true] is valid", "data": [false, true, "foo", "bar"], "valid": true }, { "description": "unique array extended from [true, false] is valid", "data": [true, false, "foo", "bar"], "valid": true }, { "description": "non-unique array extended from [false, true] is not valid", "data": [false, true, "foo", "foo"], "valid": false }, { "description": "non-unique array extended from [true, false] is not valid", "data": [true, false, "foo", "foo"], "valid": false } ] }, { "description": "uniqueItems with an array of items and additionalItems=false", "schema": { "items": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": true, "additionalItems": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is not valid", "data": [false, false], "valid": false }, { "description": "[true, true] from items array is not valid", "data": [true, true], "valid": false }, { "description": "extra items are invalid even if unique", "data": [false, true, null], "valid": false } ] }, { "description": "uniqueItems=false validation", "schema": { "uniqueItems": false }, "tests": [ { "description": "unique array of integers is valid", "data": [1, 2], "valid": true }, { "description": "non-unique array of integers is valid", "data": [1, 1], "valid": true }, { "description": "numbers are unique if mathematically unequal", "data": [1.0, 1.00, 1], "valid": true }, { "description": "false is not equal to zero", "data": [0, false], "valid": true }, { "description": "true is not equal to one", "data": [1, true], "valid": true }, { "description": "unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "baz"}], "valid": true }, { "description": "non-unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "bar"}], "valid": true }, { "description": "unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : false}}} ], "valid": true }, { "description": "non-unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : true}}} ], "valid": true }, { "description": "unique array of arrays is valid", "data": [["foo"], ["bar"]], "valid": true }, { "description": "non-unique array of arrays is valid", "data": [["foo"], ["foo"]], "valid": true }, { "description": "1 and true are unique", "data": [1, true], "valid": true }, { "description": "0 and false are unique", "data": [0, false], "valid": true }, { "description": "unique heterogeneous types are valid", "data": [{}, [1], true, null, 1], "valid": true }, { "description": "non-unique heterogeneous types are valid", "data": [{}, [1], true, null, {}, 1], "valid": true } ] }, { "description": "uniqueItems=false with an array of items", "schema": { "items": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is valid", "data": [false, false], "valid": true }, { "description": "[true, true] from items array is valid", "data": [true, true], "valid": true }, { "description": "unique array extended from [false, true] is valid", "data": [false, true, "foo", "bar"], "valid": true }, { "description": "unique array extended from [true, false] is valid", "data": [true, false, "foo", "bar"], "valid": true }, { "description": "non-unique array extended from [false, true] is valid", "data": [false, true, "foo", "foo"], "valid": true }, { "description": "non-unique array extended from [true, false] is valid", "data": [true, false, "foo", "foo"], "valid": true } ] }, { "description": "uniqueItems=false with an array of items and additionalItems=false", "schema": { "items": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": false, "additionalItems": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is valid", "data": [false, false], "valid": true }, { "description": "[true, true] from items array is valid", "data": [true, true], "valid": true }, { "description": "extra items are invalid even if unique", "data": [false, true, null], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0970972 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/0000755000175100001770000000000014653725331020560 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/additionalItems.json0000644000175100001770000001114714653725311024567 0ustar00runnerdocker[ { "description": "additionalItems as schema", "schema": { "items": [{}], "additionalItems": {"type": "integer"} }, "tests": [ { "description": "additional items match schema", "data": [ null, 2, 3, 4 ], "valid": true }, { "description": "additional items do not match schema", "data": [ null, 2, 3, "foo" ], "valid": false } ] }, { "description": "when items is schema, additionalItems does nothing", "schema": { "items": {}, "additionalItems": false }, "tests": [ { "description": "all items match schema", "data": [ 1, 2, 3, 4, 5 ], "valid": true } ] }, { "description": "array of items with no additionalItems permitted", "schema": { "items": [{}, {}, {}], "additionalItems": false }, "tests": [ { "description": "empty array", "data": [ ], "valid": true }, { "description": "fewer number of items present (1)", "data": [ 1 ], "valid": true }, { "description": "fewer number of items present (2)", "data": [ 1, 2 ], "valid": true }, { "description": "equal number of items present", "data": [ 1, 2, 3 ], "valid": true }, { "description": "additional items are not permitted", "data": [ 1, 2, 3, 4 ], "valid": false } ] }, { "description": "additionalItems as false without items", "schema": {"additionalItems": false}, "tests": [ { "description": "items defaults to empty schema so everything is valid", "data": [ 1, 2, 3, 4, 5 ], "valid": true }, { "description": "ignores non-arrays", "data": {"foo" : "bar"}, "valid": true } ] }, { "description": "additionalItems are allowed by default", "schema": {"items": [{"type": "integer"}]}, "tests": [ { "description": "only the first item is validated", "data": [1, "foo", false], "valid": true } ] }, { "description": "additionalItems does not look in applicators, valid case", "schema": { "allOf": [ { "items": [ { "type": "integer" } ] } ], "additionalItems": { "type": "boolean" } }, "tests": [ { "description": "items defined in allOf are not examined", "data": [ 1, null ], "valid": true } ] }, { "description": "additionalItems does not look in applicators, invalid case", "schema": { "allOf": [ { "items": [ { "type": "integer" }, { "type": "string" } ] } ], "items": [ {"type": "integer" } ], "additionalItems": { "type": "boolean" } }, "tests": [ { "description": "items defined in allOf are not examined", "data": [ 1, "hello" ], "valid": false } ] }, { "description": "items validation adjusts the starting index for additionalItems", "schema": { "items": [ { "type": "string" } ], "additionalItems": { "type": "integer" } }, "tests": [ { "description": "valid items", "data": [ "x", 2, 3 ], "valid": true }, { "description": "wrong type of second item", "data": [ "x", "y" ], "valid": false } ] }, { "description": "additionalItems with null instance elements", "schema": { "additionalItems": { "type": "null" } }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/additionalProperties.json0000644000175100001770000001051214653725311025635 0ustar00runnerdocker[ { "description": "additionalProperties being false does not allow other properties", "schema": { "properties": {"foo": {}, "bar": {}}, "patternProperties": { "^v": {} }, "additionalProperties": false }, "tests": [ { "description": "no additional properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "an additional property is invalid", "data": {"foo" : 1, "bar" : 2, "quux" : "boom"}, "valid": false }, { "description": "ignores arrays", "data": [1, 2, 3], "valid": true }, { "description": "ignores strings", "data": "foobarbaz", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "patternProperties are not additional properties", "data": {"foo":1, "vroom": 2}, "valid": true } ] }, { "description": "non-ASCII pattern with additionalProperties", "schema": { "patternProperties": {"^á": {}}, "additionalProperties": false }, "tests": [ { "description": "matching the pattern is valid", "data": {"ármányos": 2}, "valid": true }, { "description": "not matching the pattern is invalid", "data": {"élmény": 2}, "valid": false } ] }, { "description": "additionalProperties with schema", "schema": { "properties": {"foo": {}, "bar": {}}, "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "no additional properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "an additional valid property is valid", "data": {"foo" : 1, "bar" : 2, "quux" : true}, "valid": true }, { "description": "an additional invalid property is invalid", "data": {"foo" : 1, "bar" : 2, "quux" : 12}, "valid": false } ] }, { "description": "additionalProperties can exist by itself", "schema": { "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "an additional valid property is valid", "data": {"foo" : true}, "valid": true }, { "description": "an additional invalid property is invalid", "data": {"foo" : 1}, "valid": false } ] }, { "description": "additionalProperties are allowed by default", "schema": {"properties": {"foo": {}, "bar": {}}}, "tests": [ { "description": "additional properties are allowed", "data": {"foo": 1, "bar": 2, "quux": true}, "valid": true } ] }, { "description": "additionalProperties does not look in applicators", "schema": { "allOf": [ {"properties": {"foo": {}}} ], "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "properties defined in allOf are not examined", "data": {"foo": 1, "bar": true}, "valid": false } ] }, { "description": "additionalProperties with null valued instance properties", "schema": { "additionalProperties": { "type": "null" } }, "tests": [ { "description": "allows null values", "data": {"foo": null}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/allOf.json0000644000175100001770000001714714653725311022520 0ustar00runnerdocker[ { "description": "allOf", "schema": { "allOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "allOf", "data": {"foo": "baz", "bar": 2}, "valid": true }, { "description": "mismatch second", "data": {"foo": "baz"}, "valid": false }, { "description": "mismatch first", "data": {"bar": 2}, "valid": false }, { "description": "wrong type", "data": {"foo": "baz", "bar": "quux"}, "valid": false } ] }, { "description": "allOf with base schema", "schema": { "properties": {"bar": {"type": "integer"}}, "required": ["bar"], "allOf" : [ { "properties": { "foo": {"type": "string"} }, "required": ["foo"] }, { "properties": { "baz": {"type": "null"} }, "required": ["baz"] } ] }, "tests": [ { "description": "valid", "data": {"foo": "quux", "bar": 2, "baz": null}, "valid": true }, { "description": "mismatch base schema", "data": {"foo": "quux", "baz": null}, "valid": false }, { "description": "mismatch first allOf", "data": {"bar": 2, "baz": null}, "valid": false }, { "description": "mismatch second allOf", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "mismatch both", "data": {"bar": 2}, "valid": false } ] }, { "description": "allOf simple types", "schema": { "allOf": [ {"maximum": 30}, {"minimum": 20} ] }, "tests": [ { "description": "valid", "data": 25, "valid": true }, { "description": "mismatch one", "data": 35, "valid": false } ] }, { "description": "allOf with boolean schemas, all true", "schema": {"allOf": [true, true]}, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "allOf with boolean schemas, some false", "schema": {"allOf": [true, false]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "allOf with boolean schemas, all false", "schema": {"allOf": [false, false]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "allOf with one empty schema", "schema": { "allOf": [ {} ] }, "tests": [ { "description": "any data is valid", "data": 1, "valid": true } ] }, { "description": "allOf with two empty schemas", "schema": { "allOf": [ {}, {} ] }, "tests": [ { "description": "any data is valid", "data": 1, "valid": true } ] }, { "description": "allOf with the first empty schema", "schema": { "allOf": [ {}, { "type": "number" } ] }, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is invalid", "data": "foo", "valid": false } ] }, { "description": "allOf with the last empty schema", "schema": { "allOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is invalid", "data": "foo", "valid": false } ] }, { "description": "nested allOf, to check validation semantics", "schema": { "allOf": [ { "allOf": [ { "type": "null" } ] } ] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "anything non-null is invalid", "data": 123, "valid": false } ] }, { "description": "allOf combined with anyOf, oneOf", "schema": { "allOf": [ { "multipleOf": 2 } ], "anyOf": [ { "multipleOf": 3 } ], "oneOf": [ { "multipleOf": 5 } ] }, "tests": [ { "description": "allOf: false, anyOf: false, oneOf: false", "data": 1, "valid": false }, { "description": "allOf: false, anyOf: false, oneOf: true", "data": 5, "valid": false }, { "description": "allOf: false, anyOf: true, oneOf: false", "data": 3, "valid": false }, { "description": "allOf: false, anyOf: true, oneOf: true", "data": 15, "valid": false }, { "description": "allOf: true, anyOf: false, oneOf: false", "data": 2, "valid": false }, { "description": "allOf: true, anyOf: false, oneOf: true", "data": 10, "valid": false }, { "description": "allOf: true, anyOf: true, oneOf: false", "data": 6, "valid": false }, { "description": "allOf: true, anyOf: true, oneOf: true", "data": 30, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/anyOf.json0000644000175100001770000001133314653725311022526 0ustar00runnerdocker[ { "description": "anyOf", "schema": { "anyOf": [ { "type": "integer" }, { "minimum": 2 } ] }, "tests": [ { "description": "first anyOf valid", "data": 1, "valid": true }, { "description": "second anyOf valid", "data": 2.5, "valid": true }, { "description": "both anyOf valid", "data": 3, "valid": true }, { "description": "neither anyOf valid", "data": 1.5, "valid": false } ] }, { "description": "anyOf with base schema", "schema": { "type": "string", "anyOf" : [ { "maxLength": 2 }, { "minLength": 4 } ] }, "tests": [ { "description": "mismatch base schema", "data": 3, "valid": false }, { "description": "one anyOf valid", "data": "foobar", "valid": true }, { "description": "both anyOf invalid", "data": "foo", "valid": false } ] }, { "description": "anyOf with boolean schemas, all true", "schema": {"anyOf": [true, true]}, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "anyOf with boolean schemas, some true", "schema": {"anyOf": [true, false]}, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "anyOf with boolean schemas, all false", "schema": {"anyOf": [false, false]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "anyOf complex types", "schema": { "anyOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "first anyOf valid (complex)", "data": {"bar": 2}, "valid": true }, { "description": "second anyOf valid (complex)", "data": {"foo": "baz"}, "valid": true }, { "description": "both anyOf valid (complex)", "data": {"foo": "baz", "bar": 2}, "valid": true }, { "description": "neither anyOf valid (complex)", "data": {"foo": 2, "bar": "quux"}, "valid": false } ] }, { "description": "anyOf with one empty schema", "schema": { "anyOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "string is valid", "data": "foo", "valid": true }, { "description": "number is valid", "data": 123, "valid": true } ] }, { "description": "nested anyOf, to check validation semantics", "schema": { "anyOf": [ { "anyOf": [ { "type": "null" } ] } ] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "anything non-null is invalid", "data": 123, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/boolean_schema.json0000644000175100001770000000540214653725311024411 0ustar00runnerdocker[ { "description": "boolean schema 'true'", "schema": true, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is valid", "data": "foo", "valid": true }, { "description": "boolean true is valid", "data": true, "valid": true }, { "description": "boolean false is valid", "data": false, "valid": true }, { "description": "null is valid", "data": null, "valid": true }, { "description": "object is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "empty object is valid", "data": {}, "valid": true }, { "description": "array is valid", "data": ["foo"], "valid": true }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "boolean schema 'false'", "schema": false, "tests": [ { "description": "number is invalid", "data": 1, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false }, { "description": "boolean true is invalid", "data": true, "valid": false }, { "description": "boolean false is invalid", "data": false, "valid": false }, { "description": "null is invalid", "data": null, "valid": false }, { "description": "object is invalid", "data": {"foo": "bar"}, "valid": false }, { "description": "empty object is invalid", "data": {}, "valid": false }, { "description": "array is invalid", "data": ["foo"], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/const.json0000644000175100001770000002256414653725311022610 0ustar00runnerdocker[ { "description": "const validation", "schema": {"const": 2}, "tests": [ { "description": "same value is valid", "data": 2, "valid": true }, { "description": "another value is invalid", "data": 5, "valid": false }, { "description": "another type is invalid", "data": "a", "valid": false } ] }, { "description": "const with object", "schema": {"const": {"foo": "bar", "baz": "bax"}}, "tests": [ { "description": "same object is valid", "data": {"foo": "bar", "baz": "bax"}, "valid": true }, { "description": "same object with different property order is valid", "data": {"baz": "bax", "foo": "bar"}, "valid": true }, { "description": "another object is invalid", "data": {"foo": "bar"}, "valid": false }, { "description": "another type is invalid", "data": [1, 2], "valid": false } ] }, { "description": "const with array", "schema": {"const": [{ "foo": "bar" }]}, "tests": [ { "description": "same array is valid", "data": [{"foo": "bar"}], "valid": true }, { "description": "another array item is invalid", "data": [2], "valid": false }, { "description": "array with additional items is invalid", "data": [1, 2, 3], "valid": false } ] }, { "description": "const with null", "schema": {"const": null}, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "not null is invalid", "data": 0, "valid": false } ] }, { "description": "const with false does not match 0", "schema": {"const": false}, "tests": [ { "description": "false is valid", "data": false, "valid": true }, { "description": "integer zero is invalid", "data": 0, "valid": false }, { "description": "float zero is invalid", "data": 0.0, "valid": false } ] }, { "description": "const with true does not match 1", "schema": {"const": true}, "tests": [ { "description": "true is valid", "data": true, "valid": true }, { "description": "integer one is invalid", "data": 1, "valid": false }, { "description": "float one is invalid", "data": 1.0, "valid": false } ] }, { "description": "const with [false] does not match [0]", "schema": {"const": [false]}, "tests": [ { "description": "[false] is valid", "data": [false], "valid": true }, { "description": "[0] is invalid", "data": [0], "valid": false }, { "description": "[0.0] is invalid", "data": [0.0], "valid": false } ] }, { "description": "const with [true] does not match [1]", "schema": {"const": [true]}, "tests": [ { "description": "[true] is valid", "data": [true], "valid": true }, { "description": "[1] is invalid", "data": [1], "valid": false }, { "description": "[1.0] is invalid", "data": [1.0], "valid": false } ] }, { "description": "const with {\"a\": false} does not match {\"a\": 0}", "schema": {"const": {"a": false}}, "tests": [ { "description": "{\"a\": false} is valid", "data": {"a": false}, "valid": true }, { "description": "{\"a\": 0} is invalid", "data": {"a": 0}, "valid": false }, { "description": "{\"a\": 0.0} is invalid", "data": {"a": 0.0}, "valid": false } ] }, { "description": "const with {\"a\": true} does not match {\"a\": 1}", "schema": {"const": {"a": true}}, "tests": [ { "description": "{\"a\": true} is valid", "data": {"a": true}, "valid": true }, { "description": "{\"a\": 1} is invalid", "data": {"a": 1}, "valid": false }, { "description": "{\"a\": 1.0} is invalid", "data": {"a": 1.0}, "valid": false } ] }, { "description": "const with 0 does not match other zero-like types", "schema": {"const": 0}, "tests": [ { "description": "false is invalid", "data": false, "valid": false }, { "description": "integer zero is valid", "data": 0, "valid": true }, { "description": "float zero is valid", "data": 0.0, "valid": true }, { "description": "empty object is invalid", "data": {}, "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false }, { "description": "empty string is invalid", "data": "", "valid": false } ] }, { "description": "const with 1 does not match true", "schema": {"const": 1}, "tests": [ { "description": "true is invalid", "data": true, "valid": false }, { "description": "integer one is valid", "data": 1, "valid": true }, { "description": "float one is valid", "data": 1.0, "valid": true } ] }, { "description": "const with -2.0 matches integer and float types", "schema": {"const": -2.0}, "tests": [ { "description": "integer -2 is valid", "data": -2, "valid": true }, { "description": "integer 2 is invalid", "data": 2, "valid": false }, { "description": "float -2.0 is valid", "data": -2.0, "valid": true }, { "description": "float 2.0 is invalid", "data": 2.0, "valid": false }, { "description": "float -2.00001 is invalid", "data": -2.00001, "valid": false } ] }, { "description": "float and integers are equal up to 64-bit representation limits", "schema": {"const": 9007199254740992}, "tests": [ { "description": "integer is valid", "data": 9007199254740992, "valid": true }, { "description": "integer minus one is invalid", "data": 9007199254740991, "valid": false }, { "description": "float is valid", "data": 9007199254740992.0, "valid": true }, { "description": "float minus one is invalid", "data": 9007199254740991.0, "valid": false } ] }, { "description": "nul characters in strings", "schema": { "const": "hello\u0000there" }, "tests": [ { "description": "match string with nul", "data": "hello\u0000there", "valid": true }, { "description": "do not match string lacking nul", "data": "hellothere", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/contains.json0000644000175100001770000001001014653725311023257 0ustar00runnerdocker[ { "description": "contains keyword validation", "schema": { "contains": {"minimum": 5} }, "tests": [ { "description": "array with item matching schema (5) is valid", "data": [3, 4, 5], "valid": true }, { "description": "array with item matching schema (6) is valid", "data": [3, 4, 6], "valid": true }, { "description": "array with two items matching schema (5, 6) is valid", "data": [3, 4, 5, 6], "valid": true }, { "description": "array without items matching schema is invalid", "data": [2, 3, 4], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false }, { "description": "not array is valid", "data": {}, "valid": true } ] }, { "description": "contains keyword with const keyword", "schema": { "contains": { "const": 5 } }, "tests": [ { "description": "array with item 5 is valid", "data": [3, 4, 5], "valid": true }, { "description": "array with two items 5 is valid", "data": [3, 4, 5, 5], "valid": true }, { "description": "array without item 5 is invalid", "data": [1, 2, 3, 4], "valid": false } ] }, { "description": "contains keyword with boolean schema true", "schema": {"contains": true}, "tests": [ { "description": "any non-empty array is valid", "data": ["foo"], "valid": true }, { "description": "empty array is invalid", "data": [], "valid": false } ] }, { "description": "contains keyword with boolean schema false", "schema": {"contains": false}, "tests": [ { "description": "any non-empty array is invalid", "data": ["foo"], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false }, { "description": "non-arrays are valid", "data": "contains does not apply to strings", "valid": true } ] }, { "description": "items + contains", "schema": { "items": { "multipleOf": 2 }, "contains": { "multipleOf": 3 } }, "tests": [ { "description": "matches items, does not match contains", "data": [ 2, 4, 8 ], "valid": false }, { "description": "does not match items, matches contains", "data": [ 3, 6, 9 ], "valid": false }, { "description": "matches both items and contains", "data": [ 6, 12 ], "valid": true }, { "description": "matches neither items nor contains", "data": [ 1, 5 ], "valid": false } ] }, { "description": "contains with null instance elements", "schema": { "contains": { "type": "null" } }, "tests": [ { "description": "allows null items", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/default.json0000644000175100001770000000426714653725311023106 0ustar00runnerdocker[ { "description": "invalid type for default", "schema": { "properties": { "foo": { "type": "integer", "default": [] } } }, "tests": [ { "description": "valid when property is specified", "data": {"foo": 13}, "valid": true }, { "description": "still valid when the invalid default is used", "data": {}, "valid": true } ] }, { "description": "invalid string value for default", "schema": { "properties": { "bar": { "type": "string", "minLength": 4, "default": "bad" } } }, "tests": [ { "description": "valid when property is specified", "data": {"bar": "good"}, "valid": true }, { "description": "still valid when the invalid default is used", "data": {}, "valid": true } ] }, { "description": "the default keyword does not do anything if the property is missing", "schema": { "type": "object", "properties": { "alpha": { "type": "number", "maximum": 3, "default": 5 } } }, "tests": [ { "description": "an explicit property value is checked against maximum (passing)", "data": { "alpha": 1 }, "valid": true }, { "description": "an explicit property value is checked against maximum (failing)", "data": { "alpha": 5 }, "valid": false }, { "description": "missing properties are not filled in with the default", "data": {}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/definitions.json0000644000175100001770000000131714653725311023766 0ustar00runnerdocker[ { "description": "validate definition against metaschema", "schema": {"$ref": "http://json-schema.org/draft-06/schema#"}, "tests": [ { "description": "valid definition schema", "data": { "definitions": { "foo": {"type": "integer"} } }, "valid": true }, { "description": "invalid definition schema", "data": { "definitions": { "foo": {"type": 1} } }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/dependencies.json0000644000175100001770000001533414653725311024105 0ustar00runnerdocker[ { "description": "dependencies", "schema": { "dependencies": {"bar": ["foo"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependant", "data": {"foo": 1}, "valid": true }, { "description": "with dependency", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "missing dependency", "data": {"bar": 2}, "valid": false }, { "description": "ignores arrays", "data": ["bar"], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "dependencies with empty array", "schema": { "dependencies": {"bar": []} }, "tests": [ { "description": "empty object", "data": {}, "valid": true }, { "description": "object with one property", "data": {"bar": 2}, "valid": true }, { "description": "non-object is valid", "data": 1, "valid": true } ] }, { "description": "multiple dependencies", "schema": { "dependencies": {"quux": ["foo", "bar"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependants", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "with dependencies", "data": {"foo": 1, "bar": 2, "quux": 3}, "valid": true }, { "description": "missing dependency", "data": {"foo": 1, "quux": 2}, "valid": false }, { "description": "missing other dependency", "data": {"bar": 1, "quux": 2}, "valid": false }, { "description": "missing both dependencies", "data": {"quux": 1}, "valid": false } ] }, { "description": "multiple dependencies subschema", "schema": { "dependencies": { "bar": { "properties": { "foo": {"type": "integer"}, "bar": {"type": "integer"} } } } }, "tests": [ { "description": "valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "no dependency", "data": {"foo": "quux"}, "valid": true }, { "description": "wrong type", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "wrong type other", "data": {"foo": 2, "bar": "quux"}, "valid": false }, { "description": "wrong type both", "data": {"foo": "quux", "bar": "quux"}, "valid": false } ] }, { "description": "dependencies with boolean subschemas", "schema": { "dependencies": { "foo": true, "bar": false } }, "tests": [ { "description": "object with property having schema true is valid", "data": {"foo": 1}, "valid": true }, { "description": "object with property having schema false is invalid", "data": {"bar": 2}, "valid": false }, { "description": "object with both properties is invalid", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "dependencies with escaped characters", "schema": { "dependencies": { "foo\nbar": ["foo\rbar"], "foo\tbar": { "minProperties": 4 }, "foo'bar": {"required": ["foo\"bar"]}, "foo\"bar": ["foo'bar"] } }, "tests": [ { "description": "valid object 1", "data": { "foo\nbar": 1, "foo\rbar": 2 }, "valid": true }, { "description": "valid object 2", "data": { "foo\tbar": 1, "a": 2, "b": 3, "c": 4 }, "valid": true }, { "description": "valid object 3", "data": { "foo'bar": 1, "foo\"bar": 2 }, "valid": true }, { "description": "invalid object 1", "data": { "foo\nbar": 1, "foo": 2 }, "valid": false }, { "description": "invalid object 2", "data": { "foo\tbar": 1, "a": 2 }, "valid": false }, { "description": "invalid object 3", "data": { "foo'bar": 1 }, "valid": false }, { "description": "invalid object 4", "data": { "foo\"bar": 2 }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/enum.json0000644000175100001770000001464314653725311022425 0ustar00runnerdocker[ { "description": "simple enum validation", "schema": {"enum": [1, 2, 3]}, "tests": [ { "description": "one of the enum is valid", "data": 1, "valid": true }, { "description": "something else is invalid", "data": 4, "valid": false } ] }, { "description": "heterogeneous enum validation", "schema": {"enum": [6, "foo", [], true, {"foo": 12}]}, "tests": [ { "description": "one of the enum is valid", "data": [], "valid": true }, { "description": "something else is invalid", "data": null, "valid": false }, { "description": "objects are deep compared", "data": {"foo": false}, "valid": false }, { "description": "valid object matches", "data": {"foo": 12}, "valid": true }, { "description": "extra properties in object is invalid", "data": {"foo": 12, "boo": 42}, "valid": false } ] }, { "description": "heterogeneous enum-with-null validation", "schema": { "enum": [6, null] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "number is valid", "data": 6, "valid": true }, { "description": "something else is invalid", "data": "test", "valid": false } ] }, { "description": "enums in properties", "schema": { "type":"object", "properties": { "foo": {"enum":["foo"]}, "bar": {"enum":["bar"]} }, "required": ["bar"] }, "tests": [ { "description": "both properties are valid", "data": {"foo":"foo", "bar":"bar"}, "valid": true }, { "description": "wrong foo value", "data": {"foo":"foot", "bar":"bar"}, "valid": false }, { "description": "wrong bar value", "data": {"foo":"foo", "bar":"bart"}, "valid": false }, { "description": "missing optional property is valid", "data": {"bar":"bar"}, "valid": true }, { "description": "missing required property is invalid", "data": {"foo":"foo"}, "valid": false }, { "description": "missing all properties is invalid", "data": {}, "valid": false } ] }, { "description": "enum with escaped characters", "schema": { "enum": ["foo\nbar", "foo\rbar"] }, "tests": [ { "description": "member 1 is valid", "data": "foo\nbar", "valid": true }, { "description": "member 2 is valid", "data": "foo\rbar", "valid": true }, { "description": "another string is invalid", "data": "abc", "valid": false } ] }, { "description": "enum with false does not match 0", "schema": {"enum": [false]}, "tests": [ { "description": "false is valid", "data": false, "valid": true }, { "description": "integer zero is invalid", "data": 0, "valid": false }, { "description": "float zero is invalid", "data": 0.0, "valid": false } ] }, { "description": "enum with true does not match 1", "schema": {"enum": [true]}, "tests": [ { "description": "true is valid", "data": true, "valid": true }, { "description": "integer one is invalid", "data": 1, "valid": false }, { "description": "float one is invalid", "data": 1.0, "valid": false } ] }, { "description": "enum with 0 does not match false", "schema": {"enum": [0]}, "tests": [ { "description": "false is invalid", "data": false, "valid": false }, { "description": "integer zero is valid", "data": 0, "valid": true }, { "description": "float zero is valid", "data": 0.0, "valid": true } ] }, { "description": "enum with 1 does not match true", "schema": {"enum": [1]}, "tests": [ { "description": "true is invalid", "data": true, "valid": false }, { "description": "integer one is valid", "data": 1, "valid": true }, { "description": "float one is valid", "data": 1.0, "valid": true } ] }, { "description": "nul characters in strings", "schema": { "enum": [ "hello\u0000there" ] }, "tests": [ { "description": "match string with nul", "data": "hello\u0000there", "valid": true }, { "description": "do not match string lacking nul", "data": "hellothere", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/exclusiveMaximum.json0000644000175100001770000000140714653725311025020 0ustar00runnerdocker[ { "description": "exclusiveMaximum validation", "schema": { "exclusiveMaximum": 3.0 }, "tests": [ { "description": "below the exclusiveMaximum is valid", "data": 2.2, "valid": true }, { "description": "boundary point is invalid", "data": 3.0, "valid": false }, { "description": "above the exclusiveMaximum is invalid", "data": 3.5, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/exclusiveMinimum.json0000644000175100001770000000140714653725311025016 0ustar00runnerdocker[ { "description": "exclusiveMinimum validation", "schema": { "exclusiveMinimum": 1.1 }, "tests": [ { "description": "above the exclusiveMinimum is valid", "data": 1.2, "valid": true }, { "description": "boundary point is invalid", "data": 1.1, "valid": false }, { "description": "below the exclusiveMinimum is invalid", "data": 0.6, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/format.json0000644000175100001770000002252514653725311022747 0ustar00runnerdocker[ { "description": "email format", "schema": { "format": "email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "ipv4 format", "schema": { "format": "ipv4" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "ipv6 format", "schema": { "format": "ipv6" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "hostname format", "schema": { "format": "hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "date-time format", "schema": { "format": "date-time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "json-pointer format", "schema": { "format": "json-pointer" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uri format", "schema": { "format": "uri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uri-reference format", "schema": { "format": "uri-reference" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uri-template format", "schema": { "format": "uri-template" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/id.json0000644000175100001770000001010314653725311022040 0ustar00runnerdocker[ { "description": "id inside an enum is not a real identifier", "comment": "the implementation must not be confused by an id buried in the enum", "schema": { "definitions": { "id_in_enum": { "enum": [ { "$id": "https://localhost:1234/id/my_identifier.json", "type": "null" } ] }, "real_id_in_schema": { "$id": "https://localhost:1234/id/my_identifier.json", "type": "string" }, "zzz_id_in_const": { "const": { "$id": "https://localhost:1234/id/my_identifier.json", "type": "null" } } }, "anyOf": [ { "$ref": "#/definitions/id_in_enum" }, { "$ref": "https://localhost:1234/id/my_identifier.json" } ] }, "tests": [ { "description": "exact match to enum, and type matches", "data": { "$id": "https://localhost:1234/id/my_identifier.json", "type": "null" }, "valid": true }, { "description": "match $ref to id", "data": "a string to match #/definitions/id_in_enum", "valid": true }, { "description": "no match on enum or $ref to id", "data": 1, "valid": false } ] }, { "description": "non-schema object containing a plain-name $id property", "schema": { "definitions": { "const_not_anchor": { "const": { "$id": "#not_a_real_anchor" } } }, "oneOf": [ { "const": "skip not_a_real_anchor" }, { "allOf": [ { "not": { "const": "skip not_a_real_anchor" } }, { "$ref": "#/definitions/const_not_anchor" } ] } ] }, "tests": [ { "description": "skip traversing definition for a valid result", "data": "skip not_a_real_anchor", "valid": true }, { "description": "const at const_not_anchor does not match", "data": 1, "valid": false } ] }, { "description": "non-schema object containing an $id property", "schema": { "definitions": { "const_not_id": { "const": { "$id": "not_a_real_id" } } }, "oneOf": [ { "const":"skip not_a_real_id" }, { "allOf": [ { "not": { "const": "skip not_a_real_id" } }, { "$ref": "#/definitions/const_not_id" } ] } ] }, "tests": [ { "description": "skip traversing definition for a valid result", "data": "skip not_a_real_id", "valid": true }, { "description": "const at const_not_id does not match", "data": 1, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/infinite-loop-detection.json0000644000175100001770000000174614653725311026211 0ustar00runnerdocker[ { "description": "evaluating the same schema location against the same data location twice is not a sign of an infinite loop", "schema": { "definitions": { "int": { "type": "integer" } }, "allOf": [ { "properties": { "foo": { "$ref": "#/definitions/int" } } }, { "additionalProperties": { "$ref": "#/definitions/int" } } ] }, "tests": [ { "description": "passing case", "data": { "foo": 1 }, "valid": true }, { "description": "failing case", "data": { "foo": "a string" }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/items.json0000644000175100001770000001761414653725311022603 0ustar00runnerdocker[ { "description": "a schema given for items", "schema": { "items": {"type": "integer"} }, "tests": [ { "description": "valid items", "data": [ 1, 2, 3 ], "valid": true }, { "description": "wrong type of items", "data": [1, "x"], "valid": false }, { "description": "ignores non-arrays", "data": {"foo" : "bar"}, "valid": true }, { "description": "JavaScript pseudo-array is valid", "data": { "0": "invalid", "length": 1 }, "valid": true } ] }, { "description": "an array of schemas for items", "schema": { "items": [ {"type": "integer"}, {"type": "string"} ] }, "tests": [ { "description": "correct types", "data": [ 1, "foo" ], "valid": true }, { "description": "wrong types", "data": [ "foo", 1 ], "valid": false }, { "description": "incomplete array of items", "data": [ 1 ], "valid": true }, { "description": "array with additional items", "data": [ 1, "foo", true ], "valid": true }, { "description": "empty array", "data": [ ], "valid": true }, { "description": "JavaScript pseudo-array is valid", "data": { "0": "invalid", "1": "valid", "length": 2 }, "valid": true } ] }, { "description": "items with boolean schema (true)", "schema": {"items": true}, "tests": [ { "description": "any array is valid", "data": [ 1, "foo", true ], "valid": true }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "items with boolean schema (false)", "schema": {"items": false}, "tests": [ { "description": "any non-empty array is invalid", "data": [ 1, "foo", true ], "valid": false }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "items with boolean schemas", "schema": { "items": [true, false] }, "tests": [ { "description": "array with one item is valid", "data": [ 1 ], "valid": true }, { "description": "array with two items is invalid", "data": [ 1, "foo" ], "valid": false }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "items and subitems", "schema": { "definitions": { "item": { "type": "array", "additionalItems": false, "items": [ { "$ref": "#/definitions/sub-item" }, { "$ref": "#/definitions/sub-item" } ] }, "sub-item": { "type": "object", "required": ["foo"] } }, "type": "array", "additionalItems": false, "items": [ { "$ref": "#/definitions/item" }, { "$ref": "#/definitions/item" }, { "$ref": "#/definitions/item" } ] }, "tests": [ { "description": "valid items", "data": [ [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": true }, { "description": "too many items", "data": [ [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "too many sub-items", "data": [ [ {"foo": null}, {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "wrong item", "data": [ {"foo": null}, [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "wrong sub-item", "data": [ [ {}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "fewer items is valid", "data": [ [ {"foo": null} ], [ {"foo": null} ] ], "valid": true } ] }, { "description": "nested items", "schema": { "type": "array", "items": { "type": "array", "items": { "type": "array", "items": { "type": "array", "items": { "type": "number" } } } } }, "tests": [ { "description": "valid nested array", "data": [[[[1]], [[2],[3]]], [[[4], [5], [6]]]], "valid": true }, { "description": "nested array with invalid type", "data": [[[["1"]], [[2],[3]]], [[[4], [5], [6]]]], "valid": false }, { "description": "not deep enough", "data": [[[1], [2],[3]], [[4], [5], [6]]], "valid": false } ] }, { "description": "single-form items with null instance elements", "schema": { "items": { "type": "null" } }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] }, { "description": "array-form items with null instance elements", "schema": { "items": [ { "type": "null" } ] }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/maxItems.json0000644000175100001770000000215514653725311023243 0ustar00runnerdocker[ { "description": "maxItems validation", "schema": {"maxItems": 2}, "tests": [ { "description": "shorter is valid", "data": [1], "valid": true }, { "description": "exact length is valid", "data": [1, 2], "valid": true }, { "description": "too long is invalid", "data": [1, 2, 3], "valid": false }, { "description": "ignores non-arrays", "data": "foobar", "valid": true } ] }, { "description": "maxItems validation with a decimal", "schema": {"maxItems": 2.0}, "tests": [ { "description": "shorter is valid", "data": [1], "valid": true }, { "description": "too long is invalid", "data": [1, 2, 3], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/maxLength.json0000644000175100001770000000245114653725311023402 0ustar00runnerdocker[ { "description": "maxLength validation", "schema": {"maxLength": 2}, "tests": [ { "description": "shorter is valid", "data": "f", "valid": true }, { "description": "exact length is valid", "data": "fo", "valid": true }, { "description": "too long is invalid", "data": "foo", "valid": false }, { "description": "ignores non-strings", "data": 100, "valid": true }, { "description": "two supplementary Unicode code points is long enough", "data": "\uD83D\uDCA9\uD83D\uDCA9", "valid": true } ] }, { "description": "maxLength validation with a decimal", "schema": {"maxLength": 2.0}, "tests": [ { "description": "shorter is valid", "data": "f", "valid": true }, { "description": "too long is invalid", "data": "foo", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/maxProperties.json0000644000175100001770000000365314653725311024322 0ustar00runnerdocker[ { "description": "maxProperties validation", "schema": {"maxProperties": 2}, "tests": [ { "description": "shorter is valid", "data": {"foo": 1}, "valid": true }, { "description": "exact length is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "too long is invalid", "data": {"foo": 1, "bar": 2, "baz": 3}, "valid": false }, { "description": "ignores arrays", "data": [1, 2, 3], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "maxProperties validation with a decimal", "schema": {"maxProperties": 2.0}, "tests": [ { "description": "shorter is valid", "data": {"foo": 1}, "valid": true }, { "description": "too long is invalid", "data": {"foo": 1, "bar": 2, "baz": 3}, "valid": false } ] }, { "description": "maxProperties = 0 means the object is empty", "schema": { "maxProperties": 0 }, "tests": [ { "description": "no properties is valid", "data": {}, "valid": true }, { "description": "one property is invalid", "data": { "foo": 1 }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/maximum.json0000644000175100001770000000270414653725311023131 0ustar00runnerdocker[ { "description": "maximum validation", "schema": {"maximum": 3.0}, "tests": [ { "description": "below the maximum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 3.0, "valid": true }, { "description": "above the maximum is invalid", "data": 3.5, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] }, { "description": "maximum validation with unsigned integer", "schema": {"maximum": 300}, "tests": [ { "description": "below the maximum is invalid", "data": 299.97, "valid": true }, { "description": "boundary point integer is valid", "data": 300, "valid": true }, { "description": "boundary point float is valid", "data": 300.00, "valid": true }, { "description": "above the maximum is invalid", "data": 300.5, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/minItems.json0000644000175100001770000000213414653725311023236 0ustar00runnerdocker[ { "description": "minItems validation", "schema": {"minItems": 1}, "tests": [ { "description": "longer is valid", "data": [1, 2], "valid": true }, { "description": "exact length is valid", "data": [1], "valid": true }, { "description": "too short is invalid", "data": [], "valid": false }, { "description": "ignores non-arrays", "data": "", "valid": true } ] }, { "description": "minItems validation with a decimal", "schema": {"minItems": 1.0}, "tests": [ { "description": "longer is valid", "data": [1, 2], "valid": true }, { "description": "too short is invalid", "data": [], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/minLength.json0000644000175100001770000000243714653725311023404 0ustar00runnerdocker[ { "description": "minLength validation", "schema": {"minLength": 2}, "tests": [ { "description": "longer is valid", "data": "foo", "valid": true }, { "description": "exact length is valid", "data": "fo", "valid": true }, { "description": "too short is invalid", "data": "f", "valid": false }, { "description": "ignores non-strings", "data": 1, "valid": true }, { "description": "one supplementary Unicode code point is not long enough", "data": "\uD83D\uDCA9", "valid": false } ] }, { "description": "minLength validation with a decimal", "schema": {"minLength": 2.0}, "tests": [ { "description": "longer is valid", "data": "foo", "valid": true }, { "description": "too short is invalid", "data": "f", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/minProperties.json0000644000175100001770000000265314653725311024317 0ustar00runnerdocker[ { "description": "minProperties validation", "schema": {"minProperties": 1}, "tests": [ { "description": "longer is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "exact length is valid", "data": {"foo": 1}, "valid": true }, { "description": "too short is invalid", "data": {}, "valid": false }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "minProperties validation with a decimal", "schema": {"minProperties": 1.0}, "tests": [ { "description": "longer is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "too short is invalid", "data": {}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/minimum.json0000644000175100001770000000361214653725311023126 0ustar00runnerdocker[ { "description": "minimum validation", "schema": {"minimum": 1.1}, "tests": [ { "description": "above the minimum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 1.1, "valid": true }, { "description": "below the minimum is invalid", "data": 0.6, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] }, { "description": "minimum validation with signed integer", "schema": {"minimum": -2}, "tests": [ { "description": "negative above the minimum is valid", "data": -1, "valid": true }, { "description": "positive above the minimum is valid", "data": 0, "valid": true }, { "description": "boundary point is valid", "data": -2, "valid": true }, { "description": "boundary point with float is valid", "data": -2.0, "valid": true }, { "description": "float below the minimum is invalid", "data": -2.0001, "valid": false }, { "description": "int below the minimum is invalid", "data": -3, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/multipleOf.json0000644000175100001770000000352214653725311023573 0ustar00runnerdocker[ { "description": "by int", "schema": {"multipleOf": 2}, "tests": [ { "description": "int by int", "data": 10, "valid": true }, { "description": "int by int fail", "data": 7, "valid": false }, { "description": "ignores non-numbers", "data": "foo", "valid": true } ] }, { "description": "by number", "schema": {"multipleOf": 1.5}, "tests": [ { "description": "zero is multiple of anything", "data": 0, "valid": true }, { "description": "4.5 is multiple of 1.5", "data": 4.5, "valid": true }, { "description": "35 is not multiple of 1.5", "data": 35, "valid": false } ] }, { "description": "by small number", "schema": {"multipleOf": 0.0001}, "tests": [ { "description": "0.0075 is multiple of 0.0001", "data": 0.0075, "valid": true }, { "description": "0.00751 is not multiple of 0.0001", "data": 0.00751, "valid": false } ] }, { "description": "float division = inf", "schema": {"type": "integer", "multipleOf": 0.123456789}, "tests": [ { "description": "always invalid, but naive implementations may raise an overflow error", "data": 1e308, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/not.json0000644000175100001770000000537614653725311022264 0ustar00runnerdocker[ { "description": "not", "schema": { "not": {"type": "integer"} }, "tests": [ { "description": "allowed", "data": "foo", "valid": true }, { "description": "disallowed", "data": 1, "valid": false } ] }, { "description": "not multiple types", "schema": { "not": {"type": ["integer", "boolean"]} }, "tests": [ { "description": "valid", "data": "foo", "valid": true }, { "description": "mismatch", "data": 1, "valid": false }, { "description": "other mismatch", "data": true, "valid": false } ] }, { "description": "not more complex schema", "schema": { "not": { "type": "object", "properties": { "foo": { "type": "string" } } } }, "tests": [ { "description": "match", "data": 1, "valid": true }, { "description": "other match", "data": {"foo": 1}, "valid": true }, { "description": "mismatch", "data": {"foo": "bar"}, "valid": false } ] }, { "description": "forbidden property", "schema": { "properties": { "foo": { "not": {} } } }, "tests": [ { "description": "property present", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "property absent", "data": {"bar": 1, "baz": 2}, "valid": true } ] }, { "description": "not with boolean schema true", "schema": {"not": true}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "not with boolean schema false", "schema": {"not": false}, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/oneOf.json0000644000175100001770000001612314653725311022522 0ustar00runnerdocker[ { "description": "oneOf", "schema": { "oneOf": [ { "type": "integer" }, { "minimum": 2 } ] }, "tests": [ { "description": "first oneOf valid", "data": 1, "valid": true }, { "description": "second oneOf valid", "data": 2.5, "valid": true }, { "description": "both oneOf valid", "data": 3, "valid": false }, { "description": "neither oneOf valid", "data": 1.5, "valid": false } ] }, { "description": "oneOf with base schema", "schema": { "type": "string", "oneOf" : [ { "minLength": 2 }, { "maxLength": 4 } ] }, "tests": [ { "description": "mismatch base schema", "data": 3, "valid": false }, { "description": "one oneOf valid", "data": "foobar", "valid": true }, { "description": "both oneOf valid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, all true", "schema": {"oneOf": [true, true, true]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, one true", "schema": {"oneOf": [true, false, false]}, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "oneOf with boolean schemas, more than one true", "schema": {"oneOf": [true, true, false]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, all false", "schema": {"oneOf": [false, false, false]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf complex types", "schema": { "oneOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "first oneOf valid (complex)", "data": {"bar": 2}, "valid": true }, { "description": "second oneOf valid (complex)", "data": {"foo": "baz"}, "valid": true }, { "description": "both oneOf valid (complex)", "data": {"foo": "baz", "bar": 2}, "valid": false }, { "description": "neither oneOf valid (complex)", "data": {"foo": 2, "bar": "quux"}, "valid": false } ] }, { "description": "oneOf with empty schema", "schema": { "oneOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "one valid - valid", "data": "foo", "valid": true }, { "description": "both valid - invalid", "data": 123, "valid": false } ] }, { "description": "oneOf with required", "schema": { "type": "object", "oneOf": [ { "required": ["foo", "bar"] }, { "required": ["foo", "baz"] } ] }, "tests": [ { "description": "both invalid - invalid", "data": {"bar": 2}, "valid": false }, { "description": "first valid - valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "second valid - valid", "data": {"foo": 1, "baz": 3}, "valid": true }, { "description": "both valid - invalid", "data": {"foo": 1, "bar": 2, "baz" : 3}, "valid": false } ] }, { "description": "oneOf with missing optional property", "schema": { "oneOf": [ { "properties": { "bar": true, "baz": true }, "required": ["bar"] }, { "properties": { "foo": true }, "required": ["foo"] } ] }, "tests": [ { "description": "first oneOf valid", "data": {"bar": 8}, "valid": true }, { "description": "second oneOf valid", "data": {"foo": "foo"}, "valid": true }, { "description": "both oneOf valid", "data": {"foo": "foo", "bar": 8}, "valid": false }, { "description": "neither oneOf valid", "data": {"baz": "quux"}, "valid": false } ] }, { "description": "nested oneOf, to check validation semantics", "schema": { "oneOf": [ { "oneOf": [ { "type": "null" } ] } ] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "anything non-null is invalid", "data": 123, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0970972 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/optional/0000755000175100001770000000000014653725331022405 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/optional/bignum.json0000644000175100001770000000540114653725311024557 0ustar00runnerdocker[ { "description": "integer", "schema": { "type": "integer" }, "tests": [ { "description": "a bignum is an integer", "data": 12345678910111213141516171819202122232425262728293031, "valid": true }, { "description": "a negative bignum is an integer", "data": -12345678910111213141516171819202122232425262728293031, "valid": true } ] }, { "description": "number", "schema": { "type": "number" }, "tests": [ { "description": "a bignum is a number", "data": 98249283749234923498293171823948729348710298301928331, "valid": true }, { "description": "a negative bignum is a number", "data": -98249283749234923498293171823948729348710298301928331, "valid": true } ] }, { "description": "string", "schema": { "type": "string" }, "tests": [ { "description": "a bignum is not a string", "data": 98249283749234923498293171823948729348710298301928331, "valid": false } ] }, { "description": "maximum integer comparison", "schema": { "maximum": 18446744073709551615 }, "tests": [ { "description": "comparison works for high numbers", "data": 18446744073709551600, "valid": true } ] }, { "description": "float comparison with high precision", "schema": { "exclusiveMaximum": 972783798187987123879878123.18878137 }, "tests": [ { "description": "comparison works for high numbers", "data": 972783798187987123879878123.188781371, "valid": false } ] }, { "description": "minimum integer comparison", "schema": { "minimum": -18446744073709551615 }, "tests": [ { "description": "comparison works for very negative numbers", "data": -18446744073709551600, "valid": true } ] }, { "description": "float comparison with high precision on negative numbers", "schema": { "exclusiveMinimum": -972783798187987123879878123.18878137 }, "tests": [ { "description": "comparison works for very negative numbers", "data": -972783798187987123879878123.188781371, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/optional/ecmascript-regex.json0000644000175100001770000004410114653725311026540 0ustar00runnerdocker[ { "description": "ECMA 262 regex $ does not match trailing newline", "schema": { "type": "string", "pattern": "^abc$" }, "tests": [ { "description": "matches in Python, but not in ECMA 262", "data": "abc\\n", "valid": false }, { "description": "matches", "data": "abc", "valid": true } ] }, { "description": "ECMA 262 regex converts \\t to horizontal tab", "schema": { "type": "string", "pattern": "^\\t$" }, "tests": [ { "description": "does not match", "data": "\\t", "valid": false }, { "description": "matches", "data": "\u0009", "valid": true } ] }, { "description": "ECMA 262 regex escapes control codes with \\c and upper letter", "schema": { "type": "string", "pattern": "^\\cC$" }, "tests": [ { "description": "does not match", "data": "\\cC", "valid": false }, { "description": "matches", "data": "\u0003", "valid": true } ] }, { "description": "ECMA 262 regex escapes control codes with \\c and lower letter", "schema": { "type": "string", "pattern": "^\\cc$" }, "tests": [ { "description": "does not match", "data": "\\cc", "valid": false }, { "description": "matches", "data": "\u0003", "valid": true } ] }, { "description": "ECMA 262 \\d matches ascii digits only", "schema": { "type": "string", "pattern": "^\\d$" }, "tests": [ { "description": "ASCII zero matches", "data": "0", "valid": true }, { "description": "NKO DIGIT ZERO does not match (unlike e.g. Python)", "data": "߀", "valid": false }, { "description": "NKO DIGIT ZERO (as \\u escape) does not match", "data": "\u07c0", "valid": false } ] }, { "description": "ECMA 262 \\D matches everything but ascii digits", "schema": { "type": "string", "pattern": "^\\D$" }, "tests": [ { "description": "ASCII zero does not match", "data": "0", "valid": false }, { "description": "NKO DIGIT ZERO matches (unlike e.g. Python)", "data": "߀", "valid": true }, { "description": "NKO DIGIT ZERO (as \\u escape) matches", "data": "\u07c0", "valid": true } ] }, { "description": "ECMA 262 \\w matches ascii letters only", "schema": { "type": "string", "pattern": "^\\w$" }, "tests": [ { "description": "ASCII 'a' matches", "data": "a", "valid": true }, { "description": "latin-1 e-acute does not match (unlike e.g. Python)", "data": "é", "valid": false } ] }, { "description": "ECMA 262 \\W matches everything but ascii letters", "schema": { "type": "string", "pattern": "^\\W$" }, "tests": [ { "description": "ASCII 'a' does not match", "data": "a", "valid": false }, { "description": "latin-1 e-acute matches (unlike e.g. Python)", "data": "é", "valid": true } ] }, { "description": "ECMA 262 \\s matches whitespace", "schema": { "type": "string", "pattern": "^\\s$" }, "tests": [ { "description": "ASCII space matches", "data": " ", "valid": true }, { "description": "Character tabulation matches", "data": "\t", "valid": true }, { "description": "Line tabulation matches", "data": "\u000b", "valid": true }, { "description": "Form feed matches", "data": "\u000c", "valid": true }, { "description": "latin-1 non-breaking-space matches", "data": "\u00a0", "valid": true }, { "description": "zero-width whitespace matches", "data": "\ufeff", "valid": true }, { "description": "line feed matches (line terminator)", "data": "\u000a", "valid": true }, { "description": "paragraph separator matches (line terminator)", "data": "\u2029", "valid": true }, { "description": "EM SPACE matches (Space_Separator)", "data": "\u2003", "valid": true }, { "description": "Non-whitespace control does not match", "data": "\u0001", "valid": false }, { "description": "Non-whitespace does not match", "data": "\u2013", "valid": false } ] }, { "description": "ECMA 262 \\S matches everything but whitespace", "schema": { "type": "string", "pattern": "^\\S$" }, "tests": [ { "description": "ASCII space does not match", "data": " ", "valid": false }, { "description": "Character tabulation does not match", "data": "\t", "valid": false }, { "description": "Line tabulation does not match", "data": "\u000b", "valid": false }, { "description": "Form feed does not match", "data": "\u000c", "valid": false }, { "description": "latin-1 non-breaking-space does not match", "data": "\u00a0", "valid": false }, { "description": "zero-width whitespace does not match", "data": "\ufeff", "valid": false }, { "description": "line feed does not match (line terminator)", "data": "\u000a", "valid": false }, { "description": "paragraph separator does not match (line terminator)", "data": "\u2029", "valid": false }, { "description": "EM SPACE does not match (Space_Separator)", "data": "\u2003", "valid": false }, { "description": "Non-whitespace control matches", "data": "\u0001", "valid": true }, { "description": "Non-whitespace matches", "data": "\u2013", "valid": true } ] }, { "description": "patterns always use unicode semantics with pattern", "schema": { "pattern": "\\p{Letter}cole" }, "tests": [ { "description": "ascii character in json string", "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", "valid": true }, { "description": "literal unicode character in json string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": true }, { "description": "unicode character in hex format in string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": true }, { "description": "unicode matching is case-sensitive", "data": "LES HIVERS DE MON ENFANCE ÉTAIENT DES SAISONS LONGUES, LONGUES. NOUS VIVIONS EN TROIS LIEUX: L'ÉCOLE, L'ÉGLISE ET LA PATINOIRE; MAIS LA VRAIE VIE ÉTAIT SUR LA PATINOIRE.", "valid": false } ] }, { "description": "\\w in patterns matches [A-Za-z0-9_], not unicode letters", "schema": { "pattern": "\\wcole" }, "tests": [ { "description": "ascii character in json string", "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", "valid": true }, { "description": "literal unicode character in json string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "unicode character in hex format in string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "unicode matching is case-sensitive", "data": "LES HIVERS DE MON ENFANCE ÉTAIENT DES SAISONS LONGUES, LONGUES. NOUS VIVIONS EN TROIS LIEUX: L'ÉCOLE, L'ÉGLISE ET LA PATINOIRE; MAIS LA VRAIE VIE ÉTAIT SUR LA PATINOIRE.", "valid": false } ] }, { "description": "pattern with ASCII ranges", "schema": { "pattern": "[a-z]cole" }, "tests": [ { "description": "literal unicode character in json string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "unicode character in hex format in string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "ascii characters match", "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", "valid": true } ] }, { "description": "\\d in pattern matches [0-9], not unicode digits", "schema": { "pattern": "^\\d+$" }, "tests": [ { "description": "ascii digits", "data": "42", "valid": true }, { "description": "ascii non-digits", "data": "-%#", "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": "৪২", "valid": false } ] }, { "description": "pattern with non-ASCII digits", "schema": { "pattern": "^\\p{digit}+$" }, "tests": [ { "description": "ascii digits", "data": "42", "valid": true }, { "description": "ascii non-digits", "data": "-%#", "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": "৪২", "valid": true } ] }, { "description": "patterns always use unicode semantics with patternProperties", "schema": { "type": "object", "patternProperties": { "\\p{Letter}cole": true }, "additionalProperties": false }, "tests": [ { "description": "ascii character in json string", "data": { "l'ecole": "pas de vraie vie" }, "valid": true }, { "description": "literal unicode character in json string", "data": { "l'école": "pas de vraie vie" }, "valid": true }, { "description": "unicode character in hex format in string", "data": { "l'\u00e9cole": "pas de vraie vie" }, "valid": true }, { "description": "unicode matching is case-sensitive", "data": { "L'ÉCOLE": "PAS DE VRAIE VIE" }, "valid": false } ] }, { "description": "\\w in patternProperties matches [A-Za-z0-9_], not unicode letters", "schema": { "type": "object", "patternProperties": { "\\wcole": true }, "additionalProperties": false }, "tests": [ { "description": "ascii character in json string", "data": { "l'ecole": "pas de vraie vie" }, "valid": true }, { "description": "literal unicode character in json string", "data": { "l'école": "pas de vraie vie" }, "valid": false }, { "description": "unicode character in hex format in string", "data": { "l'\u00e9cole": "pas de vraie vie" }, "valid": false }, { "description": "unicode matching is case-sensitive", "data": { "L'ÉCOLE": "PAS DE VRAIE VIE" }, "valid": false } ] }, { "description": "patternProperties with ASCII ranges", "schema": { "type": "object", "patternProperties": { "[a-z]cole": true }, "additionalProperties": false }, "tests": [ { "description": "literal unicode character in json string", "data": { "l'école": "pas de vraie vie" }, "valid": false }, { "description": "unicode character in hex format in string", "data": { "l'\u00e9cole": "pas de vraie vie" }, "valid": false }, { "description": "ascii characters match", "data": { "l'ecole": "pas de vraie vie" }, "valid": true } ] }, { "description": "\\d in patternProperties matches [0-9], not unicode digits", "schema": { "type": "object", "patternProperties": { "^\\d+$": true }, "additionalProperties": false }, "tests": [ { "description": "ascii digits", "data": { "42": "life, the universe, and everything" }, "valid": true }, { "description": "ascii non-digits", "data": { "-%#": "spending the year dead for tax reasons" }, "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": { "৪২": "khajit has wares if you have coin" }, "valid": false } ] }, { "description": "patternProperties with non-ASCII digits", "schema": { "type": "object", "patternProperties": { "^\\p{digit}+$": true }, "additionalProperties": false }, "tests": [ { "description": "ascii digits", "data": { "42": "life, the universe, and everything" }, "valid": true }, { "description": "ascii non-digits", "data": { "-%#": "spending the year dead for tax reasons" }, "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": { "৪২": "khajit has wares if you have coin" }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/optional/float-overflow.json0000644000175100001770000000055114653725311026245 0ustar00runnerdocker[ { "description": "all integers are multiples of 0.5, if overflow is handled", "schema": {"type": "integer", "multipleOf": 0.5}, "tests": [ { "description": "valid if optional overflow handling is implemented", "data": 1e308, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1010973 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/optional/format/0000755000175100001770000000000014653725331023675 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/optional/format/date-time.json0000644000175100001770000001106014653725311026435 0ustar00runnerdocker[ { "description": "validation of date-time strings", "schema": { "format": "date-time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid date-time string", "data": "1963-06-19T08:30:06.283185Z", "valid": true }, { "description": "a valid date-time string without second fraction", "data": "1963-06-19T08:30:06Z", "valid": true }, { "description": "a valid date-time string with plus offset", "data": "1937-01-01T12:00:27.87+00:20", "valid": true }, { "description": "a valid date-time string with minus offset", "data": "1990-12-31T15:59:50.123-08:00", "valid": true }, { "description": "a valid date-time with a leap second, UTC", "data": "1998-12-31T23:59:60Z", "valid": true }, { "description": "a valid date-time with a leap second, with minus offset", "data": "1998-12-31T15:59:60.123-08:00", "valid": true }, { "description": "an invalid date-time past leap second, UTC", "data": "1998-12-31T23:59:61Z", "valid": false }, { "description": "an invalid date-time with leap second on a wrong minute, UTC", "data": "1998-12-31T23:58:60Z", "valid": false }, { "description": "an invalid date-time with leap second on a wrong hour, UTC", "data": "1998-12-31T22:59:60Z", "valid": false }, { "description": "an invalid day in date-time string", "data": "1990-02-31T15:59:59.123-08:00", "valid": false }, { "description": "an invalid offset in date-time string", "data": "1990-12-31T15:59:59-24:00", "valid": false }, { "description": "an invalid closing Z after time-zone offset", "data": "1963-06-19T08:30:06.28123+01:00Z", "valid": false }, { "description": "an invalid date-time string", "data": "06/19/1963 08:30:06 PST", "valid": false }, { "description": "case-insensitive T and Z", "data": "1963-06-19t08:30:06.283185z", "valid": true }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "2013-350T01:01:01", "valid": false }, { "description": "invalid non-padded month dates", "data": "1963-6-19T08:30:06.283185Z", "valid": false }, { "description": "invalid non-padded day dates", "data": "1963-06-1T08:30:06.283185Z", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4) in date portion", "data": "1963-06-1৪T00:00:00Z", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4) in time portion", "data": "1963-06-11T0৪:00:00Z", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/optional/format/email.json0000644000175100001770000000510414653725311025655 0ustar00runnerdocker[ { "description": "validation of e-mail addresses", "schema": { "format": "email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid e-mail address", "data": "joe.bloggs@example.com", "valid": true }, { "description": "an invalid e-mail address", "data": "2962", "valid": false }, { "description": "tilde in local part is valid", "data": "te~st@example.com", "valid": true }, { "description": "tilde before local part is valid", "data": "~test@example.com", "valid": true }, { "description": "tilde after local part is valid", "data": "test~@example.com", "valid": true }, { "description": "dot before local part is not valid", "data": ".test@example.com", "valid": false }, { "description": "dot after local part is not valid", "data": "test.@example.com", "valid": false }, { "description": "two separated dots inside local part are valid", "data": "te.s.t@example.com", "valid": true }, { "description": "two subsequent dots inside local part are not valid", "data": "te..st@example.com", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/optional/format/hostname.json0000644000175100001770000000622414653725311026410 0ustar00runnerdocker[ { "description": "validation of host names", "schema": { "format": "hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid host name", "data": "www.example.com", "valid": true }, { "description": "a valid punycoded IDN hostname", "data": "xn--4gbwdl.xn--wgbh1c", "valid": true }, { "description": "a host name starting with an illegal character", "data": "-a-host-name-that-starts-with--", "valid": false }, { "description": "a host name containing illegal characters", "data": "not_a_valid_host_name", "valid": false }, { "description": "a host name with a component too long", "data": "a-vvvvvvvvvvvvvvvveeeeeeeeeeeeeeeerrrrrrrrrrrrrrrryyyyyyyyyyyyyyyy-long-host-name-component", "valid": false }, { "description": "starts with hyphen", "data": "-hostname", "valid": false }, { "description": "ends with hyphen", "data": "hostname-", "valid": false }, { "description": "starts with underscore", "data": "_hostname", "valid": false }, { "description": "ends with underscore", "data": "hostname_", "valid": false }, { "description": "contains underscore", "data": "host_name", "valid": false }, { "description": "maximum label length", "data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.com", "valid": true }, { "description": "exceeds maximum label length", "data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl.com", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/optional/format/ipv4.json0000644000175100001770000000540414653725311025453 0ustar00runnerdocker[ { "description": "validation of IP addresses", "schema": { "format": "ipv4" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IP address", "data": "192.168.0.1", "valid": true }, { "description": "an IP address with too many components", "data": "127.0.0.0.1", "valid": false }, { "description": "an IP address with out-of-range values", "data": "256.256.256.256", "valid": false }, { "description": "an IP address without 4 components", "data": "127.0", "valid": false }, { "description": "an IP address as an integer", "data": "0x7f000001", "valid": false }, { "description": "an IP address as an integer (decimal)", "data": "2130706433", "valid": false }, { "description": "invalid leading zeroes, as they are treated as octals", "comment": "see https://sick.codes/universal-netmask-npm-package-used-by-270000-projects-vulnerable-to-octal-input-data-server-side-request-forgery-remote-file-inclusion-local-file-inclusion-and-more-cve-2021-28918/", "data": "087.10.0.1", "valid": false }, { "description": "value without leading zero is valid", "data": "87.10.0.1", "valid": true }, { "description": "invalid non-ASCII '২' (a Bengali 2)", "data": "1২7.0.0.1", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/optional/format/ipv6.json0000644000175100001770000001543714653725311025464 0ustar00runnerdocker[ { "description": "validation of IPv6 addresses", "schema": { "format": "ipv6" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IPv6 address", "data": "::1", "valid": true }, { "description": "an IPv6 address with out-of-range values", "data": "12345::", "valid": false }, { "description": "trailing 4 hex symbols is valid", "data": "::abef", "valid": true }, { "description": "trailing 5 hex symbols is invalid", "data": "::abcef", "valid": false }, { "description": "an IPv6 address with too many components", "data": "1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1", "valid": false }, { "description": "an IPv6 address containing illegal characters", "data": "::laptop", "valid": false }, { "description": "no digits is valid", "data": "::", "valid": true }, { "description": "leading colons is valid", "data": "::42:ff:1", "valid": true }, { "description": "trailing colons is valid", "data": "d6::", "valid": true }, { "description": "missing leading octet is invalid", "data": ":2:3:4:5:6:7:8", "valid": false }, { "description": "missing trailing octet is invalid", "data": "1:2:3:4:5:6:7:", "valid": false }, { "description": "missing leading octet with omitted octets later", "data": ":2:3:4::8", "valid": false }, { "description": "single set of double colons in the middle is valid", "data": "1:d6::42", "valid": true }, { "description": "two sets of double colons is invalid", "data": "1::d6::42", "valid": false }, { "description": "mixed format with the ipv4 section as decimal octets", "data": "1::d6:192.168.0.1", "valid": true }, { "description": "mixed format with double colons between the sections", "data": "1:2::192.168.0.1", "valid": true }, { "description": "mixed format with ipv4 section with octet out of range", "data": "1::2:192.168.256.1", "valid": false }, { "description": "mixed format with ipv4 section with a hex octet", "data": "1::2:192.168.ff.1", "valid": false }, { "description": "mixed format with leading double colons (ipv4-mapped ipv6 address)", "data": "::ffff:192.168.0.1", "valid": true }, { "description": "triple colons is invalid", "data": "1:2:3:4:5:::8", "valid": false }, { "description": "8 octets", "data": "1:2:3:4:5:6:7:8", "valid": true }, { "description": "insufficient octets without double colons", "data": "1:2:3:4:5:6:7", "valid": false }, { "description": "no colons is invalid", "data": "1", "valid": false }, { "description": "ipv4 is not ipv6", "data": "127.0.0.1", "valid": false }, { "description": "ipv4 segment must have 4 octets", "data": "1:2:3:4:1.2.3", "valid": false }, { "description": "leading whitespace is invalid", "data": " ::1", "valid": false }, { "description": "trailing whitespace is invalid", "data": "::1 ", "valid": false }, { "description": "netmask is not a part of ipv6 address", "data": "fe80::/64", "valid": false }, { "description": "zone id is not a part of ipv6 address", "data": "fe80::a%eth1", "valid": false }, { "description": "a long valid ipv6", "data": "1000:1000:1000:1000:1000:1000:255.255.255.255", "valid": true }, { "description": "a long invalid ipv6, below length limit, first", "data": "100:100:100:100:100:100:255.255.255.255.255", "valid": false }, { "description": "a long invalid ipv6, below length limit, second", "data": "100:100:100:100:100:100:100:255.255.255.255", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4)", "data": "1:2:3:4:5:6:7:৪", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4) in the IPv4 portion", "data": "1:2::192.16৪.0.1", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/optional/format/json-pointer.json0000644000175100001770000001506314653725311027222 0ustar00runnerdocker[ { "description": "validation of JSON-pointers (JSON String Representation)", "schema": { "format": "json-pointer" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid JSON-pointer", "data": "/foo/bar~0/baz~1/%a", "valid": true }, { "description": "not a valid JSON-pointer (~ not escaped)", "data": "/foo/bar~", "valid": false }, { "description": "valid JSON-pointer with empty segment", "data": "/foo//bar", "valid": true }, { "description": "valid JSON-pointer with the last empty segment", "data": "/foo/bar/", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #1", "data": "", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #2", "data": "/foo", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #3", "data": "/foo/0", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #4", "data": "/", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #5", "data": "/a~1b", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #6", "data": "/c%d", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #7", "data": "/e^f", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #8", "data": "/g|h", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #9", "data": "/i\\j", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #10", "data": "/k\"l", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #11", "data": "/ ", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #12", "data": "/m~0n", "valid": true }, { "description": "valid JSON-pointer used adding to the last array position", "data": "/foo/-", "valid": true }, { "description": "valid JSON-pointer (- used as object member name)", "data": "/foo/-/bar", "valid": true }, { "description": "valid JSON-pointer (multiple escaped characters)", "data": "/~1~0~0~1~1", "valid": true }, { "description": "valid JSON-pointer (escaped with fraction part) #1", "data": "/~1.1", "valid": true }, { "description": "valid JSON-pointer (escaped with fraction part) #2", "data": "/~0.1", "valid": true }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #1", "data": "#", "valid": false }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #2", "data": "#/", "valid": false }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #3", "data": "#a", "valid": false }, { "description": "not a valid JSON-pointer (some escaped, but not all) #1", "data": "/~0~", "valid": false }, { "description": "not a valid JSON-pointer (some escaped, but not all) #2", "data": "/~0/~", "valid": false }, { "description": "not a valid JSON-pointer (wrong escape character) #1", "data": "/~2", "valid": false }, { "description": "not a valid JSON-pointer (wrong escape character) #2", "data": "/~-1", "valid": false }, { "description": "not a valid JSON-pointer (multiple characters not escaped)", "data": "/~~", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #1", "data": "a", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #2", "data": "0", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #3", "data": "a/a", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/optional/format/unknown.json0000644000175100001770000000226314653725311026270 0ustar00runnerdocker[ { "description": "unknown format", "schema": { "format": "unknown" }, "tests": [ { "description": "unknown formats ignore integers", "data": 12, "valid": true }, { "description": "unknown formats ignore floats", "data": 13.7, "valid": true }, { "description": "unknown formats ignore objects", "data": {}, "valid": true }, { "description": "unknown formats ignore arrays", "data": [], "valid": true }, { "description": "unknown formats ignore booleans", "data": false, "valid": true }, { "description": "unknown formats ignore nulls", "data": null, "valid": true }, { "description": "unknown formats ignore strings", "data": "string", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/optional/format/uri-reference.json0000644000175100001770000000423714653725311027327 0ustar00runnerdocker[ { "description": "validation of URI References", "schema": { "format": "uri-reference" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid URI", "data": "http://foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid protocol-relative URI Reference", "data": "//foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid relative URI Reference", "data": "/abc", "valid": true }, { "description": "an invalid URI Reference", "data": "\\\\WINDOWS\\fileshare", "valid": false }, { "description": "a valid URI Reference", "data": "abc", "valid": true }, { "description": "a valid URI fragment", "data": "#fragment", "valid": true }, { "description": "an invalid URI fragment", "data": "#frag\\ment", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/optional/format/uri-template.json0000644000175100001770000000343114653725311027177 0ustar00runnerdocker[ { "description": "format: uri-template", "schema": { "format": "uri-template" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid uri-template", "data": "http://example.com/dictionary/{term:1}/{term}", "valid": true }, { "description": "an invalid uri-template", "data": "http://example.com/dictionary/{term:1}/{term", "valid": false }, { "description": "a valid uri-template without variables", "data": "http://example.com/dictionary", "valid": true }, { "description": "a valid relative uri-template", "data": "dictionary/{term:1}/{term}", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/optional/format/uri.json0000644000175100001770000001103414653725311025364 0ustar00runnerdocker[ { "description": "validation of URIs", "schema": { "format": "uri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid URL with anchor tag", "data": "http://foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid URL with anchor tag and parentheses", "data": "http://foo.com/blah_(wikipedia)_blah#cite-1", "valid": true }, { "description": "a valid URL with URL-encoded stuff", "data": "http://foo.bar/?q=Test%20URL-encoded%20stuff", "valid": true }, { "description": "a valid puny-coded URL ", "data": "http://xn--nw2a.xn--j6w193g/", "valid": true }, { "description": "a valid URL with many special characters", "data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", "valid": true }, { "description": "a valid URL based on IPv4", "data": "http://223.255.255.254", "valid": true }, { "description": "a valid URL with ftp scheme", "data": "ftp://ftp.is.co.za/rfc/rfc1808.txt", "valid": true }, { "description": "a valid URL for a simple text file", "data": "http://www.ietf.org/rfc/rfc2396.txt", "valid": true }, { "description": "a valid URL ", "data": "ldap://[2001:db8::7]/c=GB?objectClass?one", "valid": true }, { "description": "a valid mailto URI", "data": "mailto:John.Doe@example.com", "valid": true }, { "description": "a valid newsgroup URI", "data": "news:comp.infosystems.www.servers.unix", "valid": true }, { "description": "a valid tel URI", "data": "tel:+1-816-555-1212", "valid": true }, { "description": "a valid URN", "data": "urn:oasis:names:specification:docbook:dtd:xml:4.1.2", "valid": true }, { "description": "an invalid protocol-relative URI Reference", "data": "//foo.bar/?baz=qux#quux", "valid": false }, { "description": "an invalid relative URI Reference", "data": "/abc", "valid": false }, { "description": "an invalid URI", "data": "\\\\WINDOWS\\fileshare", "valid": false }, { "description": "an invalid URI though valid URI reference", "data": "abc", "valid": false }, { "description": "an invalid URI with spaces", "data": "http:// shouldfail.com", "valid": false }, { "description": "an invalid URI with spaces and missing scheme", "data": ":// should fail", "valid": false }, { "description": "an invalid URI with comma in scheme", "data": "bar,baz:foo", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/optional/non-bmp-regex.json0000644000175100001770000000453614653725311025764 0ustar00runnerdocker[ { "description": "Proper UTF-16 surrogate pair handling: pattern", "comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters", "schema": { "pattern": "^ðŸ²*$" }, "tests": [ { "description": "matches empty", "data": "", "valid": true }, { "description": "matches single", "data": "ðŸ²", "valid": true }, { "description": "matches two", "data": "ðŸ²ðŸ²", "valid": true }, { "description": "doesn't match one", "data": "ðŸ‰", "valid": false }, { "description": "doesn't match two", "data": "ðŸ‰ðŸ‰", "valid": false }, { "description": "doesn't match one ASCII", "data": "D", "valid": false }, { "description": "doesn't match two ASCII", "data": "DD", "valid": false } ] }, { "description": "Proper UTF-16 surrogate pair handling: patternProperties", "comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters", "schema": { "patternProperties": { "^ðŸ²*$": { "type": "integer" } } }, "tests": [ { "description": "matches empty", "data": { "": 1 }, "valid": true }, { "description": "matches single", "data": { "ðŸ²": 1 }, "valid": true }, { "description": "matches two", "data": { "ðŸ²ðŸ²": 1 }, "valid": true }, { "description": "doesn't match one", "data": { "ðŸ²": "hello" }, "valid": false }, { "description": "doesn't match two", "data": { "ðŸ²ðŸ²": "hello" }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/pattern.json0000644000175100001770000000300314653725311023122 0ustar00runnerdocker[ { "description": "pattern validation", "schema": {"pattern": "^a*$"}, "tests": [ { "description": "a matching pattern is valid", "data": "aaa", "valid": true }, { "description": "a non-matching pattern is invalid", "data": "abc", "valid": false }, { "description": "ignores booleans", "data": true, "valid": true }, { "description": "ignores integers", "data": 123, "valid": true }, { "description": "ignores floats", "data": 1.0, "valid": true }, { "description": "ignores objects", "data": {}, "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores null", "data": null, "valid": true } ] }, { "description": "pattern is not anchored", "schema": {"pattern": "a+"}, "tests": [ { "description": "matches a substring", "data": "xxaayy", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/patternProperties.json0000644000175100001770000001207114653725311025204 0ustar00runnerdocker[ { "description": "patternProperties validates properties matching a regex", "schema": { "patternProperties": { "f.*o": {"type": "integer"} } }, "tests": [ { "description": "a single valid match is valid", "data": {"foo": 1}, "valid": true }, { "description": "multiple valid matches is valid", "data": {"foo": 1, "foooooo" : 2}, "valid": true }, { "description": "a single invalid match is invalid", "data": {"foo": "bar", "fooooo": 2}, "valid": false }, { "description": "multiple invalid matches is invalid", "data": {"foo": "bar", "foooooo" : "baz"}, "valid": false }, { "description": "ignores arrays", "data": ["foo"], "valid": true }, { "description": "ignores strings", "data": "foo", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "multiple simultaneous patternProperties are validated", "schema": { "patternProperties": { "a*": {"type": "integer"}, "aaa*": {"maximum": 20} } }, "tests": [ { "description": "a single valid match is valid", "data": {"a": 21}, "valid": true }, { "description": "a simultaneous match is valid", "data": {"aaaa": 18}, "valid": true }, { "description": "multiple matches is valid", "data": {"a": 21, "aaaa": 18}, "valid": true }, { "description": "an invalid due to one is invalid", "data": {"a": "bar"}, "valid": false }, { "description": "an invalid due to the other is invalid", "data": {"aaaa": 31}, "valid": false }, { "description": "an invalid due to both is invalid", "data": {"aaa": "foo", "aaaa": 31}, "valid": false } ] }, { "description": "regexes are not anchored by default and are case sensitive", "schema": { "patternProperties": { "[0-9]{2,}": { "type": "boolean" }, "X_": { "type": "string" } } }, "tests": [ { "description": "non recognized members are ignored", "data": { "answer 1": "42" }, "valid": true }, { "description": "recognized members are accounted for", "data": { "a31b": null }, "valid": false }, { "description": "regexes are case sensitive", "data": { "a_x_3": 3 }, "valid": true }, { "description": "regexes are case sensitive, 2", "data": { "a_X_3": 3 }, "valid": false } ] }, { "description": "patternProperties with boolean schemas", "schema": { "patternProperties": { "f.*": true, "b.*": false } }, "tests": [ { "description": "object with property matching schema true is valid", "data": {"foo": 1}, "valid": true }, { "description": "object with property matching schema false is invalid", "data": {"bar": 2}, "valid": false }, { "description": "object with both properties is invalid", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "object with a property matching both true and false is invalid", "data": {"foobar":1}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "patternProperties with null valued instance properties", "schema": { "patternProperties": { "^.*bar$": {"type": "null"} } }, "tests": [ { "description": "allows null values", "data": {"foobar": null}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/properties.json0000644000175100001770000001621114653725311023646 0ustar00runnerdocker[ { "description": "object properties validation", "schema": { "properties": { "foo": {"type": "integer"}, "bar": {"type": "string"} } }, "tests": [ { "description": "both properties present and valid is valid", "data": {"foo": 1, "bar": "baz"}, "valid": true }, { "description": "one property invalid is invalid", "data": {"foo": 1, "bar": {}}, "valid": false }, { "description": "both properties invalid is invalid", "data": {"foo": [], "bar": {}}, "valid": false }, { "description": "doesn't invalidate other properties", "data": {"quux": []}, "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "properties, patternProperties, additionalProperties interaction", "schema": { "properties": { "foo": {"type": "array", "maxItems": 3}, "bar": {"type": "array"} }, "patternProperties": {"f.o": {"minItems": 2}}, "additionalProperties": {"type": "integer"} }, "tests": [ { "description": "property validates property", "data": {"foo": [1, 2]}, "valid": true }, { "description": "property invalidates property", "data": {"foo": [1, 2, 3, 4]}, "valid": false }, { "description": "patternProperty invalidates property", "data": {"foo": []}, "valid": false }, { "description": "patternProperty validates nonproperty", "data": {"fxo": [1, 2]}, "valid": true }, { "description": "patternProperty invalidates nonproperty", "data": {"fxo": []}, "valid": false }, { "description": "additionalProperty ignores property", "data": {"bar": []}, "valid": true }, { "description": "additionalProperty validates others", "data": {"quux": 3}, "valid": true }, { "description": "additionalProperty invalidates others", "data": {"quux": "foo"}, "valid": false } ] }, { "description": "properties with boolean schema", "schema": { "properties": { "foo": true, "bar": false } }, "tests": [ { "description": "no property present is valid", "data": {}, "valid": true }, { "description": "only 'true' property present is valid", "data": {"foo": 1}, "valid": true }, { "description": "only 'false' property present is invalid", "data": {"bar": 2}, "valid": false }, { "description": "both properties present is invalid", "data": {"foo": 1, "bar": 2}, "valid": false } ] }, { "description": "properties with escaped characters", "schema": { "properties": { "foo\nbar": {"type": "number"}, "foo\"bar": {"type": "number"}, "foo\\bar": {"type": "number"}, "foo\rbar": {"type": "number"}, "foo\tbar": {"type": "number"}, "foo\fbar": {"type": "number"} } }, "tests": [ { "description": "object with all numbers is valid", "data": { "foo\nbar": 1, "foo\"bar": 1, "foo\\bar": 1, "foo\rbar": 1, "foo\tbar": 1, "foo\fbar": 1 }, "valid": true }, { "description": "object with strings is invalid", "data": { "foo\nbar": "1", "foo\"bar": "1", "foo\\bar": "1", "foo\rbar": "1", "foo\tbar": "1", "foo\fbar": "1" }, "valid": false } ] }, { "description": "properties with null valued instance properties", "schema": { "properties": { "foo": {"type": "null"} } }, "tests": [ { "description": "allows null values", "data": {"foo": null}, "valid": true } ] }, { "description": "properties whose names are Javascript object property names", "comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.", "schema": { "properties": { "__proto__": {"type": "number"}, "toString": { "properties": { "length": { "type": "string" } } }, "constructor": {"type": "number"} } }, "tests": [ { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "none of the properties mentioned", "data": {}, "valid": true }, { "description": "__proto__ not valid", "data": { "__proto__": "foo" }, "valid": false }, { "description": "toString not valid", "data": { "toString": { "length": 37 } }, "valid": false }, { "description": "constructor not valid", "data": { "constructor": { "length": 37 } }, "valid": false }, { "description": "all present and valid", "data": { "__proto__": 12, "toString": { "length": "foo" }, "constructor": 37 }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/propertyNames.json0000644000175100001770000000557714653725311024337 0ustar00runnerdocker[ { "description": "propertyNames validation", "schema": { "propertyNames": {"maxLength": 3} }, "tests": [ { "description": "all property names valid", "data": { "f": {}, "foo": {} }, "valid": true }, { "description": "some property names invalid", "data": { "foo": {}, "foobar": {} }, "valid": false }, { "description": "object without properties is valid", "data": {}, "valid": true }, { "description": "ignores arrays", "data": [1, 2, 3, 4], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "propertyNames validation with pattern", "schema": { "propertyNames": { "pattern": "^a+$" } }, "tests": [ { "description": "matching property names valid", "data": { "a": {}, "aa": {}, "aaa": {} }, "valid": true }, { "description": "non-matching property name is invalid", "data": { "aaA": {} }, "valid": false }, { "description": "object without properties is valid", "data": {}, "valid": true } ] }, { "description": "propertyNames with boolean schema true", "schema": {"propertyNames": true}, "tests": [ { "description": "object with any properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "propertyNames with boolean schema false", "schema": {"propertyNames": false}, "tests": [ { "description": "object with any properties is invalid", "data": {"foo": 1}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/ref.json0000644000175100001770000005545714653725311022245 0ustar00runnerdocker[ { "description": "root pointer ref", "schema": { "properties": { "foo": {"$ref": "#"} }, "additionalProperties": false }, "tests": [ { "description": "match", "data": {"foo": false}, "valid": true }, { "description": "recursive match", "data": {"foo": {"foo": false}}, "valid": true }, { "description": "mismatch", "data": {"bar": false}, "valid": false }, { "description": "recursive mismatch", "data": {"foo": {"bar": false}}, "valid": false } ] }, { "description": "relative pointer ref to object", "schema": { "properties": { "foo": {"type": "integer"}, "bar": {"$ref": "#/properties/foo"} } }, "tests": [ { "description": "match", "data": {"bar": 3}, "valid": true }, { "description": "mismatch", "data": {"bar": true}, "valid": false } ] }, { "description": "relative pointer ref to array", "schema": { "items": [ {"type": "integer"}, {"$ref": "#/items/0"} ] }, "tests": [ { "description": "match array", "data": [1, 2], "valid": true }, { "description": "mismatch array", "data": [1, "foo"], "valid": false } ] }, { "description": "escaped pointer ref", "schema": { "definitions": { "tilde~field": {"type": "integer"}, "slash/field": {"type": "integer"}, "percent%field": {"type": "integer"} }, "properties": { "tilde": {"$ref": "#/definitions/tilde~0field"}, "slash": {"$ref": "#/definitions/slash~1field"}, "percent": {"$ref": "#/definitions/percent%25field"} } }, "tests": [ { "description": "slash invalid", "data": {"slash": "aoeu"}, "valid": false }, { "description": "tilde invalid", "data": {"tilde": "aoeu"}, "valid": false }, { "description": "percent invalid", "data": {"percent": "aoeu"}, "valid": false }, { "description": "slash valid", "data": {"slash": 123}, "valid": true }, { "description": "tilde valid", "data": {"tilde": 123}, "valid": true }, { "description": "percent valid", "data": {"percent": 123}, "valid": true } ] }, { "description": "nested refs", "schema": { "definitions": { "a": {"type": "integer"}, "b": {"$ref": "#/definitions/a"}, "c": {"$ref": "#/definitions/b"} }, "allOf": [{ "$ref": "#/definitions/c" }] }, "tests": [ { "description": "nested ref valid", "data": 5, "valid": true }, { "description": "nested ref invalid", "data": "a", "valid": false } ] }, { "description": "ref overrides any sibling keywords", "schema": { "definitions": { "reffed": { "type": "array" } }, "properties": { "foo": { "$ref": "#/definitions/reffed", "maxItems": 2 } } }, "tests": [ { "description": "ref valid", "data": { "foo": [] }, "valid": true }, { "description": "ref valid, maxItems ignored", "data": { "foo": [ 1, 2, 3] }, "valid": true }, { "description": "ref invalid", "data": { "foo": "string" }, "valid": false } ] }, { "description": "$ref prevents a sibling $id from changing the base uri", "schema": { "$id": "http://localhost:1234/sibling_id/base/", "definitions": { "foo": { "$id": "http://localhost:1234/sibling_id/foo.json", "type": "string" }, "base_foo": { "$comment": "this canonical uri is http://localhost:1234/sibling_id/base/foo.json", "$id": "foo.json", "type": "number" } }, "allOf": [ { "$comment": "$ref resolves to http://localhost:1234/sibling_id/base/foo.json, not http://localhost:1234/sibling_id/foo.json", "$id": "http://localhost:1234/sibling_id/", "$ref": "foo.json" } ] }, "tests": [ { "description": "$ref resolves to /definitions/base_foo, data does not validate", "data": "a", "valid": false }, { "description": "$ref resolves to /definitions/base_foo, data validates", "data": 1, "valid": true } ] }, { "description": "remote ref, containing refs itself", "schema": {"$ref": "http://json-schema.org/draft-06/schema#"}, "tests": [ { "description": "remote ref valid", "data": {"minLength": 1}, "valid": true }, { "description": "remote ref invalid", "data": {"minLength": -1}, "valid": false } ] }, { "description": "property named $ref that is not a reference", "schema": { "properties": { "$ref": {"type": "string"} } }, "tests": [ { "description": "property named $ref valid", "data": {"$ref": "a"}, "valid": true }, { "description": "property named $ref invalid", "data": {"$ref": 2}, "valid": false } ] }, { "description": "property named $ref, containing an actual $ref", "schema": { "properties": { "$ref": {"$ref": "#/definitions/is-string"} }, "definitions": { "is-string": { "type": "string" } } }, "tests": [ { "description": "property named $ref valid", "data": {"$ref": "a"}, "valid": true }, { "description": "property named $ref invalid", "data": {"$ref": 2}, "valid": false } ] }, { "description": "$ref to boolean schema true", "schema": { "allOf": [{ "$ref": "#/definitions/bool" }], "definitions": { "bool": true } }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "$ref to boolean schema false", "schema": { "allOf": [{ "$ref": "#/definitions/bool" }], "definitions": { "bool": false } }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "Recursive references between schemas", "schema": { "$id": "http://localhost:1234/tree", "description": "tree of nodes", "type": "object", "properties": { "meta": {"type": "string"}, "nodes": { "type": "array", "items": {"$ref": "node"} } }, "required": ["meta", "nodes"], "definitions": { "node": { "$id": "http://localhost:1234/node", "description": "node", "type": "object", "properties": { "value": {"type": "number"}, "subtree": {"$ref": "tree"} }, "required": ["value"] } } }, "tests": [ { "description": "valid tree", "data": { "meta": "root", "nodes": [ { "value": 1, "subtree": { "meta": "child", "nodes": [ {"value": 1.1}, {"value": 1.2} ] } }, { "value": 2, "subtree": { "meta": "child", "nodes": [ {"value": 2.1}, {"value": 2.2} ] } } ] }, "valid": true }, { "description": "invalid tree", "data": { "meta": "root", "nodes": [ { "value": 1, "subtree": { "meta": "child", "nodes": [ {"value": "string is invalid"}, {"value": 1.2} ] } }, { "value": 2, "subtree": { "meta": "child", "nodes": [ {"value": 2.1}, {"value": 2.2} ] } } ] }, "valid": false } ] }, { "description": "refs with quote", "schema": { "properties": { "foo\"bar": {"$ref": "#/definitions/foo%22bar"} }, "definitions": { "foo\"bar": {"type": "number"} } }, "tests": [ { "description": "object with numbers is valid", "data": { "foo\"bar": 1 }, "valid": true }, { "description": "object with strings is invalid", "data": { "foo\"bar": "1" }, "valid": false } ] }, { "description": "Location-independent identifier", "schema": { "allOf": [{ "$ref": "#foo" }], "definitions": { "A": { "$id": "#foo", "type": "integer" } } }, "tests": [ { "data": 1, "description": "match", "valid": true }, { "data": "a", "description": "mismatch", "valid": false } ] }, { "description": "Location-independent identifier with base URI change in subschema", "schema": { "$id": "http://localhost:1234/root", "allOf": [{ "$ref": "http://localhost:1234/nested.json#foo" }], "definitions": { "A": { "$id": "nested.json", "definitions": { "B": { "$id": "#foo", "type": "integer" } } } } }, "tests": [ { "data": 1, "description": "match", "valid": true }, { "data": "a", "description": "mismatch", "valid": false } ] }, { "description": "naive replacement of $ref with its destination is not correct", "schema": { "definitions": { "a_string": { "type": "string" } }, "enum": [ { "$ref": "#/definitions/a_string" } ] }, "tests": [ { "description": "do not evaluate the $ref inside the enum, matching any string", "data": "this is a string", "valid": false }, { "description": "do not evaluate the $ref inside the enum, definition exact match", "data": { "type": "string" }, "valid": false }, { "description": "match the enum exactly", "data": { "$ref": "#/definitions/a_string" }, "valid": true } ] }, { "description": "refs with relative uris and defs", "schema": { "$id": "http://example.com/schema-relative-uri-defs1.json", "properties": { "foo": { "$id": "schema-relative-uri-defs2.json", "definitions": { "inner": { "properties": { "bar": { "type": "string" } } } }, "allOf": [ { "$ref": "#/definitions/inner" } ] } }, "allOf": [ { "$ref": "schema-relative-uri-defs2.json" } ] }, "tests": [ { "description": "invalid on inner field", "data": { "foo": { "bar": 1 }, "bar": "a" }, "valid": false }, { "description": "invalid on outer field", "data": { "foo": { "bar": "a" }, "bar": 1 }, "valid": false }, { "description": "valid on both fields", "data": { "foo": { "bar": "a" }, "bar": "a" }, "valid": true } ] }, { "description": "relative refs with absolute uris and defs", "schema": { "$id": "http://example.com/schema-refs-absolute-uris-defs1.json", "properties": { "foo": { "$id": "http://example.com/schema-refs-absolute-uris-defs2.json", "definitions": { "inner": { "properties": { "bar": { "type": "string" } } } }, "allOf": [ { "$ref": "#/definitions/inner" } ] } }, "allOf": [ { "$ref": "schema-refs-absolute-uris-defs2.json" } ] }, "tests": [ { "description": "invalid on inner field", "data": { "foo": { "bar": 1 }, "bar": "a" }, "valid": false }, { "description": "invalid on outer field", "data": { "foo": { "bar": "a" }, "bar": 1 }, "valid": false }, { "description": "valid on both fields", "data": { "foo": { "bar": "a" }, "bar": "a" }, "valid": true } ] }, { "description": "simple URN base URI with $ref via the URN", "schema": { "$comment": "URIs do not have to have HTTP(s) schemes", "$id": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed", "minimum": 30, "properties": { "foo": {"$ref": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed"} } }, "tests": [ { "description": "valid under the URN IDed schema", "data": {"foo": 37}, "valid": true }, { "description": "invalid under the URN IDed schema", "data": {"foo": 12}, "valid": false } ] }, { "description": "simple URN base URI with JSON pointer", "schema": { "$comment": "URIs do not have to have HTTP(s) schemes", "$id": "urn:uuid:deadbeef-1234-00ff-ff00-4321feebdaed", "properties": { "foo": {"$ref": "#/definitions/bar"} }, "definitions": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with NSS", "schema": { "$comment": "RFC 8141 §2.2", "$id": "urn:example:1/406/47452/2", "properties": { "foo": {"$ref": "#/definitions/bar"} }, "definitions": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with r-component", "schema": { "$comment": "RFC 8141 §2.3.1", "$id": "urn:example:foo-bar-baz-qux?+CCResolve:cc=uk", "properties": { "foo": {"$ref": "#/definitions/bar"} }, "definitions": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with q-component", "schema": { "$comment": "RFC 8141 §2.3.2", "$id": "urn:example:weather?=op=map&lat=39.56&lon=-104.85&datetime=1969-07-21T02:56:15Z", "properties": { "foo": {"$ref": "#/definitions/bar"} }, "definitions": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with URN and JSON pointer ref", "schema": { "$id": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed", "properties": { "foo": {"$ref": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed#/definitions/bar"} }, "definitions": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with URN and anchor ref", "schema": { "$id": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed", "properties": { "foo": {"$ref": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed#something"} }, "definitions": { "bar": { "$id": "#something", "type": "string" } } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/refRemote.json0000644000175100001770000001504014653725311023401 0ustar00runnerdocker[ { "description": "remote ref", "schema": {"$ref": "http://localhost:1234/integer.json"}, "tests": [ { "description": "remote ref valid", "data": 1, "valid": true }, { "description": "remote ref invalid", "data": "a", "valid": false } ] }, { "description": "fragment within remote ref", "schema": {"$ref": "http://localhost:1234/subSchemas.json#/integer"}, "tests": [ { "description": "remote fragment valid", "data": 1, "valid": true }, { "description": "remote fragment invalid", "data": "a", "valid": false } ] }, { "description": "ref within remote ref", "schema": { "$ref": "http://localhost:1234/subSchemas.json#/refToInteger" }, "tests": [ { "description": "ref within ref valid", "data": 1, "valid": true }, { "description": "ref within ref invalid", "data": "a", "valid": false } ] }, { "description": "base URI change", "schema": { "$id": "http://localhost:1234/", "items": { "$id": "baseUriChange/", "items": {"$ref": "folderInteger.json"} } }, "tests": [ { "description": "base URI change ref valid", "data": [[1]], "valid": true }, { "description": "base URI change ref invalid", "data": [["a"]], "valid": false } ] }, { "description": "base URI change - change folder", "schema": { "$id": "http://localhost:1234/scope_change_defs1.json", "type" : "object", "properties": { "list": {"$ref": "#/definitions/baz"} }, "definitions": { "baz": { "$id": "baseUriChangeFolder/", "type": "array", "items": {"$ref": "folderInteger.json"} } } }, "tests": [ { "description": "number is valid", "data": {"list": [1]}, "valid": true }, { "description": "string is invalid", "data": {"list": ["a"]}, "valid": false } ] }, { "description": "base URI change - change folder in subschema", "schema": { "$id": "http://localhost:1234/scope_change_defs2.json", "type" : "object", "properties": { "list": {"$ref": "#/definitions/baz/definitions/bar"} }, "definitions": { "baz": { "$id": "baseUriChangeFolderInSubschema/", "definitions": { "bar": { "type": "array", "items": {"$ref": "folderInteger.json"} } } } } }, "tests": [ { "description": "number is valid", "data": {"list": [1]}, "valid": true }, { "description": "string is invalid", "data": {"list": ["a"]}, "valid": false } ] }, { "description": "root ref in remote ref", "schema": { "$id": "http://localhost:1234/object", "type": "object", "properties": { "name": {"$ref": "name.json#/definitions/orNull"} } }, "tests": [ { "description": "string is valid", "data": { "name": "foo" }, "valid": true }, { "description": "null is valid", "data": { "name": null }, "valid": true }, { "description": "object is invalid", "data": { "name": { "name": null } }, "valid": false } ] }, { "description": "remote ref with ref to definitions", "schema": { "$id": "http://localhost:1234/schema-remote-ref-ref-defs1.json", "allOf": [ { "$ref": "ref-and-definitions.json" } ] }, "tests": [ { "description": "invalid", "data": { "bar": 1 }, "valid": false }, { "description": "valid", "data": { "bar": "a" }, "valid": true } ] }, { "description": "Location-independent identifier in remote ref", "schema": { "$ref": "http://localhost:1234/locationIndependentIdentifierPre2019.json#/definitions/refToInteger" }, "tests": [ { "description": "integer is valid", "data": 1, "valid": true }, { "description": "string is invalid", "data": "foo", "valid": false } ] }, { "description": "retrieved nested refs resolve relative to their URI not $id", "schema": { "$id": "http://localhost:1234/some-id", "properties": { "name": {"$ref": "nested/foo-ref-string.json"} } }, "tests": [ { "description": "number is invalid", "data": { "name": {"foo": 1} }, "valid": false }, { "description": "string is valid", "data": { "name": {"foo": "a"} }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/required.json0000644000175100001770000001023414653725311023271 0ustar00runnerdocker[ { "description": "required validation", "schema": { "properties": { "foo": {}, "bar": {} }, "required": ["foo"] }, "tests": [ { "description": "present required property is valid", "data": {"foo": 1}, "valid": true }, { "description": "non-present required property is invalid", "data": {"bar": 1}, "valid": false }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "required default validation", "schema": { "properties": { "foo": {} } }, "tests": [ { "description": "not required by default", "data": {}, "valid": true } ] }, { "description": "required with empty array", "schema": { "properties": { "foo": {} }, "required": [] }, "tests": [ { "description": "property not required", "data": {}, "valid": true } ] }, { "description": "required with escaped characters", "schema": { "required": [ "foo\nbar", "foo\"bar", "foo\\bar", "foo\rbar", "foo\tbar", "foo\fbar" ] }, "tests": [ { "description": "object with all properties present is valid", "data": { "foo\nbar": 1, "foo\"bar": 1, "foo\\bar": 1, "foo\rbar": 1, "foo\tbar": 1, "foo\fbar": 1 }, "valid": true }, { "description": "object with some properties missing is invalid", "data": { "foo\nbar": "1", "foo\"bar": "1" }, "valid": false } ] }, { "description": "required properties whose names are Javascript object property names", "comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.", "schema": { "required": ["__proto__", "toString", "constructor"] }, "tests": [ { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "none of the properties mentioned", "data": {}, "valid": false }, { "description": "__proto__ present", "data": { "__proto__": "foo" }, "valid": false }, { "description": "toString present", "data": { "toString": { "length": 37 } }, "valid": false }, { "description": "constructor present", "data": { "constructor": { "length": 37 } }, "valid": false }, { "description": "all present", "data": { "__proto__": 12, "toString": { "length": "foo" }, "constructor": 37 }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/type.json0000644000175100001770000003214014653725311022432 0ustar00runnerdocker[ { "description": "integer type matches integers", "schema": {"type": "integer"}, "tests": [ { "description": "an integer is an integer", "data": 1, "valid": true }, { "description": "a float with zero fractional part is an integer", "data": 1.0, "valid": true }, { "description": "a float is not an integer", "data": 1.1, "valid": false }, { "description": "a string is not an integer", "data": "foo", "valid": false }, { "description": "a string is still not an integer, even if it looks like one", "data": "1", "valid": false }, { "description": "an object is not an integer", "data": {}, "valid": false }, { "description": "an array is not an integer", "data": [], "valid": false }, { "description": "a boolean is not an integer", "data": true, "valid": false }, { "description": "null is not an integer", "data": null, "valid": false } ] }, { "description": "number type matches numbers", "schema": {"type": "number"}, "tests": [ { "description": "an integer is a number", "data": 1, "valid": true }, { "description": "a float with zero fractional part is a number (and an integer)", "data": 1.0, "valid": true }, { "description": "a float is a number", "data": 1.1, "valid": true }, { "description": "a string is not a number", "data": "foo", "valid": false }, { "description": "a string is still not a number, even if it looks like one", "data": "1", "valid": false }, { "description": "an object is not a number", "data": {}, "valid": false }, { "description": "an array is not a number", "data": [], "valid": false }, { "description": "a boolean is not a number", "data": true, "valid": false }, { "description": "null is not a number", "data": null, "valid": false } ] }, { "description": "string type matches strings", "schema": {"type": "string"}, "tests": [ { "description": "1 is not a string", "data": 1, "valid": false }, { "description": "a float is not a string", "data": 1.1, "valid": false }, { "description": "a string is a string", "data": "foo", "valid": true }, { "description": "a string is still a string, even if it looks like a number", "data": "1", "valid": true }, { "description": "an empty string is still a string", "data": "", "valid": true }, { "description": "an object is not a string", "data": {}, "valid": false }, { "description": "an array is not a string", "data": [], "valid": false }, { "description": "a boolean is not a string", "data": true, "valid": false }, { "description": "null is not a string", "data": null, "valid": false } ] }, { "description": "object type matches objects", "schema": {"type": "object"}, "tests": [ { "description": "an integer is not an object", "data": 1, "valid": false }, { "description": "a float is not an object", "data": 1.1, "valid": false }, { "description": "a string is not an object", "data": "foo", "valid": false }, { "description": "an object is an object", "data": {}, "valid": true }, { "description": "an array is not an object", "data": [], "valid": false }, { "description": "a boolean is not an object", "data": true, "valid": false }, { "description": "null is not an object", "data": null, "valid": false } ] }, { "description": "array type matches arrays", "schema": {"type": "array"}, "tests": [ { "description": "an integer is not an array", "data": 1, "valid": false }, { "description": "a float is not an array", "data": 1.1, "valid": false }, { "description": "a string is not an array", "data": "foo", "valid": false }, { "description": "an object is not an array", "data": {}, "valid": false }, { "description": "an array is an array", "data": [], "valid": true }, { "description": "a boolean is not an array", "data": true, "valid": false }, { "description": "null is not an array", "data": null, "valid": false } ] }, { "description": "boolean type matches booleans", "schema": {"type": "boolean"}, "tests": [ { "description": "an integer is not a boolean", "data": 1, "valid": false }, { "description": "zero is not a boolean", "data": 0, "valid": false }, { "description": "a float is not a boolean", "data": 1.1, "valid": false }, { "description": "a string is not a boolean", "data": "foo", "valid": false }, { "description": "an empty string is not a boolean", "data": "", "valid": false }, { "description": "an object is not a boolean", "data": {}, "valid": false }, { "description": "an array is not a boolean", "data": [], "valid": false }, { "description": "true is a boolean", "data": true, "valid": true }, { "description": "false is a boolean", "data": false, "valid": true }, { "description": "null is not a boolean", "data": null, "valid": false } ] }, { "description": "null type matches only the null object", "schema": {"type": "null"}, "tests": [ { "description": "an integer is not null", "data": 1, "valid": false }, { "description": "a float is not null", "data": 1.1, "valid": false }, { "description": "zero is not null", "data": 0, "valid": false }, { "description": "a string is not null", "data": "foo", "valid": false }, { "description": "an empty string is not null", "data": "", "valid": false }, { "description": "an object is not null", "data": {}, "valid": false }, { "description": "an array is not null", "data": [], "valid": false }, { "description": "true is not null", "data": true, "valid": false }, { "description": "false is not null", "data": false, "valid": false }, { "description": "null is null", "data": null, "valid": true } ] }, { "description": "multiple types can be specified in an array", "schema": {"type": ["integer", "string"]}, "tests": [ { "description": "an integer is valid", "data": 1, "valid": true }, { "description": "a string is valid", "data": "foo", "valid": true }, { "description": "a float is invalid", "data": 1.1, "valid": false }, { "description": "an object is invalid", "data": {}, "valid": false }, { "description": "an array is invalid", "data": [], "valid": false }, { "description": "a boolean is invalid", "data": true, "valid": false }, { "description": "null is invalid", "data": null, "valid": false } ] }, { "description": "type as array with one item", "schema": { "type": ["string"] }, "tests": [ { "description": "string is valid", "data": "foo", "valid": true }, { "description": "number is invalid", "data": 123, "valid": false } ] }, { "description": "type: array or object", "schema": { "type": ["array", "object"] }, "tests": [ { "description": "array is valid", "data": [1,2,3], "valid": true }, { "description": "object is valid", "data": {"foo": 123}, "valid": true }, { "description": "number is invalid", "data": 123, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false }, { "description": "null is invalid", "data": null, "valid": false } ] }, { "description": "type: array, object or null", "schema": { "type": ["array", "object", "null"] }, "tests": [ { "description": "array is valid", "data": [1,2,3], "valid": true }, { "description": "object is valid", "data": {"foo": 123}, "valid": true }, { "description": "null is valid", "data": null, "valid": true }, { "description": "number is invalid", "data": 123, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/uniqueItems.json0000644000175100001770000003274014653725311023767 0ustar00runnerdocker[ { "description": "uniqueItems validation", "schema": {"uniqueItems": true}, "tests": [ { "description": "unique array of integers is valid", "data": [1, 2], "valid": true }, { "description": "non-unique array of integers is invalid", "data": [1, 1], "valid": false }, { "description": "non-unique array of more than two integers is invalid", "data": [1, 2, 1], "valid": false }, { "description": "numbers are unique if mathematically unequal", "data": [1.0, 1.00, 1], "valid": false }, { "description": "false is not equal to zero", "data": [0, false], "valid": true }, { "description": "true is not equal to one", "data": [1, true], "valid": true }, { "description": "unique array of strings is valid", "data": ["foo", "bar", "baz"], "valid": true }, { "description": "non-unique array of strings is invalid", "data": ["foo", "bar", "foo"], "valid": false }, { "description": "unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "baz"}], "valid": true }, { "description": "non-unique array of objects is invalid", "data": [{"foo": "bar"}, {"foo": "bar"}], "valid": false }, { "description": "unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : false}}} ], "valid": true }, { "description": "non-unique array of nested objects is invalid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : true}}} ], "valid": false }, { "description": "unique array of arrays is valid", "data": [["foo"], ["bar"]], "valid": true }, { "description": "non-unique array of arrays is invalid", "data": [["foo"], ["foo"]], "valid": false }, { "description": "non-unique array of more than two arrays is invalid", "data": [["foo"], ["bar"], ["foo"]], "valid": false }, { "description": "1 and true are unique", "data": [1, true], "valid": true }, { "description": "0 and false are unique", "data": [0, false], "valid": true }, { "description": "[1] and [true] are unique", "data": [[1], [true]], "valid": true }, { "description": "[0] and [false] are unique", "data": [[0], [false]], "valid": true }, { "description": "nested [1] and [true] are unique", "data": [[[1], "foo"], [[true], "foo"]], "valid": true }, { "description": "nested [0] and [false] are unique", "data": [[[0], "foo"], [[false], "foo"]], "valid": true }, { "description": "unique heterogeneous types are valid", "data": [{}, [1], true, null, 1, "{}"], "valid": true }, { "description": "non-unique heterogeneous types are invalid", "data": [{}, [1], true, null, {}, 1], "valid": false }, { "description": "different objects are unique", "data": [{"a": 1, "b": 2}, {"a": 2, "b": 1}], "valid": true }, { "description": "objects are non-unique despite key order", "data": [{"a": 1, "b": 2}, {"b": 2, "a": 1}], "valid": false }, { "description": "{\"a\": false} and {\"a\": 0} are unique", "data": [{"a": false}, {"a": 0}], "valid": true }, { "description": "{\"a\": true} and {\"a\": 1} are unique", "data": [{"a": true}, {"a": 1}], "valid": true } ] }, { "description": "uniqueItems with an array of items", "schema": { "items": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": true }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is not valid", "data": [false, false], "valid": false }, { "description": "[true, true] from items array is not valid", "data": [true, true], "valid": false }, { "description": "unique array extended from [false, true] is valid", "data": [false, true, "foo", "bar"], "valid": true }, { "description": "unique array extended from [true, false] is valid", "data": [true, false, "foo", "bar"], "valid": true }, { "description": "non-unique array extended from [false, true] is not valid", "data": [false, true, "foo", "foo"], "valid": false }, { "description": "non-unique array extended from [true, false] is not valid", "data": [true, false, "foo", "foo"], "valid": false } ] }, { "description": "uniqueItems with an array of items and additionalItems=false", "schema": { "items": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": true, "additionalItems": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is not valid", "data": [false, false], "valid": false }, { "description": "[true, true] from items array is not valid", "data": [true, true], "valid": false }, { "description": "extra items are invalid even if unique", "data": [false, true, null], "valid": false } ] }, { "description": "uniqueItems=false validation", "schema": { "uniqueItems": false }, "tests": [ { "description": "unique array of integers is valid", "data": [1, 2], "valid": true }, { "description": "non-unique array of integers is valid", "data": [1, 1], "valid": true }, { "description": "numbers are unique if mathematically unequal", "data": [1.0, 1.00, 1], "valid": true }, { "description": "false is not equal to zero", "data": [0, false], "valid": true }, { "description": "true is not equal to one", "data": [1, true], "valid": true }, { "description": "unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "baz"}], "valid": true }, { "description": "non-unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "bar"}], "valid": true }, { "description": "unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : false}}} ], "valid": true }, { "description": "non-unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : true}}} ], "valid": true }, { "description": "unique array of arrays is valid", "data": [["foo"], ["bar"]], "valid": true }, { "description": "non-unique array of arrays is valid", "data": [["foo"], ["foo"]], "valid": true }, { "description": "1 and true are unique", "data": [1, true], "valid": true }, { "description": "0 and false are unique", "data": [0, false], "valid": true }, { "description": "unique heterogeneous types are valid", "data": [{}, [1], true, null, 1], "valid": true }, { "description": "non-unique heterogeneous types are valid", "data": [{}, [1], true, null, {}, 1], "valid": true } ] }, { "description": "uniqueItems=false with an array of items", "schema": { "items": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is valid", "data": [false, false], "valid": true }, { "description": "[true, true] from items array is valid", "data": [true, true], "valid": true }, { "description": "unique array extended from [false, true] is valid", "data": [false, true, "foo", "bar"], "valid": true }, { "description": "unique array extended from [true, false] is valid", "data": [true, false, "foo", "bar"], "valid": true }, { "description": "non-unique array extended from [false, true] is valid", "data": [false, true, "foo", "foo"], "valid": true }, { "description": "non-unique array extended from [true, false] is valid", "data": [true, false, "foo", "foo"], "valid": true } ] }, { "description": "uniqueItems=false with an array of items and additionalItems=false", "schema": { "items": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": false, "additionalItems": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is valid", "data": [false, false], "valid": true }, { "description": "[true, true] from items array is valid", "data": [true, true], "valid": true }, { "description": "extra items are invalid even if unique", "data": [false, true, null], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft6/unknownKeyword.json0000644000175100001770000000374214653725311024523 0ustar00runnerdocker[ { "description": "$id inside an unknown keyword is not a real identifier", "comment": "the implementation must not be confused by an $id in locations we do not know how to parse", "schema": { "definitions": { "id_in_unknown0": { "not": { "array_of_schemas": [ { "$id": "https://localhost:1234/unknownKeyword/my_identifier.json", "type": "null" } ] } }, "real_id_in_schema": { "$id": "https://localhost:1234/unknownKeyword/my_identifier.json", "type": "string" }, "id_in_unknown1": { "not": { "object_of_schemas": { "foo": { "$id": "https://localhost:1234/unknownKeyword/my_identifier.json", "type": "integer" } } } } }, "anyOf": [ { "$ref": "#/definitions/id_in_unknown0" }, { "$ref": "#/definitions/id_in_unknown1" }, { "$ref": "https://localhost:1234/unknownKeyword/my_identifier.json" } ] }, "tests": [ { "description": "type matches second anyOf, which has a real schema in it", "data": "a string", "valid": true }, { "description": "type matches non-schema in first anyOf", "data": null, "valid": false }, { "description": "type matches non-schema in third anyOf", "data": 1, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1090975 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/0000755000175100001770000000000014653725331020561 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/additionalItems.json0000644000175100001770000001114714653725311024570 0ustar00runnerdocker[ { "description": "additionalItems as schema", "schema": { "items": [{}], "additionalItems": {"type": "integer"} }, "tests": [ { "description": "additional items match schema", "data": [ null, 2, 3, 4 ], "valid": true }, { "description": "additional items do not match schema", "data": [ null, 2, 3, "foo" ], "valid": false } ] }, { "description": "when items is schema, additionalItems does nothing", "schema": { "items": {}, "additionalItems": false }, "tests": [ { "description": "all items match schema", "data": [ 1, 2, 3, 4, 5 ], "valid": true } ] }, { "description": "array of items with no additionalItems permitted", "schema": { "items": [{}, {}, {}], "additionalItems": false }, "tests": [ { "description": "empty array", "data": [ ], "valid": true }, { "description": "fewer number of items present (1)", "data": [ 1 ], "valid": true }, { "description": "fewer number of items present (2)", "data": [ 1, 2 ], "valid": true }, { "description": "equal number of items present", "data": [ 1, 2, 3 ], "valid": true }, { "description": "additional items are not permitted", "data": [ 1, 2, 3, 4 ], "valid": false } ] }, { "description": "additionalItems as false without items", "schema": {"additionalItems": false}, "tests": [ { "description": "items defaults to empty schema so everything is valid", "data": [ 1, 2, 3, 4, 5 ], "valid": true }, { "description": "ignores non-arrays", "data": {"foo" : "bar"}, "valid": true } ] }, { "description": "additionalItems are allowed by default", "schema": {"items": [{"type": "integer"}]}, "tests": [ { "description": "only the first item is validated", "data": [1, "foo", false], "valid": true } ] }, { "description": "additionalItems does not look in applicators, valid case", "schema": { "allOf": [ { "items": [ { "type": "integer" } ] } ], "additionalItems": { "type": "boolean" } }, "tests": [ { "description": "items defined in allOf are not examined", "data": [ 1, null ], "valid": true } ] }, { "description": "additionalItems does not look in applicators, invalid case", "schema": { "allOf": [ { "items": [ { "type": "integer" }, { "type": "string" } ] } ], "items": [ {"type": "integer" } ], "additionalItems": { "type": "boolean" } }, "tests": [ { "description": "items defined in allOf are not examined", "data": [ 1, "hello" ], "valid": false } ] }, { "description": "items validation adjusts the starting index for additionalItems", "schema": { "items": [ { "type": "string" } ], "additionalItems": { "type": "integer" } }, "tests": [ { "description": "valid items", "data": [ "x", 2, 3 ], "valid": true }, { "description": "wrong type of second item", "data": [ "x", "y" ], "valid": false } ] }, { "description": "additionalItems with null instance elements", "schema": { "additionalItems": { "type": "null" } }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/additionalProperties.json0000644000175100001770000001051214653725311025636 0ustar00runnerdocker[ { "description": "additionalProperties being false does not allow other properties", "schema": { "properties": {"foo": {}, "bar": {}}, "patternProperties": { "^v": {} }, "additionalProperties": false }, "tests": [ { "description": "no additional properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "an additional property is invalid", "data": {"foo" : 1, "bar" : 2, "quux" : "boom"}, "valid": false }, { "description": "ignores arrays", "data": [1, 2, 3], "valid": true }, { "description": "ignores strings", "data": "foobarbaz", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "patternProperties are not additional properties", "data": {"foo":1, "vroom": 2}, "valid": true } ] }, { "description": "non-ASCII pattern with additionalProperties", "schema": { "patternProperties": {"^á": {}}, "additionalProperties": false }, "tests": [ { "description": "matching the pattern is valid", "data": {"ármányos": 2}, "valid": true }, { "description": "not matching the pattern is invalid", "data": {"élmény": 2}, "valid": false } ] }, { "description": "additionalProperties with schema", "schema": { "properties": {"foo": {}, "bar": {}}, "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "no additional properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "an additional valid property is valid", "data": {"foo" : 1, "bar" : 2, "quux" : true}, "valid": true }, { "description": "an additional invalid property is invalid", "data": {"foo" : 1, "bar" : 2, "quux" : 12}, "valid": false } ] }, { "description": "additionalProperties can exist by itself", "schema": { "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "an additional valid property is valid", "data": {"foo" : true}, "valid": true }, { "description": "an additional invalid property is invalid", "data": {"foo" : 1}, "valid": false } ] }, { "description": "additionalProperties are allowed by default", "schema": {"properties": {"foo": {}, "bar": {}}}, "tests": [ { "description": "additional properties are allowed", "data": {"foo": 1, "bar": 2, "quux": true}, "valid": true } ] }, { "description": "additionalProperties does not look in applicators", "schema": { "allOf": [ {"properties": {"foo": {}}} ], "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "properties defined in allOf are not examined", "data": {"foo": 1, "bar": true}, "valid": false } ] }, { "description": "additionalProperties with null valued instance properties", "schema": { "additionalProperties": { "type": "null" } }, "tests": [ { "description": "allows null values", "data": {"foo": null}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/allOf.json0000644000175100001770000001714714653725311022521 0ustar00runnerdocker[ { "description": "allOf", "schema": { "allOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "allOf", "data": {"foo": "baz", "bar": 2}, "valid": true }, { "description": "mismatch second", "data": {"foo": "baz"}, "valid": false }, { "description": "mismatch first", "data": {"bar": 2}, "valid": false }, { "description": "wrong type", "data": {"foo": "baz", "bar": "quux"}, "valid": false } ] }, { "description": "allOf with base schema", "schema": { "properties": {"bar": {"type": "integer"}}, "required": ["bar"], "allOf" : [ { "properties": { "foo": {"type": "string"} }, "required": ["foo"] }, { "properties": { "baz": {"type": "null"} }, "required": ["baz"] } ] }, "tests": [ { "description": "valid", "data": {"foo": "quux", "bar": 2, "baz": null}, "valid": true }, { "description": "mismatch base schema", "data": {"foo": "quux", "baz": null}, "valid": false }, { "description": "mismatch first allOf", "data": {"bar": 2, "baz": null}, "valid": false }, { "description": "mismatch second allOf", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "mismatch both", "data": {"bar": 2}, "valid": false } ] }, { "description": "allOf simple types", "schema": { "allOf": [ {"maximum": 30}, {"minimum": 20} ] }, "tests": [ { "description": "valid", "data": 25, "valid": true }, { "description": "mismatch one", "data": 35, "valid": false } ] }, { "description": "allOf with boolean schemas, all true", "schema": {"allOf": [true, true]}, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "allOf with boolean schemas, some false", "schema": {"allOf": [true, false]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "allOf with boolean schemas, all false", "schema": {"allOf": [false, false]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "allOf with one empty schema", "schema": { "allOf": [ {} ] }, "tests": [ { "description": "any data is valid", "data": 1, "valid": true } ] }, { "description": "allOf with two empty schemas", "schema": { "allOf": [ {}, {} ] }, "tests": [ { "description": "any data is valid", "data": 1, "valid": true } ] }, { "description": "allOf with the first empty schema", "schema": { "allOf": [ {}, { "type": "number" } ] }, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is invalid", "data": "foo", "valid": false } ] }, { "description": "allOf with the last empty schema", "schema": { "allOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is invalid", "data": "foo", "valid": false } ] }, { "description": "nested allOf, to check validation semantics", "schema": { "allOf": [ { "allOf": [ { "type": "null" } ] } ] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "anything non-null is invalid", "data": 123, "valid": false } ] }, { "description": "allOf combined with anyOf, oneOf", "schema": { "allOf": [ { "multipleOf": 2 } ], "anyOf": [ { "multipleOf": 3 } ], "oneOf": [ { "multipleOf": 5 } ] }, "tests": [ { "description": "allOf: false, anyOf: false, oneOf: false", "data": 1, "valid": false }, { "description": "allOf: false, anyOf: false, oneOf: true", "data": 5, "valid": false }, { "description": "allOf: false, anyOf: true, oneOf: false", "data": 3, "valid": false }, { "description": "allOf: false, anyOf: true, oneOf: true", "data": 15, "valid": false }, { "description": "allOf: true, anyOf: false, oneOf: false", "data": 2, "valid": false }, { "description": "allOf: true, anyOf: false, oneOf: true", "data": 10, "valid": false }, { "description": "allOf: true, anyOf: true, oneOf: false", "data": 6, "valid": false }, { "description": "allOf: true, anyOf: true, oneOf: true", "data": 30, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/anyOf.json0000644000175100001770000001133314653725311022527 0ustar00runnerdocker[ { "description": "anyOf", "schema": { "anyOf": [ { "type": "integer" }, { "minimum": 2 } ] }, "tests": [ { "description": "first anyOf valid", "data": 1, "valid": true }, { "description": "second anyOf valid", "data": 2.5, "valid": true }, { "description": "both anyOf valid", "data": 3, "valid": true }, { "description": "neither anyOf valid", "data": 1.5, "valid": false } ] }, { "description": "anyOf with base schema", "schema": { "type": "string", "anyOf" : [ { "maxLength": 2 }, { "minLength": 4 } ] }, "tests": [ { "description": "mismatch base schema", "data": 3, "valid": false }, { "description": "one anyOf valid", "data": "foobar", "valid": true }, { "description": "both anyOf invalid", "data": "foo", "valid": false } ] }, { "description": "anyOf with boolean schemas, all true", "schema": {"anyOf": [true, true]}, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "anyOf with boolean schemas, some true", "schema": {"anyOf": [true, false]}, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "anyOf with boolean schemas, all false", "schema": {"anyOf": [false, false]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "anyOf complex types", "schema": { "anyOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "first anyOf valid (complex)", "data": {"bar": 2}, "valid": true }, { "description": "second anyOf valid (complex)", "data": {"foo": "baz"}, "valid": true }, { "description": "both anyOf valid (complex)", "data": {"foo": "baz", "bar": 2}, "valid": true }, { "description": "neither anyOf valid (complex)", "data": {"foo": 2, "bar": "quux"}, "valid": false } ] }, { "description": "anyOf with one empty schema", "schema": { "anyOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "string is valid", "data": "foo", "valid": true }, { "description": "number is valid", "data": 123, "valid": true } ] }, { "description": "nested anyOf, to check validation semantics", "schema": { "anyOf": [ { "anyOf": [ { "type": "null" } ] } ] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "anything non-null is invalid", "data": 123, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/boolean_schema.json0000644000175100001770000000540214653725311024412 0ustar00runnerdocker[ { "description": "boolean schema 'true'", "schema": true, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is valid", "data": "foo", "valid": true }, { "description": "boolean true is valid", "data": true, "valid": true }, { "description": "boolean false is valid", "data": false, "valid": true }, { "description": "null is valid", "data": null, "valid": true }, { "description": "object is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "empty object is valid", "data": {}, "valid": true }, { "description": "array is valid", "data": ["foo"], "valid": true }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "boolean schema 'false'", "schema": false, "tests": [ { "description": "number is invalid", "data": 1, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false }, { "description": "boolean true is invalid", "data": true, "valid": false }, { "description": "boolean false is invalid", "data": false, "valid": false }, { "description": "null is invalid", "data": null, "valid": false }, { "description": "object is invalid", "data": {"foo": "bar"}, "valid": false }, { "description": "empty object is invalid", "data": {}, "valid": false }, { "description": "array is invalid", "data": ["foo"], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/const.json0000644000175100001770000002256414653725311022611 0ustar00runnerdocker[ { "description": "const validation", "schema": {"const": 2}, "tests": [ { "description": "same value is valid", "data": 2, "valid": true }, { "description": "another value is invalid", "data": 5, "valid": false }, { "description": "another type is invalid", "data": "a", "valid": false } ] }, { "description": "const with object", "schema": {"const": {"foo": "bar", "baz": "bax"}}, "tests": [ { "description": "same object is valid", "data": {"foo": "bar", "baz": "bax"}, "valid": true }, { "description": "same object with different property order is valid", "data": {"baz": "bax", "foo": "bar"}, "valid": true }, { "description": "another object is invalid", "data": {"foo": "bar"}, "valid": false }, { "description": "another type is invalid", "data": [1, 2], "valid": false } ] }, { "description": "const with array", "schema": {"const": [{ "foo": "bar" }]}, "tests": [ { "description": "same array is valid", "data": [{"foo": "bar"}], "valid": true }, { "description": "another array item is invalid", "data": [2], "valid": false }, { "description": "array with additional items is invalid", "data": [1, 2, 3], "valid": false } ] }, { "description": "const with null", "schema": {"const": null}, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "not null is invalid", "data": 0, "valid": false } ] }, { "description": "const with false does not match 0", "schema": {"const": false}, "tests": [ { "description": "false is valid", "data": false, "valid": true }, { "description": "integer zero is invalid", "data": 0, "valid": false }, { "description": "float zero is invalid", "data": 0.0, "valid": false } ] }, { "description": "const with true does not match 1", "schema": {"const": true}, "tests": [ { "description": "true is valid", "data": true, "valid": true }, { "description": "integer one is invalid", "data": 1, "valid": false }, { "description": "float one is invalid", "data": 1.0, "valid": false } ] }, { "description": "const with [false] does not match [0]", "schema": {"const": [false]}, "tests": [ { "description": "[false] is valid", "data": [false], "valid": true }, { "description": "[0] is invalid", "data": [0], "valid": false }, { "description": "[0.0] is invalid", "data": [0.0], "valid": false } ] }, { "description": "const with [true] does not match [1]", "schema": {"const": [true]}, "tests": [ { "description": "[true] is valid", "data": [true], "valid": true }, { "description": "[1] is invalid", "data": [1], "valid": false }, { "description": "[1.0] is invalid", "data": [1.0], "valid": false } ] }, { "description": "const with {\"a\": false} does not match {\"a\": 0}", "schema": {"const": {"a": false}}, "tests": [ { "description": "{\"a\": false} is valid", "data": {"a": false}, "valid": true }, { "description": "{\"a\": 0} is invalid", "data": {"a": 0}, "valid": false }, { "description": "{\"a\": 0.0} is invalid", "data": {"a": 0.0}, "valid": false } ] }, { "description": "const with {\"a\": true} does not match {\"a\": 1}", "schema": {"const": {"a": true}}, "tests": [ { "description": "{\"a\": true} is valid", "data": {"a": true}, "valid": true }, { "description": "{\"a\": 1} is invalid", "data": {"a": 1}, "valid": false }, { "description": "{\"a\": 1.0} is invalid", "data": {"a": 1.0}, "valid": false } ] }, { "description": "const with 0 does not match other zero-like types", "schema": {"const": 0}, "tests": [ { "description": "false is invalid", "data": false, "valid": false }, { "description": "integer zero is valid", "data": 0, "valid": true }, { "description": "float zero is valid", "data": 0.0, "valid": true }, { "description": "empty object is invalid", "data": {}, "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false }, { "description": "empty string is invalid", "data": "", "valid": false } ] }, { "description": "const with 1 does not match true", "schema": {"const": 1}, "tests": [ { "description": "true is invalid", "data": true, "valid": false }, { "description": "integer one is valid", "data": 1, "valid": true }, { "description": "float one is valid", "data": 1.0, "valid": true } ] }, { "description": "const with -2.0 matches integer and float types", "schema": {"const": -2.0}, "tests": [ { "description": "integer -2 is valid", "data": -2, "valid": true }, { "description": "integer 2 is invalid", "data": 2, "valid": false }, { "description": "float -2.0 is valid", "data": -2.0, "valid": true }, { "description": "float 2.0 is invalid", "data": 2.0, "valid": false }, { "description": "float -2.00001 is invalid", "data": -2.00001, "valid": false } ] }, { "description": "float and integers are equal up to 64-bit representation limits", "schema": {"const": 9007199254740992}, "tests": [ { "description": "integer is valid", "data": 9007199254740992, "valid": true }, { "description": "integer minus one is invalid", "data": 9007199254740991, "valid": false }, { "description": "float is valid", "data": 9007199254740992.0, "valid": true }, { "description": "float minus one is invalid", "data": 9007199254740991.0, "valid": false } ] }, { "description": "nul characters in strings", "schema": { "const": "hello\u0000there" }, "tests": [ { "description": "match string with nul", "data": "hello\u0000there", "valid": true }, { "description": "do not match string lacking nul", "data": "hellothere", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/contains.json0000644000175100001770000001103114653725311023264 0ustar00runnerdocker[ { "description": "contains keyword validation", "schema": { "contains": {"minimum": 5} }, "tests": [ { "description": "array with item matching schema (5) is valid", "data": [3, 4, 5], "valid": true }, { "description": "array with item matching schema (6) is valid", "data": [3, 4, 6], "valid": true }, { "description": "array with two items matching schema (5, 6) is valid", "data": [3, 4, 5, 6], "valid": true }, { "description": "array without items matching schema is invalid", "data": [2, 3, 4], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false }, { "description": "not array is valid", "data": {}, "valid": true } ] }, { "description": "contains keyword with const keyword", "schema": { "contains": { "const": 5 } }, "tests": [ { "description": "array with item 5 is valid", "data": [3, 4, 5], "valid": true }, { "description": "array with two items 5 is valid", "data": [3, 4, 5, 5], "valid": true }, { "description": "array without item 5 is invalid", "data": [1, 2, 3, 4], "valid": false } ] }, { "description": "contains keyword with boolean schema true", "schema": {"contains": true}, "tests": [ { "description": "any non-empty array is valid", "data": ["foo"], "valid": true }, { "description": "empty array is invalid", "data": [], "valid": false } ] }, { "description": "contains keyword with boolean schema false", "schema": {"contains": false}, "tests": [ { "description": "any non-empty array is invalid", "data": ["foo"], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false }, { "description": "non-arrays are valid", "data": "contains does not apply to strings", "valid": true } ] }, { "description": "items + contains", "schema": { "items": { "multipleOf": 2 }, "contains": { "multipleOf": 3 } }, "tests": [ { "description": "matches items, does not match contains", "data": [ 2, 4, 8 ], "valid": false }, { "description": "does not match items, matches contains", "data": [ 3, 6, 9 ], "valid": false }, { "description": "matches both items and contains", "data": [ 6, 12 ], "valid": true }, { "description": "matches neither items nor contains", "data": [ 1, 5 ], "valid": false } ] }, { "description": "contains with false if subschema", "schema": { "contains": { "if": false, "else": true } }, "tests": [ { "description": "any non-empty array is valid", "data": ["foo"], "valid": true }, { "description": "empty array is invalid", "data": [], "valid": false } ] }, { "description": "contains with null instance elements", "schema": { "contains": { "type": "null" } }, "tests": [ { "description": "allows null items", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/default.json0000644000175100001770000000426714653725311023107 0ustar00runnerdocker[ { "description": "invalid type for default", "schema": { "properties": { "foo": { "type": "integer", "default": [] } } }, "tests": [ { "description": "valid when property is specified", "data": {"foo": 13}, "valid": true }, { "description": "still valid when the invalid default is used", "data": {}, "valid": true } ] }, { "description": "invalid string value for default", "schema": { "properties": { "bar": { "type": "string", "minLength": 4, "default": "bad" } } }, "tests": [ { "description": "valid when property is specified", "data": {"bar": "good"}, "valid": true }, { "description": "still valid when the invalid default is used", "data": {}, "valid": true } ] }, { "description": "the default keyword does not do anything if the property is missing", "schema": { "type": "object", "properties": { "alpha": { "type": "number", "maximum": 3, "default": 5 } } }, "tests": [ { "description": "an explicit property value is checked against maximum (passing)", "data": { "alpha": 1 }, "valid": true }, { "description": "an explicit property value is checked against maximum (failing)", "data": { "alpha": 5 }, "valid": false }, { "description": "missing properties are not filled in with the default", "data": {}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/definitions.json0000644000175100001770000000131714653725311023767 0ustar00runnerdocker[ { "description": "validate definition against metaschema", "schema": {"$ref": "http://json-schema.org/draft-07/schema#"}, "tests": [ { "description": "valid definition schema", "data": { "definitions": { "foo": {"type": "integer"} } }, "valid": true }, { "description": "invalid definition schema", "data": { "definitions": { "foo": {"type": 1} } }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/dependencies.json0000644000175100001770000001533414653725311024106 0ustar00runnerdocker[ { "description": "dependencies", "schema": { "dependencies": {"bar": ["foo"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependant", "data": {"foo": 1}, "valid": true }, { "description": "with dependency", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "missing dependency", "data": {"bar": 2}, "valid": false }, { "description": "ignores arrays", "data": ["bar"], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "dependencies with empty array", "schema": { "dependencies": {"bar": []} }, "tests": [ { "description": "empty object", "data": {}, "valid": true }, { "description": "object with one property", "data": {"bar": 2}, "valid": true }, { "description": "non-object is valid", "data": 1, "valid": true } ] }, { "description": "multiple dependencies", "schema": { "dependencies": {"quux": ["foo", "bar"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependants", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "with dependencies", "data": {"foo": 1, "bar": 2, "quux": 3}, "valid": true }, { "description": "missing dependency", "data": {"foo": 1, "quux": 2}, "valid": false }, { "description": "missing other dependency", "data": {"bar": 1, "quux": 2}, "valid": false }, { "description": "missing both dependencies", "data": {"quux": 1}, "valid": false } ] }, { "description": "multiple dependencies subschema", "schema": { "dependencies": { "bar": { "properties": { "foo": {"type": "integer"}, "bar": {"type": "integer"} } } } }, "tests": [ { "description": "valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "no dependency", "data": {"foo": "quux"}, "valid": true }, { "description": "wrong type", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "wrong type other", "data": {"foo": 2, "bar": "quux"}, "valid": false }, { "description": "wrong type both", "data": {"foo": "quux", "bar": "quux"}, "valid": false } ] }, { "description": "dependencies with boolean subschemas", "schema": { "dependencies": { "foo": true, "bar": false } }, "tests": [ { "description": "object with property having schema true is valid", "data": {"foo": 1}, "valid": true }, { "description": "object with property having schema false is invalid", "data": {"bar": 2}, "valid": false }, { "description": "object with both properties is invalid", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "dependencies with escaped characters", "schema": { "dependencies": { "foo\nbar": ["foo\rbar"], "foo\tbar": { "minProperties": 4 }, "foo'bar": {"required": ["foo\"bar"]}, "foo\"bar": ["foo'bar"] } }, "tests": [ { "description": "valid object 1", "data": { "foo\nbar": 1, "foo\rbar": 2 }, "valid": true }, { "description": "valid object 2", "data": { "foo\tbar": 1, "a": 2, "b": 3, "c": 4 }, "valid": true }, { "description": "valid object 3", "data": { "foo'bar": 1, "foo\"bar": 2 }, "valid": true }, { "description": "invalid object 1", "data": { "foo\nbar": 1, "foo": 2 }, "valid": false }, { "description": "invalid object 2", "data": { "foo\tbar": 1, "a": 2 }, "valid": false }, { "description": "invalid object 3", "data": { "foo'bar": 1 }, "valid": false }, { "description": "invalid object 4", "data": { "foo\"bar": 2 }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/enum.json0000644000175100001770000001464314653725311022426 0ustar00runnerdocker[ { "description": "simple enum validation", "schema": {"enum": [1, 2, 3]}, "tests": [ { "description": "one of the enum is valid", "data": 1, "valid": true }, { "description": "something else is invalid", "data": 4, "valid": false } ] }, { "description": "heterogeneous enum validation", "schema": {"enum": [6, "foo", [], true, {"foo": 12}]}, "tests": [ { "description": "one of the enum is valid", "data": [], "valid": true }, { "description": "something else is invalid", "data": null, "valid": false }, { "description": "objects are deep compared", "data": {"foo": false}, "valid": false }, { "description": "valid object matches", "data": {"foo": 12}, "valid": true }, { "description": "extra properties in object is invalid", "data": {"foo": 12, "boo": 42}, "valid": false } ] }, { "description": "heterogeneous enum-with-null validation", "schema": { "enum": [6, null] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "number is valid", "data": 6, "valid": true }, { "description": "something else is invalid", "data": "test", "valid": false } ] }, { "description": "enums in properties", "schema": { "type":"object", "properties": { "foo": {"enum":["foo"]}, "bar": {"enum":["bar"]} }, "required": ["bar"] }, "tests": [ { "description": "both properties are valid", "data": {"foo":"foo", "bar":"bar"}, "valid": true }, { "description": "wrong foo value", "data": {"foo":"foot", "bar":"bar"}, "valid": false }, { "description": "wrong bar value", "data": {"foo":"foo", "bar":"bart"}, "valid": false }, { "description": "missing optional property is valid", "data": {"bar":"bar"}, "valid": true }, { "description": "missing required property is invalid", "data": {"foo":"foo"}, "valid": false }, { "description": "missing all properties is invalid", "data": {}, "valid": false } ] }, { "description": "enum with escaped characters", "schema": { "enum": ["foo\nbar", "foo\rbar"] }, "tests": [ { "description": "member 1 is valid", "data": "foo\nbar", "valid": true }, { "description": "member 2 is valid", "data": "foo\rbar", "valid": true }, { "description": "another string is invalid", "data": "abc", "valid": false } ] }, { "description": "enum with false does not match 0", "schema": {"enum": [false]}, "tests": [ { "description": "false is valid", "data": false, "valid": true }, { "description": "integer zero is invalid", "data": 0, "valid": false }, { "description": "float zero is invalid", "data": 0.0, "valid": false } ] }, { "description": "enum with true does not match 1", "schema": {"enum": [true]}, "tests": [ { "description": "true is valid", "data": true, "valid": true }, { "description": "integer one is invalid", "data": 1, "valid": false }, { "description": "float one is invalid", "data": 1.0, "valid": false } ] }, { "description": "enum with 0 does not match false", "schema": {"enum": [0]}, "tests": [ { "description": "false is invalid", "data": false, "valid": false }, { "description": "integer zero is valid", "data": 0, "valid": true }, { "description": "float zero is valid", "data": 0.0, "valid": true } ] }, { "description": "enum with 1 does not match true", "schema": {"enum": [1]}, "tests": [ { "description": "true is invalid", "data": true, "valid": false }, { "description": "integer one is valid", "data": 1, "valid": true }, { "description": "float one is valid", "data": 1.0, "valid": true } ] }, { "description": "nul characters in strings", "schema": { "enum": [ "hello\u0000there" ] }, "tests": [ { "description": "match string with nul", "data": "hello\u0000there", "valid": true }, { "description": "do not match string lacking nul", "data": "hellothere", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/exclusiveMaximum.json0000644000175100001770000000140714653725311025021 0ustar00runnerdocker[ { "description": "exclusiveMaximum validation", "schema": { "exclusiveMaximum": 3.0 }, "tests": [ { "description": "below the exclusiveMaximum is valid", "data": 2.2, "valid": true }, { "description": "boundary point is invalid", "data": 3.0, "valid": false }, { "description": "above the exclusiveMaximum is invalid", "data": 3.5, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/exclusiveMinimum.json0000644000175100001770000000140714653725311025017 0ustar00runnerdocker[ { "description": "exclusiveMinimum validation", "schema": { "exclusiveMinimum": 1.1 }, "tests": [ { "description": "above the exclusiveMinimum is valid", "data": 1.2, "valid": true }, { "description": "boundary point is invalid", "data": 1.1, "valid": false }, { "description": "below the exclusiveMinimum is invalid", "data": 0.6, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/format.json0000644000175100001770000004322314653725311022746 0ustar00runnerdocker[ { "description": "email format", "schema": { "format": "email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "idn-email format", "schema": { "format": "idn-email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "regex format", "schema": { "format": "regex" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "ipv4 format", "schema": { "format": "ipv4" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "ipv6 format", "schema": { "format": "ipv6" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "idn-hostname format", "schema": { "format": "idn-hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "hostname format", "schema": { "format": "hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "date format", "schema": { "format": "date" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "date-time format", "schema": { "format": "date-time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "time format", "schema": { "format": "time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "json-pointer format", "schema": { "format": "json-pointer" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "relative-json-pointer format", "schema": { "format": "relative-json-pointer" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "iri format", "schema": { "format": "iri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "iri-reference format", "schema": { "format": "iri-reference" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uri format", "schema": { "format": "uri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uri-reference format", "schema": { "format": "uri-reference" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uri-template format", "schema": { "format": "uri-template" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/id.json0000644000175100001770000000671214653725311022054 0ustar00runnerdocker[ { "description": "id inside an enum is not a real identifier", "comment": "the implementation must not be confused by an id buried in the enum", "schema": { "definitions": { "id_in_enum": { "enum": [ { "$id": "https://localhost:1234/id/my_identifier.json", "type": "null" } ] }, "real_id_in_schema": { "$id": "https://localhost:1234/id/my_identifier.json", "type": "string" }, "zzz_id_in_const": { "const": { "$id": "https://localhost:1234/id/my_identifier.json", "type": "null" } } }, "anyOf": [ { "$ref": "#/definitions/id_in_enum" }, { "$ref": "https://localhost:1234/id/my_identifier.json" } ] }, "tests": [ { "description": "exact match to enum, and type matches", "data": { "$id": "https://localhost:1234/id/my_identifier.json", "type": "null" }, "valid": true }, { "description": "match $ref to id", "data": "a string to match #/definitions/id_in_enum", "valid": true }, { "description": "no match on enum or $ref to id", "data": 1, "valid": false } ] }, { "description": "non-schema object containing a plain-name $id property", "schema": { "definitions": { "const_not_anchor": { "const": { "$id": "#not_a_real_anchor" } } }, "if": { "const": "skip not_a_real_anchor" }, "then": true, "else" : { "$ref": "#/definitions/const_not_anchor" } }, "tests": [ { "description": "skip traversing definition for a valid result", "data": "skip not_a_real_anchor", "valid": true }, { "description": "const at const_not_anchor does not match", "data": 1, "valid": false } ] }, { "description": "non-schema object containing an $id property", "schema": { "definitions": { "const_not_id": { "const": { "$id": "not_a_real_id" } } }, "if": { "const": "skip not_a_real_id" }, "then": true, "else" : { "$ref": "#/definitions/const_not_id" } }, "tests": [ { "description": "skip traversing definition for a valid result", "data": "skip not_a_real_id", "valid": true }, { "description": "const at const_not_id does not match", "data": 1, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/if-then-else.json0000644000175100001770000001532214653725311023735 0ustar00runnerdocker[ { "description": "ignore if without then or else", "schema": { "if": { "const": 0 } }, "tests": [ { "description": "valid when valid against lone if", "data": 0, "valid": true }, { "description": "valid when invalid against lone if", "data": "hello", "valid": true } ] }, { "description": "ignore then without if", "schema": { "then": { "const": 0 } }, "tests": [ { "description": "valid when valid against lone then", "data": 0, "valid": true }, { "description": "valid when invalid against lone then", "data": "hello", "valid": true } ] }, { "description": "ignore else without if", "schema": { "else": { "const": 0 } }, "tests": [ { "description": "valid when valid against lone else", "data": 0, "valid": true }, { "description": "valid when invalid against lone else", "data": "hello", "valid": true } ] }, { "description": "if and then without else", "schema": { "if": { "exclusiveMaximum": 0 }, "then": { "minimum": -10 } }, "tests": [ { "description": "valid through then", "data": -1, "valid": true }, { "description": "invalid through then", "data": -100, "valid": false }, { "description": "valid when if test fails", "data": 3, "valid": true } ] }, { "description": "if and else without then", "schema": { "if": { "exclusiveMaximum": 0 }, "else": { "multipleOf": 2 } }, "tests": [ { "description": "valid when if test passes", "data": -1, "valid": true }, { "description": "valid through else", "data": 4, "valid": true }, { "description": "invalid through else", "data": 3, "valid": false } ] }, { "description": "validate against correct branch, then vs else", "schema": { "if": { "exclusiveMaximum": 0 }, "then": { "minimum": -10 }, "else": { "multipleOf": 2 } }, "tests": [ { "description": "valid through then", "data": -1, "valid": true }, { "description": "invalid through then", "data": -100, "valid": false }, { "description": "valid through else", "data": 4, "valid": true }, { "description": "invalid through else", "data": 3, "valid": false } ] }, { "description": "non-interference across combined schemas", "schema": { "allOf": [ { "if": { "exclusiveMaximum": 0 } }, { "then": { "minimum": -10 } }, { "else": { "multipleOf": 2 } } ] }, "tests": [ { "description": "valid, but would have been invalid through then", "data": -100, "valid": true }, { "description": "valid, but would have been invalid through else", "data": 3, "valid": true } ] }, { "description": "if with boolean schema true", "schema": { "if": true, "then": { "const": "then" }, "else": { "const": "else" } }, "tests": [ { "description": "boolean schema true in if always chooses the then path (valid)", "data": "then", "valid": true }, { "description": "boolean schema true in if always chooses the then path (invalid)", "data": "else", "valid": false } ] }, { "description": "if with boolean schema false", "schema": { "if": false, "then": { "const": "then" }, "else": { "const": "else" } }, "tests": [ { "description": "boolean schema false in if always chooses the else path (invalid)", "data": "then", "valid": false }, { "description": "boolean schema false in if always chooses the else path (valid)", "data": "else", "valid": true } ] }, { "description": "if appears at the end when serialized (keyword processing sequence)", "schema": { "then": { "const": "yes" }, "else": { "const": "other" }, "if": { "maxLength": 4 } }, "tests": [ { "description": "yes redirects to then and passes", "data": "yes", "valid": true }, { "description": "other redirects to else and passes", "data": "other", "valid": true }, { "description": "no redirects to then and fails", "data": "no", "valid": false }, { "description": "invalid redirects to else and fails", "data": "invalid", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/infinite-loop-detection.json0000644000175100001770000000174614653725311026212 0ustar00runnerdocker[ { "description": "evaluating the same schema location against the same data location twice is not a sign of an infinite loop", "schema": { "definitions": { "int": { "type": "integer" } }, "allOf": [ { "properties": { "foo": { "$ref": "#/definitions/int" } } }, { "additionalProperties": { "$ref": "#/definitions/int" } } ] }, "tests": [ { "description": "passing case", "data": { "foo": 1 }, "valid": true }, { "description": "failing case", "data": { "foo": "a string" }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/items.json0000644000175100001770000001761414653725311022604 0ustar00runnerdocker[ { "description": "a schema given for items", "schema": { "items": {"type": "integer"} }, "tests": [ { "description": "valid items", "data": [ 1, 2, 3 ], "valid": true }, { "description": "wrong type of items", "data": [1, "x"], "valid": false }, { "description": "ignores non-arrays", "data": {"foo" : "bar"}, "valid": true }, { "description": "JavaScript pseudo-array is valid", "data": { "0": "invalid", "length": 1 }, "valid": true } ] }, { "description": "an array of schemas for items", "schema": { "items": [ {"type": "integer"}, {"type": "string"} ] }, "tests": [ { "description": "correct types", "data": [ 1, "foo" ], "valid": true }, { "description": "wrong types", "data": [ "foo", 1 ], "valid": false }, { "description": "incomplete array of items", "data": [ 1 ], "valid": true }, { "description": "array with additional items", "data": [ 1, "foo", true ], "valid": true }, { "description": "empty array", "data": [ ], "valid": true }, { "description": "JavaScript pseudo-array is valid", "data": { "0": "invalid", "1": "valid", "length": 2 }, "valid": true } ] }, { "description": "items with boolean schema (true)", "schema": {"items": true}, "tests": [ { "description": "any array is valid", "data": [ 1, "foo", true ], "valid": true }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "items with boolean schema (false)", "schema": {"items": false}, "tests": [ { "description": "any non-empty array is invalid", "data": [ 1, "foo", true ], "valid": false }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "items with boolean schemas", "schema": { "items": [true, false] }, "tests": [ { "description": "array with one item is valid", "data": [ 1 ], "valid": true }, { "description": "array with two items is invalid", "data": [ 1, "foo" ], "valid": false }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "items and subitems", "schema": { "definitions": { "item": { "type": "array", "additionalItems": false, "items": [ { "$ref": "#/definitions/sub-item" }, { "$ref": "#/definitions/sub-item" } ] }, "sub-item": { "type": "object", "required": ["foo"] } }, "type": "array", "additionalItems": false, "items": [ { "$ref": "#/definitions/item" }, { "$ref": "#/definitions/item" }, { "$ref": "#/definitions/item" } ] }, "tests": [ { "description": "valid items", "data": [ [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": true }, { "description": "too many items", "data": [ [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "too many sub-items", "data": [ [ {"foo": null}, {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "wrong item", "data": [ {"foo": null}, [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "wrong sub-item", "data": [ [ {}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "fewer items is valid", "data": [ [ {"foo": null} ], [ {"foo": null} ] ], "valid": true } ] }, { "description": "nested items", "schema": { "type": "array", "items": { "type": "array", "items": { "type": "array", "items": { "type": "array", "items": { "type": "number" } } } } }, "tests": [ { "description": "valid nested array", "data": [[[[1]], [[2],[3]]], [[[4], [5], [6]]]], "valid": true }, { "description": "nested array with invalid type", "data": [[[["1"]], [[2],[3]]], [[[4], [5], [6]]]], "valid": false }, { "description": "not deep enough", "data": [[[1], [2],[3]], [[4], [5], [6]]], "valid": false } ] }, { "description": "single-form items with null instance elements", "schema": { "items": { "type": "null" } }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] }, { "description": "array-form items with null instance elements", "schema": { "items": [ { "type": "null" } ] }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/maxItems.json0000644000175100001770000000215514653725311023244 0ustar00runnerdocker[ { "description": "maxItems validation", "schema": {"maxItems": 2}, "tests": [ { "description": "shorter is valid", "data": [1], "valid": true }, { "description": "exact length is valid", "data": [1, 2], "valid": true }, { "description": "too long is invalid", "data": [1, 2, 3], "valid": false }, { "description": "ignores non-arrays", "data": "foobar", "valid": true } ] }, { "description": "maxItems validation with a decimal", "schema": {"maxItems": 2.0}, "tests": [ { "description": "shorter is valid", "data": [1], "valid": true }, { "description": "too long is invalid", "data": [1, 2, 3], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/maxLength.json0000644000175100001770000000245114653725311023403 0ustar00runnerdocker[ { "description": "maxLength validation", "schema": {"maxLength": 2}, "tests": [ { "description": "shorter is valid", "data": "f", "valid": true }, { "description": "exact length is valid", "data": "fo", "valid": true }, { "description": "too long is invalid", "data": "foo", "valid": false }, { "description": "ignores non-strings", "data": 100, "valid": true }, { "description": "two supplementary Unicode code points is long enough", "data": "\uD83D\uDCA9\uD83D\uDCA9", "valid": true } ] }, { "description": "maxLength validation with a decimal", "schema": {"maxLength": 2.0}, "tests": [ { "description": "shorter is valid", "data": "f", "valid": true }, { "description": "too long is invalid", "data": "foo", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/maxProperties.json0000644000175100001770000000365314653725311024323 0ustar00runnerdocker[ { "description": "maxProperties validation", "schema": {"maxProperties": 2}, "tests": [ { "description": "shorter is valid", "data": {"foo": 1}, "valid": true }, { "description": "exact length is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "too long is invalid", "data": {"foo": 1, "bar": 2, "baz": 3}, "valid": false }, { "description": "ignores arrays", "data": [1, 2, 3], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "maxProperties validation with a decimal", "schema": {"maxProperties": 2.0}, "tests": [ { "description": "shorter is valid", "data": {"foo": 1}, "valid": true }, { "description": "too long is invalid", "data": {"foo": 1, "bar": 2, "baz": 3}, "valid": false } ] }, { "description": "maxProperties = 0 means the object is empty", "schema": { "maxProperties": 0 }, "tests": [ { "description": "no properties is valid", "data": {}, "valid": true }, { "description": "one property is invalid", "data": { "foo": 1 }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/maximum.json0000644000175100001770000000270414653725311023132 0ustar00runnerdocker[ { "description": "maximum validation", "schema": {"maximum": 3.0}, "tests": [ { "description": "below the maximum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 3.0, "valid": true }, { "description": "above the maximum is invalid", "data": 3.5, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] }, { "description": "maximum validation with unsigned integer", "schema": {"maximum": 300}, "tests": [ { "description": "below the maximum is invalid", "data": 299.97, "valid": true }, { "description": "boundary point integer is valid", "data": 300, "valid": true }, { "description": "boundary point float is valid", "data": 300.00, "valid": true }, { "description": "above the maximum is invalid", "data": 300.5, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/minItems.json0000644000175100001770000000213414653725311023237 0ustar00runnerdocker[ { "description": "minItems validation", "schema": {"minItems": 1}, "tests": [ { "description": "longer is valid", "data": [1, 2], "valid": true }, { "description": "exact length is valid", "data": [1], "valid": true }, { "description": "too short is invalid", "data": [], "valid": false }, { "description": "ignores non-arrays", "data": "", "valid": true } ] }, { "description": "minItems validation with a decimal", "schema": {"minItems": 1.0}, "tests": [ { "description": "longer is valid", "data": [1, 2], "valid": true }, { "description": "too short is invalid", "data": [], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/minLength.json0000644000175100001770000000243714653725311023405 0ustar00runnerdocker[ { "description": "minLength validation", "schema": {"minLength": 2}, "tests": [ { "description": "longer is valid", "data": "foo", "valid": true }, { "description": "exact length is valid", "data": "fo", "valid": true }, { "description": "too short is invalid", "data": "f", "valid": false }, { "description": "ignores non-strings", "data": 1, "valid": true }, { "description": "one supplementary Unicode code point is not long enough", "data": "\uD83D\uDCA9", "valid": false } ] }, { "description": "minLength validation with a decimal", "schema": {"minLength": 2.0}, "tests": [ { "description": "longer is valid", "data": "foo", "valid": true }, { "description": "too short is invalid", "data": "f", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/minProperties.json0000644000175100001770000000265314653725311024320 0ustar00runnerdocker[ { "description": "minProperties validation", "schema": {"minProperties": 1}, "tests": [ { "description": "longer is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "exact length is valid", "data": {"foo": 1}, "valid": true }, { "description": "too short is invalid", "data": {}, "valid": false }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "minProperties validation with a decimal", "schema": {"minProperties": 1.0}, "tests": [ { "description": "longer is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "too short is invalid", "data": {}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/minimum.json0000644000175100001770000000361214653725311023127 0ustar00runnerdocker[ { "description": "minimum validation", "schema": {"minimum": 1.1}, "tests": [ { "description": "above the minimum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 1.1, "valid": true }, { "description": "below the minimum is invalid", "data": 0.6, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] }, { "description": "minimum validation with signed integer", "schema": {"minimum": -2}, "tests": [ { "description": "negative above the minimum is valid", "data": -1, "valid": true }, { "description": "positive above the minimum is valid", "data": 0, "valid": true }, { "description": "boundary point is valid", "data": -2, "valid": true }, { "description": "boundary point with float is valid", "data": -2.0, "valid": true }, { "description": "float below the minimum is invalid", "data": -2.0001, "valid": false }, { "description": "int below the minimum is invalid", "data": -3, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/multipleOf.json0000644000175100001770000000352214653725311023574 0ustar00runnerdocker[ { "description": "by int", "schema": {"multipleOf": 2}, "tests": [ { "description": "int by int", "data": 10, "valid": true }, { "description": "int by int fail", "data": 7, "valid": false }, { "description": "ignores non-numbers", "data": "foo", "valid": true } ] }, { "description": "by number", "schema": {"multipleOf": 1.5}, "tests": [ { "description": "zero is multiple of anything", "data": 0, "valid": true }, { "description": "4.5 is multiple of 1.5", "data": 4.5, "valid": true }, { "description": "35 is not multiple of 1.5", "data": 35, "valid": false } ] }, { "description": "by small number", "schema": {"multipleOf": 0.0001}, "tests": [ { "description": "0.0075 is multiple of 0.0001", "data": 0.0075, "valid": true }, { "description": "0.00751 is not multiple of 0.0001", "data": 0.00751, "valid": false } ] }, { "description": "float division = inf", "schema": {"type": "integer", "multipleOf": 0.123456789}, "tests": [ { "description": "always invalid, but naive implementations may raise an overflow error", "data": 1e308, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/not.json0000644000175100001770000000537614653725311022265 0ustar00runnerdocker[ { "description": "not", "schema": { "not": {"type": "integer"} }, "tests": [ { "description": "allowed", "data": "foo", "valid": true }, { "description": "disallowed", "data": 1, "valid": false } ] }, { "description": "not multiple types", "schema": { "not": {"type": ["integer", "boolean"]} }, "tests": [ { "description": "valid", "data": "foo", "valid": true }, { "description": "mismatch", "data": 1, "valid": false }, { "description": "other mismatch", "data": true, "valid": false } ] }, { "description": "not more complex schema", "schema": { "not": { "type": "object", "properties": { "foo": { "type": "string" } } } }, "tests": [ { "description": "match", "data": 1, "valid": true }, { "description": "other match", "data": {"foo": 1}, "valid": true }, { "description": "mismatch", "data": {"foo": "bar"}, "valid": false } ] }, { "description": "forbidden property", "schema": { "properties": { "foo": { "not": {} } } }, "tests": [ { "description": "property present", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "property absent", "data": {"bar": 1, "baz": 2}, "valid": true } ] }, { "description": "not with boolean schema true", "schema": {"not": true}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "not with boolean schema false", "schema": {"not": false}, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/oneOf.json0000644000175100001770000001612314653725311022523 0ustar00runnerdocker[ { "description": "oneOf", "schema": { "oneOf": [ { "type": "integer" }, { "minimum": 2 } ] }, "tests": [ { "description": "first oneOf valid", "data": 1, "valid": true }, { "description": "second oneOf valid", "data": 2.5, "valid": true }, { "description": "both oneOf valid", "data": 3, "valid": false }, { "description": "neither oneOf valid", "data": 1.5, "valid": false } ] }, { "description": "oneOf with base schema", "schema": { "type": "string", "oneOf" : [ { "minLength": 2 }, { "maxLength": 4 } ] }, "tests": [ { "description": "mismatch base schema", "data": 3, "valid": false }, { "description": "one oneOf valid", "data": "foobar", "valid": true }, { "description": "both oneOf valid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, all true", "schema": {"oneOf": [true, true, true]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, one true", "schema": {"oneOf": [true, false, false]}, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "oneOf with boolean schemas, more than one true", "schema": {"oneOf": [true, true, false]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, all false", "schema": {"oneOf": [false, false, false]}, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf complex types", "schema": { "oneOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "first oneOf valid (complex)", "data": {"bar": 2}, "valid": true }, { "description": "second oneOf valid (complex)", "data": {"foo": "baz"}, "valid": true }, { "description": "both oneOf valid (complex)", "data": {"foo": "baz", "bar": 2}, "valid": false }, { "description": "neither oneOf valid (complex)", "data": {"foo": 2, "bar": "quux"}, "valid": false } ] }, { "description": "oneOf with empty schema", "schema": { "oneOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "one valid - valid", "data": "foo", "valid": true }, { "description": "both valid - invalid", "data": 123, "valid": false } ] }, { "description": "oneOf with required", "schema": { "type": "object", "oneOf": [ { "required": ["foo", "bar"] }, { "required": ["foo", "baz"] } ] }, "tests": [ { "description": "both invalid - invalid", "data": {"bar": 2}, "valid": false }, { "description": "first valid - valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "second valid - valid", "data": {"foo": 1, "baz": 3}, "valid": true }, { "description": "both valid - invalid", "data": {"foo": 1, "bar": 2, "baz" : 3}, "valid": false } ] }, { "description": "oneOf with missing optional property", "schema": { "oneOf": [ { "properties": { "bar": true, "baz": true }, "required": ["bar"] }, { "properties": { "foo": true }, "required": ["foo"] } ] }, "tests": [ { "description": "first oneOf valid", "data": {"bar": 8}, "valid": true }, { "description": "second oneOf valid", "data": {"foo": "foo"}, "valid": true }, { "description": "both oneOf valid", "data": {"foo": "foo", "bar": 8}, "valid": false }, { "description": "neither oneOf valid", "data": {"baz": "quux"}, "valid": false } ] }, { "description": "nested oneOf, to check validation semantics", "schema": { "oneOf": [ { "oneOf": [ { "type": "null" } ] } ] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "anything non-null is invalid", "data": 123, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1090975 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/0000755000175100001770000000000014653725331022406 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/bignum.json0000644000175100001770000000540114653725311024560 0ustar00runnerdocker[ { "description": "integer", "schema": { "type": "integer" }, "tests": [ { "description": "a bignum is an integer", "data": 12345678910111213141516171819202122232425262728293031, "valid": true }, { "description": "a negative bignum is an integer", "data": -12345678910111213141516171819202122232425262728293031, "valid": true } ] }, { "description": "number", "schema": { "type": "number" }, "tests": [ { "description": "a bignum is a number", "data": 98249283749234923498293171823948729348710298301928331, "valid": true }, { "description": "a negative bignum is a number", "data": -98249283749234923498293171823948729348710298301928331, "valid": true } ] }, { "description": "string", "schema": { "type": "string" }, "tests": [ { "description": "a bignum is not a string", "data": 98249283749234923498293171823948729348710298301928331, "valid": false } ] }, { "description": "maximum integer comparison", "schema": { "maximum": 18446744073709551615 }, "tests": [ { "description": "comparison works for high numbers", "data": 18446744073709551600, "valid": true } ] }, { "description": "float comparison with high precision", "schema": { "exclusiveMaximum": 972783798187987123879878123.18878137 }, "tests": [ { "description": "comparison works for high numbers", "data": 972783798187987123879878123.188781371, "valid": false } ] }, { "description": "minimum integer comparison", "schema": { "minimum": -18446744073709551615 }, "tests": [ { "description": "comparison works for very negative numbers", "data": -18446744073709551600, "valid": true } ] }, { "description": "float comparison with high precision on negative numbers", "schema": { "exclusiveMinimum": -972783798187987123879878123.18878137 }, "tests": [ { "description": "comparison works for very negative numbers", "data": -972783798187987123879878123.188781371, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/content.json0000644000175100001770000000427414653725311024760 0ustar00runnerdocker[ { "description": "validation of string-encoded content based on media type", "schema": { "contentMediaType": "application/json" }, "tests": [ { "description": "a valid JSON document", "data": "{\"foo\": \"bar\"}", "valid": true }, { "description": "an invalid JSON document", "data": "{:}", "valid": false }, { "description": "ignores non-strings", "data": 100, "valid": true } ] }, { "description": "validation of binary string-encoding", "schema": { "contentEncoding": "base64" }, "tests": [ { "description": "a valid base64 string", "data": "eyJmb28iOiAiYmFyIn0K", "valid": true }, { "description": "an invalid base64 string (% is not a valid character)", "data": "eyJmb28iOi%iYmFyIn0K", "valid": false }, { "description": "ignores non-strings", "data": 100, "valid": true } ] }, { "description": "validation of binary-encoded media type documents", "schema": { "contentMediaType": "application/json", "contentEncoding": "base64" }, "tests": [ { "description": "a valid base64-encoded JSON document", "data": "eyJmb28iOiAiYmFyIn0K", "valid": true }, { "description": "a validly-encoded invalid JSON document", "data": "ezp9Cg==", "valid": false }, { "description": "an invalid base64 string that is valid JSON", "data": "{}", "valid": false }, { "description": "ignores non-strings", "data": 100, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/cross-draft.json0000644000175100001770000000147414653725311025534 0ustar00runnerdocker[ { "description": "refs to future drafts are processed as future drafts", "schema": { "type": "object", "allOf": [ { "properties": { "foo": true } }, { "$ref": "http://localhost:1234/draft2019-09/dependentRequired.json" } ] }, "tests": [ { "description": "missing bar is invalid", "comment": "if the implementation is not processing the $ref as a 2019-09 schema, this test will fail", "data": {"foo": "any value"}, "valid": false }, { "description": "present bar is valid", "data": {"foo": "any value", "bar": "also any value"}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/ecmascript-regex.json0000644000175100001770000004410114653725311026541 0ustar00runnerdocker[ { "description": "ECMA 262 regex $ does not match trailing newline", "schema": { "type": "string", "pattern": "^abc$" }, "tests": [ { "description": "matches in Python, but not in ECMA 262", "data": "abc\\n", "valid": false }, { "description": "matches", "data": "abc", "valid": true } ] }, { "description": "ECMA 262 regex converts \\t to horizontal tab", "schema": { "type": "string", "pattern": "^\\t$" }, "tests": [ { "description": "does not match", "data": "\\t", "valid": false }, { "description": "matches", "data": "\u0009", "valid": true } ] }, { "description": "ECMA 262 regex escapes control codes with \\c and upper letter", "schema": { "type": "string", "pattern": "^\\cC$" }, "tests": [ { "description": "does not match", "data": "\\cC", "valid": false }, { "description": "matches", "data": "\u0003", "valid": true } ] }, { "description": "ECMA 262 regex escapes control codes with \\c and lower letter", "schema": { "type": "string", "pattern": "^\\cc$" }, "tests": [ { "description": "does not match", "data": "\\cc", "valid": false }, { "description": "matches", "data": "\u0003", "valid": true } ] }, { "description": "ECMA 262 \\d matches ascii digits only", "schema": { "type": "string", "pattern": "^\\d$" }, "tests": [ { "description": "ASCII zero matches", "data": "0", "valid": true }, { "description": "NKO DIGIT ZERO does not match (unlike e.g. Python)", "data": "߀", "valid": false }, { "description": "NKO DIGIT ZERO (as \\u escape) does not match", "data": "\u07c0", "valid": false } ] }, { "description": "ECMA 262 \\D matches everything but ascii digits", "schema": { "type": "string", "pattern": "^\\D$" }, "tests": [ { "description": "ASCII zero does not match", "data": "0", "valid": false }, { "description": "NKO DIGIT ZERO matches (unlike e.g. Python)", "data": "߀", "valid": true }, { "description": "NKO DIGIT ZERO (as \\u escape) matches", "data": "\u07c0", "valid": true } ] }, { "description": "ECMA 262 \\w matches ascii letters only", "schema": { "type": "string", "pattern": "^\\w$" }, "tests": [ { "description": "ASCII 'a' matches", "data": "a", "valid": true }, { "description": "latin-1 e-acute does not match (unlike e.g. Python)", "data": "é", "valid": false } ] }, { "description": "ECMA 262 \\W matches everything but ascii letters", "schema": { "type": "string", "pattern": "^\\W$" }, "tests": [ { "description": "ASCII 'a' does not match", "data": "a", "valid": false }, { "description": "latin-1 e-acute matches (unlike e.g. Python)", "data": "é", "valid": true } ] }, { "description": "ECMA 262 \\s matches whitespace", "schema": { "type": "string", "pattern": "^\\s$" }, "tests": [ { "description": "ASCII space matches", "data": " ", "valid": true }, { "description": "Character tabulation matches", "data": "\t", "valid": true }, { "description": "Line tabulation matches", "data": "\u000b", "valid": true }, { "description": "Form feed matches", "data": "\u000c", "valid": true }, { "description": "latin-1 non-breaking-space matches", "data": "\u00a0", "valid": true }, { "description": "zero-width whitespace matches", "data": "\ufeff", "valid": true }, { "description": "line feed matches (line terminator)", "data": "\u000a", "valid": true }, { "description": "paragraph separator matches (line terminator)", "data": "\u2029", "valid": true }, { "description": "EM SPACE matches (Space_Separator)", "data": "\u2003", "valid": true }, { "description": "Non-whitespace control does not match", "data": "\u0001", "valid": false }, { "description": "Non-whitespace does not match", "data": "\u2013", "valid": false } ] }, { "description": "ECMA 262 \\S matches everything but whitespace", "schema": { "type": "string", "pattern": "^\\S$" }, "tests": [ { "description": "ASCII space does not match", "data": " ", "valid": false }, { "description": "Character tabulation does not match", "data": "\t", "valid": false }, { "description": "Line tabulation does not match", "data": "\u000b", "valid": false }, { "description": "Form feed does not match", "data": "\u000c", "valid": false }, { "description": "latin-1 non-breaking-space does not match", "data": "\u00a0", "valid": false }, { "description": "zero-width whitespace does not match", "data": "\ufeff", "valid": false }, { "description": "line feed does not match (line terminator)", "data": "\u000a", "valid": false }, { "description": "paragraph separator does not match (line terminator)", "data": "\u2029", "valid": false }, { "description": "EM SPACE does not match (Space_Separator)", "data": "\u2003", "valid": false }, { "description": "Non-whitespace control matches", "data": "\u0001", "valid": true }, { "description": "Non-whitespace matches", "data": "\u2013", "valid": true } ] }, { "description": "patterns always use unicode semantics with pattern", "schema": { "pattern": "\\p{Letter}cole" }, "tests": [ { "description": "ascii character in json string", "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", "valid": true }, { "description": "literal unicode character in json string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": true }, { "description": "unicode character in hex format in string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": true }, { "description": "unicode matching is case-sensitive", "data": "LES HIVERS DE MON ENFANCE ÉTAIENT DES SAISONS LONGUES, LONGUES. NOUS VIVIONS EN TROIS LIEUX: L'ÉCOLE, L'ÉGLISE ET LA PATINOIRE; MAIS LA VRAIE VIE ÉTAIT SUR LA PATINOIRE.", "valid": false } ] }, { "description": "\\w in patterns matches [A-Za-z0-9_], not unicode letters", "schema": { "pattern": "\\wcole" }, "tests": [ { "description": "ascii character in json string", "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", "valid": true }, { "description": "literal unicode character in json string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "unicode character in hex format in string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "unicode matching is case-sensitive", "data": "LES HIVERS DE MON ENFANCE ÉTAIENT DES SAISONS LONGUES, LONGUES. NOUS VIVIONS EN TROIS LIEUX: L'ÉCOLE, L'ÉGLISE ET LA PATINOIRE; MAIS LA VRAIE VIE ÉTAIT SUR LA PATINOIRE.", "valid": false } ] }, { "description": "pattern with ASCII ranges", "schema": { "pattern": "[a-z]cole" }, "tests": [ { "description": "literal unicode character in json string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "unicode character in hex format in string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "ascii characters match", "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", "valid": true } ] }, { "description": "\\d in pattern matches [0-9], not unicode digits", "schema": { "pattern": "^\\d+$" }, "tests": [ { "description": "ascii digits", "data": "42", "valid": true }, { "description": "ascii non-digits", "data": "-%#", "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": "৪২", "valid": false } ] }, { "description": "pattern with non-ASCII digits", "schema": { "pattern": "^\\p{digit}+$" }, "tests": [ { "description": "ascii digits", "data": "42", "valid": true }, { "description": "ascii non-digits", "data": "-%#", "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": "৪২", "valid": true } ] }, { "description": "patterns always use unicode semantics with patternProperties", "schema": { "type": "object", "patternProperties": { "\\p{Letter}cole": true }, "additionalProperties": false }, "tests": [ { "description": "ascii character in json string", "data": { "l'ecole": "pas de vraie vie" }, "valid": true }, { "description": "literal unicode character in json string", "data": { "l'école": "pas de vraie vie" }, "valid": true }, { "description": "unicode character in hex format in string", "data": { "l'\u00e9cole": "pas de vraie vie" }, "valid": true }, { "description": "unicode matching is case-sensitive", "data": { "L'ÉCOLE": "PAS DE VRAIE VIE" }, "valid": false } ] }, { "description": "\\w in patternProperties matches [A-Za-z0-9_], not unicode letters", "schema": { "type": "object", "patternProperties": { "\\wcole": true }, "additionalProperties": false }, "tests": [ { "description": "ascii character in json string", "data": { "l'ecole": "pas de vraie vie" }, "valid": true }, { "description": "literal unicode character in json string", "data": { "l'école": "pas de vraie vie" }, "valid": false }, { "description": "unicode character in hex format in string", "data": { "l'\u00e9cole": "pas de vraie vie" }, "valid": false }, { "description": "unicode matching is case-sensitive", "data": { "L'ÉCOLE": "PAS DE VRAIE VIE" }, "valid": false } ] }, { "description": "patternProperties with ASCII ranges", "schema": { "type": "object", "patternProperties": { "[a-z]cole": true }, "additionalProperties": false }, "tests": [ { "description": "literal unicode character in json string", "data": { "l'école": "pas de vraie vie" }, "valid": false }, { "description": "unicode character in hex format in string", "data": { "l'\u00e9cole": "pas de vraie vie" }, "valid": false }, { "description": "ascii characters match", "data": { "l'ecole": "pas de vraie vie" }, "valid": true } ] }, { "description": "\\d in patternProperties matches [0-9], not unicode digits", "schema": { "type": "object", "patternProperties": { "^\\d+$": true }, "additionalProperties": false }, "tests": [ { "description": "ascii digits", "data": { "42": "life, the universe, and everything" }, "valid": true }, { "description": "ascii non-digits", "data": { "-%#": "spending the year dead for tax reasons" }, "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": { "৪২": "khajit has wares if you have coin" }, "valid": false } ] }, { "description": "patternProperties with non-ASCII digits", "schema": { "type": "object", "patternProperties": { "^\\p{digit}+$": true }, "additionalProperties": false }, "tests": [ { "description": "ascii digits", "data": { "42": "life, the universe, and everything" }, "valid": true }, { "description": "ascii non-digits", "data": { "-%#": "spending the year dead for tax reasons" }, "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": { "৪২": "khajit has wares if you have coin" }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/float-overflow.json0000644000175100001770000000055114653725311026246 0ustar00runnerdocker[ { "description": "all integers are multiples of 0.5, if overflow is handled", "schema": {"type": "integer", "multipleOf": 0.5}, "tests": [ { "description": "valid if optional overflow handling is implemented", "data": 1e308, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1130974 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/format/0000755000175100001770000000000014653725331023676 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/format/date-time.json0000644000175100001770000001106014653725311026436 0ustar00runnerdocker[ { "description": "validation of date-time strings", "schema": { "format": "date-time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid date-time string", "data": "1963-06-19T08:30:06.283185Z", "valid": true }, { "description": "a valid date-time string without second fraction", "data": "1963-06-19T08:30:06Z", "valid": true }, { "description": "a valid date-time string with plus offset", "data": "1937-01-01T12:00:27.87+00:20", "valid": true }, { "description": "a valid date-time string with minus offset", "data": "1990-12-31T15:59:50.123-08:00", "valid": true }, { "description": "a valid date-time with a leap second, UTC", "data": "1998-12-31T23:59:60Z", "valid": true }, { "description": "a valid date-time with a leap second, with minus offset", "data": "1998-12-31T15:59:60.123-08:00", "valid": true }, { "description": "an invalid date-time past leap second, UTC", "data": "1998-12-31T23:59:61Z", "valid": false }, { "description": "an invalid date-time with leap second on a wrong minute, UTC", "data": "1998-12-31T23:58:60Z", "valid": false }, { "description": "an invalid date-time with leap second on a wrong hour, UTC", "data": "1998-12-31T22:59:60Z", "valid": false }, { "description": "an invalid day in date-time string", "data": "1990-02-31T15:59:59.123-08:00", "valid": false }, { "description": "an invalid offset in date-time string", "data": "1990-12-31T15:59:59-24:00", "valid": false }, { "description": "an invalid closing Z after time-zone offset", "data": "1963-06-19T08:30:06.28123+01:00Z", "valid": false }, { "description": "an invalid date-time string", "data": "06/19/1963 08:30:06 PST", "valid": false }, { "description": "case-insensitive T and Z", "data": "1963-06-19t08:30:06.283185z", "valid": true }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "2013-350T01:01:01", "valid": false }, { "description": "invalid non-padded month dates", "data": "1963-6-19T08:30:06.283185Z", "valid": false }, { "description": "invalid non-padded day dates", "data": "1963-06-1T08:30:06.283185Z", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4) in date portion", "data": "1963-06-1৪T00:00:00Z", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4) in time portion", "data": "1963-06-11T0৪:00:00Z", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/format/date.json0000644000175100001770000001643014653725311025510 0ustar00runnerdocker[ { "description": "validation of date strings", "schema": { "format": "date" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid date string", "data": "1963-06-19", "valid": true }, { "description": "a valid date string with 31 days in January", "data": "2020-01-31", "valid": true }, { "description": "a invalid date string with 32 days in January", "data": "2020-01-32", "valid": false }, { "description": "a valid date string with 28 days in February (normal)", "data": "2021-02-28", "valid": true }, { "description": "a invalid date string with 29 days in February (normal)", "data": "2021-02-29", "valid": false }, { "description": "a valid date string with 29 days in February (leap)", "data": "2020-02-29", "valid": true }, { "description": "a invalid date string with 30 days in February (leap)", "data": "2020-02-30", "valid": false }, { "description": "a valid date string with 31 days in March", "data": "2020-03-31", "valid": true }, { "description": "a invalid date string with 32 days in March", "data": "2020-03-32", "valid": false }, { "description": "a valid date string with 30 days in April", "data": "2020-04-30", "valid": true }, { "description": "a invalid date string with 31 days in April", "data": "2020-04-31", "valid": false }, { "description": "a valid date string with 31 days in May", "data": "2020-05-31", "valid": true }, { "description": "a invalid date string with 32 days in May", "data": "2020-05-32", "valid": false }, { "description": "a valid date string with 30 days in June", "data": "2020-06-30", "valid": true }, { "description": "a invalid date string with 31 days in June", "data": "2020-06-31", "valid": false }, { "description": "a valid date string with 31 days in July", "data": "2020-07-31", "valid": true }, { "description": "a invalid date string with 32 days in July", "data": "2020-07-32", "valid": false }, { "description": "a valid date string with 31 days in August", "data": "2020-08-31", "valid": true }, { "description": "a invalid date string with 32 days in August", "data": "2020-08-32", "valid": false }, { "description": "a valid date string with 30 days in September", "data": "2020-09-30", "valid": true }, { "description": "a invalid date string with 31 days in September", "data": "2020-09-31", "valid": false }, { "description": "a valid date string with 31 days in October", "data": "2020-10-31", "valid": true }, { "description": "a invalid date string with 32 days in October", "data": "2020-10-32", "valid": false }, { "description": "a valid date string with 30 days in November", "data": "2020-11-30", "valid": true }, { "description": "a invalid date string with 31 days in November", "data": "2020-11-31", "valid": false }, { "description": "a valid date string with 31 days in December", "data": "2020-12-31", "valid": true }, { "description": "a invalid date string with 32 days in December", "data": "2020-12-32", "valid": false }, { "description": "a invalid date string with invalid month", "data": "2020-13-01", "valid": false }, { "description": "an invalid date string", "data": "06/19/1963", "valid": false }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "2013-350", "valid": false }, { "description": "non-padded month dates are not valid", "data": "1998-1-20", "valid": false }, { "description": "non-padded day dates are not valid", "data": "1998-01-1", "valid": false }, { "description": "invalid month", "data": "1998-13-01", "valid": false }, { "description": "invalid month-day combination", "data": "1998-04-31", "valid": false }, { "description": "2021 is not a leap year", "data": "2021-02-29", "valid": false }, { "description": "2020 is a leap year", "data": "2020-02-29", "valid": true }, { "description": "invalid non-ASCII '৪' (a Bengali 4)", "data": "1963-06-1৪", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/format/email.json0000644000175100001770000000510414653725311025656 0ustar00runnerdocker[ { "description": "validation of e-mail addresses", "schema": { "format": "email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid e-mail address", "data": "joe.bloggs@example.com", "valid": true }, { "description": "an invalid e-mail address", "data": "2962", "valid": false }, { "description": "tilde in local part is valid", "data": "te~st@example.com", "valid": true }, { "description": "tilde before local part is valid", "data": "~test@example.com", "valid": true }, { "description": "tilde after local part is valid", "data": "test~@example.com", "valid": true }, { "description": "dot before local part is not valid", "data": ".test@example.com", "valid": false }, { "description": "dot after local part is not valid", "data": "test.@example.com", "valid": false }, { "description": "two separated dots inside local part are valid", "data": "te.s.t@example.com", "valid": true }, { "description": "two subsequent dots inside local part are not valid", "data": "te..st@example.com", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/format/hostname.json0000644000175100001770000000622414653725311026411 0ustar00runnerdocker[ { "description": "validation of host names", "schema": { "format": "hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid host name", "data": "www.example.com", "valid": true }, { "description": "a valid punycoded IDN hostname", "data": "xn--4gbwdl.xn--wgbh1c", "valid": true }, { "description": "a host name starting with an illegal character", "data": "-a-host-name-that-starts-with--", "valid": false }, { "description": "a host name containing illegal characters", "data": "not_a_valid_host_name", "valid": false }, { "description": "a host name with a component too long", "data": "a-vvvvvvvvvvvvvvvveeeeeeeeeeeeeeeerrrrrrrrrrrrrrrryyyyyyyyyyyyyyyy-long-host-name-component", "valid": false }, { "description": "starts with hyphen", "data": "-hostname", "valid": false }, { "description": "ends with hyphen", "data": "hostname-", "valid": false }, { "description": "starts with underscore", "data": "_hostname", "valid": false }, { "description": "ends with underscore", "data": "hostname_", "valid": false }, { "description": "contains underscore", "data": "host_name", "valid": false }, { "description": "maximum label length", "data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.com", "valid": true }, { "description": "exceeds maximum label length", "data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl.com", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/format/idn-email.json0000644000175100001770000000335414653725311026433 0ustar00runnerdocker[ { "description": "validation of an internationalized e-mail addresses", "schema": { "format": "idn-email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid idn e-mail (example@example.test in Hangul)", "data": "실례@실례.테스트", "valid": true }, { "description": "an invalid idn e-mail address", "data": "2962", "valid": false }, { "description": "a valid e-mail address", "data": "joe.bloggs@example.com", "valid": true }, { "description": "an invalid e-mail address", "data": "2962", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/format/idn-hostname.json0000644000175100001770000003464114653725311027165 0ustar00runnerdocker[ { "description": "validation of internationalized host names", "schema": { "format": "idn-hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid host name (example.test in Hangul)", "data": "실례.테스트", "valid": true }, { "description": "illegal first char U+302E Hangul single dot tone mark", "data": "〮실례.테스트", "valid": false }, { "description": "contains illegal char U+302E Hangul single dot tone mark", "data": "실〮례.테스트", "valid": false }, { "description": "a host name with a component too long", "data": "실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실례례테스트례례례례례례례례례례례례례례례례례테스트례례례례례례례례례례례례례례례례례례례테스트례례례례례례례례례례례례테스트례례실례.테스트", "valid": false }, { "description": "invalid label, correct Punycode", "comment": "https://tools.ietf.org/html/rfc5890#section-2.3.2.1 https://tools.ietf.org/html/rfc5891#section-4.4 https://tools.ietf.org/html/rfc3492#section-7.1", "data": "-> $1.00 <--", "valid": false }, { "description": "valid Chinese Punycode", "comment": "https://tools.ietf.org/html/rfc5890#section-2.3.2.1 https://tools.ietf.org/html/rfc5891#section-4.4", "data": "xn--ihqwcrb4cv8a8dqg056pqjye", "valid": true }, { "description": "invalid Punycode", "comment": "https://tools.ietf.org/html/rfc5891#section-4.4 https://tools.ietf.org/html/rfc5890#section-2.3.2.1", "data": "xn--X", "valid": false }, { "description": "U-label contains \"--\" in the 3rd and 4th position", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1 https://tools.ietf.org/html/rfc5890#section-2.3.2.1", "data": "XN--aa---o47jg78q", "valid": false }, { "description": "U-label starts with a dash", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1", "data": "-hello", "valid": false }, { "description": "U-label ends with a dash", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1", "data": "hello-", "valid": false }, { "description": "U-label starts and ends with a dash", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1", "data": "-hello-", "valid": false }, { "description": "Begins with a Spacing Combining Mark", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2", "data": "\u0903hello", "valid": false }, { "description": "Begins with a Nonspacing Mark", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2", "data": "\u0300hello", "valid": false }, { "description": "Begins with an Enclosing Mark", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2", "data": "\u0488hello", "valid": false }, { "description": "Exceptions that are PVALID, left-to-right chars", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6", "data": "\u00df\u03c2\u0f0b\u3007", "valid": true }, { "description": "Exceptions that are PVALID, right-to-left chars", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6", "data": "\u06fd\u06fe", "valid": true }, { "description": "Exceptions that are DISALLOWED, right-to-left chars", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6", "data": "\u0640\u07fa", "valid": false }, { "description": "Exceptions that are DISALLOWED, left-to-right chars", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6 Note: The two combining marks (U+302E and U+302F) are in the middle and not at the start", "data": "\u3031\u3032\u3033\u3034\u3035\u302e\u302f\u303b", "valid": false }, { "description": "MIDDLE DOT with no preceding 'l'", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "a\u00b7l", "valid": false }, { "description": "MIDDLE DOT with nothing preceding", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "\u00b7l", "valid": false }, { "description": "MIDDLE DOT with no following 'l'", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "l\u00b7a", "valid": false }, { "description": "MIDDLE DOT with nothing following", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "l\u00b7", "valid": false }, { "description": "MIDDLE DOT with surrounding 'l's", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "l\u00b7l", "valid": true }, { "description": "Greek KERAIA not followed by Greek", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4", "data": "\u03b1\u0375S", "valid": false }, { "description": "Greek KERAIA not followed by anything", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4", "data": "\u03b1\u0375", "valid": false }, { "description": "Greek KERAIA followed by Greek", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4", "data": "\u03b1\u0375\u03b2", "valid": true }, { "description": "Hebrew GERESH not preceded by Hebrew", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5", "data": "A\u05f3\u05d1", "valid": false }, { "description": "Hebrew GERESH not preceded by anything", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5", "data": "\u05f3\u05d1", "valid": false }, { "description": "Hebrew GERESH preceded by Hebrew", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5", "data": "\u05d0\u05f3\u05d1", "valid": true }, { "description": "Hebrew GERSHAYIM not preceded by Hebrew", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6", "data": "A\u05f4\u05d1", "valid": false }, { "description": "Hebrew GERSHAYIM not preceded by anything", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6", "data": "\u05f4\u05d1", "valid": false }, { "description": "Hebrew GERSHAYIM preceded by Hebrew", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6", "data": "\u05d0\u05f4\u05d1", "valid": true }, { "description": "KATAKANA MIDDLE DOT with no Hiragana, Katakana, or Han", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "def\u30fbabc", "valid": false }, { "description": "KATAKANA MIDDLE DOT with no other characters", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "\u30fb", "valid": false }, { "description": "KATAKANA MIDDLE DOT with Hiragana", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "\u30fb\u3041", "valid": true }, { "description": "KATAKANA MIDDLE DOT with Katakana", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "\u30fb\u30a1", "valid": true }, { "description": "KATAKANA MIDDLE DOT with Han", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "\u30fb\u4e08", "valid": true }, { "description": "Arabic-Indic digits mixed with Extended Arabic-Indic digits", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.8", "data": "\u0660\u06f0", "valid": false }, { "description": "Arabic-Indic digits not mixed with Extended Arabic-Indic digits", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.8", "data": "\u0628\u0660\u0628", "valid": true }, { "description": "Extended Arabic-Indic digits not mixed with Arabic-Indic digits", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.9", "data": "\u06f00", "valid": true }, { "description": "ZERO WIDTH JOINER not preceded by Virama", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf", "data": "\u0915\u200d\u0937", "valid": false }, { "description": "ZERO WIDTH JOINER not preceded by anything", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf", "data": "\u200d\u0937", "valid": false }, { "description": "ZERO WIDTH JOINER preceded by Virama", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf", "data": "\u0915\u094d\u200d\u0937", "valid": true }, { "description": "ZERO WIDTH NON-JOINER preceded by Virama", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.1", "data": "\u0915\u094d\u200c\u0937", "valid": true }, { "description": "ZERO WIDTH NON-JOINER not preceded by Virama but matches regexp", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.1 https://www.w3.org/TR/alreq/#h_disjoining_enforcement", "data": "\u0628\u064a\u200c\u0628\u064a", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/format/ipv4.json0000644000175100001770000000540414653725311025454 0ustar00runnerdocker[ { "description": "validation of IP addresses", "schema": { "format": "ipv4" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IP address", "data": "192.168.0.1", "valid": true }, { "description": "an IP address with too many components", "data": "127.0.0.0.1", "valid": false }, { "description": "an IP address with out-of-range values", "data": "256.256.256.256", "valid": false }, { "description": "an IP address without 4 components", "data": "127.0", "valid": false }, { "description": "an IP address as an integer", "data": "0x7f000001", "valid": false }, { "description": "an IP address as an integer (decimal)", "data": "2130706433", "valid": false }, { "description": "invalid leading zeroes, as they are treated as octals", "comment": "see https://sick.codes/universal-netmask-npm-package-used-by-270000-projects-vulnerable-to-octal-input-data-server-side-request-forgery-remote-file-inclusion-local-file-inclusion-and-more-cve-2021-28918/", "data": "087.10.0.1", "valid": false }, { "description": "value without leading zero is valid", "data": "87.10.0.1", "valid": true }, { "description": "invalid non-ASCII '২' (a Bengali 2)", "data": "1২7.0.0.1", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/format/ipv6.json0000644000175100001770000001543714653725311025465 0ustar00runnerdocker[ { "description": "validation of IPv6 addresses", "schema": { "format": "ipv6" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IPv6 address", "data": "::1", "valid": true }, { "description": "an IPv6 address with out-of-range values", "data": "12345::", "valid": false }, { "description": "trailing 4 hex symbols is valid", "data": "::abef", "valid": true }, { "description": "trailing 5 hex symbols is invalid", "data": "::abcef", "valid": false }, { "description": "an IPv6 address with too many components", "data": "1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1", "valid": false }, { "description": "an IPv6 address containing illegal characters", "data": "::laptop", "valid": false }, { "description": "no digits is valid", "data": "::", "valid": true }, { "description": "leading colons is valid", "data": "::42:ff:1", "valid": true }, { "description": "trailing colons is valid", "data": "d6::", "valid": true }, { "description": "missing leading octet is invalid", "data": ":2:3:4:5:6:7:8", "valid": false }, { "description": "missing trailing octet is invalid", "data": "1:2:3:4:5:6:7:", "valid": false }, { "description": "missing leading octet with omitted octets later", "data": ":2:3:4::8", "valid": false }, { "description": "single set of double colons in the middle is valid", "data": "1:d6::42", "valid": true }, { "description": "two sets of double colons is invalid", "data": "1::d6::42", "valid": false }, { "description": "mixed format with the ipv4 section as decimal octets", "data": "1::d6:192.168.0.1", "valid": true }, { "description": "mixed format with double colons between the sections", "data": "1:2::192.168.0.1", "valid": true }, { "description": "mixed format with ipv4 section with octet out of range", "data": "1::2:192.168.256.1", "valid": false }, { "description": "mixed format with ipv4 section with a hex octet", "data": "1::2:192.168.ff.1", "valid": false }, { "description": "mixed format with leading double colons (ipv4-mapped ipv6 address)", "data": "::ffff:192.168.0.1", "valid": true }, { "description": "triple colons is invalid", "data": "1:2:3:4:5:::8", "valid": false }, { "description": "8 octets", "data": "1:2:3:4:5:6:7:8", "valid": true }, { "description": "insufficient octets without double colons", "data": "1:2:3:4:5:6:7", "valid": false }, { "description": "no colons is invalid", "data": "1", "valid": false }, { "description": "ipv4 is not ipv6", "data": "127.0.0.1", "valid": false }, { "description": "ipv4 segment must have 4 octets", "data": "1:2:3:4:1.2.3", "valid": false }, { "description": "leading whitespace is invalid", "data": " ::1", "valid": false }, { "description": "trailing whitespace is invalid", "data": "::1 ", "valid": false }, { "description": "netmask is not a part of ipv6 address", "data": "fe80::/64", "valid": false }, { "description": "zone id is not a part of ipv6 address", "data": "fe80::a%eth1", "valid": false }, { "description": "a long valid ipv6", "data": "1000:1000:1000:1000:1000:1000:255.255.255.255", "valid": true }, { "description": "a long invalid ipv6, below length limit, first", "data": "100:100:100:100:100:100:255.255.255.255.255", "valid": false }, { "description": "a long invalid ipv6, below length limit, second", "data": "100:100:100:100:100:100:100:255.255.255.255", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4)", "data": "1:2:3:4:5:6:7:৪", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4) in the IPv4 portion", "data": "1:2::192.16৪.0.1", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/format/iri-reference.json0000644000175100001770000000431214653725311027306 0ustar00runnerdocker[ { "description": "validation of IRI References", "schema": { "format": "iri-reference" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IRI", "data": "http://ƒøø.ßår/?∂éœ=πîx#πîüx", "valid": true }, { "description": "a valid protocol-relative IRI Reference", "data": "//ƒøø.ßår/?∂éœ=πîx#πîüx", "valid": true }, { "description": "a valid relative IRI Reference", "data": "/âππ", "valid": true }, { "description": "an invalid IRI Reference", "data": "\\\\WINDOWS\\filëßåré", "valid": false }, { "description": "a valid IRI Reference", "data": "âππ", "valid": true }, { "description": "a valid IRI fragment", "data": "#Æ’rägmênt", "valid": true }, { "description": "an invalid IRI fragment", "data": "#Æ’räg\\mênt", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/format/iri.json0000644000175100001770000000532414653725311025356 0ustar00runnerdocker[ { "description": "validation of IRIs", "schema": { "format": "iri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IRI with anchor tag", "data": "http://ƒøø.ßår/?∂éœ=πîx#πîüx", "valid": true }, { "description": "a valid IRI with anchor tag and parentheses", "data": "http://ƒøø.com/blah_(wîkïpédiÃ¥)_blah#ßité-1", "valid": true }, { "description": "a valid IRI with URL-encoded stuff", "data": "http://ƒøø.ßår/?q=Test%20URL-encoded%20stuff", "valid": true }, { "description": "a valid IRI with many special characters", "data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", "valid": true }, { "description": "a valid IRI based on IPv6", "data": "http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]", "valid": true }, { "description": "an invalid IRI based on IPv6", "data": "http://2001:0db8:85a3:0000:0000:8a2e:0370:7334", "valid": false }, { "description": "an invalid relative IRI Reference", "data": "/abc", "valid": false }, { "description": "an invalid IRI", "data": "\\\\WINDOWS\\filëßåré", "valid": false }, { "description": "an invalid IRI though valid IRI reference", "data": "âππ", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/format/json-pointer.json0000644000175100001770000001506314653725311027223 0ustar00runnerdocker[ { "description": "validation of JSON-pointers (JSON String Representation)", "schema": { "format": "json-pointer" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid JSON-pointer", "data": "/foo/bar~0/baz~1/%a", "valid": true }, { "description": "not a valid JSON-pointer (~ not escaped)", "data": "/foo/bar~", "valid": false }, { "description": "valid JSON-pointer with empty segment", "data": "/foo//bar", "valid": true }, { "description": "valid JSON-pointer with the last empty segment", "data": "/foo/bar/", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #1", "data": "", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #2", "data": "/foo", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #3", "data": "/foo/0", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #4", "data": "/", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #5", "data": "/a~1b", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #6", "data": "/c%d", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #7", "data": "/e^f", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #8", "data": "/g|h", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #9", "data": "/i\\j", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #10", "data": "/k\"l", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #11", "data": "/ ", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #12", "data": "/m~0n", "valid": true }, { "description": "valid JSON-pointer used adding to the last array position", "data": "/foo/-", "valid": true }, { "description": "valid JSON-pointer (- used as object member name)", "data": "/foo/-/bar", "valid": true }, { "description": "valid JSON-pointer (multiple escaped characters)", "data": "/~1~0~0~1~1", "valid": true }, { "description": "valid JSON-pointer (escaped with fraction part) #1", "data": "/~1.1", "valid": true }, { "description": "valid JSON-pointer (escaped with fraction part) #2", "data": "/~0.1", "valid": true }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #1", "data": "#", "valid": false }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #2", "data": "#/", "valid": false }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #3", "data": "#a", "valid": false }, { "description": "not a valid JSON-pointer (some escaped, but not all) #1", "data": "/~0~", "valid": false }, { "description": "not a valid JSON-pointer (some escaped, but not all) #2", "data": "/~0/~", "valid": false }, { "description": "not a valid JSON-pointer (wrong escape character) #1", "data": "/~2", "valid": false }, { "description": "not a valid JSON-pointer (wrong escape character) #2", "data": "/~-1", "valid": false }, { "description": "not a valid JSON-pointer (multiple characters not escaped)", "data": "/~~", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #1", "data": "a", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #2", "data": "0", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #3", "data": "a/a", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/format/regex.json0000644000175100001770000000261614653725311025706 0ustar00runnerdocker[ { "description": "validation of regular expressions", "schema": { "format": "regex" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid regular expression", "data": "([abc])+\\s+$", "valid": true }, { "description": "a regular expression with unclosed parens is invalid", "data": "^(abc]", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/format/relative-json-pointer.json0000644000175100001770000000574314653725311031040 0ustar00runnerdocker[ { "description": "validation of Relative JSON Pointers (RJP)", "schema": { "format": "relative-json-pointer" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid upwards RJP", "data": "1", "valid": true }, { "description": "a valid downwards RJP", "data": "0/foo/bar", "valid": true }, { "description": "a valid up and then down RJP, with array index", "data": "2/0/baz/1/zip", "valid": true }, { "description": "a valid RJP taking the member or index name", "data": "0#", "valid": true }, { "description": "an invalid RJP that is a valid JSON Pointer", "data": "/foo/bar", "valid": false }, { "description": "negative prefix", "data": "-1/foo/bar", "valid": false }, { "description": "explicit positive prefix", "data": "+1/foo/bar", "valid": false }, { "description": "## is not a valid json-pointer", "data": "0##", "valid": false }, { "description": "zero cannot be followed by other digits, plus json-pointer", "data": "01/a", "valid": false }, { "description": "zero cannot be followed by other digits, plus octothorpe", "data": "01#", "valid": false }, { "description": "empty string", "data": "", "valid": false }, { "description": "multi-digit integer prefix", "data": "120/foo/bar", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/format/time.json0000644000175100001770000001616614653725311025537 0ustar00runnerdocker[ { "description": "validation of time strings", "schema": { "format": "time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid time string", "data": "08:30:06Z", "valid": true }, { "description": "a valid time string with leap second, Zulu", "data": "23:59:60Z", "valid": true }, { "description": "invalid leap second, Zulu (wrong hour)", "data": "22:59:60Z", "valid": false }, { "description": "invalid leap second, Zulu (wrong minute)", "data": "23:58:60Z", "valid": false }, { "description": "valid leap second, zero time-offset", "data": "23:59:60+00:00", "valid": true }, { "description": "invalid leap second, zero time-offset (wrong hour)", "data": "22:59:60+00:00", "valid": false }, { "description": "invalid leap second, zero time-offset (wrong minute)", "data": "23:58:60+00:00", "valid": false }, { "description": "valid leap second, positive time-offset", "data": "01:29:60+01:30", "valid": true }, { "description": "valid leap second, large positive time-offset", "data": "23:29:60+23:30", "valid": true }, { "description": "invalid leap second, positive time-offset (wrong hour)", "data": "23:59:60+01:00", "valid": false }, { "description": "invalid leap second, positive time-offset (wrong minute)", "data": "23:59:60+00:30", "valid": false }, { "description": "valid leap second, negative time-offset", "data": "15:59:60-08:00", "valid": true }, { "description": "valid leap second, large negative time-offset", "data": "00:29:60-23:30", "valid": true }, { "description": "invalid leap second, negative time-offset (wrong hour)", "data": "23:59:60-01:00", "valid": false }, { "description": "invalid leap second, negative time-offset (wrong minute)", "data": "23:59:60-00:30", "valid": false }, { "description": "a valid time string with second fraction", "data": "23:20:50.52Z", "valid": true }, { "description": "a valid time string with precise second fraction", "data": "08:30:06.283185Z", "valid": true }, { "description": "a valid time string with plus offset", "data": "08:30:06+00:20", "valid": true }, { "description": "a valid time string with minus offset", "data": "08:30:06-08:00", "valid": true }, { "description": "a valid time string with case-insensitive Z", "data": "08:30:06z", "valid": true }, { "description": "an invalid time string with invalid hour", "data": "24:00:00Z", "valid": false }, { "description": "an invalid time string with invalid minute", "data": "00:60:00Z", "valid": false }, { "description": "an invalid time string with invalid second", "data": "00:00:61Z", "valid": false }, { "description": "an invalid time string with invalid leap second (wrong hour)", "data": "22:59:60Z", "valid": false }, { "description": "an invalid time string with invalid leap second (wrong minute)", "data": "23:58:60Z", "valid": false }, { "description": "an invalid time string with invalid time numoffset hour", "data": "01:02:03+24:00", "valid": false }, { "description": "an invalid time string with invalid time numoffset minute", "data": "01:02:03+00:60", "valid": false }, { "description": "an invalid time string with invalid time with both Z and numoffset", "data": "01:02:03Z+00:30", "valid": false }, { "description": "an invalid offset indicator", "data": "08:30:06 PST", "valid": false }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "01:01:01,1111", "valid": false }, { "description": "no time offset", "data": "12:00:00", "valid": false }, { "description": "no time offset with second fraction", "data": "12:00:00.52", "valid": false }, { "description": "invalid non-ASCII '২' (a Bengali 2)", "data": "1২:00:00Z", "valid": false }, { "description": "offset not starting with plus or minus", "data": "08:30:06#00:20", "valid": false }, { "description": "contains letters", "data": "ab:cd:ef", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/format/unknown.json0000644000175100001770000000226314653725311026271 0ustar00runnerdocker[ { "description": "unknown format", "schema": { "format": "unknown" }, "tests": [ { "description": "unknown formats ignore integers", "data": 12, "valid": true }, { "description": "unknown formats ignore floats", "data": 13.7, "valid": true }, { "description": "unknown formats ignore objects", "data": {}, "valid": true }, { "description": "unknown formats ignore arrays", "data": [], "valid": true }, { "description": "unknown formats ignore booleans", "data": false, "valid": true }, { "description": "unknown formats ignore nulls", "data": null, "valid": true }, { "description": "unknown formats ignore strings", "data": "string", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/format/uri-reference.json0000644000175100001770000000423714653725311027330 0ustar00runnerdocker[ { "description": "validation of URI References", "schema": { "format": "uri-reference" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid URI", "data": "http://foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid protocol-relative URI Reference", "data": "//foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid relative URI Reference", "data": "/abc", "valid": true }, { "description": "an invalid URI Reference", "data": "\\\\WINDOWS\\fileshare", "valid": false }, { "description": "a valid URI Reference", "data": "abc", "valid": true }, { "description": "a valid URI fragment", "data": "#fragment", "valid": true }, { "description": "an invalid URI fragment", "data": "#frag\\ment", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/format/uri-template.json0000644000175100001770000000343114653725311027200 0ustar00runnerdocker[ { "description": "format: uri-template", "schema": { "format": "uri-template" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid uri-template", "data": "http://example.com/dictionary/{term:1}/{term}", "valid": true }, { "description": "an invalid uri-template", "data": "http://example.com/dictionary/{term:1}/{term", "valid": false }, { "description": "a valid uri-template without variables", "data": "http://example.com/dictionary", "valid": true }, { "description": "a valid relative uri-template", "data": "dictionary/{term:1}/{term}", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/format/uri.json0000644000175100001770000001103414653725311025365 0ustar00runnerdocker[ { "description": "validation of URIs", "schema": { "format": "uri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid URL with anchor tag", "data": "http://foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid URL with anchor tag and parentheses", "data": "http://foo.com/blah_(wikipedia)_blah#cite-1", "valid": true }, { "description": "a valid URL with URL-encoded stuff", "data": "http://foo.bar/?q=Test%20URL-encoded%20stuff", "valid": true }, { "description": "a valid puny-coded URL ", "data": "http://xn--nw2a.xn--j6w193g/", "valid": true }, { "description": "a valid URL with many special characters", "data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", "valid": true }, { "description": "a valid URL based on IPv4", "data": "http://223.255.255.254", "valid": true }, { "description": "a valid URL with ftp scheme", "data": "ftp://ftp.is.co.za/rfc/rfc1808.txt", "valid": true }, { "description": "a valid URL for a simple text file", "data": "http://www.ietf.org/rfc/rfc2396.txt", "valid": true }, { "description": "a valid URL ", "data": "ldap://[2001:db8::7]/c=GB?objectClass?one", "valid": true }, { "description": "a valid mailto URI", "data": "mailto:John.Doe@example.com", "valid": true }, { "description": "a valid newsgroup URI", "data": "news:comp.infosystems.www.servers.unix", "valid": true }, { "description": "a valid tel URI", "data": "tel:+1-816-555-1212", "valid": true }, { "description": "a valid URN", "data": "urn:oasis:names:specification:docbook:dtd:xml:4.1.2", "valid": true }, { "description": "an invalid protocol-relative URI Reference", "data": "//foo.bar/?baz=qux#quux", "valid": false }, { "description": "an invalid relative URI Reference", "data": "/abc", "valid": false }, { "description": "an invalid URI", "data": "\\\\WINDOWS\\fileshare", "valid": false }, { "description": "an invalid URI though valid URI reference", "data": "abc", "valid": false }, { "description": "an invalid URI with spaces", "data": "http:// shouldfail.com", "valid": false }, { "description": "an invalid URI with spaces and missing scheme", "data": ":// should fail", "valid": false }, { "description": "an invalid URI with comma in scheme", "data": "bar,baz:foo", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/optional/non-bmp-regex.json0000644000175100001770000000453614653725311025765 0ustar00runnerdocker[ { "description": "Proper UTF-16 surrogate pair handling: pattern", "comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters", "schema": { "pattern": "^ðŸ²*$" }, "tests": [ { "description": "matches empty", "data": "", "valid": true }, { "description": "matches single", "data": "ðŸ²", "valid": true }, { "description": "matches two", "data": "ðŸ²ðŸ²", "valid": true }, { "description": "doesn't match one", "data": "ðŸ‰", "valid": false }, { "description": "doesn't match two", "data": "ðŸ‰ðŸ‰", "valid": false }, { "description": "doesn't match one ASCII", "data": "D", "valid": false }, { "description": "doesn't match two ASCII", "data": "DD", "valid": false } ] }, { "description": "Proper UTF-16 surrogate pair handling: patternProperties", "comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters", "schema": { "patternProperties": { "^ðŸ²*$": { "type": "integer" } } }, "tests": [ { "description": "matches empty", "data": { "": 1 }, "valid": true }, { "description": "matches single", "data": { "ðŸ²": 1 }, "valid": true }, { "description": "matches two", "data": { "ðŸ²ðŸ²": 1 }, "valid": true }, { "description": "doesn't match one", "data": { "ðŸ²": "hello" }, "valid": false }, { "description": "doesn't match two", "data": { "ðŸ²ðŸ²": "hello" }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/pattern.json0000644000175100001770000000300314653725311023123 0ustar00runnerdocker[ { "description": "pattern validation", "schema": {"pattern": "^a*$"}, "tests": [ { "description": "a matching pattern is valid", "data": "aaa", "valid": true }, { "description": "a non-matching pattern is invalid", "data": "abc", "valid": false }, { "description": "ignores booleans", "data": true, "valid": true }, { "description": "ignores integers", "data": 123, "valid": true }, { "description": "ignores floats", "data": 1.0, "valid": true }, { "description": "ignores objects", "data": {}, "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores null", "data": null, "valid": true } ] }, { "description": "pattern is not anchored", "schema": {"pattern": "a+"}, "tests": [ { "description": "matches a substring", "data": "xxaayy", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/patternProperties.json0000644000175100001770000001207114653725311025205 0ustar00runnerdocker[ { "description": "patternProperties validates properties matching a regex", "schema": { "patternProperties": { "f.*o": {"type": "integer"} } }, "tests": [ { "description": "a single valid match is valid", "data": {"foo": 1}, "valid": true }, { "description": "multiple valid matches is valid", "data": {"foo": 1, "foooooo" : 2}, "valid": true }, { "description": "a single invalid match is invalid", "data": {"foo": "bar", "fooooo": 2}, "valid": false }, { "description": "multiple invalid matches is invalid", "data": {"foo": "bar", "foooooo" : "baz"}, "valid": false }, { "description": "ignores arrays", "data": ["foo"], "valid": true }, { "description": "ignores strings", "data": "foo", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "multiple simultaneous patternProperties are validated", "schema": { "patternProperties": { "a*": {"type": "integer"}, "aaa*": {"maximum": 20} } }, "tests": [ { "description": "a single valid match is valid", "data": {"a": 21}, "valid": true }, { "description": "a simultaneous match is valid", "data": {"aaaa": 18}, "valid": true }, { "description": "multiple matches is valid", "data": {"a": 21, "aaaa": 18}, "valid": true }, { "description": "an invalid due to one is invalid", "data": {"a": "bar"}, "valid": false }, { "description": "an invalid due to the other is invalid", "data": {"aaaa": 31}, "valid": false }, { "description": "an invalid due to both is invalid", "data": {"aaa": "foo", "aaaa": 31}, "valid": false } ] }, { "description": "regexes are not anchored by default and are case sensitive", "schema": { "patternProperties": { "[0-9]{2,}": { "type": "boolean" }, "X_": { "type": "string" } } }, "tests": [ { "description": "non recognized members are ignored", "data": { "answer 1": "42" }, "valid": true }, { "description": "recognized members are accounted for", "data": { "a31b": null }, "valid": false }, { "description": "regexes are case sensitive", "data": { "a_x_3": 3 }, "valid": true }, { "description": "regexes are case sensitive, 2", "data": { "a_X_3": 3 }, "valid": false } ] }, { "description": "patternProperties with boolean schemas", "schema": { "patternProperties": { "f.*": true, "b.*": false } }, "tests": [ { "description": "object with property matching schema true is valid", "data": {"foo": 1}, "valid": true }, { "description": "object with property matching schema false is invalid", "data": {"bar": 2}, "valid": false }, { "description": "object with both properties is invalid", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "object with a property matching both true and false is invalid", "data": {"foobar":1}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "patternProperties with null valued instance properties", "schema": { "patternProperties": { "^.*bar$": {"type": "null"} } }, "tests": [ { "description": "allows null values", "data": {"foobar": null}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/properties.json0000644000175100001770000001621114653725311023647 0ustar00runnerdocker[ { "description": "object properties validation", "schema": { "properties": { "foo": {"type": "integer"}, "bar": {"type": "string"} } }, "tests": [ { "description": "both properties present and valid is valid", "data": {"foo": 1, "bar": "baz"}, "valid": true }, { "description": "one property invalid is invalid", "data": {"foo": 1, "bar": {}}, "valid": false }, { "description": "both properties invalid is invalid", "data": {"foo": [], "bar": {}}, "valid": false }, { "description": "doesn't invalidate other properties", "data": {"quux": []}, "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "properties, patternProperties, additionalProperties interaction", "schema": { "properties": { "foo": {"type": "array", "maxItems": 3}, "bar": {"type": "array"} }, "patternProperties": {"f.o": {"minItems": 2}}, "additionalProperties": {"type": "integer"} }, "tests": [ { "description": "property validates property", "data": {"foo": [1, 2]}, "valid": true }, { "description": "property invalidates property", "data": {"foo": [1, 2, 3, 4]}, "valid": false }, { "description": "patternProperty invalidates property", "data": {"foo": []}, "valid": false }, { "description": "patternProperty validates nonproperty", "data": {"fxo": [1, 2]}, "valid": true }, { "description": "patternProperty invalidates nonproperty", "data": {"fxo": []}, "valid": false }, { "description": "additionalProperty ignores property", "data": {"bar": []}, "valid": true }, { "description": "additionalProperty validates others", "data": {"quux": 3}, "valid": true }, { "description": "additionalProperty invalidates others", "data": {"quux": "foo"}, "valid": false } ] }, { "description": "properties with boolean schema", "schema": { "properties": { "foo": true, "bar": false } }, "tests": [ { "description": "no property present is valid", "data": {}, "valid": true }, { "description": "only 'true' property present is valid", "data": {"foo": 1}, "valid": true }, { "description": "only 'false' property present is invalid", "data": {"bar": 2}, "valid": false }, { "description": "both properties present is invalid", "data": {"foo": 1, "bar": 2}, "valid": false } ] }, { "description": "properties with escaped characters", "schema": { "properties": { "foo\nbar": {"type": "number"}, "foo\"bar": {"type": "number"}, "foo\\bar": {"type": "number"}, "foo\rbar": {"type": "number"}, "foo\tbar": {"type": "number"}, "foo\fbar": {"type": "number"} } }, "tests": [ { "description": "object with all numbers is valid", "data": { "foo\nbar": 1, "foo\"bar": 1, "foo\\bar": 1, "foo\rbar": 1, "foo\tbar": 1, "foo\fbar": 1 }, "valid": true }, { "description": "object with strings is invalid", "data": { "foo\nbar": "1", "foo\"bar": "1", "foo\\bar": "1", "foo\rbar": "1", "foo\tbar": "1", "foo\fbar": "1" }, "valid": false } ] }, { "description": "properties with null valued instance properties", "schema": { "properties": { "foo": {"type": "null"} } }, "tests": [ { "description": "allows null values", "data": {"foo": null}, "valid": true } ] }, { "description": "properties whose names are Javascript object property names", "comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.", "schema": { "properties": { "__proto__": {"type": "number"}, "toString": { "properties": { "length": { "type": "string" } } }, "constructor": {"type": "number"} } }, "tests": [ { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "none of the properties mentioned", "data": {}, "valid": true }, { "description": "__proto__ not valid", "data": { "__proto__": "foo" }, "valid": false }, { "description": "toString not valid", "data": { "toString": { "length": 37 } }, "valid": false }, { "description": "constructor not valid", "data": { "constructor": { "length": 37 } }, "valid": false }, { "description": "all present and valid", "data": { "__proto__": 12, "toString": { "length": "foo" }, "constructor": 37 }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/propertyNames.json0000644000175100001770000000557714653725311024340 0ustar00runnerdocker[ { "description": "propertyNames validation", "schema": { "propertyNames": {"maxLength": 3} }, "tests": [ { "description": "all property names valid", "data": { "f": {}, "foo": {} }, "valid": true }, { "description": "some property names invalid", "data": { "foo": {}, "foobar": {} }, "valid": false }, { "description": "object without properties is valid", "data": {}, "valid": true }, { "description": "ignores arrays", "data": [1, 2, 3, 4], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "propertyNames validation with pattern", "schema": { "propertyNames": { "pattern": "^a+$" } }, "tests": [ { "description": "matching property names valid", "data": { "a": {}, "aa": {}, "aaa": {} }, "valid": true }, { "description": "non-matching property name is invalid", "data": { "aaA": {} }, "valid": false }, { "description": "object without properties is valid", "data": {}, "valid": true } ] }, { "description": "propertyNames with boolean schema true", "schema": {"propertyNames": true}, "tests": [ { "description": "object with any properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "propertyNames with boolean schema false", "schema": {"propertyNames": false}, "tests": [ { "description": "object with any properties is invalid", "data": {"foo": 1}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/ref.json0000644000175100001770000005751414653725311022242 0ustar00runnerdocker[ { "description": "root pointer ref", "schema": { "properties": { "foo": {"$ref": "#"} }, "additionalProperties": false }, "tests": [ { "description": "match", "data": {"foo": false}, "valid": true }, { "description": "recursive match", "data": {"foo": {"foo": false}}, "valid": true }, { "description": "mismatch", "data": {"bar": false}, "valid": false }, { "description": "recursive mismatch", "data": {"foo": {"bar": false}}, "valid": false } ] }, { "description": "relative pointer ref to object", "schema": { "properties": { "foo": {"type": "integer"}, "bar": {"$ref": "#/properties/foo"} } }, "tests": [ { "description": "match", "data": {"bar": 3}, "valid": true }, { "description": "mismatch", "data": {"bar": true}, "valid": false } ] }, { "description": "relative pointer ref to array", "schema": { "items": [ {"type": "integer"}, {"$ref": "#/items/0"} ] }, "tests": [ { "description": "match array", "data": [1, 2], "valid": true }, { "description": "mismatch array", "data": [1, "foo"], "valid": false } ] }, { "description": "escaped pointer ref", "schema": { "definitions": { "tilde~field": {"type": "integer"}, "slash/field": {"type": "integer"}, "percent%field": {"type": "integer"} }, "properties": { "tilde": {"$ref": "#/definitions/tilde~0field"}, "slash": {"$ref": "#/definitions/slash~1field"}, "percent": {"$ref": "#/definitions/percent%25field"} } }, "tests": [ { "description": "slash invalid", "data": {"slash": "aoeu"}, "valid": false }, { "description": "tilde invalid", "data": {"tilde": "aoeu"}, "valid": false }, { "description": "percent invalid", "data": {"percent": "aoeu"}, "valid": false }, { "description": "slash valid", "data": {"slash": 123}, "valid": true }, { "description": "tilde valid", "data": {"tilde": 123}, "valid": true }, { "description": "percent valid", "data": {"percent": 123}, "valid": true } ] }, { "description": "nested refs", "schema": { "definitions": { "a": {"type": "integer"}, "b": {"$ref": "#/definitions/a"}, "c": {"$ref": "#/definitions/b"} }, "allOf": [{ "$ref": "#/definitions/c" }] }, "tests": [ { "description": "nested ref valid", "data": 5, "valid": true }, { "description": "nested ref invalid", "data": "a", "valid": false } ] }, { "description": "ref overrides any sibling keywords", "schema": { "definitions": { "reffed": { "type": "array" } }, "properties": { "foo": { "$ref": "#/definitions/reffed", "maxItems": 2 } } }, "tests": [ { "description": "ref valid", "data": { "foo": [] }, "valid": true }, { "description": "ref valid, maxItems ignored", "data": { "foo": [ 1, 2, 3] }, "valid": true }, { "description": "ref invalid", "data": { "foo": "string" }, "valid": false } ] }, { "description": "$ref prevents a sibling $id from changing the base uri", "schema": { "$id": "http://localhost:1234/sibling_id/base/", "definitions": { "foo": { "$id": "http://localhost:1234/sibling_id/foo.json", "type": "string" }, "base_foo": { "$comment": "this canonical uri is http://localhost:1234/sibling_id/base/foo.json", "$id": "foo.json", "type": "number" } }, "allOf": [ { "$comment": "$ref resolves to http://localhost:1234/sibling_id/base/foo.json, not http://localhost:1234/sibling_id/foo.json", "$id": "http://localhost:1234/sibling_id/", "$ref": "foo.json" } ] }, "tests": [ { "description": "$ref resolves to /definitions/base_foo, data does not validate", "data": "a", "valid": false }, { "description": "$ref resolves to /definitions/base_foo, data validates", "data": 1, "valid": true } ] }, { "description": "remote ref, containing refs itself", "schema": {"$ref": "http://json-schema.org/draft-07/schema#"}, "tests": [ { "description": "remote ref valid", "data": {"minLength": 1}, "valid": true }, { "description": "remote ref invalid", "data": {"minLength": -1}, "valid": false } ] }, { "description": "property named $ref that is not a reference", "schema": { "properties": { "$ref": {"type": "string"} } }, "tests": [ { "description": "property named $ref valid", "data": {"$ref": "a"}, "valid": true }, { "description": "property named $ref invalid", "data": {"$ref": 2}, "valid": false } ] }, { "description": "property named $ref, containing an actual $ref", "schema": { "properties": { "$ref": {"$ref": "#/definitions/is-string"} }, "definitions": { "is-string": { "type": "string" } } }, "tests": [ { "description": "property named $ref valid", "data": {"$ref": "a"}, "valid": true }, { "description": "property named $ref invalid", "data": {"$ref": 2}, "valid": false } ] }, { "description": "$ref to boolean schema true", "schema": { "allOf": [{ "$ref": "#/definitions/bool" }], "definitions": { "bool": true } }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "$ref to boolean schema false", "schema": { "allOf": [{ "$ref": "#/definitions/bool" }], "definitions": { "bool": false } }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "Recursive references between schemas", "schema": { "$id": "http://localhost:1234/tree", "description": "tree of nodes", "type": "object", "properties": { "meta": {"type": "string"}, "nodes": { "type": "array", "items": {"$ref": "node"} } }, "required": ["meta", "nodes"], "definitions": { "node": { "$id": "http://localhost:1234/node", "description": "node", "type": "object", "properties": { "value": {"type": "number"}, "subtree": {"$ref": "tree"} }, "required": ["value"] } } }, "tests": [ { "description": "valid tree", "data": { "meta": "root", "nodes": [ { "value": 1, "subtree": { "meta": "child", "nodes": [ {"value": 1.1}, {"value": 1.2} ] } }, { "value": 2, "subtree": { "meta": "child", "nodes": [ {"value": 2.1}, {"value": 2.2} ] } } ] }, "valid": true }, { "description": "invalid tree", "data": { "meta": "root", "nodes": [ { "value": 1, "subtree": { "meta": "child", "nodes": [ {"value": "string is invalid"}, {"value": 1.2} ] } }, { "value": 2, "subtree": { "meta": "child", "nodes": [ {"value": 2.1}, {"value": 2.2} ] } } ] }, "valid": false } ] }, { "description": "refs with quote", "schema": { "properties": { "foo\"bar": {"$ref": "#/definitions/foo%22bar"} }, "definitions": { "foo\"bar": {"type": "number"} } }, "tests": [ { "description": "object with numbers is valid", "data": { "foo\"bar": 1 }, "valid": true }, { "description": "object with strings is invalid", "data": { "foo\"bar": "1" }, "valid": false } ] }, { "description": "Location-independent identifier", "schema": { "allOf": [{ "$ref": "#foo" }], "definitions": { "A": { "$id": "#foo", "type": "integer" } } }, "tests": [ { "data": 1, "description": "match", "valid": true }, { "data": "a", "description": "mismatch", "valid": false } ] }, { "description": "Location-independent identifier with base URI change in subschema", "schema": { "$id": "http://localhost:1234/root", "allOf": [{ "$ref": "http://localhost:1234/nested.json#foo" }], "definitions": { "A": { "$id": "nested.json", "definitions": { "B": { "$id": "#foo", "type": "integer" } } } } }, "tests": [ { "data": 1, "description": "match", "valid": true }, { "data": "a", "description": "mismatch", "valid": false } ] }, { "description": "naive replacement of $ref with its destination is not correct", "schema": { "definitions": { "a_string": { "type": "string" } }, "enum": [ { "$ref": "#/definitions/a_string" } ] }, "tests": [ { "description": "do not evaluate the $ref inside the enum, matching any string", "data": "this is a string", "valid": false }, { "description": "do not evaluate the $ref inside the enum, definition exact match", "data": { "type": "string" }, "valid": false }, { "description": "match the enum exactly", "data": { "$ref": "#/definitions/a_string" }, "valid": true } ] }, { "description": "refs with relative uris and defs", "schema": { "$id": "http://example.com/schema-relative-uri-defs1.json", "properties": { "foo": { "$id": "schema-relative-uri-defs2.json", "definitions": { "inner": { "properties": { "bar": { "type": "string" } } } }, "allOf": [ { "$ref": "#/definitions/inner" } ] } }, "allOf": [ { "$ref": "schema-relative-uri-defs2.json" } ] }, "tests": [ { "description": "invalid on inner field", "data": { "foo": { "bar": 1 }, "bar": "a" }, "valid": false }, { "description": "invalid on outer field", "data": { "foo": { "bar": "a" }, "bar": 1 }, "valid": false }, { "description": "valid on both fields", "data": { "foo": { "bar": "a" }, "bar": "a" }, "valid": true } ] }, { "description": "relative refs with absolute uris and defs", "schema": { "$id": "http://example.com/schema-refs-absolute-uris-defs1.json", "properties": { "foo": { "$id": "http://example.com/schema-refs-absolute-uris-defs2.json", "definitions": { "inner": { "properties": { "bar": { "type": "string" } } } }, "allOf": [ { "$ref": "#/definitions/inner" } ] } }, "allOf": [ { "$ref": "schema-refs-absolute-uris-defs2.json" } ] }, "tests": [ { "description": "invalid on inner field", "data": { "foo": { "bar": 1 }, "bar": "a" }, "valid": false }, { "description": "invalid on outer field", "data": { "foo": { "bar": "a" }, "bar": 1 }, "valid": false }, { "description": "valid on both fields", "data": { "foo": { "bar": "a" }, "bar": "a" }, "valid": true } ] }, { "description": "$id must be resolved against nearest parent, not just immediate parent", "schema": { "$id": "http://example.com/a.json", "definitions": { "x": { "$id": "http://example.com/b/c.json", "not": { "definitions": { "y": { "$id": "d.json", "type": "number" } } } } }, "allOf": [ { "$ref": "http://example.com/b/d.json" } ] }, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "non-number is invalid", "data": "a", "valid": false } ] }, { "description": "simple URN base URI with $ref via the URN", "schema": { "$comment": "URIs do not have to have HTTP(s) schemes", "$id": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed", "minimum": 30, "properties": { "foo": {"$ref": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed"} } }, "tests": [ { "description": "valid under the URN IDed schema", "data": {"foo": 37}, "valid": true }, { "description": "invalid under the URN IDed schema", "data": {"foo": 12}, "valid": false } ] }, { "description": "simple URN base URI with JSON pointer", "schema": { "$comment": "URIs do not have to have HTTP(s) schemes", "$id": "urn:uuid:deadbeef-1234-00ff-ff00-4321feebdaed", "properties": { "foo": {"$ref": "#/definitions/bar"} }, "definitions": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with NSS", "schema": { "$comment": "RFC 8141 §2.2", "$id": "urn:example:1/406/47452/2", "properties": { "foo": {"$ref": "#/definitions/bar"} }, "definitions": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with r-component", "schema": { "$comment": "RFC 8141 §2.3.1", "$id": "urn:example:foo-bar-baz-qux?+CCResolve:cc=uk", "properties": { "foo": {"$ref": "#/definitions/bar"} }, "definitions": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with q-component", "schema": { "$comment": "RFC 8141 §2.3.2", "$id": "urn:example:weather?=op=map&lat=39.56&lon=-104.85&datetime=1969-07-21T02:56:15Z", "properties": { "foo": {"$ref": "#/definitions/bar"} }, "definitions": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with URN and JSON pointer ref", "schema": { "$id": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed", "properties": { "foo": {"$ref": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed#/definitions/bar"} }, "definitions": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with URN and anchor ref", "schema": { "$id": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed", "properties": { "foo": {"$ref": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed#something"} }, "definitions": { "bar": { "$id": "#something", "type": "string" } } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/refRemote.json0000644000175100001770000001504014653725311023402 0ustar00runnerdocker[ { "description": "remote ref", "schema": {"$ref": "http://localhost:1234/integer.json"}, "tests": [ { "description": "remote ref valid", "data": 1, "valid": true }, { "description": "remote ref invalid", "data": "a", "valid": false } ] }, { "description": "fragment within remote ref", "schema": {"$ref": "http://localhost:1234/subSchemas.json#/integer"}, "tests": [ { "description": "remote fragment valid", "data": 1, "valid": true }, { "description": "remote fragment invalid", "data": "a", "valid": false } ] }, { "description": "ref within remote ref", "schema": { "$ref": "http://localhost:1234/subSchemas.json#/refToInteger" }, "tests": [ { "description": "ref within ref valid", "data": 1, "valid": true }, { "description": "ref within ref invalid", "data": "a", "valid": false } ] }, { "description": "base URI change", "schema": { "$id": "http://localhost:1234/", "items": { "$id": "baseUriChange/", "items": {"$ref": "folderInteger.json"} } }, "tests": [ { "description": "base URI change ref valid", "data": [[1]], "valid": true }, { "description": "base URI change ref invalid", "data": [["a"]], "valid": false } ] }, { "description": "base URI change - change folder", "schema": { "$id": "http://localhost:1234/scope_change_defs1.json", "type" : "object", "properties": { "list": {"$ref": "#/definitions/baz"} }, "definitions": { "baz": { "$id": "baseUriChangeFolder/", "type": "array", "items": {"$ref": "folderInteger.json"} } } }, "tests": [ { "description": "number is valid", "data": {"list": [1]}, "valid": true }, { "description": "string is invalid", "data": {"list": ["a"]}, "valid": false } ] }, { "description": "base URI change - change folder in subschema", "schema": { "$id": "http://localhost:1234/scope_change_defs2.json", "type" : "object", "properties": { "list": {"$ref": "#/definitions/baz/definitions/bar"} }, "definitions": { "baz": { "$id": "baseUriChangeFolderInSubschema/", "definitions": { "bar": { "type": "array", "items": {"$ref": "folderInteger.json"} } } } } }, "tests": [ { "description": "number is valid", "data": {"list": [1]}, "valid": true }, { "description": "string is invalid", "data": {"list": ["a"]}, "valid": false } ] }, { "description": "root ref in remote ref", "schema": { "$id": "http://localhost:1234/object", "type": "object", "properties": { "name": {"$ref": "name.json#/definitions/orNull"} } }, "tests": [ { "description": "string is valid", "data": { "name": "foo" }, "valid": true }, { "description": "null is valid", "data": { "name": null }, "valid": true }, { "description": "object is invalid", "data": { "name": { "name": null } }, "valid": false } ] }, { "description": "remote ref with ref to definitions", "schema": { "$id": "http://localhost:1234/schema-remote-ref-ref-defs1.json", "allOf": [ { "$ref": "ref-and-definitions.json" } ] }, "tests": [ { "description": "invalid", "data": { "bar": 1 }, "valid": false }, { "description": "valid", "data": { "bar": "a" }, "valid": true } ] }, { "description": "Location-independent identifier in remote ref", "schema": { "$ref": "http://localhost:1234/locationIndependentIdentifierPre2019.json#/definitions/refToInteger" }, "tests": [ { "description": "integer is valid", "data": 1, "valid": true }, { "description": "string is invalid", "data": "foo", "valid": false } ] }, { "description": "retrieved nested refs resolve relative to their URI not $id", "schema": { "$id": "http://localhost:1234/some-id", "properties": { "name": {"$ref": "nested/foo-ref-string.json"} } }, "tests": [ { "description": "number is invalid", "data": { "name": {"foo": 1} }, "valid": false }, { "description": "string is valid", "data": { "name": {"foo": "a"} }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/required.json0000644000175100001770000001023414653725311023272 0ustar00runnerdocker[ { "description": "required validation", "schema": { "properties": { "foo": {}, "bar": {} }, "required": ["foo"] }, "tests": [ { "description": "present required property is valid", "data": {"foo": 1}, "valid": true }, { "description": "non-present required property is invalid", "data": {"bar": 1}, "valid": false }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "required default validation", "schema": { "properties": { "foo": {} } }, "tests": [ { "description": "not required by default", "data": {}, "valid": true } ] }, { "description": "required with empty array", "schema": { "properties": { "foo": {} }, "required": [] }, "tests": [ { "description": "property not required", "data": {}, "valid": true } ] }, { "description": "required with escaped characters", "schema": { "required": [ "foo\nbar", "foo\"bar", "foo\\bar", "foo\rbar", "foo\tbar", "foo\fbar" ] }, "tests": [ { "description": "object with all properties present is valid", "data": { "foo\nbar": 1, "foo\"bar": 1, "foo\\bar": 1, "foo\rbar": 1, "foo\tbar": 1, "foo\fbar": 1 }, "valid": true }, { "description": "object with some properties missing is invalid", "data": { "foo\nbar": "1", "foo\"bar": "1" }, "valid": false } ] }, { "description": "required properties whose names are Javascript object property names", "comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.", "schema": { "required": ["__proto__", "toString", "constructor"] }, "tests": [ { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "none of the properties mentioned", "data": {}, "valid": false }, { "description": "__proto__ present", "data": { "__proto__": "foo" }, "valid": false }, { "description": "toString present", "data": { "toString": { "length": 37 } }, "valid": false }, { "description": "constructor present", "data": { "constructor": { "length": 37 } }, "valid": false }, { "description": "all present", "data": { "__proto__": 12, "toString": { "length": "foo" }, "constructor": 37 }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/type.json0000644000175100001770000003214014653725311022433 0ustar00runnerdocker[ { "description": "integer type matches integers", "schema": {"type": "integer"}, "tests": [ { "description": "an integer is an integer", "data": 1, "valid": true }, { "description": "a float with zero fractional part is an integer", "data": 1.0, "valid": true }, { "description": "a float is not an integer", "data": 1.1, "valid": false }, { "description": "a string is not an integer", "data": "foo", "valid": false }, { "description": "a string is still not an integer, even if it looks like one", "data": "1", "valid": false }, { "description": "an object is not an integer", "data": {}, "valid": false }, { "description": "an array is not an integer", "data": [], "valid": false }, { "description": "a boolean is not an integer", "data": true, "valid": false }, { "description": "null is not an integer", "data": null, "valid": false } ] }, { "description": "number type matches numbers", "schema": {"type": "number"}, "tests": [ { "description": "an integer is a number", "data": 1, "valid": true }, { "description": "a float with zero fractional part is a number (and an integer)", "data": 1.0, "valid": true }, { "description": "a float is a number", "data": 1.1, "valid": true }, { "description": "a string is not a number", "data": "foo", "valid": false }, { "description": "a string is still not a number, even if it looks like one", "data": "1", "valid": false }, { "description": "an object is not a number", "data": {}, "valid": false }, { "description": "an array is not a number", "data": [], "valid": false }, { "description": "a boolean is not a number", "data": true, "valid": false }, { "description": "null is not a number", "data": null, "valid": false } ] }, { "description": "string type matches strings", "schema": {"type": "string"}, "tests": [ { "description": "1 is not a string", "data": 1, "valid": false }, { "description": "a float is not a string", "data": 1.1, "valid": false }, { "description": "a string is a string", "data": "foo", "valid": true }, { "description": "a string is still a string, even if it looks like a number", "data": "1", "valid": true }, { "description": "an empty string is still a string", "data": "", "valid": true }, { "description": "an object is not a string", "data": {}, "valid": false }, { "description": "an array is not a string", "data": [], "valid": false }, { "description": "a boolean is not a string", "data": true, "valid": false }, { "description": "null is not a string", "data": null, "valid": false } ] }, { "description": "object type matches objects", "schema": {"type": "object"}, "tests": [ { "description": "an integer is not an object", "data": 1, "valid": false }, { "description": "a float is not an object", "data": 1.1, "valid": false }, { "description": "a string is not an object", "data": "foo", "valid": false }, { "description": "an object is an object", "data": {}, "valid": true }, { "description": "an array is not an object", "data": [], "valid": false }, { "description": "a boolean is not an object", "data": true, "valid": false }, { "description": "null is not an object", "data": null, "valid": false } ] }, { "description": "array type matches arrays", "schema": {"type": "array"}, "tests": [ { "description": "an integer is not an array", "data": 1, "valid": false }, { "description": "a float is not an array", "data": 1.1, "valid": false }, { "description": "a string is not an array", "data": "foo", "valid": false }, { "description": "an object is not an array", "data": {}, "valid": false }, { "description": "an array is an array", "data": [], "valid": true }, { "description": "a boolean is not an array", "data": true, "valid": false }, { "description": "null is not an array", "data": null, "valid": false } ] }, { "description": "boolean type matches booleans", "schema": {"type": "boolean"}, "tests": [ { "description": "an integer is not a boolean", "data": 1, "valid": false }, { "description": "zero is not a boolean", "data": 0, "valid": false }, { "description": "a float is not a boolean", "data": 1.1, "valid": false }, { "description": "a string is not a boolean", "data": "foo", "valid": false }, { "description": "an empty string is not a boolean", "data": "", "valid": false }, { "description": "an object is not a boolean", "data": {}, "valid": false }, { "description": "an array is not a boolean", "data": [], "valid": false }, { "description": "true is a boolean", "data": true, "valid": true }, { "description": "false is a boolean", "data": false, "valid": true }, { "description": "null is not a boolean", "data": null, "valid": false } ] }, { "description": "null type matches only the null object", "schema": {"type": "null"}, "tests": [ { "description": "an integer is not null", "data": 1, "valid": false }, { "description": "a float is not null", "data": 1.1, "valid": false }, { "description": "zero is not null", "data": 0, "valid": false }, { "description": "a string is not null", "data": "foo", "valid": false }, { "description": "an empty string is not null", "data": "", "valid": false }, { "description": "an object is not null", "data": {}, "valid": false }, { "description": "an array is not null", "data": [], "valid": false }, { "description": "true is not null", "data": true, "valid": false }, { "description": "false is not null", "data": false, "valid": false }, { "description": "null is null", "data": null, "valid": true } ] }, { "description": "multiple types can be specified in an array", "schema": {"type": ["integer", "string"]}, "tests": [ { "description": "an integer is valid", "data": 1, "valid": true }, { "description": "a string is valid", "data": "foo", "valid": true }, { "description": "a float is invalid", "data": 1.1, "valid": false }, { "description": "an object is invalid", "data": {}, "valid": false }, { "description": "an array is invalid", "data": [], "valid": false }, { "description": "a boolean is invalid", "data": true, "valid": false }, { "description": "null is invalid", "data": null, "valid": false } ] }, { "description": "type as array with one item", "schema": { "type": ["string"] }, "tests": [ { "description": "string is valid", "data": "foo", "valid": true }, { "description": "number is invalid", "data": 123, "valid": false } ] }, { "description": "type: array or object", "schema": { "type": ["array", "object"] }, "tests": [ { "description": "array is valid", "data": [1,2,3], "valid": true }, { "description": "object is valid", "data": {"foo": 123}, "valid": true }, { "description": "number is invalid", "data": 123, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false }, { "description": "null is invalid", "data": null, "valid": false } ] }, { "description": "type: array, object or null", "schema": { "type": ["array", "object", "null"] }, "tests": [ { "description": "array is valid", "data": [1,2,3], "valid": true }, { "description": "object is valid", "data": {"foo": 123}, "valid": true }, { "description": "null is valid", "data": null, "valid": true }, { "description": "number is invalid", "data": 123, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/uniqueItems.json0000644000175100001770000003274014653725311023770 0ustar00runnerdocker[ { "description": "uniqueItems validation", "schema": {"uniqueItems": true}, "tests": [ { "description": "unique array of integers is valid", "data": [1, 2], "valid": true }, { "description": "non-unique array of integers is invalid", "data": [1, 1], "valid": false }, { "description": "non-unique array of more than two integers is invalid", "data": [1, 2, 1], "valid": false }, { "description": "numbers are unique if mathematically unequal", "data": [1.0, 1.00, 1], "valid": false }, { "description": "false is not equal to zero", "data": [0, false], "valid": true }, { "description": "true is not equal to one", "data": [1, true], "valid": true }, { "description": "unique array of strings is valid", "data": ["foo", "bar", "baz"], "valid": true }, { "description": "non-unique array of strings is invalid", "data": ["foo", "bar", "foo"], "valid": false }, { "description": "unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "baz"}], "valid": true }, { "description": "non-unique array of objects is invalid", "data": [{"foo": "bar"}, {"foo": "bar"}], "valid": false }, { "description": "unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : false}}} ], "valid": true }, { "description": "non-unique array of nested objects is invalid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : true}}} ], "valid": false }, { "description": "unique array of arrays is valid", "data": [["foo"], ["bar"]], "valid": true }, { "description": "non-unique array of arrays is invalid", "data": [["foo"], ["foo"]], "valid": false }, { "description": "non-unique array of more than two arrays is invalid", "data": [["foo"], ["bar"], ["foo"]], "valid": false }, { "description": "1 and true are unique", "data": [1, true], "valid": true }, { "description": "0 and false are unique", "data": [0, false], "valid": true }, { "description": "[1] and [true] are unique", "data": [[1], [true]], "valid": true }, { "description": "[0] and [false] are unique", "data": [[0], [false]], "valid": true }, { "description": "nested [1] and [true] are unique", "data": [[[1], "foo"], [[true], "foo"]], "valid": true }, { "description": "nested [0] and [false] are unique", "data": [[[0], "foo"], [[false], "foo"]], "valid": true }, { "description": "unique heterogeneous types are valid", "data": [{}, [1], true, null, 1, "{}"], "valid": true }, { "description": "non-unique heterogeneous types are invalid", "data": [{}, [1], true, null, {}, 1], "valid": false }, { "description": "different objects are unique", "data": [{"a": 1, "b": 2}, {"a": 2, "b": 1}], "valid": true }, { "description": "objects are non-unique despite key order", "data": [{"a": 1, "b": 2}, {"b": 2, "a": 1}], "valid": false }, { "description": "{\"a\": false} and {\"a\": 0} are unique", "data": [{"a": false}, {"a": 0}], "valid": true }, { "description": "{\"a\": true} and {\"a\": 1} are unique", "data": [{"a": true}, {"a": 1}], "valid": true } ] }, { "description": "uniqueItems with an array of items", "schema": { "items": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": true }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is not valid", "data": [false, false], "valid": false }, { "description": "[true, true] from items array is not valid", "data": [true, true], "valid": false }, { "description": "unique array extended from [false, true] is valid", "data": [false, true, "foo", "bar"], "valid": true }, { "description": "unique array extended from [true, false] is valid", "data": [true, false, "foo", "bar"], "valid": true }, { "description": "non-unique array extended from [false, true] is not valid", "data": [false, true, "foo", "foo"], "valid": false }, { "description": "non-unique array extended from [true, false] is not valid", "data": [true, false, "foo", "foo"], "valid": false } ] }, { "description": "uniqueItems with an array of items and additionalItems=false", "schema": { "items": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": true, "additionalItems": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is not valid", "data": [false, false], "valid": false }, { "description": "[true, true] from items array is not valid", "data": [true, true], "valid": false }, { "description": "extra items are invalid even if unique", "data": [false, true, null], "valid": false } ] }, { "description": "uniqueItems=false validation", "schema": { "uniqueItems": false }, "tests": [ { "description": "unique array of integers is valid", "data": [1, 2], "valid": true }, { "description": "non-unique array of integers is valid", "data": [1, 1], "valid": true }, { "description": "numbers are unique if mathematically unequal", "data": [1.0, 1.00, 1], "valid": true }, { "description": "false is not equal to zero", "data": [0, false], "valid": true }, { "description": "true is not equal to one", "data": [1, true], "valid": true }, { "description": "unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "baz"}], "valid": true }, { "description": "non-unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "bar"}], "valid": true }, { "description": "unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : false}}} ], "valid": true }, { "description": "non-unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : true}}} ], "valid": true }, { "description": "unique array of arrays is valid", "data": [["foo"], ["bar"]], "valid": true }, { "description": "non-unique array of arrays is valid", "data": [["foo"], ["foo"]], "valid": true }, { "description": "1 and true are unique", "data": [1, true], "valid": true }, { "description": "0 and false are unique", "data": [0, false], "valid": true }, { "description": "unique heterogeneous types are valid", "data": [{}, [1], true, null, 1], "valid": true }, { "description": "non-unique heterogeneous types are valid", "data": [{}, [1], true, null, {}, 1], "valid": true } ] }, { "description": "uniqueItems=false with an array of items", "schema": { "items": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is valid", "data": [false, false], "valid": true }, { "description": "[true, true] from items array is valid", "data": [true, true], "valid": true }, { "description": "unique array extended from [false, true] is valid", "data": [false, true, "foo", "bar"], "valid": true }, { "description": "unique array extended from [true, false] is valid", "data": [true, false, "foo", "bar"], "valid": true }, { "description": "non-unique array extended from [false, true] is valid", "data": [false, true, "foo", "foo"], "valid": true }, { "description": "non-unique array extended from [true, false] is valid", "data": [true, false, "foo", "foo"], "valid": true } ] }, { "description": "uniqueItems=false with an array of items and additionalItems=false", "schema": { "items": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": false, "additionalItems": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is valid", "data": [false, false], "valid": true }, { "description": "[true, true] from items array is valid", "data": [true, true], "valid": true }, { "description": "extra items are invalid even if unique", "data": [false, true, null], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/draft7/unknownKeyword.json0000644000175100001770000000374214653725311024524 0ustar00runnerdocker[ { "description": "$id inside an unknown keyword is not a real identifier", "comment": "the implementation must not be confused by an $id in locations we do not know how to parse", "schema": { "definitions": { "id_in_unknown0": { "not": { "array_of_schemas": [ { "$id": "https://localhost:1234/unknownKeyword/my_identifier.json", "type": "null" } ] } }, "real_id_in_schema": { "$id": "https://localhost:1234/unknownKeyword/my_identifier.json", "type": "string" }, "id_in_unknown1": { "not": { "object_of_schemas": { "foo": { "$id": "https://localhost:1234/unknownKeyword/my_identifier.json", "type": "integer" } } } } }, "anyOf": [ { "$ref": "#/definitions/id_in_unknown0" }, { "$ref": "#/definitions/id_in_unknown1" }, { "$ref": "https://localhost:1234/unknownKeyword/my_identifier.json" } ] }, "tests": [ { "description": "type matches second anyOf, which has a real schema in it", "data": "a string", "valid": true }, { "description": "type matches non-schema in first anyOf", "data": null, "valid": false }, { "description": "type matches non-schema in third anyOf", "data": 1, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1210978 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/0000755000175100001770000000000014653725331020666 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/additionalProperties.json0000644000175100001770000001152114653725311025744 0ustar00runnerdocker[ { "description": "additionalProperties being false does not allow other properties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": {"foo": {}, "bar": {}}, "patternProperties": { "^v": {} }, "additionalProperties": false }, "tests": [ { "description": "no additional properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "an additional property is invalid", "data": {"foo" : 1, "bar" : 2, "quux" : "boom"}, "valid": false }, { "description": "ignores arrays", "data": [1, 2, 3], "valid": true }, { "description": "ignores strings", "data": "foobarbaz", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "patternProperties are not additional properties", "data": {"foo":1, "vroom": 2}, "valid": true } ] }, { "description": "non-ASCII pattern with additionalProperties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "patternProperties": {"^á": {}}, "additionalProperties": false }, "tests": [ { "description": "matching the pattern is valid", "data": {"ármányos": 2}, "valid": true }, { "description": "not matching the pattern is invalid", "data": {"élmény": 2}, "valid": false } ] }, { "description": "additionalProperties with schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": {"foo": {}, "bar": {}}, "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "no additional properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "an additional valid property is valid", "data": {"foo" : 1, "bar" : 2, "quux" : true}, "valid": true }, { "description": "an additional invalid property is invalid", "data": {"foo" : 1, "bar" : 2, "quux" : 12}, "valid": false } ] }, { "description": "additionalProperties can exist by itself", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "an additional valid property is valid", "data": {"foo" : true}, "valid": true }, { "description": "an additional invalid property is invalid", "data": {"foo" : 1}, "valid": false } ] }, { "description": "additionalProperties are allowed by default", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": {"foo": {}, "bar": {}} }, "tests": [ { "description": "additional properties are allowed", "data": {"foo": 1, "bar": 2, "quux": true}, "valid": true } ] }, { "description": "additionalProperties does not look in applicators", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ {"properties": {"foo": {}}} ], "additionalProperties": {"type": "boolean"} }, "tests": [ { "description": "properties defined in allOf are not examined", "data": {"foo": 1, "bar": true}, "valid": false } ] }, { "description": "additionalProperties with null valued instance properties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": { "type": "null" } }, "tests": [ { "description": "allows null values", "data": {"foo": null}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/allOf.json0000644000175100001770000002077514653725311022627 0ustar00runnerdocker[ { "description": "allOf", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "allOf", "data": {"foo": "baz", "bar": 2}, "valid": true }, { "description": "mismatch second", "data": {"foo": "baz"}, "valid": false }, { "description": "mismatch first", "data": {"bar": 2}, "valid": false }, { "description": "wrong type", "data": {"foo": "baz", "bar": "quux"}, "valid": false } ] }, { "description": "allOf with base schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": {"bar": {"type": "integer"}}, "required": ["bar"], "allOf" : [ { "properties": { "foo": {"type": "string"} }, "required": ["foo"] }, { "properties": { "baz": {"type": "null"} }, "required": ["baz"] } ] }, "tests": [ { "description": "valid", "data": {"foo": "quux", "bar": 2, "baz": null}, "valid": true }, { "description": "mismatch base schema", "data": {"foo": "quux", "baz": null}, "valid": false }, { "description": "mismatch first allOf", "data": {"bar": 2, "baz": null}, "valid": false }, { "description": "mismatch second allOf", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "mismatch both", "data": {"bar": 2}, "valid": false } ] }, { "description": "allOf simple types", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ {"maximum": 30}, {"minimum": 20} ] }, "tests": [ { "description": "valid", "data": 25, "valid": true }, { "description": "mismatch one", "data": 35, "valid": false } ] }, { "description": "allOf with boolean schemas, all true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [true, true] }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "allOf with boolean schemas, some false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [true, false] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "allOf with boolean schemas, all false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [false, false] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "allOf with one empty schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ {} ] }, "tests": [ { "description": "any data is valid", "data": 1, "valid": true } ] }, { "description": "allOf with two empty schemas", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ {}, {} ] }, "tests": [ { "description": "any data is valid", "data": 1, "valid": true } ] }, { "description": "allOf with the first empty schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ {}, { "type": "number" } ] }, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is invalid", "data": "foo", "valid": false } ] }, { "description": "allOf with the last empty schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is invalid", "data": "foo", "valid": false } ] }, { "description": "nested allOf, to check validation semantics", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "allOf": [ { "type": "null" } ] } ] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "anything non-null is invalid", "data": 123, "valid": false } ] }, { "description": "allOf combined with anyOf, oneOf", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "multipleOf": 2 } ], "anyOf": [ { "multipleOf": 3 } ], "oneOf": [ { "multipleOf": 5 } ] }, "tests": [ { "description": "allOf: false, anyOf: false, oneOf: false", "data": 1, "valid": false }, { "description": "allOf: false, anyOf: false, oneOf: true", "data": 5, "valid": false }, { "description": "allOf: false, anyOf: true, oneOf: false", "data": 3, "valid": false }, { "description": "allOf: false, anyOf: true, oneOf: true", "data": 15, "valid": false }, { "description": "allOf: true, anyOf: false, oneOf: false", "data": 2, "valid": false }, { "description": "allOf: true, anyOf: false, oneOf: true", "data": 10, "valid": false }, { "description": "allOf: true, anyOf: true, oneOf: false", "data": 6, "valid": false }, { "description": "allOf: true, anyOf: true, oneOf: true", "data": 30, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/anchor.json0000644000175100001770000001604614653725311023040 0ustar00runnerdocker[ { "description": "Location-independent identifier", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "#foo", "$defs": { "A": { "$anchor": "foo", "type": "integer" } } }, "tests": [ { "data": 1, "description": "match", "valid": true }, { "data": "a", "description": "mismatch", "valid": false } ] }, { "description": "Location-independent identifier with absolute URI", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "http://localhost:1234/draft2020-12/bar#foo", "$defs": { "A": { "$id": "http://localhost:1234/draft2020-12/bar", "$anchor": "foo", "type": "integer" } } }, "tests": [ { "data": 1, "description": "match", "valid": true }, { "data": "a", "description": "mismatch", "valid": false } ] }, { "description": "Location-independent identifier with base URI change in subschema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/root", "$ref": "http://localhost:1234/draft2020-12/nested.json#foo", "$defs": { "A": { "$id": "nested.json", "$defs": { "B": { "$anchor": "foo", "type": "integer" } } } } }, "tests": [ { "data": 1, "description": "match", "valid": true }, { "data": "a", "description": "mismatch", "valid": false } ] }, { "description": "$anchor inside an enum is not a real identifier", "comment": "the implementation must not be confused by an $anchor buried in the enum", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "anchor_in_enum": { "enum": [ { "$anchor": "my_anchor", "type": "null" } ] }, "real_identifier_in_schema": { "$anchor": "my_anchor", "type": "string" }, "zzz_anchor_in_const": { "const": { "$anchor": "my_anchor", "type": "null" } } }, "anyOf": [ { "$ref": "#/$defs/anchor_in_enum" }, { "$ref": "#my_anchor" } ] }, "tests": [ { "description": "exact match to enum, and type matches", "data": { "$anchor": "my_anchor", "type": "null" }, "valid": true }, { "description": "in implementations that strip $anchor, this may match either $def", "data": { "type": "null" }, "valid": false }, { "description": "match $ref to $anchor", "data": "a string to match #/$defs/anchor_in_enum", "valid": true }, { "description": "no match on enum or $ref to $anchor", "data": 1, "valid": false } ] }, { "description": "same $anchor with different base uri", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/foobar", "$defs": { "A": { "$id": "child1", "allOf": [ { "$id": "child2", "$anchor": "my_anchor", "type": "number" }, { "$anchor": "my_anchor", "type": "string" } ] } }, "$ref": "child1#my_anchor" }, "tests": [ { "description": "$ref resolves to /$defs/A/allOf/1", "data": "a", "valid": true }, { "description": "$ref does not resolve to /$defs/A/allOf/0", "data": 1, "valid": false } ] }, { "description": "non-schema object containing an $anchor property", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "const_not_anchor": { "const": { "$anchor": "not_a_real_anchor" } } }, "if": { "const": "skip not_a_real_anchor" }, "then": true, "else" : { "$ref": "#/$defs/const_not_anchor" } }, "tests": [ { "description": "skip traversing definition for a valid result", "data": "skip not_a_real_anchor", "valid": true }, { "description": "const at const_not_anchor does not match", "data": 1, "valid": false } ] }, { "description": "invalid anchors", "comment": "Section 8.2.2", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "https://json-schema.org/draft/2020-12/schema" }, "tests": [ { "description": "MUST start with a letter (and not #)", "data": { "$anchor" : "#foo" }, "valid": false }, { "description": "JSON pointers are not valid", "data": { "$anchor" : "/a/b" }, "valid": false }, { "description": "invalid with valid beginning", "data": { "$anchor" : "foo#something" }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/anyOf.json0000644000175100001770000001252514653725311022640 0ustar00runnerdocker[ { "description": "anyOf", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "anyOf": [ { "type": "integer" }, { "minimum": 2 } ] }, "tests": [ { "description": "first anyOf valid", "data": 1, "valid": true }, { "description": "second anyOf valid", "data": 2.5, "valid": true }, { "description": "both anyOf valid", "data": 3, "valid": true }, { "description": "neither anyOf valid", "data": 1.5, "valid": false } ] }, { "description": "anyOf with base schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "anyOf" : [ { "maxLength": 2 }, { "minLength": 4 } ] }, "tests": [ { "description": "mismatch base schema", "data": 3, "valid": false }, { "description": "one anyOf valid", "data": "foobar", "valid": true }, { "description": "both anyOf invalid", "data": "foo", "valid": false } ] }, { "description": "anyOf with boolean schemas, all true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "anyOf": [true, true] }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "anyOf with boolean schemas, some true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "anyOf": [true, false] }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "anyOf with boolean schemas, all false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "anyOf": [false, false] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "anyOf complex types", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "anyOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "first anyOf valid (complex)", "data": {"bar": 2}, "valid": true }, { "description": "second anyOf valid (complex)", "data": {"foo": "baz"}, "valid": true }, { "description": "both anyOf valid (complex)", "data": {"foo": "baz", "bar": 2}, "valid": true }, { "description": "neither anyOf valid (complex)", "data": {"foo": 2, "bar": "quux"}, "valid": false } ] }, { "description": "anyOf with one empty schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "anyOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "string is valid", "data": "foo", "valid": true }, { "description": "number is valid", "data": 123, "valid": true } ] }, { "description": "nested anyOf, to check validation semantics", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "anyOf": [ { "anyOf": [ { "type": "null" } ] } ] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "anything non-null is invalid", "data": 123, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/boolean_schema.json0000644000175100001770000000540214653725311024517 0ustar00runnerdocker[ { "description": "boolean schema 'true'", "schema": true, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is valid", "data": "foo", "valid": true }, { "description": "boolean true is valid", "data": true, "valid": true }, { "description": "boolean false is valid", "data": false, "valid": true }, { "description": "null is valid", "data": null, "valid": true }, { "description": "object is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "empty object is valid", "data": {}, "valid": true }, { "description": "array is valid", "data": ["foo"], "valid": true }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "boolean schema 'false'", "schema": false, "tests": [ { "description": "number is invalid", "data": 1, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false }, { "description": "boolean true is invalid", "data": true, "valid": false }, { "description": "boolean false is invalid", "data": false, "valid": false }, { "description": "null is invalid", "data": null, "valid": false }, { "description": "object is invalid", "data": {"foo": "bar"}, "valid": false }, { "description": "empty object is invalid", "data": {}, "valid": false }, { "description": "array is invalid", "data": ["foo"], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/const.json0000644000175100001770000002534514653725311022716 0ustar00runnerdocker[ { "description": "const validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": 2 }, "tests": [ { "description": "same value is valid", "data": 2, "valid": true }, { "description": "another value is invalid", "data": 5, "valid": false }, { "description": "another type is invalid", "data": "a", "valid": false } ] }, { "description": "const with object", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": {"foo": "bar", "baz": "bax"} }, "tests": [ { "description": "same object is valid", "data": {"foo": "bar", "baz": "bax"}, "valid": true }, { "description": "same object with different property order is valid", "data": {"baz": "bax", "foo": "bar"}, "valid": true }, { "description": "another object is invalid", "data": {"foo": "bar"}, "valid": false }, { "description": "another type is invalid", "data": [1, 2], "valid": false } ] }, { "description": "const with array", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": [{ "foo": "bar" }] }, "tests": [ { "description": "same array is valid", "data": [{"foo": "bar"}], "valid": true }, { "description": "another array item is invalid", "data": [2], "valid": false }, { "description": "array with additional items is invalid", "data": [1, 2, 3], "valid": false } ] }, { "description": "const with null", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": null }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "not null is invalid", "data": 0, "valid": false } ] }, { "description": "const with false does not match 0", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": false }, "tests": [ { "description": "false is valid", "data": false, "valid": true }, { "description": "integer zero is invalid", "data": 0, "valid": false }, { "description": "float zero is invalid", "data": 0.0, "valid": false } ] }, { "description": "const with true does not match 1", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": true }, "tests": [ { "description": "true is valid", "data": true, "valid": true }, { "description": "integer one is invalid", "data": 1, "valid": false }, { "description": "float one is invalid", "data": 1.0, "valid": false } ] }, { "description": "const with [false] does not match [0]", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": [false] }, "tests": [ { "description": "[false] is valid", "data": [false], "valid": true }, { "description": "[0] is invalid", "data": [0], "valid": false }, { "description": "[0.0] is invalid", "data": [0.0], "valid": false } ] }, { "description": "const with [true] does not match [1]", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": [true] }, "tests": [ { "description": "[true] is valid", "data": [true], "valid": true }, { "description": "[1] is invalid", "data": [1], "valid": false }, { "description": "[1.0] is invalid", "data": [1.0], "valid": false } ] }, { "description": "const with {\"a\": false} does not match {\"a\": 0}", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": {"a": false} }, "tests": [ { "description": "{\"a\": false} is valid", "data": {"a": false}, "valid": true }, { "description": "{\"a\": 0} is invalid", "data": {"a": 0}, "valid": false }, { "description": "{\"a\": 0.0} is invalid", "data": {"a": 0.0}, "valid": false } ] }, { "description": "const with {\"a\": true} does not match {\"a\": 1}", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": {"a": true} }, "tests": [ { "description": "{\"a\": true} is valid", "data": {"a": true}, "valid": true }, { "description": "{\"a\": 1} is invalid", "data": {"a": 1}, "valid": false }, { "description": "{\"a\": 1.0} is invalid", "data": {"a": 1.0}, "valid": false } ] }, { "description": "const with 0 does not match other zero-like types", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": 0 }, "tests": [ { "description": "false is invalid", "data": false, "valid": false }, { "description": "integer zero is valid", "data": 0, "valid": true }, { "description": "float zero is valid", "data": 0.0, "valid": true }, { "description": "empty object is invalid", "data": {}, "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false }, { "description": "empty string is invalid", "data": "", "valid": false } ] }, { "description": "const with 1 does not match true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": 1 }, "tests": [ { "description": "true is invalid", "data": true, "valid": false }, { "description": "integer one is valid", "data": 1, "valid": true }, { "description": "float one is valid", "data": 1.0, "valid": true } ] }, { "description": "const with -2.0 matches integer and float types", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": -2.0 }, "tests": [ { "description": "integer -2 is valid", "data": -2, "valid": true }, { "description": "integer 2 is invalid", "data": 2, "valid": false }, { "description": "float -2.0 is valid", "data": -2.0, "valid": true }, { "description": "float 2.0 is invalid", "data": 2.0, "valid": false }, { "description": "float -2.00001 is invalid", "data": -2.00001, "valid": false } ] }, { "description": "float and integers are equal up to 64-bit representation limits", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": 9007199254740992 }, "tests": [ { "description": "integer is valid", "data": 9007199254740992, "valid": true }, { "description": "integer minus one is invalid", "data": 9007199254740991, "valid": false }, { "description": "float is valid", "data": 9007199254740992.0, "valid": true }, { "description": "float minus one is invalid", "data": 9007199254740991.0, "valid": false } ] }, { "description": "nul characters in strings", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "const": "hello\u0000there" }, "tests": [ { "description": "match string with nul", "data": "hello\u0000there", "valid": true }, { "description": "do not match string lacking nul", "data": "hellothere", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/contains.json0000644000175100001770000001206614653725311023402 0ustar00runnerdocker[ { "description": "contains keyword validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": {"minimum": 5} }, "tests": [ { "description": "array with item matching schema (5) is valid", "data": [3, 4, 5], "valid": true }, { "description": "array with item matching schema (6) is valid", "data": [3, 4, 6], "valid": true }, { "description": "array with two items matching schema (5, 6) is valid", "data": [3, 4, 5, 6], "valid": true }, { "description": "array without items matching schema is invalid", "data": [2, 3, 4], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false }, { "description": "not array is valid", "data": {}, "valid": true } ] }, { "description": "contains keyword with const keyword", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": { "const": 5 } }, "tests": [ { "description": "array with item 5 is valid", "data": [3, 4, 5], "valid": true }, { "description": "array with two items 5 is valid", "data": [3, 4, 5, 5], "valid": true }, { "description": "array without item 5 is invalid", "data": [1, 2, 3, 4], "valid": false } ] }, { "description": "contains keyword with boolean schema true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": true }, "tests": [ { "description": "any non-empty array is valid", "data": ["foo"], "valid": true }, { "description": "empty array is invalid", "data": [], "valid": false } ] }, { "description": "contains keyword with boolean schema false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": false }, "tests": [ { "description": "any non-empty array is invalid", "data": ["foo"], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false }, { "description": "non-arrays are valid", "data": "contains does not apply to strings", "valid": true } ] }, { "description": "items + contains", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "items": { "multipleOf": 2 }, "contains": { "multipleOf": 3 } }, "tests": [ { "description": "matches items, does not match contains", "data": [ 2, 4, 8 ], "valid": false }, { "description": "does not match items, matches contains", "data": [ 3, 6, 9 ], "valid": false }, { "description": "matches both items and contains", "data": [ 6, 12 ], "valid": true }, { "description": "matches neither items nor contains", "data": [ 1, 5 ], "valid": false } ] }, { "description": "contains with false if subschema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": { "if": false, "else": true } }, "tests": [ { "description": "any non-empty array is valid", "data": ["foo"], "valid": true }, { "description": "empty array is invalid", "data": [], "valid": false } ] }, { "description": "contains with null instance elements", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": { "type": "null" } }, "tests": [ { "description": "allows null items", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/content.json0000644000175100001770000001045514653725311023236 0ustar00runnerdocker[ { "description": "validation of string-encoded content based on media type", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contentMediaType": "application/json" }, "tests": [ { "description": "a valid JSON document", "data": "{\"foo\": \"bar\"}", "valid": true }, { "description": "an invalid JSON document; validates true", "data": "{:}", "valid": true }, { "description": "ignores non-strings", "data": 100, "valid": true } ] }, { "description": "validation of binary string-encoding", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contentEncoding": "base64" }, "tests": [ { "description": "a valid base64 string", "data": "eyJmb28iOiAiYmFyIn0K", "valid": true }, { "description": "an invalid base64 string (% is not a valid character); validates true", "data": "eyJmb28iOi%iYmFyIn0K", "valid": true }, { "description": "ignores non-strings", "data": 100, "valid": true } ] }, { "description": "validation of binary-encoded media type documents", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contentMediaType": "application/json", "contentEncoding": "base64" }, "tests": [ { "description": "a valid base64-encoded JSON document", "data": "eyJmb28iOiAiYmFyIn0K", "valid": true }, { "description": "a validly-encoded invalid JSON document; validates true", "data": "ezp9Cg==", "valid": true }, { "description": "an invalid base64 string that is valid JSON; validates true", "data": "{}", "valid": true }, { "description": "ignores non-strings", "data": 100, "valid": true } ] }, { "description": "validation of binary-encoded media type documents with schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contentMediaType": "application/json", "contentEncoding": "base64", "contentSchema": { "type": "object", "required": ["foo"], "properties": { "foo": { "type": "string" } } } }, "tests": [ { "description": "a valid base64-encoded JSON document", "data": "eyJmb28iOiAiYmFyIn0K", "valid": true }, { "description": "another valid base64-encoded JSON document", "data": "eyJib28iOiAyMCwgImZvbyI6ICJiYXoifQ==", "valid": true }, { "description": "an invalid base64-encoded JSON document; validates true", "data": "eyJib28iOiAyMH0=", "valid": true }, { "description": "an empty object as a base64-encoded JSON document; validates true", "data": "e30=", "valid": true }, { "description": "an empty array as a base64-encoded JSON document", "data": "W10=", "valid": true }, { "description": "a validly-encoded invalid JSON document; validates true", "data": "ezp9Cg==", "valid": true }, { "description": "an invalid base64 string that is valid JSON; validates true", "data": "{}", "valid": true }, { "description": "ignores non-strings", "data": 100, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/default.json0000644000175100001770000000461414653725311023210 0ustar00runnerdocker[ { "description": "invalid type for default", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": { "type": "integer", "default": [] } } }, "tests": [ { "description": "valid when property is specified", "data": {"foo": 13}, "valid": true }, { "description": "still valid when the invalid default is used", "data": {}, "valid": true } ] }, { "description": "invalid string value for default", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "bar": { "type": "string", "minLength": 4, "default": "bad" } } }, "tests": [ { "description": "valid when property is specified", "data": {"bar": "good"}, "valid": true }, { "description": "still valid when the invalid default is used", "data": {}, "valid": true } ] }, { "description": "the default keyword does not do anything if the property is missing", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "alpha": { "type": "number", "maximum": 3, "default": 5 } } }, "tests": [ { "description": "an explicit property value is checked against maximum (passing)", "data": { "alpha": 1 }, "valid": true }, { "description": "an explicit property value is checked against maximum (failing)", "data": { "alpha": 5 }, "valid": false }, { "description": "missing properties are not filled in with the default", "data": {}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/defs.json0000644000175100001770000000117514653725311022504 0ustar00runnerdocker[ { "description": "validate definition against metaschema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "https://json-schema.org/draft/2020-12/schema" }, "tests": [ { "description": "valid definition schema", "data": {"$defs": {"foo": {"type": "integer"}}}, "valid": true }, { "description": "invalid definition schema", "data": {"$defs": {"foo": {"type": 1}}}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/dependentRequired.json0000644000175100001770000001030614653725311025226 0ustar00runnerdocker[ { "description": "single dependency", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependentRequired": {"bar": ["foo"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependant", "data": {"foo": 1}, "valid": true }, { "description": "with dependency", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "missing dependency", "data": {"bar": 2}, "valid": false }, { "description": "ignores arrays", "data": ["bar"], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "empty dependents", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependentRequired": {"bar": []} }, "tests": [ { "description": "empty object", "data": {}, "valid": true }, { "description": "object with one property", "data": {"bar": 2}, "valid": true }, { "description": "non-object is valid", "data": 1, "valid": true } ] }, { "description": "multiple dependents required", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependentRequired": {"quux": ["foo", "bar"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependants", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "with dependencies", "data": {"foo": 1, "bar": 2, "quux": 3}, "valid": true }, { "description": "missing dependency", "data": {"foo": 1, "quux": 2}, "valid": false }, { "description": "missing other dependency", "data": {"bar": 1, "quux": 2}, "valid": false }, { "description": "missing both dependencies", "data": {"quux": 1}, "valid": false } ] }, { "description": "dependencies with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependentRequired": { "foo\nbar": ["foo\rbar"], "foo\"bar": ["foo'bar"] } }, "tests": [ { "description": "CRLF", "data": { "foo\nbar": 1, "foo\rbar": 2 }, "valid": true }, { "description": "quoted quotes", "data": { "foo'bar": 1, "foo\"bar": 2 }, "valid": true }, { "description": "CRLF missing dependent", "data": { "foo\nbar": 1, "foo": 2 }, "valid": false }, { "description": "quoted quotes missing dependent", "data": { "foo\"bar": 2 }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/dependentSchemas.json0000644000175100001770000000743714653725311025044 0ustar00runnerdocker[ { "description": "single dependency", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependentSchemas": { "bar": { "properties": { "foo": {"type": "integer"}, "bar": {"type": "integer"} } } } }, "tests": [ { "description": "valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "no dependency", "data": {"foo": "quux"}, "valid": true }, { "description": "wrong type", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "wrong type other", "data": {"foo": 2, "bar": "quux"}, "valid": false }, { "description": "wrong type both", "data": {"foo": "quux", "bar": "quux"}, "valid": false }, { "description": "ignores arrays", "data": ["bar"], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "boolean subschemas", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependentSchemas": { "foo": true, "bar": false } }, "tests": [ { "description": "object with property having schema true is valid", "data": {"foo": 1}, "valid": true }, { "description": "object with property having schema false is invalid", "data": {"bar": 2}, "valid": false }, { "description": "object with both properties is invalid", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "dependencies with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependentSchemas": { "foo\tbar": {"minProperties": 4}, "foo'bar": {"required": ["foo\"bar"]} } }, "tests": [ { "description": "quoted tab", "data": { "foo\tbar": 1, "a": 2, "b": 3, "c": 4 }, "valid": true }, { "description": "quoted quote", "data": { "foo'bar": {"foo\"bar": 1} }, "valid": false }, { "description": "quoted tab invalid under dependent schema", "data": { "foo\tbar": 1, "a": 2 }, "valid": false }, { "description": "quoted quote invalid under dependent schema", "data": {"foo'bar": 1}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/dynamicRef.json0000644000175100001770000005212414653725311023644 0ustar00runnerdocker[ { "description": "A $dynamicRef to a $dynamicAnchor in the same schema resource behaves like a normal $ref to an $anchor", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/dynamicRef-dynamicAnchor-same-schema/root", "type": "array", "items": { "$dynamicRef": "#items" }, "$defs": { "foo": { "$dynamicAnchor": "items", "type": "string" } } }, "tests": [ { "description": "An array of strings is valid", "data": ["foo", "bar"], "valid": true }, { "description": "An array containing non-strings is invalid", "data": ["foo", 42], "valid": false } ] }, { "description": "A $dynamicRef to an $anchor in the same schema resource behaves like a normal $ref to an $anchor", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/dynamicRef-anchor-same-schema/root", "type": "array", "items": { "$dynamicRef": "#items" }, "$defs": { "foo": { "$anchor": "items", "type": "string" } } }, "tests": [ { "description": "An array of strings is valid", "data": ["foo", "bar"], "valid": true }, { "description": "An array containing non-strings is invalid", "data": ["foo", 42], "valid": false } ] }, { "description": "A $ref to a $dynamicAnchor in the same schema resource behaves like a normal $ref to an $anchor", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/ref-dynamicAnchor-same-schema/root", "type": "array", "items": { "$ref": "#items" }, "$defs": { "foo": { "$dynamicAnchor": "items", "type": "string" } } }, "tests": [ { "description": "An array of strings is valid", "data": ["foo", "bar"], "valid": true }, { "description": "An array containing non-strings is invalid", "data": ["foo", 42], "valid": false } ] }, { "description": "A $dynamicRef resolves to the first $dynamicAnchor still in scope that is encountered when the schema is evaluated", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/typical-dynamic-resolution/root", "$ref": "list", "$defs": { "foo": { "$dynamicAnchor": "items", "type": "string" }, "list": { "$id": "list", "type": "array", "items": { "$dynamicRef": "#items" }, "$defs": { "items": { "$comment": "This is only needed to satisfy the bookending requirement", "$dynamicAnchor": "items" } } } } }, "tests": [ { "description": "An array of strings is valid", "data": ["foo", "bar"], "valid": true }, { "description": "An array containing non-strings is invalid", "data": ["foo", 42], "valid": false } ] }, { "description": "A $dynamicRef with intermediate scopes that don't include a matching $dynamicAnchor does not affect dynamic scope resolution", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/dynamic-resolution-with-intermediate-scopes/root", "$ref": "intermediate-scope", "$defs": { "foo": { "$dynamicAnchor": "items", "type": "string" }, "intermediate-scope": { "$id": "intermediate-scope", "$ref": "list" }, "list": { "$id": "list", "type": "array", "items": { "$dynamicRef": "#items" }, "$defs": { "items": { "$comment": "This is only needed to satisfy the bookending requirement", "$dynamicAnchor": "items" } } } } }, "tests": [ { "description": "An array of strings is valid", "data": ["foo", "bar"], "valid": true }, { "description": "An array containing non-strings is invalid", "data": ["foo", 42], "valid": false } ] }, { "description": "An $anchor with the same name as a $dynamicAnchor is not used for dynamic scope resolution", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/dynamic-resolution-ignores-anchors/root", "$ref": "list", "$defs": { "foo": { "$anchor": "items", "type": "string" }, "list": { "$id": "list", "type": "array", "items": { "$dynamicRef": "#items" }, "$defs": { "items": { "$comment": "This is only needed to satisfy the bookending requirement", "$dynamicAnchor": "items" } } } } }, "tests": [ { "description": "Any array is valid", "data": ["foo", 42], "valid": true } ] }, { "description": "A $dynamicRef without a matching $dynamicAnchor in the same schema resource behaves like a normal $ref to $anchor", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/dynamic-resolution-without-bookend/root", "$ref": "list", "$defs": { "foo": { "$dynamicAnchor": "items", "type": "string" }, "list": { "$id": "list", "type": "array", "items": { "$dynamicRef": "#items" }, "$defs": { "items": { "$comment": "This is only needed to give the reference somewhere to resolve to when it behaves like $ref", "$anchor": "items" } } } } }, "tests": [ { "description": "Any array is valid", "data": ["foo", 42], "valid": true } ] }, { "description": "A $dynamicRef with a non-matching $dynamicAnchor in the same schema resource behaves like a normal $ref to $anchor", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/unmatched-dynamic-anchor/root", "$ref": "list", "$defs": { "foo": { "$dynamicAnchor": "items", "type": "string" }, "list": { "$id": "list", "type": "array", "items": { "$dynamicRef": "#items" }, "$defs": { "items": { "$comment": "This is only needed to give the reference somewhere to resolve to when it behaves like $ref", "$anchor": "items", "$dynamicAnchor": "foo" } } } } }, "tests": [ { "description": "Any array is valid", "data": ["foo", 42], "valid": true } ] }, { "description": "A $dynamicRef that initially resolves to a schema with a matching $dynamicAnchor resolves to the first $dynamicAnchor in the dynamic scope", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/relative-dynamic-reference/root", "$dynamicAnchor": "meta", "type": "object", "properties": { "foo": { "const": "pass" } }, "$ref": "extended", "$defs": { "extended": { "$id": "extended", "$dynamicAnchor": "meta", "type": "object", "properties": { "bar": { "$ref": "bar" } } }, "bar": { "$id": "bar", "type": "object", "properties": { "baz": { "$dynamicRef": "extended#meta" } } } } }, "tests": [ { "description": "The recursive part is valid against the root", "data": { "foo": "pass", "bar": { "baz": { "foo": "pass" } } }, "valid": true }, { "description": "The recursive part is not valid against the root", "data": { "foo": "pass", "bar": { "baz": { "foo": "fail" } } }, "valid": false } ] }, { "description": "A $dynamicRef that initially resolves to a schema without a matching $dynamicAnchor behaves like a normal $ref to $anchor", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/relative-dynamic-reference-without-bookend/root", "$dynamicAnchor": "meta", "type": "object", "properties": { "foo": { "const": "pass" } }, "$ref": "extended", "$defs": { "extended": { "$id": "extended", "$anchor": "meta", "type": "object", "properties": { "bar": { "$ref": "bar" } } }, "bar": { "$id": "bar", "type": "object", "properties": { "baz": { "$dynamicRef": "extended#meta" } } } } }, "tests": [ { "description": "The recursive part doesn't need to validate against the root", "data": { "foo": "pass", "bar": { "baz": { "foo": "fail" } } }, "valid": true } ] }, { "description": "multiple dynamic paths to the $dynamicRef keyword", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/dynamic-ref-with-multiple-paths/main", "$defs": { "inner": { "$id": "inner", "$dynamicAnchor": "foo", "title": "inner", "additionalProperties": { "$dynamicRef": "#foo" } } }, "if": { "propertyNames": { "pattern": "^[a-m]" } }, "then": { "title": "any type of node", "$id": "anyLeafNode", "$dynamicAnchor": "foo", "$ref": "inner" }, "else": { "title": "integer node", "$id": "integerNode", "$dynamicAnchor": "foo", "type": [ "object", "integer" ], "$ref": "inner" } }, "tests": [ { "description": "recurse to anyLeafNode - floats are allowed", "data": { "alpha": 1.1 }, "valid": true }, { "description": "recurse to integerNode - floats are not allowed", "data": { "november": 1.1 }, "valid": false } ] }, { "description": "after leaving a dynamic scope, it is not used by a $dynamicRef", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://test.json-schema.org/dynamic-ref-leaving-dynamic-scope/main", "if": { "$id": "first_scope", "$defs": { "thingy": { "$comment": "this is first_scope#thingy", "$dynamicAnchor": "thingy", "type": "number" } } }, "then": { "$id": "second_scope", "$ref": "start", "$defs": { "thingy": { "$comment": "this is second_scope#thingy, the final destination of the $dynamicRef", "$dynamicAnchor": "thingy", "type": "null" } } }, "$defs": { "start": { "$comment": "this is the landing spot from $ref", "$id": "start", "$dynamicRef": "inner_scope#thingy" }, "thingy": { "$comment": "this is the first stop for the $dynamicRef", "$id": "inner_scope", "$dynamicAnchor": "thingy", "type": "string" } } }, "tests": [ { "description": "string matches /$defs/thingy, but the $dynamicRef does not stop here", "data": "a string", "valid": false }, { "description": "first_scope is not in dynamic scope for the $dynamicRef", "data": 42, "valid": false }, { "description": "/then/$defs/thingy is the final stop for the $dynamicRef", "data": null, "valid": true } ] }, { "description": "strict-tree schema, guards against misspelled properties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/strict-tree.json", "$dynamicAnchor": "node", "$ref": "tree.json", "unevaluatedProperties": false }, "tests": [ { "description": "instance with misspelled field", "data": { "children": [{ "daat": 1 }] }, "valid": false }, { "description": "instance with correct field", "data": { "children": [{ "data": 1 }] }, "valid": true } ] }, { "description": "tests for implementation dynamic anchor and reference link", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/strict-extendible.json", "$ref": "extendible-dynamic-ref.json", "$defs": { "elements": { "$dynamicAnchor": "elements", "properties": { "a": true }, "required": ["a"], "additionalProperties": false } } }, "tests": [ { "description": "incorrect parent schema", "data": { "a": true }, "valid": false }, { "description": "incorrect extended schema", "data": { "elements": [ { "b": 1 } ] }, "valid": false }, { "description": "correct extended schema", "data": { "elements": [ { "a": 1 } ] }, "valid": true } ] }, { "description": "$ref and $dynamicAnchor are independent of order - $defs first", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/strict-extendible-allof-defs-first.json", "allOf": [ { "$ref": "extendible-dynamic-ref.json" }, { "$defs": { "elements": { "$dynamicAnchor": "elements", "properties": { "a": true }, "required": ["a"], "additionalProperties": false } } } ] }, "tests": [ { "description": "incorrect parent schema", "data": { "a": true }, "valid": false }, { "description": "incorrect extended schema", "data": { "elements": [ { "b": 1 } ] }, "valid": false }, { "description": "correct extended schema", "data": { "elements": [ { "a": 1 } ] }, "valid": true } ] }, { "description": "$ref and $dynamicAnchor are independent of order - $ref first", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/strict-extendible-allof-ref-first.json", "allOf": [ { "$defs": { "elements": { "$dynamicAnchor": "elements", "properties": { "a": true }, "required": ["a"], "additionalProperties": false } } }, { "$ref": "extendible-dynamic-ref.json" } ] }, "tests": [ { "description": "incorrect parent schema", "data": { "a": true }, "valid": false }, { "description": "incorrect extended schema", "data": { "elements": [ { "b": 1 } ] }, "valid": false }, { "description": "correct extended schema", "data": { "elements": [ { "a": 1 } ] }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/enum.json0000644000175100001770000001642514653725311022533 0ustar00runnerdocker[ { "description": "simple enum validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "enum": [1, 2, 3] }, "tests": [ { "description": "one of the enum is valid", "data": 1, "valid": true }, { "description": "something else is invalid", "data": 4, "valid": false } ] }, { "description": "heterogeneous enum validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "enum": [6, "foo", [], true, {"foo": 12}] }, "tests": [ { "description": "one of the enum is valid", "data": [], "valid": true }, { "description": "something else is invalid", "data": null, "valid": false }, { "description": "objects are deep compared", "data": {"foo": false}, "valid": false }, { "description": "valid object matches", "data": {"foo": 12}, "valid": true }, { "description": "extra properties in object is invalid", "data": {"foo": 12, "boo": 42}, "valid": false } ] }, { "description": "heterogeneous enum-with-null validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "enum": [6, null] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "number is valid", "data": 6, "valid": true }, { "description": "something else is invalid", "data": "test", "valid": false } ] }, { "description": "enums in properties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type":"object", "properties": { "foo": {"enum":["foo"]}, "bar": {"enum":["bar"]} }, "required": ["bar"] }, "tests": [ { "description": "both properties are valid", "data": {"foo":"foo", "bar":"bar"}, "valid": true }, { "description": "wrong foo value", "data": {"foo":"foot", "bar":"bar"}, "valid": false }, { "description": "wrong bar value", "data": {"foo":"foo", "bar":"bart"}, "valid": false }, { "description": "missing optional property is valid", "data": {"bar":"bar"}, "valid": true }, { "description": "missing required property is invalid", "data": {"foo":"foo"}, "valid": false }, { "description": "missing all properties is invalid", "data": {}, "valid": false } ] }, { "description": "enum with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "enum": ["foo\nbar", "foo\rbar"] }, "tests": [ { "description": "member 1 is valid", "data": "foo\nbar", "valid": true }, { "description": "member 2 is valid", "data": "foo\rbar", "valid": true }, { "description": "another string is invalid", "data": "abc", "valid": false } ] }, { "description": "enum with false does not match 0", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "enum": [false] }, "tests": [ { "description": "false is valid", "data": false, "valid": true }, { "description": "integer zero is invalid", "data": 0, "valid": false }, { "description": "float zero is invalid", "data": 0.0, "valid": false } ] }, { "description": "enum with true does not match 1", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "enum": [true] }, "tests": [ { "description": "true is valid", "data": true, "valid": true }, { "description": "integer one is invalid", "data": 1, "valid": false }, { "description": "float one is invalid", "data": 1.0, "valid": false } ] }, { "description": "enum with 0 does not match false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "enum": [0] }, "tests": [ { "description": "false is invalid", "data": false, "valid": false }, { "description": "integer zero is valid", "data": 0, "valid": true }, { "description": "float zero is valid", "data": 0.0, "valid": true } ] }, { "description": "enum with 1 does not match true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "enum": [1] }, "tests": [ { "description": "true is invalid", "data": true, "valid": false }, { "description": "integer one is valid", "data": 1, "valid": true }, { "description": "float one is valid", "data": 1.0, "valid": true } ] }, { "description": "nul characters in strings", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "enum": [ "hello\u0000there" ] }, "tests": [ { "description": "match string with nul", "data": "hello\u0000there", "valid": true }, { "description": "do not match string lacking nul", "data": "hellothere", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/exclusiveMaximum.json0000644000175100001770000000151614653725311025127 0ustar00runnerdocker[ { "description": "exclusiveMaximum validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "exclusiveMaximum": 3.0 }, "tests": [ { "description": "below the exclusiveMaximum is valid", "data": 2.2, "valid": true }, { "description": "boundary point is invalid", "data": 3.0, "valid": false }, { "description": "above the exclusiveMaximum is invalid", "data": 3.5, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/exclusiveMinimum.json0000644000175100001770000000151614653725311025125 0ustar00runnerdocker[ { "description": "exclusiveMinimum validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "exclusiveMinimum": 1.1 }, "tests": [ { "description": "above the exclusiveMinimum is valid", "data": 1.2, "valid": true }, { "description": "boundary point is invalid", "data": 1.1, "valid": false }, { "description": "below the exclusiveMinimum is invalid", "data": 0.6, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/format.json0000644000175100001770000005263014653725311023055 0ustar00runnerdocker[ { "description": "email format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "idn-email format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "idn-email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "regex format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "regex" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "ipv4 format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "ipv4" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "ipv6 format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "ipv6" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "idn-hostname format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "idn-hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "hostname format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "date format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "date" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "date-time format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "date-time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "time format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "json-pointer format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "json-pointer" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "relative-json-pointer format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "relative-json-pointer" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "iri format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "iri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "iri-reference format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "iri-reference" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uri format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "uri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uri-reference format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "uri-reference" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uri-template format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "uri-template" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "uuid format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "uuid" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] }, { "description": "duration format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "duration" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/id.json0000644000175100001770000002406614653725311022163 0ustar00runnerdocker[ { "description": "Invalid use of fragments in location-independent $id", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "https://json-schema.org/draft/2020-12/schema" }, "tests": [ { "description": "Identifier name", "data": { "$ref": "#foo", "$defs": { "A": { "$id": "#foo", "type": "integer" } } }, "valid": false }, { "description": "Identifier name and no ref", "data": { "$defs": { "A": { "$id": "#foo" } } }, "valid": false }, { "description": "Identifier path", "data": { "$ref": "#/a/b", "$defs": { "A": { "$id": "#/a/b", "type": "integer" } } }, "valid": false }, { "description": "Identifier name with absolute URI", "data": { "$ref": "http://localhost:1234/draft2020-12/bar#foo", "$defs": { "A": { "$id": "http://localhost:1234/draft2020-12/bar#foo", "type": "integer" } } }, "valid": false }, { "description": "Identifier path with absolute URI", "data": { "$ref": "http://localhost:1234/draft2020-12/bar#/a/b", "$defs": { "A": { "$id": "http://localhost:1234/draft2020-12/bar#/a/b", "type": "integer" } } }, "valid": false }, { "description": "Identifier name with base URI change in subschema", "data": { "$id": "http://localhost:1234/draft2020-12/root", "$ref": "http://localhost:1234/draft2020-12/nested.json#foo", "$defs": { "A": { "$id": "nested.json", "$defs": { "B": { "$id": "#foo", "type": "integer" } } } } }, "valid": false }, { "description": "Identifier path with base URI change in subschema", "data": { "$id": "http://localhost:1234/draft2020-12/root", "$ref": "http://localhost:1234/draft2020-12/nested.json#/a/b", "$defs": { "A": { "$id": "nested.json", "$defs": { "B": { "$id": "#/a/b", "type": "integer" } } } } }, "valid": false } ] }, { "description": "Valid use of empty fragments in location-independent $id", "comment": "These are allowed but discouraged", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "https://json-schema.org/draft/2020-12/schema" }, "tests": [ { "description": "Identifier name with absolute URI", "data": { "$ref": "http://localhost:1234/draft2020-12/bar", "$defs": { "A": { "$id": "http://localhost:1234/draft2020-12/bar#", "type": "integer" } } }, "valid": true }, { "description": "Identifier name with base URI change in subschema", "data": { "$id": "http://localhost:1234/draft2020-12/root", "$ref": "http://localhost:1234/draft2020-12/nested.json#/$defs/B", "$defs": { "A": { "$id": "nested.json", "$defs": { "B": { "$id": "#", "type": "integer" } } } } }, "valid": true } ] }, { "description": "Unnormalized $ids are allowed but discouraged", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "https://json-schema.org/draft/2020-12/schema" }, "tests": [ { "description": "Unnormalized identifier", "data": { "$ref": "http://localhost:1234/draft2020-12/foo/baz", "$defs": { "A": { "$id": "http://localhost:1234/draft2020-12/foo/bar/../baz", "type": "integer" } } }, "valid": true }, { "description": "Unnormalized identifier and no ref", "data": { "$defs": { "A": { "$id": "http://localhost:1234/draft2020-12/foo/bar/../baz", "type": "integer" } } }, "valid": true }, { "description": "Unnormalized identifier with empty fragment", "data": { "$ref": "http://localhost:1234/draft2020-12/foo/baz", "$defs": { "A": { "$id": "http://localhost:1234/draft2020-12/foo/bar/../baz#", "type": "integer" } } }, "valid": true }, { "description": "Unnormalized identifier with empty fragment and no ref", "data": { "$defs": { "A": { "$id": "http://localhost:1234/draft2020-12/foo/bar/../baz#", "type": "integer" } } }, "valid": true } ] }, { "description": "$id inside an enum is not a real identifier", "comment": "the implementation must not be confused by an $id buried in the enum", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "id_in_enum": { "enum": [ { "$id": "https://localhost:1234/draft2020-12/id/my_identifier.json", "type": "null" } ] }, "real_id_in_schema": { "$id": "https://localhost:1234/draft2020-12/id/my_identifier.json", "type": "string" }, "zzz_id_in_const": { "const": { "$id": "https://localhost:1234/draft2020-12/id/my_identifier.json", "type": "null" } } }, "anyOf": [ { "$ref": "#/$defs/id_in_enum" }, { "$ref": "https://localhost:1234/draft2020-12/id/my_identifier.json" } ] }, "tests": [ { "description": "exact match to enum, and type matches", "data": { "$id": "https://localhost:1234/draft2020-12/id/my_identifier.json", "type": "null" }, "valid": true }, { "description": "match $ref to $id", "data": "a string to match #/$defs/id_in_enum", "valid": true }, { "description": "no match on enum or $ref to $id", "data": 1, "valid": false } ] }, { "description": "non-schema object containing an $id property", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "const_not_id": { "const": { "$id": "not_a_real_id" } } }, "if": { "const": "skip not_a_real_id" }, "then": true, "else" : { "$ref": "#/$defs/const_not_id" } }, "tests": [ { "description": "skip traversing definition for a valid result", "data": "skip not_a_real_id", "valid": true }, { "description": "const at const_not_id does not match", "data": 1, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/if-then-else.json0000644000175100001770000001663014653725311024045 0ustar00runnerdocker[ { "description": "ignore if without then or else", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "if": { "const": 0 } }, "tests": [ { "description": "valid when valid against lone if", "data": 0, "valid": true }, { "description": "valid when invalid against lone if", "data": "hello", "valid": true } ] }, { "description": "ignore then without if", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "then": { "const": 0 } }, "tests": [ { "description": "valid when valid against lone then", "data": 0, "valid": true }, { "description": "valid when invalid against lone then", "data": "hello", "valid": true } ] }, { "description": "ignore else without if", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "else": { "const": 0 } }, "tests": [ { "description": "valid when valid against lone else", "data": 0, "valid": true }, { "description": "valid when invalid against lone else", "data": "hello", "valid": true } ] }, { "description": "if and then without else", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "if": { "exclusiveMaximum": 0 }, "then": { "minimum": -10 } }, "tests": [ { "description": "valid through then", "data": -1, "valid": true }, { "description": "invalid through then", "data": -100, "valid": false }, { "description": "valid when if test fails", "data": 3, "valid": true } ] }, { "description": "if and else without then", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "if": { "exclusiveMaximum": 0 }, "else": { "multipleOf": 2 } }, "tests": [ { "description": "valid when if test passes", "data": -1, "valid": true }, { "description": "valid through else", "data": 4, "valid": true }, { "description": "invalid through else", "data": 3, "valid": false } ] }, { "description": "validate against correct branch, then vs else", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "if": { "exclusiveMaximum": 0 }, "then": { "minimum": -10 }, "else": { "multipleOf": 2 } }, "tests": [ { "description": "valid through then", "data": -1, "valid": true }, { "description": "invalid through then", "data": -100, "valid": false }, { "description": "valid through else", "data": 4, "valid": true }, { "description": "invalid through else", "data": 3, "valid": false } ] }, { "description": "non-interference across combined schemas", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "if": { "exclusiveMaximum": 0 } }, { "then": { "minimum": -10 } }, { "else": { "multipleOf": 2 } } ] }, "tests": [ { "description": "valid, but would have been invalid through then", "data": -100, "valid": true }, { "description": "valid, but would have been invalid through else", "data": 3, "valid": true } ] }, { "description": "if with boolean schema true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "if": true, "then": { "const": "then" }, "else": { "const": "else" } }, "tests": [ { "description": "boolean schema true in if always chooses the then path (valid)", "data": "then", "valid": true }, { "description": "boolean schema true in if always chooses the then path (invalid)", "data": "else", "valid": false } ] }, { "description": "if with boolean schema false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "if": false, "then": { "const": "then" }, "else": { "const": "else" } }, "tests": [ { "description": "boolean schema false in if always chooses the else path (invalid)", "data": "then", "valid": false }, { "description": "boolean schema false in if always chooses the else path (valid)", "data": "else", "valid": true } ] }, { "description": "if appears at the end when serialized (keyword processing sequence)", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "then": { "const": "yes" }, "else": { "const": "other" }, "if": { "maxLength": 4 } }, "tests": [ { "description": "yes redirects to then and passes", "data": "yes", "valid": true }, { "description": "other redirects to else and passes", "data": "other", "valid": true }, { "description": "no redirects to then and fails", "data": "no", "valid": false }, { "description": "invalid redirects to else and fails", "data": "invalid", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/infinite-loop-detection.json0000644000175100001770000000203314653725311026305 0ustar00runnerdocker[ { "description": "evaluating the same schema location against the same data location twice is not a sign of an infinite loop", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "int": { "type": "integer" } }, "allOf": [ { "properties": { "foo": { "$ref": "#/$defs/int" } } }, { "additionalProperties": { "$ref": "#/$defs/int" } } ] }, "tests": [ { "description": "passing case", "data": { "foo": 1 }, "valid": true }, { "description": "failing case", "data": { "foo": "a string" }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/items.json0000644000175100001770000002067414653725311022711 0ustar00runnerdocker[ { "description": "a schema given for items", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "items": {"type": "integer"} }, "tests": [ { "description": "valid items", "data": [ 1, 2, 3 ], "valid": true }, { "description": "wrong type of items", "data": [1, "x"], "valid": false }, { "description": "ignores non-arrays", "data": {"foo" : "bar"}, "valid": true }, { "description": "JavaScript pseudo-array is valid", "data": { "0": "invalid", "length": 1 }, "valid": true } ] }, { "description": "items with boolean schema (true)", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "items": true }, "tests": [ { "description": "any array is valid", "data": [ 1, "foo", true ], "valid": true }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "items with boolean schema (false)", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "items": false }, "tests": [ { "description": "any non-empty array is invalid", "data": [ 1, "foo", true ], "valid": false }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "items and subitems", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "item": { "type": "array", "items": false, "prefixItems": [ { "$ref": "#/$defs/sub-item" }, { "$ref": "#/$defs/sub-item" } ] }, "sub-item": { "type": "object", "required": ["foo"] } }, "type": "array", "items": false, "prefixItems": [ { "$ref": "#/$defs/item" }, { "$ref": "#/$defs/item" }, { "$ref": "#/$defs/item" } ] }, "tests": [ { "description": "valid items", "data": [ [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": true }, { "description": "too many items", "data": [ [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "too many sub-items", "data": [ [ {"foo": null}, {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "wrong item", "data": [ {"foo": null}, [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "wrong sub-item", "data": [ [ {}, {"foo": null} ], [ {"foo": null}, {"foo": null} ], [ {"foo": null}, {"foo": null} ] ], "valid": false }, { "description": "fewer items is valid", "data": [ [ {"foo": null} ], [ {"foo": null} ] ], "valid": true } ] }, { "description": "nested items", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "array", "items": { "type": "array", "items": { "type": "array", "items": { "type": "array", "items": { "type": "number" } } } } }, "tests": [ { "description": "valid nested array", "data": [[[[1]], [[2],[3]]], [[[4], [5], [6]]]], "valid": true }, { "description": "nested array with invalid type", "data": [[[["1"]], [[2],[3]]], [[[4], [5], [6]]]], "valid": false }, { "description": "not deep enough", "data": [[[1], [2],[3]], [[4], [5], [6]]], "valid": false } ] }, { "description": "prefixItems with no additional items allowed", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [{}, {}, {}], "items": false }, "tests": [ { "description": "empty array", "data": [ ], "valid": true }, { "description": "fewer number of items present (1)", "data": [ 1 ], "valid": true }, { "description": "fewer number of items present (2)", "data": [ 1, 2 ], "valid": true }, { "description": "equal number of items present", "data": [ 1, 2, 3 ], "valid": true }, { "description": "additional items are not permitted", "data": [ 1, 2, 3, 4 ], "valid": false } ] }, { "description": "items does not look in applicators, valid case", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "prefixItems": [ { "minimum": 3 } ] } ], "items": { "minimum": 5 } }, "tests": [ { "description": "prefixItems in allOf does not constrain items, invalid case", "data": [ 3, 5 ], "valid": false }, { "description": "prefixItems in allOf does not constrain items, valid case", "data": [ 5, 5 ], "valid": true } ] }, { "description": "prefixItems validation adjusts the starting index for items", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [ { "type": "string" } ], "items": { "type": "integer" } }, "tests": [ { "description": "valid items", "data": [ "x", 2, 3 ], "valid": true }, { "description": "wrong type of second item", "data": [ "x", "y" ], "valid": false } ] }, { "description": "items with null instance elements", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "items": { "type": "null" } }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/maxContains.json0000644000175100001770000000574614653725311024057 0ustar00runnerdocker[ { "description": "maxContains without contains is ignored", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "maxContains": 1 }, "tests": [ { "description": "one item valid against lone maxContains", "data": [ 1 ], "valid": true }, { "description": "two items still valid against lone maxContains", "data": [ 1, 2 ], "valid": true } ] }, { "description": "maxContains with contains", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": {"const": 1}, "maxContains": 1 }, "tests": [ { "description": "empty data", "data": [ ], "valid": false }, { "description": "all elements match, valid maxContains", "data": [ 1 ], "valid": true }, { "description": "all elements match, invalid maxContains", "data": [ 1, 1 ], "valid": false }, { "description": "some elements match, valid maxContains", "data": [ 1, 2 ], "valid": true }, { "description": "some elements match, invalid maxContains", "data": [ 1, 2, 1 ], "valid": false } ] }, { "description": "maxContains with contains, value with a decimal", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": {"const": 1}, "maxContains": 1.0 }, "tests": [ { "description": "one element matches, valid maxContains", "data": [ 1 ], "valid": true }, { "description": "too many elements match, invalid maxContains", "data": [ 1, 1 ], "valid": false } ] }, { "description": "minContains < maxContains", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": {"const": 1}, "minContains": 1, "maxContains": 3 }, "tests": [ { "description": "actual < minContains < maxContains", "data": [ ], "valid": false }, { "description": "minContains < actual < maxContains", "data": [ 1, 1 ], "valid": true }, { "description": "minContains < maxContains < actual", "data": [ 1, 1, 1, 1 ], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/maxItems.json0000644000175100001770000000244714653725311023355 0ustar00runnerdocker[ { "description": "maxItems validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "maxItems": 2 }, "tests": [ { "description": "shorter is valid", "data": [1], "valid": true }, { "description": "exact length is valid", "data": [1, 2], "valid": true }, { "description": "too long is invalid", "data": [1, 2, 3], "valid": false }, { "description": "ignores non-arrays", "data": "foobar", "valid": true } ] }, { "description": "maxItems validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "maxItems": 2.0 }, "tests": [ { "description": "shorter is valid", "data": [1], "valid": true }, { "description": "too long is invalid", "data": [1, 2, 3], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/maxLength.json0000644000175100001770000000274314653725311023514 0ustar00runnerdocker[ { "description": "maxLength validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "maxLength": 2 }, "tests": [ { "description": "shorter is valid", "data": "f", "valid": true }, { "description": "exact length is valid", "data": "fo", "valid": true }, { "description": "too long is invalid", "data": "foo", "valid": false }, { "description": "ignores non-strings", "data": 100, "valid": true }, { "description": "two supplementary Unicode code points is long enough", "data": "\uD83D\uDCA9\uD83D\uDCA9", "valid": true } ] }, { "description": "maxLength validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "maxLength": 2.0 }, "tests": [ { "description": "shorter is valid", "data": "f", "valid": true }, { "description": "too long is invalid", "data": "foo", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/maxProperties.json0000644000175100001770000000430014653725311024416 0ustar00runnerdocker[ { "description": "maxProperties validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "maxProperties": 2 }, "tests": [ { "description": "shorter is valid", "data": {"foo": 1}, "valid": true }, { "description": "exact length is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "too long is invalid", "data": {"foo": 1, "bar": 2, "baz": 3}, "valid": false }, { "description": "ignores arrays", "data": [1, 2, 3], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "maxProperties validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "maxProperties": 2.0 }, "tests": [ { "description": "shorter is valid", "data": {"foo": 1}, "valid": true }, { "description": "too long is invalid", "data": {"foo": 1, "bar": 2, "baz": 3}, "valid": false } ] }, { "description": "maxProperties = 0 means the object is empty", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "maxProperties": 0 }, "tests": [ { "description": "no properties is valid", "data": {}, "valid": true }, { "description": "one property is invalid", "data": { "foo": 1 }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/maximum.json0000644000175100001770000000317614653725311023243 0ustar00runnerdocker[ { "description": "maximum validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "maximum": 3.0 }, "tests": [ { "description": "below the maximum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 3.0, "valid": true }, { "description": "above the maximum is invalid", "data": 3.5, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] }, { "description": "maximum validation with unsigned integer", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "maximum": 300 }, "tests": [ { "description": "below the maximum is invalid", "data": 299.97, "valid": true }, { "description": "boundary point integer is valid", "data": 300, "valid": true }, { "description": "boundary point float is valid", "data": 300.00, "valid": true }, { "description": "above the maximum is invalid", "data": 300.5, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/minContains.json0000644000175100001770000001471414653725311024050 0ustar00runnerdocker[ { "description": "minContains without contains is ignored", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "minContains": 1 }, "tests": [ { "description": "one item valid against lone minContains", "data": [ 1 ], "valid": true }, { "description": "zero items still valid against lone minContains", "data": [], "valid": true } ] }, { "description": "minContains=1 with contains", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": {"const": 1}, "minContains": 1 }, "tests": [ { "description": "empty data", "data": [ ], "valid": false }, { "description": "no elements match", "data": [ 2 ], "valid": false }, { "description": "single element matches, valid minContains", "data": [ 1 ], "valid": true }, { "description": "some elements match, valid minContains", "data": [ 1, 2 ], "valid": true }, { "description": "all elements match, valid minContains", "data": [ 1, 1 ], "valid": true } ] }, { "description": "minContains=2 with contains", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": {"const": 1}, "minContains": 2 }, "tests": [ { "description": "empty data", "data": [ ], "valid": false }, { "description": "all elements match, invalid minContains", "data": [ 1 ], "valid": false }, { "description": "some elements match, invalid minContains", "data": [ 1, 2 ], "valid": false }, { "description": "all elements match, valid minContains (exactly as needed)", "data": [ 1, 1 ], "valid": true }, { "description": "all elements match, valid minContains (more than needed)", "data": [ 1, 1, 1 ], "valid": true }, { "description": "some elements match, valid minContains", "data": [ 1, 2, 1 ], "valid": true } ] }, { "description": "minContains=2 with contains with a decimal value", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": {"const": 1}, "minContains": 2.0 }, "tests": [ { "description": "one element matches, invalid minContains", "data": [ 1 ], "valid": false }, { "description": "both elements match, valid minContains", "data": [ 1, 1 ], "valid": true } ] }, { "description": "maxContains = minContains", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": {"const": 1}, "maxContains": 2, "minContains": 2 }, "tests": [ { "description": "empty data", "data": [ ], "valid": false }, { "description": "all elements match, invalid minContains", "data": [ 1 ], "valid": false }, { "description": "all elements match, invalid maxContains", "data": [ 1, 1, 1 ], "valid": false }, { "description": "all elements match, valid maxContains and minContains", "data": [ 1, 1 ], "valid": true } ] }, { "description": "maxContains < minContains", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": {"const": 1}, "maxContains": 1, "minContains": 3 }, "tests": [ { "description": "empty data", "data": [ ], "valid": false }, { "description": "invalid minContains", "data": [ 1 ], "valid": false }, { "description": "invalid maxContains", "data": [ 1, 1, 1 ], "valid": false }, { "description": "invalid maxContains and minContains", "data": [ 1, 1 ], "valid": false } ] }, { "description": "minContains = 0", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": {"const": 1}, "minContains": 0 }, "tests": [ { "description": "empty data", "data": [ ], "valid": true }, { "description": "minContains = 0 makes contains always pass", "data": [ 2 ], "valid": true } ] }, { "description": "minContains = 0 with maxContains", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "contains": {"const": 1}, "minContains": 0, "maxContains": 1 }, "tests": [ { "description": "empty data", "data": [ ], "valid": true }, { "description": "not more than maxContains", "data": [ 1 ], "valid": true }, { "description": "too many", "data": [ 1, 1 ], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/minItems.json0000644000175100001770000000242614653725311023350 0ustar00runnerdocker[ { "description": "minItems validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "minItems": 1 }, "tests": [ { "description": "longer is valid", "data": [1, 2], "valid": true }, { "description": "exact length is valid", "data": [1], "valid": true }, { "description": "too short is invalid", "data": [], "valid": false }, { "description": "ignores non-arrays", "data": "", "valid": true } ] }, { "description": "minItems validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "minItems": 1.0 }, "tests": [ { "description": "longer is valid", "data": [1, 2], "valid": true }, { "description": "too short is invalid", "data": [], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/minLength.json0000644000175100001770000000273114653725311023507 0ustar00runnerdocker[ { "description": "minLength validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "minLength": 2 }, "tests": [ { "description": "longer is valid", "data": "foo", "valid": true }, { "description": "exact length is valid", "data": "fo", "valid": true }, { "description": "too short is invalid", "data": "f", "valid": false }, { "description": "ignores non-strings", "data": 1, "valid": true }, { "description": "one supplementary Unicode code point is not long enough", "data": "\uD83D\uDCA9", "valid": false } ] }, { "description": "minLength validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "minLength": 2.0 }, "tests": [ { "description": "longer is valid", "data": "foo", "valid": true }, { "description": "too short is invalid", "data": "f", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/minProperties.json0000644000175100001770000000314514653725311024422 0ustar00runnerdocker[ { "description": "minProperties validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "minProperties": 1 }, "tests": [ { "description": "longer is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "exact length is valid", "data": {"foo": 1}, "valid": true }, { "description": "too short is invalid", "data": {}, "valid": false }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "minProperties validation with a decimal", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "minProperties": 1.0 }, "tests": [ { "description": "longer is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "too short is invalid", "data": {}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/minimum.json0000644000175100001770000000410414653725311023231 0ustar00runnerdocker[ { "description": "minimum validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "minimum": 1.1 }, "tests": [ { "description": "above the minimum is valid", "data": 2.6, "valid": true }, { "description": "boundary point is valid", "data": 1.1, "valid": true }, { "description": "below the minimum is invalid", "data": 0.6, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] }, { "description": "minimum validation with signed integer", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "minimum": -2 }, "tests": [ { "description": "negative above the minimum is valid", "data": -1, "valid": true }, { "description": "positive above the minimum is valid", "data": 0, "valid": true }, { "description": "boundary point is valid", "data": -2, "valid": true }, { "description": "boundary point with float is valid", "data": -2.0, "valid": true }, { "description": "float below the minimum is invalid", "data": -2.0001, "valid": false }, { "description": "int below the minimum is invalid", "data": -3, "valid": false }, { "description": "ignores non-numbers", "data": "x", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/multipleOf.json0000644000175100001770000000430614653725311023702 0ustar00runnerdocker[ { "description": "by int", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "multipleOf": 2 }, "tests": [ { "description": "int by int", "data": 10, "valid": true }, { "description": "int by int fail", "data": 7, "valid": false }, { "description": "ignores non-numbers", "data": "foo", "valid": true } ] }, { "description": "by number", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "multipleOf": 1.5 }, "tests": [ { "description": "zero is multiple of anything", "data": 0, "valid": true }, { "description": "4.5 is multiple of 1.5", "data": 4.5, "valid": true }, { "description": "35 is not multiple of 1.5", "data": 35, "valid": false } ] }, { "description": "by small number", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "multipleOf": 0.0001 }, "tests": [ { "description": "0.0075 is multiple of 0.0001", "data": 0.0075, "valid": true }, { "description": "0.00751 is not multiple of 0.0001", "data": 0.00751, "valid": false } ] }, { "description": "float division = inf", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "integer", "multipleOf": 0.123456789 }, "tests": [ { "description": "always invalid, but naive implementations may raise an overflow error", "data": 1e308, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/not.json0000644000175100001770000000632414653725311022364 0ustar00runnerdocker[ { "description": "not", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "not": {"type": "integer"} }, "tests": [ { "description": "allowed", "data": "foo", "valid": true }, { "description": "disallowed", "data": 1, "valid": false } ] }, { "description": "not multiple types", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "not": {"type": ["integer", "boolean"]} }, "tests": [ { "description": "valid", "data": "foo", "valid": true }, { "description": "mismatch", "data": 1, "valid": false }, { "description": "other mismatch", "data": true, "valid": false } ] }, { "description": "not more complex schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "not": { "type": "object", "properties": { "foo": { "type": "string" } } } }, "tests": [ { "description": "match", "data": 1, "valid": true }, { "description": "other match", "data": {"foo": 1}, "valid": true }, { "description": "mismatch", "data": {"foo": "bar"}, "valid": false } ] }, { "description": "forbidden property", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": { "not": {} } } }, "tests": [ { "description": "property present", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "property absent", "data": {"bar": 1, "baz": 2}, "valid": true } ] }, { "description": "not with boolean schema true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "not": true }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "not with boolean schema false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "not": false }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/oneOf.json0000644000175100001770000001767014653725311022640 0ustar00runnerdocker[ { "description": "oneOf", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "type": "integer" }, { "minimum": 2 } ] }, "tests": [ { "description": "first oneOf valid", "data": 1, "valid": true }, { "description": "second oneOf valid", "data": 2.5, "valid": true }, { "description": "both oneOf valid", "data": 3, "valid": false }, { "description": "neither oneOf valid", "data": 1.5, "valid": false } ] }, { "description": "oneOf with base schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "oneOf" : [ { "minLength": 2 }, { "maxLength": 4 } ] }, "tests": [ { "description": "mismatch base schema", "data": 3, "valid": false }, { "description": "one oneOf valid", "data": "foobar", "valid": true }, { "description": "both oneOf valid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, all true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [true, true, true] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, one true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [true, false, false] }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "oneOf with boolean schemas, more than one true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [true, true, false] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf with boolean schemas, all false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [false, false, false] }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "oneOf complex types", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "properties": { "bar": {"type": "integer"} }, "required": ["bar"] }, { "properties": { "foo": {"type": "string"} }, "required": ["foo"] } ] }, "tests": [ { "description": "first oneOf valid (complex)", "data": {"bar": 2}, "valid": true }, { "description": "second oneOf valid (complex)", "data": {"foo": "baz"}, "valid": true }, { "description": "both oneOf valid (complex)", "data": {"foo": "baz", "bar": 2}, "valid": false }, { "description": "neither oneOf valid (complex)", "data": {"foo": 2, "bar": "quux"}, "valid": false } ] }, { "description": "oneOf with empty schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "one valid - valid", "data": "foo", "valid": true }, { "description": "both valid - invalid", "data": 123, "valid": false } ] }, { "description": "oneOf with required", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "oneOf": [ { "required": ["foo", "bar"] }, { "required": ["foo", "baz"] } ] }, "tests": [ { "description": "both invalid - invalid", "data": {"bar": 2}, "valid": false }, { "description": "first valid - valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "second valid - valid", "data": {"foo": 1, "baz": 3}, "valid": true }, { "description": "both valid - invalid", "data": {"foo": 1, "bar": 2, "baz" : 3}, "valid": false } ] }, { "description": "oneOf with missing optional property", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "properties": { "bar": true, "baz": true }, "required": ["bar"] }, { "properties": { "foo": true }, "required": ["foo"] } ] }, "tests": [ { "description": "first oneOf valid", "data": {"bar": 8}, "valid": true }, { "description": "second oneOf valid", "data": {"foo": "foo"}, "valid": true }, { "description": "both oneOf valid", "data": {"foo": "foo", "bar": 8}, "valid": false }, { "description": "neither oneOf valid", "data": {"baz": "quux"}, "valid": false } ] }, { "description": "nested oneOf, to check validation semantics", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "oneOf": [ { "type": "null" } ] } ] }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "anything non-null is invalid", "data": 123, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1210978 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/0000755000175100001770000000000014653725331022513 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/bignum.json0000644000175100001770000000652614653725311024676 0ustar00runnerdocker[ { "description": "integer", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "integer" }, "tests": [ { "description": "a bignum is an integer", "data": 12345678910111213141516171819202122232425262728293031, "valid": true }, { "description": "a negative bignum is an integer", "data": -12345678910111213141516171819202122232425262728293031, "valid": true } ] }, { "description": "number", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "number" }, "tests": [ { "description": "a bignum is a number", "data": 98249283749234923498293171823948729348710298301928331, "valid": true }, { "description": "a negative bignum is a number", "data": -98249283749234923498293171823948729348710298301928331, "valid": true } ] }, { "description": "string", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string" }, "tests": [ { "description": "a bignum is not a string", "data": 98249283749234923498293171823948729348710298301928331, "valid": false } ] }, { "description": "maximum integer comparison", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "maximum": 18446744073709551615 }, "tests": [ { "description": "comparison works for high numbers", "data": 18446744073709551600, "valid": true } ] }, { "description": "float comparison with high precision", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "exclusiveMaximum": 972783798187987123879878123.18878137 }, "tests": [ { "description": "comparison works for high numbers", "data": 972783798187987123879878123.188781371, "valid": false } ] }, { "description": "minimum integer comparison", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "minimum": -18446744073709551615 }, "tests": [ { "description": "comparison works for very negative numbers", "data": -18446744073709551600, "valid": true } ] }, { "description": "float comparison with high precision on negative numbers", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "exclusiveMinimum": -972783798187987123879878123.18878137 }, "tests": [ { "description": "comparison works for very negative numbers", "data": -972783798187987123879878123.188781371, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/cross-draft.json0000644000175100001770000000115414653725311025634 0ustar00runnerdocker[ { "description": "refs to historic drafts are processed as historic drafts", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "array", "$ref": "http://localhost:1234/draft2019-09/ignore-prefixItems.json" }, "tests": [ { "description": "first item not a string is valid", "comment": "if the implementation is not processing the $ref as a 2019-09 schema, this test will fail", "data": [1, 2, 3], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/dependencies-compatibility.json0000644000175100001770000001772014653725311030710 0ustar00runnerdocker[ { "description": "single dependency", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependencies": {"bar": ["foo"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependant", "data": {"foo": 1}, "valid": true }, { "description": "with dependency", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "missing dependency", "data": {"bar": 2}, "valid": false }, { "description": "ignores arrays", "data": ["bar"], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "empty dependents", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependencies": {"bar": []} }, "tests": [ { "description": "empty object", "data": {}, "valid": true }, { "description": "object with one property", "data": {"bar": 2}, "valid": true }, { "description": "non-object is valid", "data": 1, "valid": true } ] }, { "description": "multiple dependents required", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependencies": {"quux": ["foo", "bar"]} }, "tests": [ { "description": "neither", "data": {}, "valid": true }, { "description": "nondependants", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "with dependencies", "data": {"foo": 1, "bar": 2, "quux": 3}, "valid": true }, { "description": "missing dependency", "data": {"foo": 1, "quux": 2}, "valid": false }, { "description": "missing other dependency", "data": {"bar": 1, "quux": 2}, "valid": false }, { "description": "missing both dependencies", "data": {"quux": 1}, "valid": false } ] }, { "description": "dependencies with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependencies": { "foo\nbar": ["foo\rbar"], "foo\"bar": ["foo'bar"] } }, "tests": [ { "description": "CRLF", "data": { "foo\nbar": 1, "foo\rbar": 2 }, "valid": true }, { "description": "quoted quotes", "data": { "foo'bar": 1, "foo\"bar": 2 }, "valid": true }, { "description": "CRLF missing dependent", "data": { "foo\nbar": 1, "foo": 2 }, "valid": false }, { "description": "quoted quotes missing dependent", "data": { "foo\"bar": 2 }, "valid": false } ] }, { "description": "single schema dependency", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependencies": { "bar": { "properties": { "foo": {"type": "integer"}, "bar": {"type": "integer"} } } } }, "tests": [ { "description": "valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "no dependency", "data": {"foo": "quux"}, "valid": true }, { "description": "wrong type", "data": {"foo": "quux", "bar": 2}, "valid": false }, { "description": "wrong type other", "data": {"foo": 2, "bar": "quux"}, "valid": false }, { "description": "wrong type both", "data": {"foo": "quux", "bar": "quux"}, "valid": false }, { "description": "ignores arrays", "data": ["bar"], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "boolean subschemas", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependencies": { "foo": true, "bar": false } }, "tests": [ { "description": "object with property having schema true is valid", "data": {"foo": 1}, "valid": true }, { "description": "object with property having schema false is invalid", "data": {"bar": 2}, "valid": false }, { "description": "object with both properties is invalid", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "schema dependencies with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "dependencies": { "foo\tbar": {"minProperties": 4}, "foo'bar": {"required": ["foo\"bar"]} } }, "tests": [ { "description": "quoted tab", "data": { "foo\tbar": 1, "a": 2, "b": 3, "c": 4 }, "valid": true }, { "description": "quoted quote", "data": { "foo'bar": {"foo\"bar": 1} }, "valid": false }, { "description": "quoted tab invalid under dependent schema", "data": { "foo\tbar": 1, "a": 2 }, "valid": false }, { "description": "quoted quote invalid under dependent schema", "data": {"foo'bar": 1}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/ecmascript-regex.json0000644000175100001770000004774614653725311026670 0ustar00runnerdocker[ { "description": "ECMA 262 regex $ does not match trailing newline", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "pattern": "^abc$" }, "tests": [ { "description": "matches in Python, but not in ECMA 262", "data": "abc\\n", "valid": false }, { "description": "matches", "data": "abc", "valid": true } ] }, { "description": "ECMA 262 regex converts \\t to horizontal tab", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "pattern": "^\\t$" }, "tests": [ { "description": "does not match", "data": "\\t", "valid": false }, { "description": "matches", "data": "\u0009", "valid": true } ] }, { "description": "ECMA 262 regex escapes control codes with \\c and upper letter", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "pattern": "^\\cC$" }, "tests": [ { "description": "does not match", "data": "\\cC", "valid": false }, { "description": "matches", "data": "\u0003", "valid": true } ] }, { "description": "ECMA 262 regex escapes control codes with \\c and lower letter", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "pattern": "^\\cc$" }, "tests": [ { "description": "does not match", "data": "\\cc", "valid": false }, { "description": "matches", "data": "\u0003", "valid": true } ] }, { "description": "ECMA 262 \\d matches ascii digits only", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "pattern": "^\\d$" }, "tests": [ { "description": "ASCII zero matches", "data": "0", "valid": true }, { "description": "NKO DIGIT ZERO does not match (unlike e.g. Python)", "data": "߀", "valid": false }, { "description": "NKO DIGIT ZERO (as \\u escape) does not match", "data": "\u07c0", "valid": false } ] }, { "description": "ECMA 262 \\D matches everything but ascii digits", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "pattern": "^\\D$" }, "tests": [ { "description": "ASCII zero does not match", "data": "0", "valid": false }, { "description": "NKO DIGIT ZERO matches (unlike e.g. Python)", "data": "߀", "valid": true }, { "description": "NKO DIGIT ZERO (as \\u escape) matches", "data": "\u07c0", "valid": true } ] }, { "description": "ECMA 262 \\w matches ascii letters only", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "pattern": "^\\w$" }, "tests": [ { "description": "ASCII 'a' matches", "data": "a", "valid": true }, { "description": "latin-1 e-acute does not match (unlike e.g. Python)", "data": "é", "valid": false } ] }, { "description": "ECMA 262 \\W matches everything but ascii letters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "pattern": "^\\W$" }, "tests": [ { "description": "ASCII 'a' does not match", "data": "a", "valid": false }, { "description": "latin-1 e-acute matches (unlike e.g. Python)", "data": "é", "valid": true } ] }, { "description": "ECMA 262 \\s matches whitespace", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "pattern": "^\\s$" }, "tests": [ { "description": "ASCII space matches", "data": " ", "valid": true }, { "description": "Character tabulation matches", "data": "\t", "valid": true }, { "description": "Line tabulation matches", "data": "\u000b", "valid": true }, { "description": "Form feed matches", "data": "\u000c", "valid": true }, { "description": "latin-1 non-breaking-space matches", "data": "\u00a0", "valid": true }, { "description": "zero-width whitespace matches", "data": "\ufeff", "valid": true }, { "description": "line feed matches (line terminator)", "data": "\u000a", "valid": true }, { "description": "paragraph separator matches (line terminator)", "data": "\u2029", "valid": true }, { "description": "EM SPACE matches (Space_Separator)", "data": "\u2003", "valid": true }, { "description": "Non-whitespace control does not match", "data": "\u0001", "valid": false }, { "description": "Non-whitespace does not match", "data": "\u2013", "valid": false } ] }, { "description": "ECMA 262 \\S matches everything but whitespace", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "pattern": "^\\S$" }, "tests": [ { "description": "ASCII space does not match", "data": " ", "valid": false }, { "description": "Character tabulation does not match", "data": "\t", "valid": false }, { "description": "Line tabulation does not match", "data": "\u000b", "valid": false }, { "description": "Form feed does not match", "data": "\u000c", "valid": false }, { "description": "latin-1 non-breaking-space does not match", "data": "\u00a0", "valid": false }, { "description": "zero-width whitespace does not match", "data": "\ufeff", "valid": false }, { "description": "line feed does not match (line terminator)", "data": "\u000a", "valid": false }, { "description": "paragraph separator does not match (line terminator)", "data": "\u2029", "valid": false }, { "description": "EM SPACE does not match (Space_Separator)", "data": "\u2003", "valid": false }, { "description": "Non-whitespace control matches", "data": "\u0001", "valid": true }, { "description": "Non-whitespace matches", "data": "\u2013", "valid": true } ] }, { "description": "patterns always use unicode semantics with pattern", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "pattern": "\\p{Letter}cole" }, "tests": [ { "description": "ascii character in json string", "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", "valid": true }, { "description": "literal unicode character in json string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": true }, { "description": "unicode character in hex format in string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": true }, { "description": "unicode matching is case-sensitive", "data": "LES HIVERS DE MON ENFANCE ÉTAIENT DES SAISONS LONGUES, LONGUES. NOUS VIVIONS EN TROIS LIEUX: L'ÉCOLE, L'ÉGLISE ET LA PATINOIRE; MAIS LA VRAIE VIE ÉTAIT SUR LA PATINOIRE.", "valid": false } ] }, { "description": "\\w in patterns matches [A-Za-z0-9_], not unicode letters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "pattern": "\\wcole" }, "tests": [ { "description": "ascii character in json string", "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", "valid": true }, { "description": "literal unicode character in json string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "unicode character in hex format in string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "unicode matching is case-sensitive", "data": "LES HIVERS DE MON ENFANCE ÉTAIENT DES SAISONS LONGUES, LONGUES. NOUS VIVIONS EN TROIS LIEUX: L'ÉCOLE, L'ÉGLISE ET LA PATINOIRE; MAIS LA VRAIE VIE ÉTAIT SUR LA PATINOIRE.", "valid": false } ] }, { "description": "pattern with ASCII ranges", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "pattern": "[a-z]cole" }, "tests": [ { "description": "literal unicode character in json string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "unicode character in hex format in string", "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", "valid": false }, { "description": "ascii characters match", "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", "valid": true } ] }, { "description": "\\d in pattern matches [0-9], not unicode digits", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "pattern": "^\\d+$" }, "tests": [ { "description": "ascii digits", "data": "42", "valid": true }, { "description": "ascii non-digits", "data": "-%#", "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": "৪২", "valid": false } ] }, { "description": "\\a is not an ECMA 262 control escape", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "https://json-schema.org/draft/2020-12/schema" }, "tests": [ { "description": "when used as a pattern", "data": { "pattern": "\\a" }, "valid": false } ] }, { "description": "pattern with non-ASCII digits", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "pattern": "^\\p{digit}+$" }, "tests": [ { "description": "ascii digits", "data": "42", "valid": true }, { "description": "ascii non-digits", "data": "-%#", "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": "৪২", "valid": true } ] }, { "description": "patterns always use unicode semantics with patternProperties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "patternProperties": { "\\p{Letter}cole": true }, "additionalProperties": false }, "tests": [ { "description": "ascii character in json string", "data": { "l'ecole": "pas de vraie vie" }, "valid": true }, { "description": "literal unicode character in json string", "data": { "l'école": "pas de vraie vie" }, "valid": true }, { "description": "unicode character in hex format in string", "data": { "l'\u00e9cole": "pas de vraie vie" }, "valid": true }, { "description": "unicode matching is case-sensitive", "data": { "L'ÉCOLE": "PAS DE VRAIE VIE" }, "valid": false } ] }, { "description": "\\w in patternProperties matches [A-Za-z0-9_], not unicode letters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "patternProperties": { "\\wcole": true }, "additionalProperties": false }, "tests": [ { "description": "ascii character in json string", "data": { "l'ecole": "pas de vraie vie" }, "valid": true }, { "description": "literal unicode character in json string", "data": { "l'école": "pas de vraie vie" }, "valid": false }, { "description": "unicode character in hex format in string", "data": { "l'\u00e9cole": "pas de vraie vie" }, "valid": false }, { "description": "unicode matching is case-sensitive", "data": { "L'ÉCOLE": "PAS DE VRAIE VIE" }, "valid": false } ] }, { "description": "patternProperties with ASCII ranges", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "patternProperties": { "[a-z]cole": true }, "additionalProperties": false }, "tests": [ { "description": "literal unicode character in json string", "data": { "l'école": "pas de vraie vie" }, "valid": false }, { "description": "unicode character in hex format in string", "data": { "l'\u00e9cole": "pas de vraie vie" }, "valid": false }, { "description": "ascii characters match", "data": { "l'ecole": "pas de vraie vie" }, "valid": true } ] }, { "description": "\\d in patternProperties matches [0-9], not unicode digits", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "patternProperties": { "^\\d+$": true }, "additionalProperties": false }, "tests": [ { "description": "ascii digits", "data": { "42": "life, the universe, and everything" }, "valid": true }, { "description": "ascii non-digits", "data": { "-%#": "spending the year dead for tax reasons" }, "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": { "৪২": "khajit has wares if you have coin" }, "valid": false } ] }, { "description": "patternProperties with non-ASCII digits", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "patternProperties": { "^\\p{digit}+$": true }, "additionalProperties": false }, "tests": [ { "description": "ascii digits", "data": { "42": "life, the universe, and everything" }, "valid": true }, { "description": "ascii non-digits", "data": { "-%#": "spending the year dead for tax reasons" }, "valid": false }, { "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", "data": { "৪২": "khajit has wares if you have coin" }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/float-overflow.json0000644000175100001770000000072214653725311026353 0ustar00runnerdocker[ { "description": "all integers are multiples of 0.5, if overflow is handled", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "integer", "multipleOf": 0.5 }, "tests": [ { "description": "valid if optional overflow handling is implemented", "data": 1e308, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1250978 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/format/0000755000175100001770000000000014653725331024003 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/format/date-time.json0000644000175100001770000001121314653725311026543 0ustar00runnerdocker[ { "description": "validation of date-time strings", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "date-time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid date-time string", "data": "1963-06-19T08:30:06.283185Z", "valid": true }, { "description": "a valid date-time string without second fraction", "data": "1963-06-19T08:30:06Z", "valid": true }, { "description": "a valid date-time string with plus offset", "data": "1937-01-01T12:00:27.87+00:20", "valid": true }, { "description": "a valid date-time string with minus offset", "data": "1990-12-31T15:59:50.123-08:00", "valid": true }, { "description": "a valid date-time with a leap second, UTC", "data": "1998-12-31T23:59:60Z", "valid": true }, { "description": "a valid date-time with a leap second, with minus offset", "data": "1998-12-31T15:59:60.123-08:00", "valid": true }, { "description": "an invalid date-time past leap second, UTC", "data": "1998-12-31T23:59:61Z", "valid": false }, { "description": "an invalid date-time with leap second on a wrong minute, UTC", "data": "1998-12-31T23:58:60Z", "valid": false }, { "description": "an invalid date-time with leap second on a wrong hour, UTC", "data": "1998-12-31T22:59:60Z", "valid": false }, { "description": "an invalid day in date-time string", "data": "1990-02-31T15:59:59.123-08:00", "valid": false }, { "description": "an invalid offset in date-time string", "data": "1990-12-31T15:59:59-24:00", "valid": false }, { "description": "an invalid closing Z after time-zone offset", "data": "1963-06-19T08:30:06.28123+01:00Z", "valid": false }, { "description": "an invalid date-time string", "data": "06/19/1963 08:30:06 PST", "valid": false }, { "description": "case-insensitive T and Z", "data": "1963-06-19t08:30:06.283185z", "valid": true }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "2013-350T01:01:01", "valid": false }, { "description": "invalid non-padded month dates", "data": "1963-6-19T08:30:06.283185Z", "valid": false }, { "description": "invalid non-padded day dates", "data": "1963-06-1T08:30:06.283185Z", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4) in date portion", "data": "1963-06-1৪T00:00:00Z", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4) in time portion", "data": "1963-06-11T0৪:00:00Z", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/format/date.json0000644000175100001770000001656314653725311025624 0ustar00runnerdocker[ { "description": "validation of date strings", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "date" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid date string", "data": "1963-06-19", "valid": true }, { "description": "a valid date string with 31 days in January", "data": "2020-01-31", "valid": true }, { "description": "a invalid date string with 32 days in January", "data": "2020-01-32", "valid": false }, { "description": "a valid date string with 28 days in February (normal)", "data": "2021-02-28", "valid": true }, { "description": "a invalid date string with 29 days in February (normal)", "data": "2021-02-29", "valid": false }, { "description": "a valid date string with 29 days in February (leap)", "data": "2020-02-29", "valid": true }, { "description": "a invalid date string with 30 days in February (leap)", "data": "2020-02-30", "valid": false }, { "description": "a valid date string with 31 days in March", "data": "2020-03-31", "valid": true }, { "description": "a invalid date string with 32 days in March", "data": "2020-03-32", "valid": false }, { "description": "a valid date string with 30 days in April", "data": "2020-04-30", "valid": true }, { "description": "a invalid date string with 31 days in April", "data": "2020-04-31", "valid": false }, { "description": "a valid date string with 31 days in May", "data": "2020-05-31", "valid": true }, { "description": "a invalid date string with 32 days in May", "data": "2020-05-32", "valid": false }, { "description": "a valid date string with 30 days in June", "data": "2020-06-30", "valid": true }, { "description": "a invalid date string with 31 days in June", "data": "2020-06-31", "valid": false }, { "description": "a valid date string with 31 days in July", "data": "2020-07-31", "valid": true }, { "description": "a invalid date string with 32 days in July", "data": "2020-07-32", "valid": false }, { "description": "a valid date string with 31 days in August", "data": "2020-08-31", "valid": true }, { "description": "a invalid date string with 32 days in August", "data": "2020-08-32", "valid": false }, { "description": "a valid date string with 30 days in September", "data": "2020-09-30", "valid": true }, { "description": "a invalid date string with 31 days in September", "data": "2020-09-31", "valid": false }, { "description": "a valid date string with 31 days in October", "data": "2020-10-31", "valid": true }, { "description": "a invalid date string with 32 days in October", "data": "2020-10-32", "valid": false }, { "description": "a valid date string with 30 days in November", "data": "2020-11-30", "valid": true }, { "description": "a invalid date string with 31 days in November", "data": "2020-11-31", "valid": false }, { "description": "a valid date string with 31 days in December", "data": "2020-12-31", "valid": true }, { "description": "a invalid date string with 32 days in December", "data": "2020-12-32", "valid": false }, { "description": "a invalid date string with invalid month", "data": "2020-13-01", "valid": false }, { "description": "an invalid date string", "data": "06/19/1963", "valid": false }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "2013-350", "valid": false }, { "description": "non-padded month dates are not valid", "data": "1998-1-20", "valid": false }, { "description": "non-padded day dates are not valid", "data": "1998-01-1", "valid": false }, { "description": "invalid month", "data": "1998-13-01", "valid": false }, { "description": "invalid month-day combination", "data": "1998-04-31", "valid": false }, { "description": "2021 is not a leap year", "data": "2021-02-29", "valid": false }, { "description": "2020 is a leap year", "data": "2020-02-29", "valid": true }, { "description": "invalid non-ASCII '৪' (a Bengali 4)", "data": "1963-06-1৪", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/format/duration.json0000644000175100001770000000772014653725311026527 0ustar00runnerdocker[ { "description": "validation of duration strings", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "duration" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid duration string", "data": "P4DT12H30M5S", "valid": true }, { "description": "an invalid duration string", "data": "PT1D", "valid": false }, { "description": "no elements present", "data": "P", "valid": false }, { "description": "no time elements present", "data": "P1YT", "valid": false }, { "description": "no date or time elements present", "data": "PT", "valid": false }, { "description": "elements out of order", "data": "P2D1Y", "valid": false }, { "description": "missing time separator", "data": "P1D2H", "valid": false }, { "description": "time element in the date position", "data": "P2S", "valid": false }, { "description": "four years duration", "data": "P4Y", "valid": true }, { "description": "zero time, in seconds", "data": "PT0S", "valid": true }, { "description": "zero time, in days", "data": "P0D", "valid": true }, { "description": "one month duration", "data": "P1M", "valid": true }, { "description": "one minute duration", "data": "PT1M", "valid": true }, { "description": "one and a half days, in hours", "data": "PT36H", "valid": true }, { "description": "one and a half days, in days and hours", "data": "P1DT12H", "valid": true }, { "description": "two weeks", "data": "P2W", "valid": true }, { "description": "weeks cannot be combined with other units", "data": "P1Y2W", "valid": false }, { "description": "invalid non-ASCII '২' (a Bengali 2)", "data": "P২Y", "valid": false }, { "description": "element without unit", "data": "P1", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/format/email.json0000644000175100001770000000772414653725311025775 0ustar00runnerdocker[ { "description": "validation of e-mail addresses", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid e-mail address", "data": "joe.bloggs@example.com", "valid": true }, { "description": "an invalid e-mail address", "data": "2962", "valid": false }, { "description": "tilde in local part is valid", "data": "te~st@example.com", "valid": true }, { "description": "tilde before local part is valid", "data": "~test@example.com", "valid": true }, { "description": "tilde after local part is valid", "data": "test~@example.com", "valid": true }, { "description": "a quoted string with a space in the local part is valid", "data": "\"joe bloggs\"@example.com", "valid": true }, { "description": "a quoted string with a double dot in the local part is valid", "data": "\"joe..bloggs\"@example.com", "valid": true }, { "description": "a quoted string with a @ in the local part is valid", "data": "\"joe@bloggs\"@example.com", "valid": true }, { "description": "an IPv4-address-literal after the @ is valid", "data": "joe.bloggs@[127.0.0.1]", "valid": true }, { "description": "an IPv6-address-literal after the @ is valid", "data": "joe.bloggs@[IPv6:::1]", "valid": true }, { "description": "dot before local part is not valid", "data": ".test@example.com", "valid": false }, { "description": "dot after local part is not valid", "data": "test.@example.com", "valid": false }, { "description": "two separated dots inside local part are valid", "data": "te.s.t@example.com", "valid": true }, { "description": "two subsequent dots inside local part are not valid", "data": "te..st@example.com", "valid": false }, { "description": "an invalid domain", "data": "joe.bloggs@invalid=domain.com", "valid": false }, { "description": "an invalid IPv4-address-literal", "data": "joe.bloggs@[127.0.0.300]", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/format/hostname.json0000644000175100001770000000635714653725311026525 0ustar00runnerdocker[ { "description": "validation of host names", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid host name", "data": "www.example.com", "valid": true }, { "description": "a valid punycoded IDN hostname", "data": "xn--4gbwdl.xn--wgbh1c", "valid": true }, { "description": "a host name starting with an illegal character", "data": "-a-host-name-that-starts-with--", "valid": false }, { "description": "a host name containing illegal characters", "data": "not_a_valid_host_name", "valid": false }, { "description": "a host name with a component too long", "data": "a-vvvvvvvvvvvvvvvveeeeeeeeeeeeeeeerrrrrrrrrrrrrrrryyyyyyyyyyyyyyyy-long-host-name-component", "valid": false }, { "description": "starts with hyphen", "data": "-hostname", "valid": false }, { "description": "ends with hyphen", "data": "hostname-", "valid": false }, { "description": "starts with underscore", "data": "_hostname", "valid": false }, { "description": "ends with underscore", "data": "hostname_", "valid": false }, { "description": "contains underscore", "data": "host_name", "valid": false }, { "description": "maximum label length", "data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.com", "valid": true }, { "description": "exceeds maximum label length", "data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl.com", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/format/idn-email.json0000644000175100001770000000350714653725311026540 0ustar00runnerdocker[ { "description": "validation of an internationalized e-mail addresses", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "idn-email" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid idn e-mail (example@example.test in Hangul)", "data": "실례@실례.테스트", "valid": true }, { "description": "an invalid idn e-mail address", "data": "2962", "valid": false }, { "description": "a valid e-mail address", "data": "joe.bloggs@example.com", "valid": true }, { "description": "an invalid e-mail address", "data": "2962", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/format/idn-hostname.json0000644000175100001770000003477414653725311027301 0ustar00runnerdocker[ { "description": "validation of internationalized host names", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "idn-hostname" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid host name (example.test in Hangul)", "data": "실례.테스트", "valid": true }, { "description": "illegal first char U+302E Hangul single dot tone mark", "data": "〮실례.테스트", "valid": false }, { "description": "contains illegal char U+302E Hangul single dot tone mark", "data": "실〮례.테스트", "valid": false }, { "description": "a host name with a component too long", "data": "실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실례례테스트례례례례례례례례례례례례례례례례례테스트례례례례례례례례례례례례례례례례례례례테스트례례례례례례례례례례례례테스트례례실례.테스트", "valid": false }, { "description": "invalid label, correct Punycode", "comment": "https://tools.ietf.org/html/rfc5890#section-2.3.2.1 https://tools.ietf.org/html/rfc5891#section-4.4 https://tools.ietf.org/html/rfc3492#section-7.1", "data": "-> $1.00 <--", "valid": false }, { "description": "valid Chinese Punycode", "comment": "https://tools.ietf.org/html/rfc5890#section-2.3.2.1 https://tools.ietf.org/html/rfc5891#section-4.4", "data": "xn--ihqwcrb4cv8a8dqg056pqjye", "valid": true }, { "description": "invalid Punycode", "comment": "https://tools.ietf.org/html/rfc5891#section-4.4 https://tools.ietf.org/html/rfc5890#section-2.3.2.1", "data": "xn--X", "valid": false }, { "description": "U-label contains \"--\" in the 3rd and 4th position", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1 https://tools.ietf.org/html/rfc5890#section-2.3.2.1", "data": "XN--aa---o47jg78q", "valid": false }, { "description": "U-label starts with a dash", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1", "data": "-hello", "valid": false }, { "description": "U-label ends with a dash", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1", "data": "hello-", "valid": false }, { "description": "U-label starts and ends with a dash", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1", "data": "-hello-", "valid": false }, { "description": "Begins with a Spacing Combining Mark", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2", "data": "\u0903hello", "valid": false }, { "description": "Begins with a Nonspacing Mark", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2", "data": "\u0300hello", "valid": false }, { "description": "Begins with an Enclosing Mark", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2", "data": "\u0488hello", "valid": false }, { "description": "Exceptions that are PVALID, left-to-right chars", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6", "data": "\u00df\u03c2\u0f0b\u3007", "valid": true }, { "description": "Exceptions that are PVALID, right-to-left chars", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6", "data": "\u06fd\u06fe", "valid": true }, { "description": "Exceptions that are DISALLOWED, right-to-left chars", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6", "data": "\u0640\u07fa", "valid": false }, { "description": "Exceptions that are DISALLOWED, left-to-right chars", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6 Note: The two combining marks (U+302E and U+302F) are in the middle and not at the start", "data": "\u3031\u3032\u3033\u3034\u3035\u302e\u302f\u303b", "valid": false }, { "description": "MIDDLE DOT with no preceding 'l'", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "a\u00b7l", "valid": false }, { "description": "MIDDLE DOT with nothing preceding", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "\u00b7l", "valid": false }, { "description": "MIDDLE DOT with no following 'l'", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "l\u00b7a", "valid": false }, { "description": "MIDDLE DOT with nothing following", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "l\u00b7", "valid": false }, { "description": "MIDDLE DOT with surrounding 'l's", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", "data": "l\u00b7l", "valid": true }, { "description": "Greek KERAIA not followed by Greek", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4", "data": "\u03b1\u0375S", "valid": false }, { "description": "Greek KERAIA not followed by anything", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4", "data": "\u03b1\u0375", "valid": false }, { "description": "Greek KERAIA followed by Greek", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4", "data": "\u03b1\u0375\u03b2", "valid": true }, { "description": "Hebrew GERESH not preceded by Hebrew", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5", "data": "A\u05f3\u05d1", "valid": false }, { "description": "Hebrew GERESH not preceded by anything", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5", "data": "\u05f3\u05d1", "valid": false }, { "description": "Hebrew GERESH preceded by Hebrew", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5", "data": "\u05d0\u05f3\u05d1", "valid": true }, { "description": "Hebrew GERSHAYIM not preceded by Hebrew", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6", "data": "A\u05f4\u05d1", "valid": false }, { "description": "Hebrew GERSHAYIM not preceded by anything", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6", "data": "\u05f4\u05d1", "valid": false }, { "description": "Hebrew GERSHAYIM preceded by Hebrew", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6", "data": "\u05d0\u05f4\u05d1", "valid": true }, { "description": "KATAKANA MIDDLE DOT with no Hiragana, Katakana, or Han", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "def\u30fbabc", "valid": false }, { "description": "KATAKANA MIDDLE DOT with no other characters", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "\u30fb", "valid": false }, { "description": "KATAKANA MIDDLE DOT with Hiragana", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "\u30fb\u3041", "valid": true }, { "description": "KATAKANA MIDDLE DOT with Katakana", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "\u30fb\u30a1", "valid": true }, { "description": "KATAKANA MIDDLE DOT with Han", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", "data": "\u30fb\u4e08", "valid": true }, { "description": "Arabic-Indic digits mixed with Extended Arabic-Indic digits", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.8", "data": "\u0660\u06f0", "valid": false }, { "description": "Arabic-Indic digits not mixed with Extended Arabic-Indic digits", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.8", "data": "\u0628\u0660\u0628", "valid": true }, { "description": "Extended Arabic-Indic digits not mixed with Arabic-Indic digits", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.9", "data": "\u06f00", "valid": true }, { "description": "ZERO WIDTH JOINER not preceded by Virama", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf", "data": "\u0915\u200d\u0937", "valid": false }, { "description": "ZERO WIDTH JOINER not preceded by anything", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf", "data": "\u200d\u0937", "valid": false }, { "description": "ZERO WIDTH JOINER preceded by Virama", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf", "data": "\u0915\u094d\u200d\u0937", "valid": true }, { "description": "ZERO WIDTH NON-JOINER preceded by Virama", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.1", "data": "\u0915\u094d\u200c\u0937", "valid": true }, { "description": "ZERO WIDTH NON-JOINER not preceded by Virama but matches regexp", "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.1 https://www.w3.org/TR/alreq/#h_disjoining_enforcement", "data": "\u0628\u064a\u200c\u0628\u064a", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/format/ipv4.json0000644000175100001770000000553714653725311025570 0ustar00runnerdocker[ { "description": "validation of IP addresses", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "ipv4" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IP address", "data": "192.168.0.1", "valid": true }, { "description": "an IP address with too many components", "data": "127.0.0.0.1", "valid": false }, { "description": "an IP address with out-of-range values", "data": "256.256.256.256", "valid": false }, { "description": "an IP address without 4 components", "data": "127.0", "valid": false }, { "description": "an IP address as an integer", "data": "0x7f000001", "valid": false }, { "description": "an IP address as an integer (decimal)", "data": "2130706433", "valid": false }, { "description": "invalid leading zeroes, as they are treated as octals", "comment": "see https://sick.codes/universal-netmask-npm-package-used-by-270000-projects-vulnerable-to-octal-input-data-server-side-request-forgery-remote-file-inclusion-local-file-inclusion-and-more-cve-2021-28918/", "data": "087.10.0.1", "valid": false }, { "description": "value without leading zero is valid", "data": "87.10.0.1", "valid": true }, { "description": "invalid non-ASCII '২' (a Bengali 2)", "data": "1২7.0.0.1", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/format/ipv6.json0000644000175100001770000001557214653725311025572 0ustar00runnerdocker[ { "description": "validation of IPv6 addresses", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "ipv6" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IPv6 address", "data": "::1", "valid": true }, { "description": "an IPv6 address with out-of-range values", "data": "12345::", "valid": false }, { "description": "trailing 4 hex symbols is valid", "data": "::abef", "valid": true }, { "description": "trailing 5 hex symbols is invalid", "data": "::abcef", "valid": false }, { "description": "an IPv6 address with too many components", "data": "1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1", "valid": false }, { "description": "an IPv6 address containing illegal characters", "data": "::laptop", "valid": false }, { "description": "no digits is valid", "data": "::", "valid": true }, { "description": "leading colons is valid", "data": "::42:ff:1", "valid": true }, { "description": "trailing colons is valid", "data": "d6::", "valid": true }, { "description": "missing leading octet is invalid", "data": ":2:3:4:5:6:7:8", "valid": false }, { "description": "missing trailing octet is invalid", "data": "1:2:3:4:5:6:7:", "valid": false }, { "description": "missing leading octet with omitted octets later", "data": ":2:3:4::8", "valid": false }, { "description": "single set of double colons in the middle is valid", "data": "1:d6::42", "valid": true }, { "description": "two sets of double colons is invalid", "data": "1::d6::42", "valid": false }, { "description": "mixed format with the ipv4 section as decimal octets", "data": "1::d6:192.168.0.1", "valid": true }, { "description": "mixed format with double colons between the sections", "data": "1:2::192.168.0.1", "valid": true }, { "description": "mixed format with ipv4 section with octet out of range", "data": "1::2:192.168.256.1", "valid": false }, { "description": "mixed format with ipv4 section with a hex octet", "data": "1::2:192.168.ff.1", "valid": false }, { "description": "mixed format with leading double colons (ipv4-mapped ipv6 address)", "data": "::ffff:192.168.0.1", "valid": true }, { "description": "triple colons is invalid", "data": "1:2:3:4:5:::8", "valid": false }, { "description": "8 octets", "data": "1:2:3:4:5:6:7:8", "valid": true }, { "description": "insufficient octets without double colons", "data": "1:2:3:4:5:6:7", "valid": false }, { "description": "no colons is invalid", "data": "1", "valid": false }, { "description": "ipv4 is not ipv6", "data": "127.0.0.1", "valid": false }, { "description": "ipv4 segment must have 4 octets", "data": "1:2:3:4:1.2.3", "valid": false }, { "description": "leading whitespace is invalid", "data": " ::1", "valid": false }, { "description": "trailing whitespace is invalid", "data": "::1 ", "valid": false }, { "description": "netmask is not a part of ipv6 address", "data": "fe80::/64", "valid": false }, { "description": "zone id is not a part of ipv6 address", "data": "fe80::a%eth1", "valid": false }, { "description": "a long valid ipv6", "data": "1000:1000:1000:1000:1000:1000:255.255.255.255", "valid": true }, { "description": "a long invalid ipv6, below length limit, first", "data": "100:100:100:100:100:100:255.255.255.255.255", "valid": false }, { "description": "a long invalid ipv6, below length limit, second", "data": "100:100:100:100:100:100:100:255.255.255.255", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4)", "data": "1:2:3:4:5:6:7:৪", "valid": false }, { "description": "invalid non-ASCII '৪' (a Bengali 4) in the IPv4 portion", "data": "1:2::192.16৪.0.1", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/format/iri-reference.json0000644000175100001770000000444514653725311027422 0ustar00runnerdocker[ { "description": "validation of IRI References", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "iri-reference" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IRI", "data": "http://ƒøø.ßår/?∂éœ=πîx#πîüx", "valid": true }, { "description": "a valid protocol-relative IRI Reference", "data": "//ƒøø.ßår/?∂éœ=πîx#πîüx", "valid": true }, { "description": "a valid relative IRI Reference", "data": "/âππ", "valid": true }, { "description": "an invalid IRI Reference", "data": "\\\\WINDOWS\\filëßåré", "valid": false }, { "description": "a valid IRI Reference", "data": "âππ", "valid": true }, { "description": "a valid IRI fragment", "data": "#Æ’rägmênt", "valid": true }, { "description": "an invalid IRI fragment", "data": "#Æ’räg\\mênt", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/format/iri.json0000644000175100001770000000545714653725311025472 0ustar00runnerdocker[ { "description": "validation of IRIs", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "iri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid IRI with anchor tag", "data": "http://ƒøø.ßår/?∂éœ=πîx#πîüx", "valid": true }, { "description": "a valid IRI with anchor tag and parentheses", "data": "http://ƒøø.com/blah_(wîkïpédiÃ¥)_blah#ßité-1", "valid": true }, { "description": "a valid IRI with URL-encoded stuff", "data": "http://ƒøø.ßår/?q=Test%20URL-encoded%20stuff", "valid": true }, { "description": "a valid IRI with many special characters", "data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", "valid": true }, { "description": "a valid IRI based on IPv6", "data": "http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]", "valid": true }, { "description": "an invalid IRI based on IPv6", "data": "http://2001:0db8:85a3:0000:0000:8a2e:0370:7334", "valid": false }, { "description": "an invalid relative IRI Reference", "data": "/abc", "valid": false }, { "description": "an invalid IRI", "data": "\\\\WINDOWS\\filëßåré", "valid": false }, { "description": "an invalid IRI though valid IRI reference", "data": "âππ", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/format/json-pointer.json0000644000175100001770000001521614653725311027330 0ustar00runnerdocker[ { "description": "validation of JSON-pointers (JSON String Representation)", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "json-pointer" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid JSON-pointer", "data": "/foo/bar~0/baz~1/%a", "valid": true }, { "description": "not a valid JSON-pointer (~ not escaped)", "data": "/foo/bar~", "valid": false }, { "description": "valid JSON-pointer with empty segment", "data": "/foo//bar", "valid": true }, { "description": "valid JSON-pointer with the last empty segment", "data": "/foo/bar/", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #1", "data": "", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #2", "data": "/foo", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #3", "data": "/foo/0", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #4", "data": "/", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #5", "data": "/a~1b", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #6", "data": "/c%d", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #7", "data": "/e^f", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #8", "data": "/g|h", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #9", "data": "/i\\j", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #10", "data": "/k\"l", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #11", "data": "/ ", "valid": true }, { "description": "valid JSON-pointer as stated in RFC 6901 #12", "data": "/m~0n", "valid": true }, { "description": "valid JSON-pointer used adding to the last array position", "data": "/foo/-", "valid": true }, { "description": "valid JSON-pointer (- used as object member name)", "data": "/foo/-/bar", "valid": true }, { "description": "valid JSON-pointer (multiple escaped characters)", "data": "/~1~0~0~1~1", "valid": true }, { "description": "valid JSON-pointer (escaped with fraction part) #1", "data": "/~1.1", "valid": true }, { "description": "valid JSON-pointer (escaped with fraction part) #2", "data": "/~0.1", "valid": true }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #1", "data": "#", "valid": false }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #2", "data": "#/", "valid": false }, { "description": "not a valid JSON-pointer (URI Fragment Identifier) #3", "data": "#a", "valid": false }, { "description": "not a valid JSON-pointer (some escaped, but not all) #1", "data": "/~0~", "valid": false }, { "description": "not a valid JSON-pointer (some escaped, but not all) #2", "data": "/~0/~", "valid": false }, { "description": "not a valid JSON-pointer (wrong escape character) #1", "data": "/~2", "valid": false }, { "description": "not a valid JSON-pointer (wrong escape character) #2", "data": "/~-1", "valid": false }, { "description": "not a valid JSON-pointer (multiple characters not escaped)", "data": "/~~", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #1", "data": "a", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #2", "data": "0", "valid": false }, { "description": "not a valid JSON-pointer (isn't empty nor starts with /) #3", "data": "a/a", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/format/regex.json0000644000175100001770000000275114653725311026013 0ustar00runnerdocker[ { "description": "validation of regular expressions", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "regex" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid regular expression", "data": "([abc])+\\s+$", "valid": true }, { "description": "a regular expression with unclosed parens is invalid", "data": "^(abc]", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/format/relative-json-pointer.json0000644000175100001770000000607614653725311031145 0ustar00runnerdocker[ { "description": "validation of Relative JSON Pointers (RJP)", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "relative-json-pointer" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid upwards RJP", "data": "1", "valid": true }, { "description": "a valid downwards RJP", "data": "0/foo/bar", "valid": true }, { "description": "a valid up and then down RJP, with array index", "data": "2/0/baz/1/zip", "valid": true }, { "description": "a valid RJP taking the member or index name", "data": "0#", "valid": true }, { "description": "an invalid RJP that is a valid JSON Pointer", "data": "/foo/bar", "valid": false }, { "description": "negative prefix", "data": "-1/foo/bar", "valid": false }, { "description": "explicit positive prefix", "data": "+1/foo/bar", "valid": false }, { "description": "## is not a valid json-pointer", "data": "0##", "valid": false }, { "description": "zero cannot be followed by other digits, plus json-pointer", "data": "01/a", "valid": false }, { "description": "zero cannot be followed by other digits, plus octothorpe", "data": "01#", "valid": false }, { "description": "empty string", "data": "", "valid": false }, { "description": "multi-digit integer prefix", "data": "120/foo/bar", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/format/time.json0000644000175100001770000001632114653725311025635 0ustar00runnerdocker[ { "description": "validation of time strings", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "time" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid time string", "data": "08:30:06Z", "valid": true }, { "description": "a valid time string with leap second, Zulu", "data": "23:59:60Z", "valid": true }, { "description": "invalid leap second, Zulu (wrong hour)", "data": "22:59:60Z", "valid": false }, { "description": "invalid leap second, Zulu (wrong minute)", "data": "23:58:60Z", "valid": false }, { "description": "valid leap second, zero time-offset", "data": "23:59:60+00:00", "valid": true }, { "description": "invalid leap second, zero time-offset (wrong hour)", "data": "22:59:60+00:00", "valid": false }, { "description": "invalid leap second, zero time-offset (wrong minute)", "data": "23:58:60+00:00", "valid": false }, { "description": "valid leap second, positive time-offset", "data": "01:29:60+01:30", "valid": true }, { "description": "valid leap second, large positive time-offset", "data": "23:29:60+23:30", "valid": true }, { "description": "invalid leap second, positive time-offset (wrong hour)", "data": "23:59:60+01:00", "valid": false }, { "description": "invalid leap second, positive time-offset (wrong minute)", "data": "23:59:60+00:30", "valid": false }, { "description": "valid leap second, negative time-offset", "data": "15:59:60-08:00", "valid": true }, { "description": "valid leap second, large negative time-offset", "data": "00:29:60-23:30", "valid": true }, { "description": "invalid leap second, negative time-offset (wrong hour)", "data": "23:59:60-01:00", "valid": false }, { "description": "invalid leap second, negative time-offset (wrong minute)", "data": "23:59:60-00:30", "valid": false }, { "description": "a valid time string with second fraction", "data": "23:20:50.52Z", "valid": true }, { "description": "a valid time string with precise second fraction", "data": "08:30:06.283185Z", "valid": true }, { "description": "a valid time string with plus offset", "data": "08:30:06+00:20", "valid": true }, { "description": "a valid time string with minus offset", "data": "08:30:06-08:00", "valid": true }, { "description": "a valid time string with case-insensitive Z", "data": "08:30:06z", "valid": true }, { "description": "an invalid time string with invalid hour", "data": "24:00:00Z", "valid": false }, { "description": "an invalid time string with invalid minute", "data": "00:60:00Z", "valid": false }, { "description": "an invalid time string with invalid second", "data": "00:00:61Z", "valid": false }, { "description": "an invalid time string with invalid leap second (wrong hour)", "data": "22:59:60Z", "valid": false }, { "description": "an invalid time string with invalid leap second (wrong minute)", "data": "23:58:60Z", "valid": false }, { "description": "an invalid time string with invalid time numoffset hour", "data": "01:02:03+24:00", "valid": false }, { "description": "an invalid time string with invalid time numoffset minute", "data": "01:02:03+00:60", "valid": false }, { "description": "an invalid time string with invalid time with both Z and numoffset", "data": "01:02:03Z+00:30", "valid": false }, { "description": "an invalid offset indicator", "data": "08:30:06 PST", "valid": false }, { "description": "only RFC3339 not all of ISO 8601 are valid", "data": "01:01:01,1111", "valid": false }, { "description": "no time offset", "data": "12:00:00", "valid": false }, { "description": "no time offset with second fraction", "data": "12:00:00.52", "valid": false }, { "description": "invalid non-ASCII '২' (a Bengali 2)", "data": "1২:00:00Z", "valid": false }, { "description": "offset not starting with plus or minus", "data": "08:30:06#00:20", "valid": false }, { "description": "contains letters", "data": "ab:cd:ef", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/format/unknown.json0000644000175100001770000000241614653725311026376 0ustar00runnerdocker[ { "description": "unknown format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "unknown" }, "tests": [ { "description": "unknown formats ignore integers", "data": 12, "valid": true }, { "description": "unknown formats ignore floats", "data": 13.7, "valid": true }, { "description": "unknown formats ignore objects", "data": {}, "valid": true }, { "description": "unknown formats ignore arrays", "data": [], "valid": true }, { "description": "unknown formats ignore booleans", "data": false, "valid": true }, { "description": "unknown formats ignore nulls", "data": null, "valid": true }, { "description": "unknown formats ignore strings", "data": "string", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/format/uri-reference.json0000644000175100001770000000437214653725311027435 0ustar00runnerdocker[ { "description": "validation of URI References", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "uri-reference" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid URI", "data": "http://foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid protocol-relative URI Reference", "data": "//foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid relative URI Reference", "data": "/abc", "valid": true }, { "description": "an invalid URI Reference", "data": "\\\\WINDOWS\\fileshare", "valid": false }, { "description": "a valid URI Reference", "data": "abc", "valid": true }, { "description": "a valid URI fragment", "data": "#fragment", "valid": true }, { "description": "an invalid URI fragment", "data": "#frag\\ment", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/format/uri-template.json0000644000175100001770000000356414653725311027314 0ustar00runnerdocker[ { "description": "format: uri-template", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "uri-template" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid uri-template", "data": "http://example.com/dictionary/{term:1}/{term}", "valid": true }, { "description": "an invalid uri-template", "data": "http://example.com/dictionary/{term:1}/{term", "valid": false }, { "description": "a valid uri-template without variables", "data": "http://example.com/dictionary", "valid": true }, { "description": "a valid relative uri-template", "data": "dictionary/{term:1}/{term}", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/format/uri.json0000644000175100001770000001116714653725311025501 0ustar00runnerdocker[ { "description": "validation of URIs", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "uri" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "a valid URL with anchor tag", "data": "http://foo.bar/?baz=qux#quux", "valid": true }, { "description": "a valid URL with anchor tag and parentheses", "data": "http://foo.com/blah_(wikipedia)_blah#cite-1", "valid": true }, { "description": "a valid URL with URL-encoded stuff", "data": "http://foo.bar/?q=Test%20URL-encoded%20stuff", "valid": true }, { "description": "a valid puny-coded URL ", "data": "http://xn--nw2a.xn--j6w193g/", "valid": true }, { "description": "a valid URL with many special characters", "data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", "valid": true }, { "description": "a valid URL based on IPv4", "data": "http://223.255.255.254", "valid": true }, { "description": "a valid URL with ftp scheme", "data": "ftp://ftp.is.co.za/rfc/rfc1808.txt", "valid": true }, { "description": "a valid URL for a simple text file", "data": "http://www.ietf.org/rfc/rfc2396.txt", "valid": true }, { "description": "a valid URL ", "data": "ldap://[2001:db8::7]/c=GB?objectClass?one", "valid": true }, { "description": "a valid mailto URI", "data": "mailto:John.Doe@example.com", "valid": true }, { "description": "a valid newsgroup URI", "data": "news:comp.infosystems.www.servers.unix", "valid": true }, { "description": "a valid tel URI", "data": "tel:+1-816-555-1212", "valid": true }, { "description": "a valid URN", "data": "urn:oasis:names:specification:docbook:dtd:xml:4.1.2", "valid": true }, { "description": "an invalid protocol-relative URI Reference", "data": "//foo.bar/?baz=qux#quux", "valid": false }, { "description": "an invalid relative URI Reference", "data": "/abc", "valid": false }, { "description": "an invalid URI", "data": "\\\\WINDOWS\\fileshare", "valid": false }, { "description": "an invalid URI though valid URI reference", "data": "abc", "valid": false }, { "description": "an invalid URI with spaces", "data": "http:// shouldfail.com", "valid": false }, { "description": "an invalid URI with spaces and missing scheme", "data": ":// should fail", "valid": false }, { "description": "an invalid URI with comma in scheme", "data": "bar,baz:foo", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/format/uuid.json0000644000175100001770000000725714653725311025655 0ustar00runnerdocker[ { "description": "uuid format", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "format": "uuid" }, "tests": [ { "description": "all string formats ignore integers", "data": 12, "valid": true }, { "description": "all string formats ignore floats", "data": 13.7, "valid": true }, { "description": "all string formats ignore objects", "data": {}, "valid": true }, { "description": "all string formats ignore arrays", "data": [], "valid": true }, { "description": "all string formats ignore booleans", "data": false, "valid": true }, { "description": "all string formats ignore nulls", "data": null, "valid": true }, { "description": "all upper-case", "data": "2EB8AA08-AA98-11EA-B4AA-73B441D16380", "valid": true }, { "description": "all lower-case", "data": "2eb8aa08-aa98-11ea-b4aa-73b441d16380", "valid": true }, { "description": "mixed case", "data": "2eb8aa08-AA98-11ea-B4Aa-73B441D16380", "valid": true }, { "description": "all zeroes is valid", "data": "00000000-0000-0000-0000-000000000000", "valid": true }, { "description": "wrong length", "data": "2eb8aa08-aa98-11ea-b4aa-73b441d1638", "valid": false }, { "description": "missing section", "data": "2eb8aa08-aa98-11ea-73b441d16380", "valid": false }, { "description": "bad characters (not hex)", "data": "2eb8aa08-aa98-11ea-b4ga-73b441d16380", "valid": false }, { "description": "no dashes", "data": "2eb8aa08aa9811eab4aa73b441d16380", "valid": false }, { "description": "too few dashes", "data": "2eb8aa08aa98-11ea-b4aa73b441d16380", "valid": false }, { "description": "too many dashes", "data": "2eb8-aa08-aa98-11ea-b4aa73b44-1d16380", "valid": false }, { "description": "dashes in the wrong spot", "data": "2eb8aa08aa9811eab4aa73b441d16380----", "valid": false }, { "description": "valid version 4", "data": "98d80576-482e-427f-8434-7f86890ab222", "valid": true }, { "description": "valid version 5", "data": "99c17cbb-656f-564a-940f-1a4568f03487", "valid": true }, { "description": "hypothetical version 6", "data": "99c17cbb-656f-664a-940f-1a4568f03487", "valid": true }, { "description": "hypothetical version 15", "data": "99c17cbb-656f-f64a-940f-1a4568f03487", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/format-assertion.json0000644000175100001770000000253414653725311026705 0ustar00runnerdocker[ { "description": "schema that uses custom metaschema with format-assertion: false", "schema": { "$id": "https://schema/using/format-assertion/false", "$schema": "http://localhost:1234/draft2020-12/format-assertion-false.json", "format": "ipv4" }, "tests": [ { "description": "format-assertion: false: valid string", "data": "127.0.0.1", "valid": true }, { "description": "format-assertion: false: invalid string", "data": "not-an-ipv4", "valid": false } ] }, { "description": "schema that uses custom metaschema with format-assertion: true", "schema": { "$id": "https://schema/using/format-assertion/true", "$schema": "http://localhost:1234/draft2020-12/format-assertion-true.json", "format": "ipv4" }, "tests": [ { "description": "format-assertion: true: valid string", "data": "127.0.0.1", "valid": true }, { "description": "format-assertion: true: invalid string", "data": "not-an-ipv4", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/no-schema.json0000644000175100001770000000123614653725311025260 0ustar00runnerdocker[ { "description": "validation without $schema", "comment": "minLength is the same across all drafts", "schema": { "minLength": 2 }, "tests": [ { "description": "a 3-character string is valid", "data": "foo", "valid": true }, { "description": "a 1-character string is not valid", "data": "a", "valid": false }, { "description": "a non-string is valid", "data": 5, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/non-bmp-regex.json0000644000175100001770000000500014653725311026055 0ustar00runnerdocker[ { "description": "Proper UTF-16 surrogate pair handling: pattern", "comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "pattern": "^ðŸ²*$" }, "tests": [ { "description": "matches empty", "data": "", "valid": true }, { "description": "matches single", "data": "ðŸ²", "valid": true }, { "description": "matches two", "data": "ðŸ²ðŸ²", "valid": true }, { "description": "doesn't match one", "data": "ðŸ‰", "valid": false }, { "description": "doesn't match two", "data": "ðŸ‰ðŸ‰", "valid": false }, { "description": "doesn't match one ASCII", "data": "D", "valid": false }, { "description": "doesn't match two ASCII", "data": "DD", "valid": false } ] }, { "description": "Proper UTF-16 surrogate pair handling: patternProperties", "comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "patternProperties": { "^ðŸ²*$": { "type": "integer" } } }, "tests": [ { "description": "matches empty", "data": { "": 1 }, "valid": true }, { "description": "matches single", "data": { "ðŸ²": 1 }, "valid": true }, { "description": "matches two", "data": { "ðŸ²ðŸ²": 1 }, "valid": true }, { "description": "doesn't match one", "data": { "ðŸ²": "hello" }, "valid": false }, { "description": "doesn't match two", "data": { "ðŸ²ðŸ²": "hello" }, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/optional/refOfUnknownKeyword.json0000644000175100001770000000243214653725311027373 0ustar00runnerdocker[ { "description": "reference of a root arbitrary keyword ", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "unknown-keyword": {"type": "integer"}, "properties": { "bar": {"$ref": "#/unknown-keyword"} } }, "tests": [ { "description": "match", "data": {"bar": 3}, "valid": true }, { "description": "mismatch", "data": {"bar": true}, "valid": false } ] }, { "description": "reference of an arbitrary keyword of a sub-schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": {"unknown-keyword": {"type": "integer"}}, "bar": {"$ref": "#/properties/foo/unknown-keyword"} } }, "tests": [ { "description": "match", "data": {"bar": 3}, "valid": true }, { "description": "mismatch", "data": {"bar": true}, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/pattern.json0000644000175100001770000000327514653725311023243 0ustar00runnerdocker[ { "description": "pattern validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "pattern": "^a*$" }, "tests": [ { "description": "a matching pattern is valid", "data": "aaa", "valid": true }, { "description": "a non-matching pattern is invalid", "data": "abc", "valid": false }, { "description": "ignores booleans", "data": true, "valid": true }, { "description": "ignores integers", "data": 123, "valid": true }, { "description": "ignores floats", "data": 1.0, "valid": true }, { "description": "ignores objects", "data": {}, "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores null", "data": null, "valid": true } ] }, { "description": "pattern is not anchored", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "pattern": "a+" }, "tests": [ { "description": "matches a substring", "data": "xxaayy", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/patternProperties.json0000644000175100001770000001263414653725311025317 0ustar00runnerdocker[ { "description": "patternProperties validates properties matching a regex", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "patternProperties": { "f.*o": {"type": "integer"} } }, "tests": [ { "description": "a single valid match is valid", "data": {"foo": 1}, "valid": true }, { "description": "multiple valid matches is valid", "data": {"foo": 1, "foooooo" : 2}, "valid": true }, { "description": "a single invalid match is invalid", "data": {"foo": "bar", "fooooo": 2}, "valid": false }, { "description": "multiple invalid matches is invalid", "data": {"foo": "bar", "foooooo" : "baz"}, "valid": false }, { "description": "ignores arrays", "data": ["foo"], "valid": true }, { "description": "ignores strings", "data": "foo", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "multiple simultaneous patternProperties are validated", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "patternProperties": { "a*": {"type": "integer"}, "aaa*": {"maximum": 20} } }, "tests": [ { "description": "a single valid match is valid", "data": {"a": 21}, "valid": true }, { "description": "a simultaneous match is valid", "data": {"aaaa": 18}, "valid": true }, { "description": "multiple matches is valid", "data": {"a": 21, "aaaa": 18}, "valid": true }, { "description": "an invalid due to one is invalid", "data": {"a": "bar"}, "valid": false }, { "description": "an invalid due to the other is invalid", "data": {"aaaa": 31}, "valid": false }, { "description": "an invalid due to both is invalid", "data": {"aaa": "foo", "aaaa": 31}, "valid": false } ] }, { "description": "regexes are not anchored by default and are case sensitive", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "patternProperties": { "[0-9]{2,}": { "type": "boolean" }, "X_": { "type": "string" } } }, "tests": [ { "description": "non recognized members are ignored", "data": { "answer 1": "42" }, "valid": true }, { "description": "recognized members are accounted for", "data": { "a31b": null }, "valid": false }, { "description": "regexes are case sensitive", "data": { "a_x_3": 3 }, "valid": true }, { "description": "regexes are case sensitive, 2", "data": { "a_X_3": 3 }, "valid": false } ] }, { "description": "patternProperties with boolean schemas", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "patternProperties": { "f.*": true, "b.*": false } }, "tests": [ { "description": "object with property matching schema true is valid", "data": {"foo": 1}, "valid": true }, { "description": "object with property matching schema false is invalid", "data": {"bar": 2}, "valid": false }, { "description": "object with both properties is invalid", "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "object with a property matching both true and false is invalid", "data": {"foobar":1}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "patternProperties with null valued instance properties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "patternProperties": { "^.*bar$": {"type": "null"} } }, "tests": [ { "description": "allows null values", "data": {"foobar": null}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/prefixItems.json0000644000175100001770000000556114653725311024065 0ustar00runnerdocker[ { "description": "a schema given for prefixItems", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [ {"type": "integer"}, {"type": "string"} ] }, "tests": [ { "description": "correct types", "data": [ 1, "foo" ], "valid": true }, { "description": "wrong types", "data": [ "foo", 1 ], "valid": false }, { "description": "incomplete array of items", "data": [ 1 ], "valid": true }, { "description": "array with additional items", "data": [ 1, "foo", true ], "valid": true }, { "description": "empty array", "data": [ ], "valid": true }, { "description": "JavaScript pseudo-array is valid", "data": { "0": "invalid", "1": "valid", "length": 2 }, "valid": true } ] }, { "description": "prefixItems with boolean schemas", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [true, false] }, "tests": [ { "description": "array with one item is valid", "data": [ 1 ], "valid": true }, { "description": "array with two items is invalid", "data": [ 1, "foo" ], "valid": false }, { "description": "empty array is valid", "data": [], "valid": true } ] }, { "description": "additional items are allowed by default", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [{"type": "integer"}] }, "tests": [ { "description": "only the first item is validated", "data": [1, "foo", false], "valid": true } ] }, { "description": "prefixItems with null instance elements", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [ { "type": "null" } ] }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/properties.json0000644000175100001770000001706314653725311023762 0ustar00runnerdocker[ { "description": "object properties validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": {"type": "integer"}, "bar": {"type": "string"} } }, "tests": [ { "description": "both properties present and valid is valid", "data": {"foo": 1, "bar": "baz"}, "valid": true }, { "description": "one property invalid is invalid", "data": {"foo": 1, "bar": {}}, "valid": false }, { "description": "both properties invalid is invalid", "data": {"foo": [], "bar": {}}, "valid": false }, { "description": "doesn't invalidate other properties", "data": {"quux": []}, "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "properties, patternProperties, additionalProperties interaction", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": {"type": "array", "maxItems": 3}, "bar": {"type": "array"} }, "patternProperties": {"f.o": {"minItems": 2}}, "additionalProperties": {"type": "integer"} }, "tests": [ { "description": "property validates property", "data": {"foo": [1, 2]}, "valid": true }, { "description": "property invalidates property", "data": {"foo": [1, 2, 3, 4]}, "valid": false }, { "description": "patternProperty invalidates property", "data": {"foo": []}, "valid": false }, { "description": "patternProperty validates nonproperty", "data": {"fxo": [1, 2]}, "valid": true }, { "description": "patternProperty invalidates nonproperty", "data": {"fxo": []}, "valid": false }, { "description": "additionalProperty ignores property", "data": {"bar": []}, "valid": true }, { "description": "additionalProperty validates others", "data": {"quux": 3}, "valid": true }, { "description": "additionalProperty invalidates others", "data": {"quux": "foo"}, "valid": false } ] }, { "description": "properties with boolean schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": true, "bar": false } }, "tests": [ { "description": "no property present is valid", "data": {}, "valid": true }, { "description": "only 'true' property present is valid", "data": {"foo": 1}, "valid": true }, { "description": "only 'false' property present is invalid", "data": {"bar": 2}, "valid": false }, { "description": "both properties present is invalid", "data": {"foo": 1, "bar": 2}, "valid": false } ] }, { "description": "properties with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo\nbar": {"type": "number"}, "foo\"bar": {"type": "number"}, "foo\\bar": {"type": "number"}, "foo\rbar": {"type": "number"}, "foo\tbar": {"type": "number"}, "foo\fbar": {"type": "number"} } }, "tests": [ { "description": "object with all numbers is valid", "data": { "foo\nbar": 1, "foo\"bar": 1, "foo\\bar": 1, "foo\rbar": 1, "foo\tbar": 1, "foo\fbar": 1 }, "valid": true }, { "description": "object with strings is invalid", "data": { "foo\nbar": "1", "foo\"bar": "1", "foo\\bar": "1", "foo\rbar": "1", "foo\tbar": "1", "foo\fbar": "1" }, "valid": false } ] }, { "description": "properties with null valued instance properties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": {"type": "null"} } }, "tests": [ { "description": "allows null values", "data": {"foo": null}, "valid": true } ] }, { "description": "properties whose names are Javascript object property names", "comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "__proto__": {"type": "number"}, "toString": { "properties": { "length": { "type": "string" } } }, "constructor": {"type": "number"} } }, "tests": [ { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "none of the properties mentioned", "data": {}, "valid": true }, { "description": "__proto__ not valid", "data": { "__proto__": "foo" }, "valid": false }, { "description": "toString not valid", "data": { "toString": { "length": 37 } }, "valid": false }, { "description": "constructor not valid", "data": { "constructor": { "length": 37 } }, "valid": false }, { "description": "all present and valid", "data": { "__proto__": 12, "toString": { "length": "foo" }, "constructor": 37 }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/propertyNames.json0000644000175100001770000000453114653725311024432 0ustar00runnerdocker[ { "description": "propertyNames validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "propertyNames": {"maxLength": 3} }, "tests": [ { "description": "all property names valid", "data": { "f": {}, "foo": {} }, "valid": true }, { "description": "some property names invalid", "data": { "foo": {}, "foobar": {} }, "valid": false }, { "description": "object without properties is valid", "data": {}, "valid": true }, { "description": "ignores arrays", "data": [1, 2, 3, 4], "valid": true }, { "description": "ignores strings", "data": "foobar", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "propertyNames with boolean schema true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "propertyNames": true }, "tests": [ { "description": "object with any properties is valid", "data": {"foo": 1}, "valid": true }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "propertyNames with boolean schema false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "propertyNames": false }, "tests": [ { "description": "object with any properties is invalid", "data": {"foo": 1}, "valid": false }, { "description": "empty object is valid", "data": {}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/ref.json0000644000175100001770000006556414653725311022353 0ustar00runnerdocker[ { "description": "root pointer ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": {"$ref": "#"} }, "additionalProperties": false }, "tests": [ { "description": "match", "data": {"foo": false}, "valid": true }, { "description": "recursive match", "data": {"foo": {"foo": false}}, "valid": true }, { "description": "mismatch", "data": {"bar": false}, "valid": false }, { "description": "recursive mismatch", "data": {"foo": {"bar": false}}, "valid": false } ] }, { "description": "relative pointer ref to object", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": {"type": "integer"}, "bar": {"$ref": "#/properties/foo"} } }, "tests": [ { "description": "match", "data": {"bar": 3}, "valid": true }, { "description": "mismatch", "data": {"bar": true}, "valid": false } ] }, { "description": "relative pointer ref to array", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [ {"type": "integer"}, {"$ref": "#/prefixItems/0"} ] }, "tests": [ { "description": "match array", "data": [1, 2], "valid": true }, { "description": "mismatch array", "data": [1, "foo"], "valid": false } ] }, { "description": "escaped pointer ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "tilde~field": {"type": "integer"}, "slash/field": {"type": "integer"}, "percent%field": {"type": "integer"} }, "properties": { "tilde": {"$ref": "#/$defs/tilde~0field"}, "slash": {"$ref": "#/$defs/slash~1field"}, "percent": {"$ref": "#/$defs/percent%25field"} } }, "tests": [ { "description": "slash invalid", "data": {"slash": "aoeu"}, "valid": false }, { "description": "tilde invalid", "data": {"tilde": "aoeu"}, "valid": false }, { "description": "percent invalid", "data": {"percent": "aoeu"}, "valid": false }, { "description": "slash valid", "data": {"slash": 123}, "valid": true }, { "description": "tilde valid", "data": {"tilde": 123}, "valid": true }, { "description": "percent valid", "data": {"percent": 123}, "valid": true } ] }, { "description": "nested refs", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "a": {"type": "integer"}, "b": {"$ref": "#/$defs/a"}, "c": {"$ref": "#/$defs/b"} }, "$ref": "#/$defs/c" }, "tests": [ { "description": "nested ref valid", "data": 5, "valid": true }, { "description": "nested ref invalid", "data": "a", "valid": false } ] }, { "description": "ref applies alongside sibling keywords", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "reffed": { "type": "array" } }, "properties": { "foo": { "$ref": "#/$defs/reffed", "maxItems": 2 } } }, "tests": [ { "description": "ref valid, maxItems valid", "data": { "foo": [] }, "valid": true }, { "description": "ref valid, maxItems invalid", "data": { "foo": [1, 2, 3] }, "valid": false }, { "description": "ref invalid", "data": { "foo": "string" }, "valid": false } ] }, { "description": "remote ref, containing refs itself", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "https://json-schema.org/draft/2020-12/schema" }, "tests": [ { "description": "remote ref valid", "data": {"minLength": 1}, "valid": true }, { "description": "remote ref invalid", "data": {"minLength": -1}, "valid": false } ] }, { "description": "property named $ref that is not a reference", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "$ref": {"type": "string"} } }, "tests": [ { "description": "property named $ref valid", "data": {"$ref": "a"}, "valid": true }, { "description": "property named $ref invalid", "data": {"$ref": 2}, "valid": false } ] }, { "description": "property named $ref, containing an actual $ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "$ref": {"$ref": "#/$defs/is-string"} }, "$defs": { "is-string": { "type": "string" } } }, "tests": [ { "description": "property named $ref valid", "data": {"$ref": "a"}, "valid": true }, { "description": "property named $ref invalid", "data": {"$ref": 2}, "valid": false } ] }, { "description": "$ref to boolean schema true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "#/$defs/bool", "$defs": { "bool": true } }, "tests": [ { "description": "any value is valid", "data": "foo", "valid": true } ] }, { "description": "$ref to boolean schema false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "#/$defs/bool", "$defs": { "bool": false } }, "tests": [ { "description": "any value is invalid", "data": "foo", "valid": false } ] }, { "description": "Recursive references between schemas", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/tree", "description": "tree of nodes", "type": "object", "properties": { "meta": {"type": "string"}, "nodes": { "type": "array", "items": {"$ref": "node"} } }, "required": ["meta", "nodes"], "$defs": { "node": { "$id": "http://localhost:1234/draft2020-12/node", "description": "node", "type": "object", "properties": { "value": {"type": "number"}, "subtree": {"$ref": "tree"} }, "required": ["value"] } } }, "tests": [ { "description": "valid tree", "data": { "meta": "root", "nodes": [ { "value": 1, "subtree": { "meta": "child", "nodes": [ {"value": 1.1}, {"value": 1.2} ] } }, { "value": 2, "subtree": { "meta": "child", "nodes": [ {"value": 2.1}, {"value": 2.2} ] } } ] }, "valid": true }, { "description": "invalid tree", "data": { "meta": "root", "nodes": [ { "value": 1, "subtree": { "meta": "child", "nodes": [ {"value": "string is invalid"}, {"value": 1.2} ] } }, { "value": 2, "subtree": { "meta": "child", "nodes": [ {"value": 2.1}, {"value": 2.2} ] } } ] }, "valid": false } ] }, { "description": "refs with quote", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo\"bar": {"$ref": "#/$defs/foo%22bar"} }, "$defs": { "foo\"bar": {"type": "number"} } }, "tests": [ { "description": "object with numbers is valid", "data": { "foo\"bar": 1 }, "valid": true }, { "description": "object with strings is invalid", "data": { "foo\"bar": "1" }, "valid": false } ] }, { "description": "ref creates new scope when adjacent to keywords", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "A": { "unevaluatedProperties": false } }, "properties": { "prop1": { "type": "string" } }, "$ref": "#/$defs/A" }, "tests": [ { "description": "referenced subschema doesn't see annotations from properties", "data": { "prop1": "match" }, "valid": false } ] }, { "description": "naive replacement of $ref with its destination is not correct", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "a_string": { "type": "string" } }, "enum": [ { "$ref": "#/$defs/a_string" } ] }, "tests": [ { "description": "do not evaluate the $ref inside the enum, matching any string", "data": "this is a string", "valid": false }, { "description": "do not evaluate the $ref inside the enum, definition exact match", "data": { "type": "string" }, "valid": false }, { "description": "match the enum exactly", "data": { "$ref": "#/$defs/a_string" }, "valid": true } ] }, { "description": "refs with relative uris and defs", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://example.com/schema-relative-uri-defs1.json", "properties": { "foo": { "$id": "schema-relative-uri-defs2.json", "$defs": { "inner": { "properties": { "bar": { "type": "string" } } } }, "$ref": "#/$defs/inner" } }, "$ref": "schema-relative-uri-defs2.json" }, "tests": [ { "description": "invalid on inner field", "data": { "foo": { "bar": 1 }, "bar": "a" }, "valid": false }, { "description": "invalid on outer field", "data": { "foo": { "bar": "a" }, "bar": 1 }, "valid": false }, { "description": "valid on both fields", "data": { "foo": { "bar": "a" }, "bar": "a" }, "valid": true } ] }, { "description": "relative refs with absolute uris and defs", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://example.com/schema-refs-absolute-uris-defs1.json", "properties": { "foo": { "$id": "http://example.com/schema-refs-absolute-uris-defs2.json", "$defs": { "inner": { "properties": { "bar": { "type": "string" } } } }, "$ref": "#/$defs/inner" } }, "$ref": "schema-refs-absolute-uris-defs2.json" }, "tests": [ { "description": "invalid on inner field", "data": { "foo": { "bar": 1 }, "bar": "a" }, "valid": false }, { "description": "invalid on outer field", "data": { "foo": { "bar": "a" }, "bar": 1 }, "valid": false }, { "description": "valid on both fields", "data": { "foo": { "bar": "a" }, "bar": "a" }, "valid": true } ] }, { "description": "$id must be resolved against nearest parent, not just immediate parent", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://example.com/a.json", "$defs": { "x": { "$id": "http://example.com/b/c.json", "not": { "$defs": { "y": { "$id": "d.json", "type": "number" } } } } }, "allOf": [ { "$ref": "http://example.com/b/d.json" } ] }, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "non-number is invalid", "data": "a", "valid": false } ] }, { "description": "order of evaluation: $id and $ref", "schema": { "$comment": "$id must be evaluated before $ref to get the proper $ref destination", "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "/draft2020-12/ref-and-id1/base.json", "$ref": "int.json", "$defs": { "bigint": { "$comment": "canonical uri: /ref-and-id1/int.json", "$id": "int.json", "maximum": 10 }, "smallint": { "$comment": "canonical uri: /ref-and-id1-int.json", "$id": "/draft2020-12/ref-and-id1-int.json", "maximum": 2 } } }, "tests": [ { "description": "data is valid against first definition", "data": 5, "valid": true }, { "description": "data is invalid against first definition", "data": 50, "valid": false } ] }, { "description": "order of evaluation: $id and $anchor and $ref", "schema": { "$comment": "$id must be evaluated before $ref to get the proper $ref destination", "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "/draft2020-12/ref-and-id2/base.json", "$ref": "#bigint", "$defs": { "bigint": { "$comment": "canonical uri: /ref-and-id2/base.json#/$defs/bigint; another valid uri for this location: /ref-and-id2/base.json#bigint", "$anchor": "bigint", "maximum": 10 }, "smallint": { "$comment": "canonical uri: /ref-and-id2#/$defs/smallint; another valid uri for this location: /ref-and-id2/#bigint", "$id": "/draft2020-12/ref-and-id2/", "$anchor": "bigint", "maximum": 2 } } }, "tests": [ { "description": "data is valid against first definition", "data": 5, "valid": true }, { "description": "data is invalid against first definition", "data": 50, "valid": false } ] }, { "description": "simple URN base URI with $ref via the URN", "schema": { "$comment": "URIs do not have to have HTTP(s) schemes", "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed", "minimum": 30, "properties": { "foo": {"$ref": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed"} } }, "tests": [ { "description": "valid under the URN IDed schema", "data": {"foo": 37}, "valid": true }, { "description": "invalid under the URN IDed schema", "data": {"foo": 12}, "valid": false } ] }, { "description": "simple URN base URI with JSON pointer", "schema": { "$comment": "URIs do not have to have HTTP(s) schemes", "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "urn:uuid:deadbeef-1234-00ff-ff00-4321feebdaed", "properties": { "foo": {"$ref": "#/$defs/bar"} }, "$defs": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with NSS", "schema": { "$comment": "RFC 8141 §2.2", "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "urn:example:1/406/47452/2", "properties": { "foo": {"$ref": "#/$defs/bar"} }, "$defs": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with r-component", "schema": { "$comment": "RFC 8141 §2.3.1", "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "urn:example:foo-bar-baz-qux?+CCResolve:cc=uk", "properties": { "foo": {"$ref": "#/$defs/bar"} }, "$defs": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with q-component", "schema": { "$comment": "RFC 8141 §2.3.2", "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "urn:example:weather?=op=map&lat=39.56&lon=-104.85&datetime=1969-07-21T02:56:15Z", "properties": { "foo": {"$ref": "#/$defs/bar"} }, "$defs": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with f-component", "schema": { "$comment": "RFC 8141 §2.3.3, but we don't allow fragments", "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "https://json-schema.org/draft/2020-12/schema" }, "tests": [ { "description": "is invalid", "data": {"$id": "urn:example:foo-bar-baz-qux#somepart"}, "valid": false } ] }, { "description": "URN base URI with URN and JSON pointer ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed", "properties": { "foo": {"$ref": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed#/$defs/bar"} }, "$defs": { "bar": {"type": "string"} } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN base URI with URN and anchor ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed", "properties": { "foo": {"$ref": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed#something"} }, "$defs": { "bar": { "$anchor": "something", "type": "string" } } }, "tests": [ { "description": "a string is valid", "data": {"foo": "bar"}, "valid": true }, { "description": "a non-string is invalid", "data": {"foo": 12}, "valid": false } ] }, { "description": "URN ref with nested pointer ref", "schema": { "$ref": "urn:uuid:deadbeef-4321-ffff-ffff-1234feebdaed", "$defs": { "foo": { "$id": "urn:uuid:deadbeef-4321-ffff-ffff-1234feebdaed", "$defs": {"bar": {"type": "string"}}, "$ref": "#/$defs/bar" } } }, "tests": [ { "description": "a string is valid", "data": "bar", "valid": true }, { "description": "a non-string is invalid", "data": 12, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/refRemote.json0000644000175100001770000002122314653725311023507 0ustar00runnerdocker[ { "description": "remote ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "http://localhost:1234/draft2020-12/integer.json" }, "tests": [ { "description": "remote ref valid", "data": 1, "valid": true }, { "description": "remote ref invalid", "data": "a", "valid": false } ] }, { "description": "fragment within remote ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "http://localhost:1234/draft2020-12/subSchemas-defs.json#/$defs/integer" }, "tests": [ { "description": "remote fragment valid", "data": 1, "valid": true }, { "description": "remote fragment invalid", "data": "a", "valid": false } ] }, { "description": "ref within remote ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "http://localhost:1234/draft2020-12/subSchemas-defs.json#/$defs/refToInteger" }, "tests": [ { "description": "ref within ref valid", "data": 1, "valid": true }, { "description": "ref within ref invalid", "data": "a", "valid": false } ] }, { "description": "base URI change", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/", "items": { "$id": "baseUriChange/", "items": {"$ref": "folderInteger.json"} } }, "tests": [ { "description": "base URI change ref valid", "data": [[1]], "valid": true }, { "description": "base URI change ref invalid", "data": [["a"]], "valid": false } ] }, { "description": "base URI change - change folder", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/scope_change_defs1.json", "type" : "object", "properties": {"list": {"$ref": "baseUriChangeFolder/"}}, "$defs": { "baz": { "$id": "baseUriChangeFolder/", "type": "array", "items": {"$ref": "folderInteger.json"} } } }, "tests": [ { "description": "number is valid", "data": {"list": [1]}, "valid": true }, { "description": "string is invalid", "data": {"list": ["a"]}, "valid": false } ] }, { "description": "base URI change - change folder in subschema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/scope_change_defs2.json", "type" : "object", "properties": {"list": {"$ref": "baseUriChangeFolderInSubschema/#/$defs/bar"}}, "$defs": { "baz": { "$id": "baseUriChangeFolderInSubschema/", "$defs": { "bar": { "type": "array", "items": {"$ref": "folderInteger.json"} } } } } }, "tests": [ { "description": "number is valid", "data": {"list": [1]}, "valid": true }, { "description": "string is invalid", "data": {"list": ["a"]}, "valid": false } ] }, { "description": "root ref in remote ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/object", "type": "object", "properties": { "name": {"$ref": "name-defs.json#/$defs/orNull"} } }, "tests": [ { "description": "string is valid", "data": { "name": "foo" }, "valid": true }, { "description": "null is valid", "data": { "name": null }, "valid": true }, { "description": "object is invalid", "data": { "name": { "name": null } }, "valid": false } ] }, { "description": "remote ref with ref to defs", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/schema-remote-ref-ref-defs1.json", "$ref": "ref-and-defs.json" }, "tests": [ { "description": "invalid", "data": { "bar": 1 }, "valid": false }, { "description": "valid", "data": { "bar": "a" }, "valid": true } ] }, { "description": "Location-independent identifier in remote ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "http://localhost:1234/draft2020-12/locationIndependentIdentifier.json#/$defs/refToInteger" }, "tests": [ { "description": "integer is valid", "data": 1, "valid": true }, { "description": "string is invalid", "data": "foo", "valid": false } ] }, { "description": "retrieved nested refs resolve relative to their URI not $id", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "http://localhost:1234/draft2020-12/some-id", "properties": { "name": {"$ref": "nested/foo-ref-string.json"} } }, "tests": [ { "description": "number is invalid", "data": { "name": {"foo": 1} }, "valid": false }, { "description": "string is valid", "data": { "name": {"foo": "a"} }, "valid": true } ] }, { "description": "remote HTTP ref with different $id", "schema": {"$ref": "http://localhost:1234/different-id-ref-string.json"}, "tests": [ { "description": "number is invalid", "data": 1, "valid": false }, { "description": "string is valid", "data": "foo", "valid": true } ] }, { "description": "remote HTTP ref with different URN $id", "schema": {"$ref": "http://localhost:1234/urn-ref-string.json"}, "tests": [ { "description": "number is invalid", "data": 1, "valid": false }, { "description": "string is valid", "data": "foo", "valid": true } ] }, { "description": "remote HTTP ref with nested absolute ref", "schema": {"$ref": "http://localhost:1234/nested-absolute-ref-to-string.json"}, "tests": [ { "description": "number is invalid", "data": 1, "valid": false }, { "description": "string is valid", "data": "foo", "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/required.json0000644000175100001770000001102314653725311023374 0ustar00runnerdocker[ { "description": "required validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": {}, "bar": {} }, "required": ["foo"] }, "tests": [ { "description": "present required property is valid", "data": {"foo": 1}, "valid": true }, { "description": "non-present required property is invalid", "data": {"bar": 1}, "valid": false }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "", "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true } ] }, { "description": "required default validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": {} } }, "tests": [ { "description": "not required by default", "data": {}, "valid": true } ] }, { "description": "required with empty array", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": {} }, "required": [] }, "tests": [ { "description": "property not required", "data": {}, "valid": true } ] }, { "description": "required with escaped characters", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "required": [ "foo\nbar", "foo\"bar", "foo\\bar", "foo\rbar", "foo\tbar", "foo\fbar" ] }, "tests": [ { "description": "object with all properties present is valid", "data": { "foo\nbar": 1, "foo\"bar": 1, "foo\\bar": 1, "foo\rbar": 1, "foo\tbar": 1, "foo\fbar": 1 }, "valid": true }, { "description": "object with some properties missing is invalid", "data": { "foo\nbar": "1", "foo\"bar": "1" }, "valid": false } ] }, { "description": "required properties whose names are Javascript object property names", "comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "required": ["__proto__", "toString", "constructor"] }, "tests": [ { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores other non-objects", "data": 12, "valid": true }, { "description": "none of the properties mentioned", "data": {}, "valid": false }, { "description": "__proto__ present", "data": { "__proto__": "foo" }, "valid": false }, { "description": "toString present", "data": { "toString": { "length": 37 } }, "valid": false }, { "description": "constructor present", "data": { "constructor": { "length": 37 } }, "valid": false }, { "description": "all present", "data": { "__proto__": 12, "toString": { "length": "foo" }, "constructor": 37 }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/type.json0000644000175100001770000003403514653725311022545 0ustar00runnerdocker[ { "description": "integer type matches integers", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "integer" }, "tests": [ { "description": "an integer is an integer", "data": 1, "valid": true }, { "description": "a float with zero fractional part is an integer", "data": 1.0, "valid": true }, { "description": "a float is not an integer", "data": 1.1, "valid": false }, { "description": "a string is not an integer", "data": "foo", "valid": false }, { "description": "a string is still not an integer, even if it looks like one", "data": "1", "valid": false }, { "description": "an object is not an integer", "data": {}, "valid": false }, { "description": "an array is not an integer", "data": [], "valid": false }, { "description": "a boolean is not an integer", "data": true, "valid": false }, { "description": "null is not an integer", "data": null, "valid": false } ] }, { "description": "number type matches numbers", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "number" }, "tests": [ { "description": "an integer is a number", "data": 1, "valid": true }, { "description": "a float with zero fractional part is a number (and an integer)", "data": 1.0, "valid": true }, { "description": "a float is a number", "data": 1.1, "valid": true }, { "description": "a string is not a number", "data": "foo", "valid": false }, { "description": "a string is still not a number, even if it looks like one", "data": "1", "valid": false }, { "description": "an object is not a number", "data": {}, "valid": false }, { "description": "an array is not a number", "data": [], "valid": false }, { "description": "a boolean is not a number", "data": true, "valid": false }, { "description": "null is not a number", "data": null, "valid": false } ] }, { "description": "string type matches strings", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string" }, "tests": [ { "description": "1 is not a string", "data": 1, "valid": false }, { "description": "a float is not a string", "data": 1.1, "valid": false }, { "description": "a string is a string", "data": "foo", "valid": true }, { "description": "a string is still a string, even if it looks like a number", "data": "1", "valid": true }, { "description": "an empty string is still a string", "data": "", "valid": true }, { "description": "an object is not a string", "data": {}, "valid": false }, { "description": "an array is not a string", "data": [], "valid": false }, { "description": "a boolean is not a string", "data": true, "valid": false }, { "description": "null is not a string", "data": null, "valid": false } ] }, { "description": "object type matches objects", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object" }, "tests": [ { "description": "an integer is not an object", "data": 1, "valid": false }, { "description": "a float is not an object", "data": 1.1, "valid": false }, { "description": "a string is not an object", "data": "foo", "valid": false }, { "description": "an object is an object", "data": {}, "valid": true }, { "description": "an array is not an object", "data": [], "valid": false }, { "description": "a boolean is not an object", "data": true, "valid": false }, { "description": "null is not an object", "data": null, "valid": false } ] }, { "description": "array type matches arrays", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "array" }, "tests": [ { "description": "an integer is not an array", "data": 1, "valid": false }, { "description": "a float is not an array", "data": 1.1, "valid": false }, { "description": "a string is not an array", "data": "foo", "valid": false }, { "description": "an object is not an array", "data": {}, "valid": false }, { "description": "an array is an array", "data": [], "valid": true }, { "description": "a boolean is not an array", "data": true, "valid": false }, { "description": "null is not an array", "data": null, "valid": false } ] }, { "description": "boolean type matches booleans", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "boolean" }, "tests": [ { "description": "an integer is not a boolean", "data": 1, "valid": false }, { "description": "zero is not a boolean", "data": 0, "valid": false }, { "description": "a float is not a boolean", "data": 1.1, "valid": false }, { "description": "a string is not a boolean", "data": "foo", "valid": false }, { "description": "an empty string is not a boolean", "data": "", "valid": false }, { "description": "an object is not a boolean", "data": {}, "valid": false }, { "description": "an array is not a boolean", "data": [], "valid": false }, { "description": "true is a boolean", "data": true, "valid": true }, { "description": "false is a boolean", "data": false, "valid": true }, { "description": "null is not a boolean", "data": null, "valid": false } ] }, { "description": "null type matches only the null object", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "null" }, "tests": [ { "description": "an integer is not null", "data": 1, "valid": false }, { "description": "a float is not null", "data": 1.1, "valid": false }, { "description": "zero is not null", "data": 0, "valid": false }, { "description": "a string is not null", "data": "foo", "valid": false }, { "description": "an empty string is not null", "data": "", "valid": false }, { "description": "an object is not null", "data": {}, "valid": false }, { "description": "an array is not null", "data": [], "valid": false }, { "description": "true is not null", "data": true, "valid": false }, { "description": "false is not null", "data": false, "valid": false }, { "description": "null is null", "data": null, "valid": true } ] }, { "description": "multiple types can be specified in an array", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": ["integer", "string"] }, "tests": [ { "description": "an integer is valid", "data": 1, "valid": true }, { "description": "a string is valid", "data": "foo", "valid": true }, { "description": "a float is invalid", "data": 1.1, "valid": false }, { "description": "an object is invalid", "data": {}, "valid": false }, { "description": "an array is invalid", "data": [], "valid": false }, { "description": "a boolean is invalid", "data": true, "valid": false }, { "description": "null is invalid", "data": null, "valid": false } ] }, { "description": "type as array with one item", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": ["string"] }, "tests": [ { "description": "string is valid", "data": "foo", "valid": true }, { "description": "number is invalid", "data": 123, "valid": false } ] }, { "description": "type: array or object", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": ["array", "object"] }, "tests": [ { "description": "array is valid", "data": [1,2,3], "valid": true }, { "description": "object is valid", "data": {"foo": 123}, "valid": true }, { "description": "number is invalid", "data": 123, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false }, { "description": "null is invalid", "data": null, "valid": false } ] }, { "description": "type: array, object or null", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": ["array", "object", "null"] }, "tests": [ { "description": "array is valid", "data": [1,2,3], "valid": true }, { "description": "object is valid", "data": {"foo": 123}, "valid": true }, { "description": "null is valid", "data": null, "valid": true }, { "description": "number is invalid", "data": 123, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/unevaluatedItems.json0000644000175100001770000004651014653725311025104 0ustar00runnerdocker[ { "description": "unevaluatedItems true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "unevaluatedItems": true }, "tests": [ { "description": "with no unevaluated items", "data": [], "valid": true }, { "description": "with unevaluated items", "data": ["foo"], "valid": true } ] }, { "description": "unevaluatedItems false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "unevaluatedItems": false }, "tests": [ { "description": "with no unevaluated items", "data": [], "valid": true }, { "description": "with unevaluated items", "data": ["foo"], "valid": false } ] }, { "description": "unevaluatedItems as schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "unevaluatedItems": { "type": "string" } }, "tests": [ { "description": "with no unevaluated items", "data": [], "valid": true }, { "description": "with valid unevaluated items", "data": ["foo"], "valid": true }, { "description": "with invalid unevaluated items", "data": [42], "valid": false } ] }, { "description": "unevaluatedItems with uniform items", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "items": { "type": "string" }, "unevaluatedItems": false }, "tests": [ { "description": "unevaluatedItems doesn't apply", "data": ["foo", "bar"], "valid": true } ] }, { "description": "unevaluatedItems with tuple", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [ { "type": "string" } ], "unevaluatedItems": false }, "tests": [ { "description": "with no unevaluated items", "data": ["foo"], "valid": true }, { "description": "with unevaluated items", "data": ["foo", "bar"], "valid": false } ] }, { "description": "unevaluatedItems with items", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [ { "type": "string" } ], "items": true, "unevaluatedItems": false }, "tests": [ { "description": "unevaluatedItems doesn't apply", "data": ["foo", 42], "valid": true } ] }, { "description": "unevaluatedItems with nested tuple", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [ { "type": "string" } ], "allOf": [ { "prefixItems": [ true, { "type": "number" } ] } ], "unevaluatedItems": false }, "tests": [ { "description": "with no unevaluated items", "data": ["foo", 42], "valid": true }, { "description": "with unevaluated items", "data": ["foo", 42, true], "valid": false } ] }, { "description": "unevaluatedItems with nested items", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "unevaluatedItems": {"type": "boolean"}, "anyOf": [ { "items": {"type": "string"} }, true ] }, "tests": [ { "description": "with only (valid) additional items", "data": [true, false], "valid": true }, { "description": "with no additional items", "data": ["yes", "no"], "valid": true }, { "description": "with invalid additional item", "data": ["yes", false], "valid": false } ] }, { "description": "unevaluatedItems with nested prefixItems and items", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "prefixItems": [ { "type": "string" } ], "items": true } ], "unevaluatedItems": false }, "tests": [ { "description": "with no additional items", "data": ["foo"], "valid": true }, { "description": "with additional items", "data": ["foo", 42, true], "valid": true } ] }, { "description": "unevaluatedItems with nested unevaluatedItems", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "prefixItems": [ { "type": "string" } ] }, { "unevaluatedItems": true } ], "unevaluatedItems": false }, "tests": [ { "description": "with no additional items", "data": ["foo"], "valid": true }, { "description": "with additional items", "data": ["foo", 42, true], "valid": true } ] }, { "description": "unevaluatedItems with anyOf", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [ { "const": "foo" } ], "anyOf": [ { "prefixItems": [ true, { "const": "bar" } ] }, { "prefixItems": [ true, true, { "const": "baz" } ] } ], "unevaluatedItems": false }, "tests": [ { "description": "when one schema matches and has no unevaluated items", "data": ["foo", "bar"], "valid": true }, { "description": "when one schema matches and has unevaluated items", "data": ["foo", "bar", 42], "valid": false }, { "description": "when two schemas match and has no unevaluated items", "data": ["foo", "bar", "baz"], "valid": true }, { "description": "when two schemas match and has unevaluated items", "data": ["foo", "bar", "baz", 42], "valid": false } ] }, { "description": "unevaluatedItems with oneOf", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [ { "const": "foo" } ], "oneOf": [ { "prefixItems": [ true, { "const": "bar" } ] }, { "prefixItems": [ true, { "const": "baz" } ] } ], "unevaluatedItems": false }, "tests": [ { "description": "with no unevaluated items", "data": ["foo", "bar"], "valid": true }, { "description": "with unevaluated items", "data": ["foo", "bar", 42], "valid": false } ] }, { "description": "unevaluatedItems with not", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [ { "const": "foo" } ], "not": { "not": { "prefixItems": [ true, { "const": "bar" } ] } }, "unevaluatedItems": false }, "tests": [ { "description": "with unevaluated items", "data": ["foo", "bar"], "valid": false } ] }, { "description": "unevaluatedItems with if/then/else", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [ { "const": "foo" } ], "if": { "prefixItems": [ true, { "const": "bar" } ] }, "then": { "prefixItems": [ true, true, { "const": "then" } ] }, "else": { "prefixItems": [ true, true, true, { "const": "else" } ] }, "unevaluatedItems": false }, "tests": [ { "description": "when if matches and it has no unevaluated items", "data": ["foo", "bar", "then"], "valid": true }, { "description": "when if matches and it has unevaluated items", "data": ["foo", "bar", "then", "else"], "valid": false }, { "description": "when if doesn't match and it has no unevaluated items", "data": ["foo", 42, 42, "else"], "valid": true }, { "description": "when if doesn't match and it has unevaluated items", "data": ["foo", 42, 42, "else", 42], "valid": false } ] }, { "description": "unevaluatedItems with boolean schemas", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [true], "unevaluatedItems": false }, "tests": [ { "description": "with no unevaluated items", "data": [], "valid": true }, { "description": "with unevaluated items", "data": ["foo"], "valid": false } ] }, { "description": "unevaluatedItems with $ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$ref": "#/$defs/bar", "prefixItems": [ { "type": "string" } ], "unevaluatedItems": false, "$defs": { "bar": { "prefixItems": [ true, { "type": "string" } ] } } }, "tests": [ { "description": "with no unevaluated items", "data": ["foo", "bar"], "valid": true }, { "description": "with unevaluated items", "data": ["foo", "bar", "baz"], "valid": false } ] }, { "description": "unevaluatedItems can't see inside cousins", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "prefixItems": [ true ] }, { "unevaluatedItems": false } ] }, "tests": [ { "description": "always fails", "data": [ 1 ], "valid": false } ] }, { "description": "item is evaluated in an uncle schema to unevaluatedItems", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "foo": { "prefixItems": [ { "type": "string" } ], "unevaluatedItems": false } }, "anyOf": [ { "properties": { "foo": { "prefixItems": [ true, { "type": "string" } ] } } } ] }, "tests": [ { "description": "no extra items", "data": { "foo": [ "test" ] }, "valid": true }, { "description": "uncle keyword evaluation is not significant", "data": { "foo": [ "test", "test" ] }, "valid": false } ] }, { "description": "unevaluatedItems depends on adjacent contains", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [true], "contains": {"type": "string"}, "unevaluatedItems": false }, "tests": [ { "description": "second item is evaluated by contains", "data": [ 1, "foo" ], "valid": true }, { "description": "contains fails, second item is not evaluated", "data": [ 1, 2 ], "valid": false }, { "description": "contains passes, second item is not evaluated", "data": [ 1, 2, "foo" ], "valid": false } ] }, { "description": "unevaluatedItems depends on multiple nested contains", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "contains": { "multipleOf": 2 } }, { "contains": { "multipleOf": 3 } } ], "unevaluatedItems": { "multipleOf": 5 } }, "tests": [ { "description": "5 not evaluated, passes unevaluatedItems", "data": [ 2, 3, 4, 5, 6 ], "valid": true }, { "description": "7 not evaluated, fails unevaluatedItems", "data": [ 2, 3, 4, 7, 8 ], "valid": false } ] }, { "description": "unevaluatedItems and contains interact to control item dependency relationship", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "if": { "contains": {"const": "a"} }, "then": { "if": { "contains": {"const": "b"} }, "then": { "if": { "contains": {"const": "c"} } } }, "unevaluatedItems": false }, "tests": [ { "description": "empty array is valid", "data": [], "valid": true }, { "description": "only a's are valid", "data": [ "a", "a" ], "valid": true }, { "description": "a's and b's are valid", "data": [ "a", "b", "a", "b", "a" ], "valid": true }, { "description": "a's, b's and c's are valid", "data": [ "c", "a", "c", "c", "b", "a" ], "valid": true }, { "description": "only b's are invalid", "data": [ "b", "b" ], "valid": false }, { "description": "only c's are invalid", "data": [ "c", "c" ], "valid": false }, { "description": "only b's and c's are invalid", "data": [ "c", "b", "c", "b", "c" ], "valid": false }, { "description": "only a's and c's are invalid", "data": [ "c", "a", "c", "a", "c" ], "valid": false } ] }, { "description": "non-array instances are valid", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "unevaluatedItems": false }, "tests": [ { "description": "ignores booleans", "data": true, "valid": true }, { "description": "ignores integers", "data": 123, "valid": true }, { "description": "ignores floats", "data": 1.0, "valid": true }, { "description": "ignores objects", "data": {}, "valid": true }, { "description": "ignores strings", "data": "foo", "valid": true }, { "description": "ignores null", "data": null, "valid": true } ] }, { "description": "unevaluatedItems with null instance elements", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "unevaluatedItems": { "type": "null" } }, "tests": [ { "description": "allows null elements", "data": [ null ], "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/unevaluatedProperties.json0000644000175100001770000012243414653725311026157 0ustar00runnerdocker[ { "description": "unevaluatedProperties true", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "unevaluatedProperties": true }, "tests": [ { "description": "with no unevaluated properties", "data": {}, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo" }, "valid": true } ] }, { "description": "unevaluatedProperties schema", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "unevaluatedProperties": { "type": "string", "minLength": 3 } }, "tests": [ { "description": "with no unevaluated properties", "data": {}, "valid": true }, { "description": "with valid unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with invalid unevaluated properties", "data": { "foo": "fo" }, "valid": false } ] }, { "description": "unevaluatedProperties false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": {}, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo" }, "valid": false } ] }, { "description": "unevaluatedProperties with adjacent properties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "unevaluatedProperties with adjacent patternProperties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "patternProperties": { "^foo": { "type": "string" } }, "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "unevaluatedProperties with adjacent additionalProperties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "additionalProperties": true, "unevaluatedProperties": false }, "tests": [ { "description": "with no additional properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with additional properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true } ] }, { "description": "unevaluatedProperties with nested properties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "properties": { "bar": { "type": "string" } } } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no additional properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "with additional properties", "data": { "foo": "foo", "bar": "bar", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties with nested patternProperties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "patternProperties": { "^bar": { "type": "string" } } } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no additional properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "with additional properties", "data": { "foo": "foo", "bar": "bar", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties with nested additionalProperties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "additionalProperties": true } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no additional properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with additional properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true } ] }, { "description": "unevaluatedProperties with nested unevaluatedProperties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "unevaluatedProperties": true } ], "unevaluatedProperties": { "type": "string", "maxLength": 2 } }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true } ] }, { "description": "unevaluatedProperties with anyOf", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "anyOf": [ { "properties": { "bar": { "const": "bar" } }, "required": ["bar"] }, { "properties": { "baz": { "const": "baz" } }, "required": ["baz"] }, { "properties": { "quux": { "const": "quux" } }, "required": ["quux"] } ], "unevaluatedProperties": false }, "tests": [ { "description": "when one matches and has no unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "when one matches and has unevaluated properties", "data": { "foo": "foo", "bar": "bar", "baz": "not-baz" }, "valid": false }, { "description": "when two match and has no unevaluated properties", "data": { "foo": "foo", "bar": "bar", "baz": "baz" }, "valid": true }, { "description": "when two match and has unevaluated properties", "data": { "foo": "foo", "bar": "bar", "baz": "baz", "quux": "not-quux" }, "valid": false } ] }, { "description": "unevaluatedProperties with oneOf", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "oneOf": [ { "properties": { "bar": { "const": "bar" } }, "required": ["bar"] }, { "properties": { "baz": { "const": "baz" } }, "required": ["baz"] } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo", "bar": "bar", "quux": "quux" }, "valid": false } ] }, { "description": "unevaluatedProperties with not", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "not": { "not": { "properties": { "bar": { "const": "bar" } }, "required": ["bar"] } }, "unevaluatedProperties": false }, "tests": [ { "description": "with unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "unevaluatedProperties with if/then/else", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "if": { "properties": { "foo": { "const": "then" } }, "required": ["foo"] }, "then": { "properties": { "bar": { "type": "string" } }, "required": ["bar"] }, "else": { "properties": { "baz": { "type": "string" } }, "required": ["baz"] }, "unevaluatedProperties": false }, "tests": [ { "description": "when if is true and has no unevaluated properties", "data": { "foo": "then", "bar": "bar" }, "valid": true }, { "description": "when if is true and has unevaluated properties", "data": { "foo": "then", "bar": "bar", "baz": "baz" }, "valid": false }, { "description": "when if is false and has no unevaluated properties", "data": { "baz": "baz" }, "valid": true }, { "description": "when if is false and has unevaluated properties", "data": { "foo": "else", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties with if/then/else, then not defined", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "if": { "properties": { "foo": { "const": "then" } }, "required": ["foo"] }, "else": { "properties": { "baz": { "type": "string" } }, "required": ["baz"] }, "unevaluatedProperties": false }, "tests": [ { "description": "when if is true and has no unevaluated properties", "data": { "foo": "then", "bar": "bar" }, "valid": false }, { "description": "when if is true and has unevaluated properties", "data": { "foo": "then", "bar": "bar", "baz": "baz" }, "valid": false }, { "description": "when if is false and has no unevaluated properties", "data": { "baz": "baz" }, "valid": true }, { "description": "when if is false and has unevaluated properties", "data": { "foo": "else", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties with if/then/else, else not defined", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "if": { "properties": { "foo": { "const": "then" } }, "required": ["foo"] }, "then": { "properties": { "bar": { "type": "string" } }, "required": ["bar"] }, "unevaluatedProperties": false }, "tests": [ { "description": "when if is true and has no unevaluated properties", "data": { "foo": "then", "bar": "bar" }, "valid": true }, { "description": "when if is true and has unevaluated properties", "data": { "foo": "then", "bar": "bar", "baz": "baz" }, "valid": false }, { "description": "when if is false and has no unevaluated properties", "data": { "baz": "baz" }, "valid": false }, { "description": "when if is false and has unevaluated properties", "data": { "foo": "else", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties with dependentSchemas", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "dependentSchemas": { "foo": { "properties": { "bar": { "const": "bar" } }, "required": ["bar"] } }, "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "with unevaluated properties", "data": { "bar": "bar" }, "valid": false } ] }, { "description": "unevaluatedProperties with boolean schemas", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [true], "unevaluatedProperties": false }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with unevaluated properties", "data": { "bar": "bar" }, "valid": false } ] }, { "description": "unevaluatedProperties with $ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "$ref": "#/$defs/bar", "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": false, "$defs": { "bar": { "properties": { "bar": { "type": "string" } } } } }, "tests": [ { "description": "with no unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true }, { "description": "with unevaluated properties", "data": { "foo": "foo", "bar": "bar", "baz": "baz" }, "valid": false } ] }, { "description": "unevaluatedProperties can't see inside cousins", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "properties": { "foo": true } }, { "unevaluatedProperties": false } ] }, "tests": [ { "description": "always fails", "data": { "foo": 1 }, "valid": false } ] }, { "description": "unevaluatedProperties can't see inside cousins (reverse order)", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "unevaluatedProperties": false }, { "properties": { "foo": true } } ] }, "tests": [ { "description": "always fails", "data": { "foo": 1 }, "valid": false } ] }, { "description": "nested unevaluatedProperties, outer false, inner true, properties outside", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "unevaluatedProperties": true } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true } ] }, { "description": "nested unevaluatedProperties, outer false, inner true, properties inside", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "allOf": [ { "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": true } ], "unevaluatedProperties": false }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": true } ] }, { "description": "nested unevaluatedProperties, outer true, inner false, properties outside", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "string" } }, "allOf": [ { "unevaluatedProperties": false } ], "unevaluatedProperties": true }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": false }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "nested unevaluatedProperties, outer true, inner false, properties inside", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "allOf": [ { "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": false } ], "unevaluatedProperties": true }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "cousin unevaluatedProperties, true and false, true with properties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "allOf": [ { "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": true }, { "unevaluatedProperties": false } ] }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": false }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "cousin unevaluatedProperties, true and false, false with properties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "allOf": [ { "unevaluatedProperties": true }, { "properties": { "foo": { "type": "string" } }, "unevaluatedProperties": false } ] }, "tests": [ { "description": "with no nested unevaluated properties", "data": { "foo": "foo" }, "valid": true }, { "description": "with nested unevaluated properties", "data": { "foo": "foo", "bar": "bar" }, "valid": false } ] }, { "description": "property is evaluated in an uncle schema to unevaluatedProperties", "comment": "see https://stackoverflow.com/questions/66936884/deeply-nested-unevaluatedproperties-and-their-expectations", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "foo": { "type": "object", "properties": { "bar": { "type": "string" } }, "unevaluatedProperties": false } }, "anyOf": [ { "properties": { "foo": { "properties": { "faz": { "type": "string" } } } } } ] }, "tests": [ { "description": "no extra properties", "data": { "foo": { "bar": "test" } }, "valid": true }, { "description": "uncle keyword evaluation is not significant", "data": { "foo": { "bar": "test", "faz": "test" } }, "valid": false } ] }, { "description": "in-place applicator siblings, allOf has unevaluated", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "allOf": [ { "properties": { "foo": true }, "unevaluatedProperties": false } ], "anyOf": [ { "properties": { "bar": true } } ] }, "tests": [ { "description": "base case: both properties present", "data": { "foo": 1, "bar": 1 }, "valid": false }, { "description": "in place applicator siblings, bar is missing", "data": { "foo": 1 }, "valid": true }, { "description": "in place applicator siblings, foo is missing", "data": { "bar": 1 }, "valid": false } ] }, { "description": "in-place applicator siblings, anyOf has unevaluated", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "allOf": [ { "properties": { "foo": true } } ], "anyOf": [ { "properties": { "bar": true }, "unevaluatedProperties": false } ] }, "tests": [ { "description": "base case: both properties present", "data": { "foo": 1, "bar": 1 }, "valid": false }, { "description": "in place applicator siblings, bar is missing", "data": { "foo": 1 }, "valid": false }, { "description": "in place applicator siblings, foo is missing", "data": { "bar": 1 }, "valid": true } ] }, { "description": "unevaluatedProperties + single cyclic ref", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "x": { "$ref": "#" } }, "unevaluatedProperties": false }, "tests": [ { "description": "Empty is valid", "data": {}, "valid": true }, { "description": "Single is valid", "data": { "x": {} }, "valid": true }, { "description": "Unevaluated on 1st level is invalid", "data": { "x": {}, "y": {} }, "valid": false }, { "description": "Nested is valid", "data": { "x": { "x": {} } }, "valid": true }, { "description": "Unevaluated on 2nd level is invalid", "data": { "x": { "x": {}, "y": {} } }, "valid": false }, { "description": "Deep nested is valid", "data": { "x": { "x": { "x": {} } } }, "valid": true }, { "description": "Unevaluated on 3rd level is invalid", "data": { "x": { "x": { "x": {}, "y": {} } } }, "valid": false } ] }, { "description": "unevaluatedProperties + ref inside allOf / oneOf", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "one": { "properties": { "a": true } }, "two": { "required": ["x"], "properties": { "x": true } } }, "allOf": [ { "$ref": "#/$defs/one" }, { "properties": { "b": true } }, { "oneOf": [ { "$ref": "#/$defs/two" }, { "required": ["y"], "properties": { "y": true } } ] } ], "unevaluatedProperties": false }, "tests": [ { "description": "Empty is invalid (no x or y)", "data": {}, "valid": false }, { "description": "a and b are invalid (no x or y)", "data": { "a": 1, "b": 1 }, "valid": false }, { "description": "x and y are invalid", "data": { "x": 1, "y": 1 }, "valid": false }, { "description": "a and x are valid", "data": { "a": 1, "x": 1 }, "valid": true }, { "description": "a and y are valid", "data": { "a": 1, "y": 1 }, "valid": true }, { "description": "a and b and x are valid", "data": { "a": 1, "b": 1, "x": 1 }, "valid": true }, { "description": "a and b and y are valid", "data": { "a": 1, "b": 1, "y": 1 }, "valid": true }, { "description": "a and b and x and y are invalid", "data": { "a": 1, "b": 1, "x": 1, "y": 1 }, "valid": false } ] }, { "description": "dynamic evalation inside nested refs", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "one": { "oneOf": [ { "$ref": "#/$defs/two" }, { "required": ["b"], "properties": { "b": true } }, { "required": ["xx"], "patternProperties": { "x": true } }, { "required": ["all"], "unevaluatedProperties": true } ] }, "two": { "oneOf": [ { "required": ["c"], "properties": { "c": true } }, { "required": ["d"], "properties": { "d": true } } ] } }, "oneOf": [ { "$ref": "#/$defs/one" }, { "required": ["a"], "properties": { "a": true } } ], "unevaluatedProperties": false }, "tests": [ { "description": "Empty is invalid", "data": {}, "valid": false }, { "description": "a is valid", "data": { "a": 1 }, "valid": true }, { "description": "b is valid", "data": { "b": 1 }, "valid": true }, { "description": "c is valid", "data": { "c": 1 }, "valid": true }, { "description": "d is valid", "data": { "d": 1 }, "valid": true }, { "description": "a + b is invalid", "data": { "a": 1, "b": 1 }, "valid": false }, { "description": "a + c is invalid", "data": { "a": 1, "c": 1 }, "valid": false }, { "description": "a + d is invalid", "data": { "a": 1, "d": 1 }, "valid": false }, { "description": "b + c is invalid", "data": { "b": 1, "c": 1 }, "valid": false }, { "description": "b + d is invalid", "data": { "b": 1, "d": 1 }, "valid": false }, { "description": "c + d is invalid", "data": { "c": 1, "d": 1 }, "valid": false }, { "description": "xx is valid", "data": { "xx": 1 }, "valid": true }, { "description": "xx + foox is valid", "data": { "xx": 1, "foox": 1 }, "valid": true }, { "description": "xx + foo is invalid", "data": { "xx": 1, "foo": 1 }, "valid": false }, { "description": "xx + a is invalid", "data": { "xx": 1, "a": 1 }, "valid": false }, { "description": "xx + b is invalid", "data": { "xx": 1, "b": 1 }, "valid": false }, { "description": "xx + c is invalid", "data": { "xx": 1, "c": 1 }, "valid": false }, { "description": "xx + d is invalid", "data": { "xx": 1, "d": 1 }, "valid": false }, { "description": "all is valid", "data": { "all": 1 }, "valid": true }, { "description": "all + foo is valid", "data": { "all": 1, "foo": 1 }, "valid": true }, { "description": "all + a is invalid", "data": { "all": 1, "a": 1 }, "valid": false } ] }, { "description": "non-object instances are valid", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "unevaluatedProperties": false }, "tests": [ { "description": "ignores booleans", "data": true, "valid": true }, { "description": "ignores integers", "data": 123, "valid": true }, { "description": "ignores floats", "data": 1.0, "valid": true }, { "description": "ignores arrays", "data": [], "valid": true }, { "description": "ignores strings", "data": "foo", "valid": true }, { "description": "ignores null", "data": null, "valid": true } ] }, { "description": "unevaluatedProperties with null valued instance properties", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "unevaluatedProperties": { "type": "null" } }, "tests": [ { "description": "allows null valued properties", "data": {"foo": null}, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/uniqueItems.json0000644000175100001770000003367014653725311024100 0ustar00runnerdocker[ { "description": "uniqueItems validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "uniqueItems": true }, "tests": [ { "description": "unique array of integers is valid", "data": [1, 2], "valid": true }, { "description": "non-unique array of integers is invalid", "data": [1, 1], "valid": false }, { "description": "non-unique array of more than two integers is invalid", "data": [1, 2, 1], "valid": false }, { "description": "numbers are unique if mathematically unequal", "data": [1.0, 1.00, 1], "valid": false }, { "description": "false is not equal to zero", "data": [0, false], "valid": true }, { "description": "true is not equal to one", "data": [1, true], "valid": true }, { "description": "unique array of strings is valid", "data": ["foo", "bar", "baz"], "valid": true }, { "description": "non-unique array of strings is invalid", "data": ["foo", "bar", "foo"], "valid": false }, { "description": "unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "baz"}], "valid": true }, { "description": "non-unique array of objects is invalid", "data": [{"foo": "bar"}, {"foo": "bar"}], "valid": false }, { "description": "unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : false}}} ], "valid": true }, { "description": "non-unique array of nested objects is invalid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : true}}} ], "valid": false }, { "description": "unique array of arrays is valid", "data": [["foo"], ["bar"]], "valid": true }, { "description": "non-unique array of arrays is invalid", "data": [["foo"], ["foo"]], "valid": false }, { "description": "non-unique array of more than two arrays is invalid", "data": [["foo"], ["bar"], ["foo"]], "valid": false }, { "description": "1 and true are unique", "data": [1, true], "valid": true }, { "description": "0 and false are unique", "data": [0, false], "valid": true }, { "description": "[1] and [true] are unique", "data": [[1], [true]], "valid": true }, { "description": "[0] and [false] are unique", "data": [[0], [false]], "valid": true }, { "description": "nested [1] and [true] are unique", "data": [[[1], "foo"], [[true], "foo"]], "valid": true }, { "description": "nested [0] and [false] are unique", "data": [[[0], "foo"], [[false], "foo"]], "valid": true }, { "description": "unique heterogeneous types are valid", "data": [{}, [1], true, null, 1, "{}"], "valid": true }, { "description": "non-unique heterogeneous types are invalid", "data": [{}, [1], true, null, {}, 1], "valid": false }, { "description": "different objects are unique", "data": [{"a": 1, "b": 2}, {"a": 2, "b": 1}], "valid": true }, { "description": "objects are non-unique despite key order", "data": [{"a": 1, "b": 2}, {"b": 2, "a": 1}], "valid": false }, { "description": "{\"a\": false} and {\"a\": 0} are unique", "data": [{"a": false}, {"a": 0}], "valid": true }, { "description": "{\"a\": true} and {\"a\": 1} are unique", "data": [{"a": true}, {"a": 1}], "valid": true } ] }, { "description": "uniqueItems with an array of items", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": true }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is not valid", "data": [false, false], "valid": false }, { "description": "[true, true] from items array is not valid", "data": [true, true], "valid": false }, { "description": "unique array extended from [false, true] is valid", "data": [false, true, "foo", "bar"], "valid": true }, { "description": "unique array extended from [true, false] is valid", "data": [true, false, "foo", "bar"], "valid": true }, { "description": "non-unique array extended from [false, true] is not valid", "data": [false, true, "foo", "foo"], "valid": false }, { "description": "non-unique array extended from [true, false] is not valid", "data": [true, false, "foo", "foo"], "valid": false } ] }, { "description": "uniqueItems with an array of items and additionalItems=false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": true, "items": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is not valid", "data": [false, false], "valid": false }, { "description": "[true, true] from items array is not valid", "data": [true, true], "valid": false }, { "description": "extra items are invalid even if unique", "data": [false, true, null], "valid": false } ] }, { "description": "uniqueItems=false validation", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "uniqueItems": false }, "tests": [ { "description": "unique array of integers is valid", "data": [1, 2], "valid": true }, { "description": "non-unique array of integers is valid", "data": [1, 1], "valid": true }, { "description": "numbers are unique if mathematically unequal", "data": [1.0, 1.00, 1], "valid": true }, { "description": "false is not equal to zero", "data": [0, false], "valid": true }, { "description": "true is not equal to one", "data": [1, true], "valid": true }, { "description": "unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "baz"}], "valid": true }, { "description": "non-unique array of objects is valid", "data": [{"foo": "bar"}, {"foo": "bar"}], "valid": true }, { "description": "unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : false}}} ], "valid": true }, { "description": "non-unique array of nested objects is valid", "data": [ {"foo": {"bar" : {"baz" : true}}}, {"foo": {"bar" : {"baz" : true}}} ], "valid": true }, { "description": "unique array of arrays is valid", "data": [["foo"], ["bar"]], "valid": true }, { "description": "non-unique array of arrays is valid", "data": [["foo"], ["foo"]], "valid": true }, { "description": "1 and true are unique", "data": [1, true], "valid": true }, { "description": "0 and false are unique", "data": [0, false], "valid": true }, { "description": "unique heterogeneous types are valid", "data": [{}, [1], true, null, 1], "valid": true }, { "description": "non-unique heterogeneous types are valid", "data": [{}, [1], true, null, {}, 1], "valid": true } ] }, { "description": "uniqueItems=false with an array of items", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is valid", "data": [false, false], "valid": true }, { "description": "[true, true] from items array is valid", "data": [true, true], "valid": true }, { "description": "unique array extended from [false, true] is valid", "data": [false, true, "foo", "bar"], "valid": true }, { "description": "unique array extended from [true, false] is valid", "data": [true, false, "foo", "bar"], "valid": true }, { "description": "non-unique array extended from [false, true] is valid", "data": [false, true, "foo", "foo"], "valid": true }, { "description": "non-unique array extended from [true, false] is valid", "data": [true, false, "foo", "foo"], "valid": true } ] }, { "description": "uniqueItems=false with an array of items and additionalItems=false", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "prefixItems": [{"type": "boolean"}, {"type": "boolean"}], "uniqueItems": false, "items": false }, "tests": [ { "description": "[false, true] from items array is valid", "data": [false, true], "valid": true }, { "description": "[true, false] from items array is valid", "data": [true, false], "valid": true }, { "description": "[false, false] from items array is valid", "data": [false, false], "valid": true }, { "description": "[true, true] from items array is valid", "data": [true, true], "valid": true }, { "description": "extra items are invalid even if unique", "data": [false, true, null], "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/unknownKeyword.json0000644000175100001770000000411314653725311024622 0ustar00runnerdocker[ { "description": "$id inside an unknown keyword is not a real identifier", "comment": "the implementation must not be confused by an $id in locations we do not know how to parse", "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "id_in_unknown0": { "not": { "array_of_schemas": [ { "$id": "https://localhost:1234/draft2020-12/unknownKeyword/my_identifier.json", "type": "null" } ] } }, "real_id_in_schema": { "$id": "https://localhost:1234/draft2020-12/unknownKeyword/my_identifier.json", "type": "string" }, "id_in_unknown1": { "not": { "object_of_schemas": { "foo": { "$id": "https://localhost:1234/draft2020-12/unknownKeyword/my_identifier.json", "type": "integer" } } } } }, "anyOf": [ { "$ref": "#/$defs/id_in_unknown0" }, { "$ref": "#/$defs/id_in_unknown1" }, { "$ref": "https://localhost:1234/draft2020-12/unknownKeyword/my_identifier.json" } ] }, "tests": [ { "description": "type matches second anyOf, which has a real schema in it", "data": "a string", "valid": true }, { "description": "type matches non-schema in first anyOf", "data": null, "valid": false }, { "description": "type matches non-schema in third anyOf", "data": 1, "valid": false } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tests/latest/vocabulary.json0000644000175100001770000000221714653725311023730 0ustar00runnerdocker[ { "description": "schema that uses custom metaschema with with no validation vocabulary", "schema": { "$id": "https://schema/using/no/validation", "$schema": "http://localhost:1234/draft2020-12/metaschema-no-validation.json", "properties": { "badProperty": false, "numberProperty": { "minimum": 10 } } }, "tests": [ { "description": "applicator vocabulary still works", "data": { "badProperty": "this property should not exist" }, "valid": false }, { "description": "no validation: valid number", "data": { "numberProperty": 20 }, "valid": true }, { "description": "no validation: invalid number, but it still validates", "data": { "numberProperty": 1 }, "valid": true } ] } ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/json/tox.ini0000644000175100001770000000034114653725311017537 0ustar00runnerdocker[tox] minversion = 1.6 envlist = sanity skipsdist = True [testenv:sanity] # used just for validating the structure of the test case files themselves deps = jsonschema==4.6.1 commands = {envpython} bin/jsonschema_suite check ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/protocols.py0000644000175100001770000001706514653725311017664 0ustar00runnerdocker""" typing.Protocol classes for asdf._jsonschema interfaces. """ # for reference material on Protocols, see # https://www.python.org/dev/peps/pep-0544/ from __future__ import annotations from collections.abc import Callable, Mapping from typing import TYPE_CHECKING, Any, ClassVar, Iterable import sys # doing these imports with `try ... except ImportError` doesn't pass mypy # checking because mypy sees `typing._SpecialForm` and # `typing_extensions._SpecialForm` as incompatible # # see: # https://mypy.readthedocs.io/en/stable/runtime_troubles.html#using-new-additions-to-the-typing-module # https://github.com/python/mypy/issues/4427 if sys.version_info >= (3, 8): from typing import Protocol, runtime_checkable else: from typing_extensions import Protocol, runtime_checkable # in order for Sphinx to resolve references accurately from type annotations, # it needs to see names like `asdf._jsonschema.TypeChecker` # therefore, only import at type-checking time (to avoid circular references), # but use `asdf._jsonschema` for any types which will otherwise not be resolvable if TYPE_CHECKING: import asdf._jsonschema import asdf._jsonschema.validators from asdf._jsonschema.exceptions import ValidationError # For code authors working on the validator protocol, these are the three # use-cases which should be kept in mind: # # 1. As a protocol class, it can be used in type annotations to describe the # available methods and attributes of a validator # 2. It is the source of autodoc for the validator documentation # 3. It is runtime_checkable, meaning that it can be used in isinstance() # checks. # # Since protocols are not base classes, isinstance() checking is limited in # its capabilities. See docs on runtime_checkable for detail @runtime_checkable class Validator(Protocol): """ The protocol to which all validator classes adhere. Arguments: schema: The schema that the validator object will validate with. It is assumed to be valid, and providing an invalid schema can lead to undefined behavior. See `Validator.check_schema` to validate a schema first. resolver: a resolver that will be used to resolve :kw:`$ref` properties (JSON references). If unprovided, one will be created. format_checker: if provided, a checker which will be used to assert about :kw:`format` properties present in the schema. If unprovided, *no* format validation is done, and the presence of format within schemas is strictly informational. Certain formats require additional packages to be installed in order to assert against instances. Ensure you've installed `asdf._jsonschema` with its `extra (optional) dependencies ` when invoking ``pip``. .. deprecated:: v4.12.0 Subclassing validator classes now explicitly warns this is not part of their public API. """ #: An object representing the validator's meta schema (the schema that #: describes valid schemas in the given version). META_SCHEMA: ClassVar[Mapping] #: A mapping of validation keywords (`str`\s) to functions that #: validate the keyword with that name. For more information see #: `creating-validators`. VALIDATORS: ClassVar[Mapping] #: A `asdf._jsonschema.TypeChecker` that will be used when validating #: :kw:`type` keywords in JSON schemas. TYPE_CHECKER: ClassVar[asdf._jsonschema.TypeChecker] #: A `asdf._jsonschema.FormatChecker` that will be used when validating #: :kw:`format` keywords in JSON schemas. FORMAT_CHECKER: ClassVar[asdf._jsonschema.FormatChecker] #: A function which given a schema returns its ID. ID_OF: Callable[[Any], str | None] #: The schema that will be used to validate instances schema: Mapping | bool def __init__( self, schema: Mapping | bool, resolver: asdf._jsonschema.validators.RefResolver | None = None, format_checker: asdf._jsonschema.FormatChecker | None = None, ) -> None: ... @classmethod def check_schema(cls, schema: Mapping | bool) -> None: """ Validate the given schema against the validator's `META_SCHEMA`. Raises: `asdf._jsonschema.exceptions.SchemaError`: if the schema is invalid """ def is_type(self, instance: Any, type: str) -> bool: """ Check if the instance is of the given (JSON Schema) type. Arguments: instance: the value to check type: the name of a known (JSON Schema) type Returns: whether the instance is of the given type Raises: `asdf._jsonschema.exceptions.UnknownType`: if ``type`` is not a known type """ def is_valid(self, instance: Any) -> bool: """ Check if the instance is valid under the current `schema`. Returns: whether the instance is valid or not >>> from asdf._jsonschema import Draft202012Validator >>> schema = {"maxItems" : 2} >>> Draft202012Validator(schema).is_valid([2, 3, 4]) False """ def iter_errors(self, instance: Any) -> Iterable[ValidationError]: r""" Lazily yield each of the validation errors in the given instance. >>> from asdf._jsonschema import Draft202012Validator >>> schema = { ... "type" : "array", ... "items" : {"enum" : [1, 2, 3]}, ... "maxItems" : 2, ... } >>> v = Draft202012Validator(schema) >>> for error in sorted(v.iter_errors([2, 3, 4]), key=str): ... print(error.message) 4 is not one of [1, 2, 3] [2, 3, 4] is too long .. deprecated:: v4.0.0 Calling this function with a second schema argument is deprecated. Use `Validator.evolve` instead. """ def validate(self, instance: Any) -> None: """ Check if the instance is valid under the current `schema`. Raises: `asdf._jsonschema.exceptions.ValidationError`: if the instance is invalid >>> from asdf._jsonschema import Draft202012Validator >>> schema = {"maxItems" : 2} >>> Draft202012Validator(schema).validate([2, 3, 4]) # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... ValidationError: [2, 3, 4] is too long """ def evolve(self, **kwargs) -> "Validator": """ Create a new validator like this one, but with given changes. Preserves all other attributes, so can be used to e.g. create a validator with a different schema but with the same :kw:`$ref` resolution behavior. >>> from asdf._jsonschema import Draft202012Validator >>> validator = Draft202012Validator({}) >>> validator.evolve(schema={"type": "number"}) Draft202012Validator(schema={'type': 'number'}, format_checker=None) The returned object satisfies the validator protocol, but may not be of the same concrete class! In particular this occurs when a :kw:`$ref` occurs to a schema with a different :kw:`$schema` than this one (i.e. for a different draft). >>> from asdf._jsonschema import Draft7Validator >>> validator.evolve( ... schema={"$schema": Draft7Validator.META_SCHEMA["$id"]} ... ) Draft7Validator(schema=..., format_checker=None) """ ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1250978 asdf-3.4.0/asdf/_jsonschema/schemas/0000755000175100001770000000000014653725331016702 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/schemas/draft2019-09.json0000644000175100001770000000337114653725311021441 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "https://json-schema.org/draft/2019-09/schema", "$vocabulary": { "https://json-schema.org/draft/2019-09/vocab/core": true, "https://json-schema.org/draft/2019-09/vocab/applicator": true, "https://json-schema.org/draft/2019-09/vocab/validation": true, "https://json-schema.org/draft/2019-09/vocab/meta-data": true, "https://json-schema.org/draft/2019-09/vocab/format": false, "https://json-schema.org/draft/2019-09/vocab/content": true }, "$recursiveAnchor": true, "title": "Core and Validation specifications meta-schema", "allOf": [ {"$ref": "meta/core"}, {"$ref": "meta/applicator"}, {"$ref": "meta/validation"}, {"$ref": "meta/meta-data"}, {"$ref": "meta/format"}, {"$ref": "meta/content"} ], "type": ["object", "boolean"], "properties": { "definitions": { "$comment": "While no longer an official keyword as it is replaced by $defs, this keyword is retained in the meta-schema to prevent incompatible extensions as it remains in common use.", "type": "object", "additionalProperties": { "$recursiveRef": "#" }, "default": {} }, "dependencies": { "$comment": "\"dependencies\" is no longer a keyword, but schema authors should avoid redefining it to facilitate a smooth transition to \"dependentSchemas\" and \"dependentRequired\"", "type": "object", "additionalProperties": { "anyOf": [ { "$recursiveRef": "#" }, { "$ref": "meta/validation#/$defs/stringArray" } ] } } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/schemas/draft2020-12.json0000644000175100001770000000462414653725311021425 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://json-schema.org/draft/2020-12/schema", "$vocabulary": { "https://json-schema.org/draft/2020-12/vocab/core": true, "https://json-schema.org/draft/2020-12/vocab/applicator": true, "https://json-schema.org/draft/2020-12/vocab/unevaluated": true, "https://json-schema.org/draft/2020-12/vocab/validation": true, "https://json-schema.org/draft/2020-12/vocab/meta-data": true, "https://json-schema.org/draft/2020-12/vocab/format-annotation": true, "https://json-schema.org/draft/2020-12/vocab/content": true }, "$dynamicAnchor": "meta", "title": "Core and Validation specifications meta-schema", "allOf": [ {"$ref": "meta/core"}, {"$ref": "meta/applicator"}, {"$ref": "meta/unevaluated"}, {"$ref": "meta/validation"}, {"$ref": "meta/meta-data"}, {"$ref": "meta/format-annotation"}, {"$ref": "meta/content"} ], "type": ["object", "boolean"], "$comment": "This meta-schema also defines keywords that have appeared in previous drafts in order to prevent incompatible extensions as they remain in common use.", "properties": { "definitions": { "$comment": "\"definitions\" has been replaced by \"$defs\".", "type": "object", "additionalProperties": { "$dynamicRef": "#meta" }, "deprecated": true, "default": {} }, "dependencies": { "$comment": "\"dependencies\" has been split and replaced by \"dependentSchemas\" and \"dependentRequired\" in order to serve their differing semantics.", "type": "object", "additionalProperties": { "anyOf": [ { "$dynamicRef": "#meta" }, { "$ref": "meta/validation#/$defs/stringArray" } ] }, "deprecated": true, "default": {} }, "$recursiveAnchor": { "$comment": "\"$recursiveAnchor\" has been replaced by \"$dynamicAnchor\".", "$ref": "meta/core#/$defs/anchorString", "deprecated": true }, "$recursiveRef": { "$comment": "\"$recursiveRef\" has been replaced by \"$dynamicRef\".", "$ref": "meta/core#/$defs/uriReferenceString", "deprecated": true } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/schemas/draft3.json0000644000175100001770000000505014653725311020756 0ustar00runnerdocker{ "$schema" : "http://json-schema.org/draft-03/schema#", "id" : "http://json-schema.org/draft-03/schema#", "type" : "object", "properties" : { "type" : { "type" : ["string", "array"], "items" : { "type" : ["string", {"$ref" : "#"}] }, "uniqueItems" : true, "default" : "any" }, "properties" : { "type" : "object", "additionalProperties" : {"$ref" : "#"}, "default" : {} }, "patternProperties" : { "type" : "object", "additionalProperties" : {"$ref" : "#"}, "default" : {} }, "additionalProperties" : { "type" : [{"$ref" : "#"}, "boolean"], "default" : {} }, "items" : { "type" : [{"$ref" : "#"}, "array"], "items" : {"$ref" : "#"}, "default" : {} }, "additionalItems" : { "type" : [{"$ref" : "#"}, "boolean"], "default" : {} }, "required" : { "type" : "boolean", "default" : false }, "dependencies" : { "type" : "object", "additionalProperties" : { "type" : ["string", "array", {"$ref" : "#"}], "items" : { "type" : "string" } }, "default" : {} }, "minimum" : { "type" : "number" }, "maximum" : { "type" : "number" }, "exclusiveMinimum" : { "type" : "boolean", "default" : false }, "exclusiveMaximum" : { "type" : "boolean", "default" : false }, "minItems" : { "type" : "integer", "minimum" : 0, "default" : 0 }, "maxItems" : { "type" : "integer", "minimum" : 0 }, "uniqueItems" : { "type" : "boolean", "default" : false }, "pattern" : { "type" : "string", "format" : "regex" }, "minLength" : { "type" : "integer", "minimum" : 0, "default" : 0 }, "maxLength" : { "type" : "integer" }, "enum" : { "type" : "array", "minItems" : 1, "uniqueItems" : true }, "default" : { "type" : "any" }, "title" : { "type" : "string" }, "description" : { "type" : "string" }, "format" : { "type" : "string" }, "divisibleBy" : { "type" : "number", "minimum" : 0, "exclusiveMinimum" : true, "default" : 1 }, "disallow" : { "type" : ["string", "array"], "items" : { "type" : ["string", {"$ref" : "#"}] }, "uniqueItems" : true }, "extends" : { "type" : [{"$ref" : "#"}, "array"], "items" : {"$ref" : "#"}, "default" : {} }, "id" : { "type" : "string" }, "$ref" : { "type" : "string" }, "$schema" : { "type" : "string", "format" : "uri" } }, "dependencies" : { "exclusiveMinimum" : "minimum", "exclusiveMaximum" : "maximum" }, "default" : {} } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/schemas/draft4.json0000644000175100001770000001040514653725311020757 0ustar00runnerdocker{ "id": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#", "description": "Core schema meta-schema", "definitions": { "schemaArray": { "type": "array", "minItems": 1, "items": { "$ref": "#" } }, "positiveInteger": { "type": "integer", "minimum": 0 }, "positiveIntegerDefault0": { "allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ] }, "simpleTypes": { "enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ] }, "stringArray": { "type": "array", "items": { "type": "string" }, "minItems": 1, "uniqueItems": true } }, "type": "object", "properties": { "id": { "type": "string" }, "$schema": { "type": "string" }, "title": { "type": "string" }, "description": { "type": "string" }, "default": {}, "multipleOf": { "type": "number", "minimum": 0, "exclusiveMinimum": true }, "maximum": { "type": "number" }, "exclusiveMaximum": { "type": "boolean", "default": false }, "minimum": { "type": "number" }, "exclusiveMinimum": { "type": "boolean", "default": false }, "maxLength": { "$ref": "#/definitions/positiveInteger" }, "minLength": { "$ref": "#/definitions/positiveIntegerDefault0" }, "pattern": { "type": "string", "format": "regex" }, "additionalItems": { "anyOf": [ { "type": "boolean" }, { "$ref": "#" } ], "default": {} }, "items": { "anyOf": [ { "$ref": "#" }, { "$ref": "#/definitions/schemaArray" } ], "default": {} }, "maxItems": { "$ref": "#/definitions/positiveInteger" }, "minItems": { "$ref": "#/definitions/positiveIntegerDefault0" }, "uniqueItems": { "type": "boolean", "default": false }, "maxProperties": { "$ref": "#/definitions/positiveInteger" }, "minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" }, "required": { "$ref": "#/definitions/stringArray" }, "additionalProperties": { "anyOf": [ { "type": "boolean" }, { "$ref": "#" } ], "default": {} }, "definitions": { "type": "object", "additionalProperties": { "$ref": "#" }, "default": {} }, "properties": { "type": "object", "additionalProperties": { "$ref": "#" }, "default": {} }, "patternProperties": { "type": "object", "additionalProperties": { "$ref": "#" }, "default": {} }, "dependencies": { "type": "object", "additionalProperties": { "anyOf": [ { "$ref": "#" }, { "$ref": "#/definitions/stringArray" } ] } }, "enum": { "type": "array", "minItems": 1, "uniqueItems": true }, "type": { "anyOf": [ { "$ref": "#/definitions/simpleTypes" }, { "type": "array", "items": { "$ref": "#/definitions/simpleTypes" }, "minItems": 1, "uniqueItems": true } ] }, "format": { "type": "string" }, "allOf": { "$ref": "#/definitions/schemaArray" }, "anyOf": { "$ref": "#/definitions/schemaArray" }, "oneOf": { "$ref": "#/definitions/schemaArray" }, "not": { "$ref": "#" } }, "dependencies": { "exclusiveMaximum": [ "maximum" ], "exclusiveMinimum": [ "minimum" ] }, "default": {} } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/schemas/draft6.json0000644000175100001770000001052514653725311020764 0ustar00runnerdocker{ "$schema": "http://json-schema.org/draft-06/schema#", "$id": "http://json-schema.org/draft-06/schema#", "title": "Core schema meta-schema", "definitions": { "schemaArray": { "type": "array", "minItems": 1, "items": { "$ref": "#" } }, "nonNegativeInteger": { "type": "integer", "minimum": 0 }, "nonNegativeIntegerDefault0": { "allOf": [ { "$ref": "#/definitions/nonNegativeInteger" }, { "default": 0 } ] }, "simpleTypes": { "enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ] }, "stringArray": { "type": "array", "items": { "type": "string" }, "uniqueItems": true, "default": [] } }, "type": ["object", "boolean"], "properties": { "$id": { "type": "string", "format": "uri-reference" }, "$schema": { "type": "string", "format": "uri" }, "$ref": { "type": "string", "format": "uri-reference" }, "title": { "type": "string" }, "description": { "type": "string" }, "default": {}, "examples": { "type": "array", "items": {} }, "multipleOf": { "type": "number", "exclusiveMinimum": 0 }, "maximum": { "type": "number" }, "exclusiveMaximum": { "type": "number" }, "minimum": { "type": "number" }, "exclusiveMinimum": { "type": "number" }, "maxLength": { "$ref": "#/definitions/nonNegativeInteger" }, "minLength": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, "pattern": { "type": "string", "format": "regex" }, "additionalItems": { "$ref": "#" }, "items": { "anyOf": [ { "$ref": "#" }, { "$ref": "#/definitions/schemaArray" } ], "default": {} }, "maxItems": { "$ref": "#/definitions/nonNegativeInteger" }, "minItems": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, "uniqueItems": { "type": "boolean", "default": false }, "contains": { "$ref": "#" }, "maxProperties": { "$ref": "#/definitions/nonNegativeInteger" }, "minProperties": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, "required": { "$ref": "#/definitions/stringArray" }, "additionalProperties": { "$ref": "#" }, "definitions": { "type": "object", "additionalProperties": { "$ref": "#" }, "default": {} }, "properties": { "type": "object", "additionalProperties": { "$ref": "#" }, "default": {} }, "patternProperties": { "type": "object", "additionalProperties": { "$ref": "#" }, "propertyNames": { "format": "regex" }, "default": {} }, "dependencies": { "type": "object", "additionalProperties": { "anyOf": [ { "$ref": "#" }, { "$ref": "#/definitions/stringArray" } ] } }, "propertyNames": { "$ref": "#" }, "const": {}, "enum": { "type": "array" }, "type": { "anyOf": [ { "$ref": "#/definitions/simpleTypes" }, { "type": "array", "items": { "$ref": "#/definitions/simpleTypes" }, "minItems": 1, "uniqueItems": true } ] }, "format": { "type": "string" }, "allOf": { "$ref": "#/definitions/schemaArray" }, "anyOf": { "$ref": "#/definitions/schemaArray" }, "oneOf": { "$ref": "#/definitions/schemaArray" }, "not": { "$ref": "#" } }, "default": {} } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/schemas/draft7.json0000644000175100001770000001132314653725311020762 0ustar00runnerdocker{ "$schema": "http://json-schema.org/draft-07/schema#", "$id": "http://json-schema.org/draft-07/schema#", "title": "Core schema meta-schema", "definitions": { "schemaArray": { "type": "array", "minItems": 1, "items": { "$ref": "#" } }, "nonNegativeInteger": { "type": "integer", "minimum": 0 }, "nonNegativeIntegerDefault0": { "allOf": [ { "$ref": "#/definitions/nonNegativeInteger" }, { "default": 0 } ] }, "simpleTypes": { "enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ] }, "stringArray": { "type": "array", "items": { "type": "string" }, "uniqueItems": true, "default": [] } }, "type": ["object", "boolean"], "properties": { "$id": { "type": "string", "format": "uri-reference" }, "$schema": { "type": "string", "format": "uri" }, "$ref": { "type": "string", "format": "uri-reference" }, "$comment": { "type": "string" }, "title": { "type": "string" }, "description": { "type": "string" }, "default": true, "readOnly": { "type": "boolean", "default": false }, "examples": { "type": "array", "items": true }, "multipleOf": { "type": "number", "exclusiveMinimum": 0 }, "maximum": { "type": "number" }, "exclusiveMaximum": { "type": "number" }, "minimum": { "type": "number" }, "exclusiveMinimum": { "type": "number" }, "maxLength": { "$ref": "#/definitions/nonNegativeInteger" }, "minLength": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, "pattern": { "type": "string", "format": "regex" }, "additionalItems": { "$ref": "#" }, "items": { "anyOf": [ { "$ref": "#" }, { "$ref": "#/definitions/schemaArray" } ], "default": true }, "maxItems": { "$ref": "#/definitions/nonNegativeInteger" }, "minItems": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, "uniqueItems": { "type": "boolean", "default": false }, "contains": { "$ref": "#" }, "maxProperties": { "$ref": "#/definitions/nonNegativeInteger" }, "minProperties": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, "required": { "$ref": "#/definitions/stringArray" }, "additionalProperties": { "$ref": "#" }, "definitions": { "type": "object", "additionalProperties": { "$ref": "#" }, "default": {} }, "properties": { "type": "object", "additionalProperties": { "$ref": "#" }, "default": {} }, "patternProperties": { "type": "object", "additionalProperties": { "$ref": "#" }, "propertyNames": { "format": "regex" }, "default": {} }, "dependencies": { "type": "object", "additionalProperties": { "anyOf": [ { "$ref": "#" }, { "$ref": "#/definitions/stringArray" } ] } }, "propertyNames": { "$ref": "#" }, "const": true, "enum": { "type": "array", "items": true }, "type": { "anyOf": [ { "$ref": "#/definitions/simpleTypes" }, { "type": "array", "items": { "$ref": "#/definitions/simpleTypes" }, "minItems": 1, "uniqueItems": true } ] }, "format": { "type": "string" }, "contentMediaType": { "type": "string" }, "contentEncoding": { "type": "string" }, "if": {"$ref": "#"}, "then": {"$ref": "#"}, "else": {"$ref": "#"}, "allOf": { "$ref": "#/definitions/schemaArray" }, "anyOf": { "$ref": "#/definitions/schemaArray" }, "oneOf": { "$ref": "#/definitions/schemaArray" }, "not": { "$ref": "#" } }, "default": true } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.0130956 asdf-3.4.0/asdf/_jsonschema/schemas/vocabularies/0000755000175100001770000000000014653725331021361 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.129098 asdf-3.4.0/asdf/_jsonschema/schemas/vocabularies/draft2019-09/0000755000175100001770000000000014653725331023223 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/schemas/vocabularies/draft2019-09/applicator0000644000175100001770000000350414653725311025304 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "https://json-schema.org/draft/2019-09/meta/applicator", "$vocabulary": { "https://json-schema.org/draft/2019-09/vocab/applicator": true }, "$recursiveAnchor": true, "title": "Applicator vocabulary meta-schema", "type": ["object", "boolean"], "properties": { "additionalItems": { "$recursiveRef": "#" }, "unevaluatedItems": { "$recursiveRef": "#" }, "items": { "anyOf": [ { "$recursiveRef": "#" }, { "$ref": "#/$defs/schemaArray" } ] }, "contains": { "$recursiveRef": "#" }, "additionalProperties": { "$recursiveRef": "#" }, "unevaluatedProperties": { "$recursiveRef": "#" }, "properties": { "type": "object", "additionalProperties": { "$recursiveRef": "#" }, "default": {} }, "patternProperties": { "type": "object", "additionalProperties": { "$recursiveRef": "#" }, "propertyNames": { "format": "regex" }, "default": {} }, "dependentSchemas": { "type": "object", "additionalProperties": { "$recursiveRef": "#" } }, "propertyNames": { "$recursiveRef": "#" }, "if": { "$recursiveRef": "#" }, "then": { "$recursiveRef": "#" }, "else": { "$recursiveRef": "#" }, "allOf": { "$ref": "#/$defs/schemaArray" }, "anyOf": { "$ref": "#/$defs/schemaArray" }, "oneOf": { "$ref": "#/$defs/schemaArray" }, "not": { "$recursiveRef": "#" } }, "$defs": { "schemaArray": { "type": "array", "minItems": 1, "items": { "$recursiveRef": "#" } } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/schemas/vocabularies/draft2019-09/content0000644000175100001770000000100514653725311024612 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "https://json-schema.org/draft/2019-09/meta/content", "$vocabulary": { "https://json-schema.org/draft/2019-09/vocab/content": true }, "$recursiveAnchor": true, "title": "Content vocabulary meta-schema", "type": ["object", "boolean"], "properties": { "contentMediaType": { "type": "string" }, "contentEncoding": { "type": "string" }, "contentSchema": { "$recursiveRef": "#" } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/schemas/vocabularies/draft2019-09/core0000644000175100001770000000277314653725311024105 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "https://json-schema.org/draft/2019-09/meta/core", "$vocabulary": { "https://json-schema.org/draft/2019-09/vocab/core": true }, "$recursiveAnchor": true, "title": "Core vocabulary meta-schema", "type": ["object", "boolean"], "properties": { "$id": { "type": "string", "format": "uri-reference", "$comment": "Non-empty fragments not allowed.", "pattern": "^[^#]*#?$" }, "$schema": { "type": "string", "format": "uri" }, "$anchor": { "type": "string", "pattern": "^[A-Za-z][-A-Za-z0-9.:_]*$" }, "$ref": { "type": "string", "format": "uri-reference" }, "$recursiveRef": { "type": "string", "format": "uri-reference" }, "$recursiveAnchor": { "type": "boolean", "default": false }, "$vocabulary": { "type": "object", "propertyNames": { "type": "string", "format": "uri" }, "additionalProperties": { "type": "boolean" } }, "$comment": { "type": "string" }, "$defs": { "type": "object", "additionalProperties": { "$recursiveRef": "#" }, "default": {} } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/schemas/vocabularies/draft2019-09/meta-data0000644000175100001770000000157414653725311025010 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "https://json-schema.org/draft/2019-09/meta/meta-data", "$vocabulary": { "https://json-schema.org/draft/2019-09/vocab/meta-data": true }, "$recursiveAnchor": true, "title": "Meta-data vocabulary meta-schema", "type": ["object", "boolean"], "properties": { "title": { "type": "string" }, "description": { "type": "string" }, "default": true, "deprecated": { "type": "boolean", "default": false }, "readOnly": { "type": "boolean", "default": false }, "writeOnly": { "type": "boolean", "default": false }, "examples": { "type": "array", "items": true } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/schemas/vocabularies/draft2019-09/validation0000644000175100001770000000542214653725311025301 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "https://json-schema.org/draft/2019-09/meta/validation", "$vocabulary": { "https://json-schema.org/draft/2019-09/vocab/validation": true }, "$recursiveAnchor": true, "title": "Validation vocabulary meta-schema", "type": ["object", "boolean"], "properties": { "multipleOf": { "type": "number", "exclusiveMinimum": 0 }, "maximum": { "type": "number" }, "exclusiveMaximum": { "type": "number" }, "minimum": { "type": "number" }, "exclusiveMinimum": { "type": "number" }, "maxLength": { "$ref": "#/$defs/nonNegativeInteger" }, "minLength": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, "pattern": { "type": "string", "format": "regex" }, "maxItems": { "$ref": "#/$defs/nonNegativeInteger" }, "minItems": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, "uniqueItems": { "type": "boolean", "default": false }, "maxContains": { "$ref": "#/$defs/nonNegativeInteger" }, "minContains": { "$ref": "#/$defs/nonNegativeInteger", "default": 1 }, "maxProperties": { "$ref": "#/$defs/nonNegativeInteger" }, "minProperties": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, "required": { "$ref": "#/$defs/stringArray" }, "dependentRequired": { "type": "object", "additionalProperties": { "$ref": "#/$defs/stringArray" } }, "const": true, "enum": { "type": "array", "items": true }, "type": { "anyOf": [ { "$ref": "#/$defs/simpleTypes" }, { "type": "array", "items": { "$ref": "#/$defs/simpleTypes" }, "minItems": 1, "uniqueItems": true } ] } }, "$defs": { "nonNegativeInteger": { "type": "integer", "minimum": 0 }, "nonNegativeIntegerDefault0": { "$ref": "#/$defs/nonNegativeInteger", "default": 0 }, "simpleTypes": { "enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ] }, "stringArray": { "type": "array", "items": { "type": "string" }, "uniqueItems": true, "default": [] } } } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.129098 asdf-3.4.0/asdf/_jsonschema/schemas/vocabularies/draft2020-12/0000755000175100001770000000000014653725331023205 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/schemas/vocabularies/draft2020-12/applicator0000644000175100001770000000317314653725311025270 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://json-schema.org/draft/2020-12/meta/applicator", "$vocabulary": { "https://json-schema.org/draft/2020-12/vocab/applicator": true }, "$dynamicAnchor": "meta", "title": "Applicator vocabulary meta-schema", "type": ["object", "boolean"], "properties": { "prefixItems": { "$ref": "#/$defs/schemaArray" }, "items": { "$dynamicRef": "#meta" }, "contains": { "$dynamicRef": "#meta" }, "additionalProperties": { "$dynamicRef": "#meta" }, "properties": { "type": "object", "additionalProperties": { "$dynamicRef": "#meta" }, "default": {} }, "patternProperties": { "type": "object", "additionalProperties": { "$dynamicRef": "#meta" }, "propertyNames": { "format": "regex" }, "default": {} }, "dependentSchemas": { "type": "object", "additionalProperties": { "$dynamicRef": "#meta" }, "default": {} }, "propertyNames": { "$dynamicRef": "#meta" }, "if": { "$dynamicRef": "#meta" }, "then": { "$dynamicRef": "#meta" }, "else": { "$dynamicRef": "#meta" }, "allOf": { "$ref": "#/$defs/schemaArray" }, "anyOf": { "$ref": "#/$defs/schemaArray" }, "oneOf": { "$ref": "#/$defs/schemaArray" }, "not": { "$dynamicRef": "#meta" } }, "$defs": { "schemaArray": { "type": "array", "minItems": 1, "items": { "$dynamicRef": "#meta" } } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/schemas/vocabularies/draft2020-12/content0000644000175100001770000000100714653725311024576 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://json-schema.org/draft/2020-12/meta/content", "$vocabulary": { "https://json-schema.org/draft/2020-12/vocab/content": true }, "$dynamicAnchor": "meta", "title": "Content vocabulary meta-schema", "type": ["object", "boolean"], "properties": { "contentEncoding": { "type": "string" }, "contentMediaType": { "type": "string" }, "contentSchema": { "$dynamicRef": "#meta" } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/schemas/vocabularies/draft2020-12/core0000644000175100001770000000303414653725311024056 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://json-schema.org/draft/2020-12/meta/core", "$vocabulary": { "https://json-schema.org/draft/2020-12/vocab/core": true }, "$dynamicAnchor": "meta", "title": "Core vocabulary meta-schema", "type": ["object", "boolean"], "properties": { "$id": { "$ref": "#/$defs/uriReferenceString", "$comment": "Non-empty fragments not allowed.", "pattern": "^[^#]*#?$" }, "$schema": { "$ref": "#/$defs/uriString" }, "$ref": { "$ref": "#/$defs/uriReferenceString" }, "$anchor": { "$ref": "#/$defs/anchorString" }, "$dynamicRef": { "$ref": "#/$defs/uriReferenceString" }, "$dynamicAnchor": { "$ref": "#/$defs/anchorString" }, "$vocabulary": { "type": "object", "propertyNames": { "$ref": "#/$defs/uriString" }, "additionalProperties": { "type": "boolean" } }, "$comment": { "type": "string" }, "$defs": { "type": "object", "additionalProperties": { "$dynamicRef": "#meta" } } }, "$defs": { "anchorString": { "type": "string", "pattern": "^[A-Za-z_][-A-Za-z0-9._]*$" }, "uriString": { "type": "string", "format": "uri" }, "uriReferenceString": { "type": "string", "format": "uri-reference" } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/schemas/vocabularies/draft2020-12/format0000644000175100001770000000062314653725311024417 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "https://json-schema.org/draft/2019-09/meta/format", "$vocabulary": { "https://json-schema.org/draft/2019-09/vocab/format": true }, "$recursiveAnchor": true, "title": "Format vocabulary meta-schema", "type": ["object", "boolean"], "properties": { "format": { "type": "string" } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/schemas/vocabularies/draft2020-12/format-annotation0000644000175100001770000000070014653725311026563 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://json-schema.org/draft/2020-12/meta/format-annotation", "$vocabulary": { "https://json-schema.org/draft/2020-12/vocab/format-annotation": true }, "$dynamicAnchor": "meta", "title": "Format vocabulary meta-schema for annotation results", "type": ["object", "boolean"], "properties": { "format": { "type": "string" } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/schemas/vocabularies/draft2020-12/format-assertion0000644000175100001770000000067514653725311026433 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://json-schema.org/draft/2020-12/meta/format-assertion", "$vocabulary": { "https://json-schema.org/draft/2020-12/vocab/format-assertion": true }, "$dynamicAnchor": "meta", "title": "Format vocabulary meta-schema for assertion results", "type": ["object", "boolean"], "properties": { "format": { "type": "string" } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/schemas/vocabularies/draft2020-12/meta-data0000644000175100001770000000157414653725311024772 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://json-schema.org/draft/2020-12/meta/meta-data", "$vocabulary": { "https://json-schema.org/draft/2020-12/vocab/meta-data": true }, "$dynamicAnchor": "meta", "title": "Meta-data vocabulary meta-schema", "type": ["object", "boolean"], "properties": { "title": { "type": "string" }, "description": { "type": "string" }, "default": true, "deprecated": { "type": "boolean", "default": false }, "readOnly": { "type": "boolean", "default": false }, "writeOnly": { "type": "boolean", "default": false }, "examples": { "type": "array", "items": true } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/schemas/vocabularies/draft2020-12/unevaluated0000644000175100001770000000077214653725311025451 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://json-schema.org/draft/2020-12/meta/unevaluated", "$vocabulary": { "https://json-schema.org/draft/2020-12/vocab/unevaluated": true }, "$dynamicAnchor": "meta", "title": "Unevaluated applicator vocabulary meta-schema", "type": ["object", "boolean"], "properties": { "unevaluatedItems": { "$dynamicRef": "#meta" }, "unevaluatedProperties": { "$dynamicRef": "#meta" } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/schemas/vocabularies/draft2020-12/validation0000644000175100001770000000542214653725311025263 0ustar00runnerdocker{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://json-schema.org/draft/2020-12/meta/validation", "$vocabulary": { "https://json-schema.org/draft/2020-12/vocab/validation": true }, "$dynamicAnchor": "meta", "title": "Validation vocabulary meta-schema", "type": ["object", "boolean"], "properties": { "type": { "anyOf": [ { "$ref": "#/$defs/simpleTypes" }, { "type": "array", "items": { "$ref": "#/$defs/simpleTypes" }, "minItems": 1, "uniqueItems": true } ] }, "const": true, "enum": { "type": "array", "items": true }, "multipleOf": { "type": "number", "exclusiveMinimum": 0 }, "maximum": { "type": "number" }, "exclusiveMaximum": { "type": "number" }, "minimum": { "type": "number" }, "exclusiveMinimum": { "type": "number" }, "maxLength": { "$ref": "#/$defs/nonNegativeInteger" }, "minLength": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, "pattern": { "type": "string", "format": "regex" }, "maxItems": { "$ref": "#/$defs/nonNegativeInteger" }, "minItems": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, "uniqueItems": { "type": "boolean", "default": false }, "maxContains": { "$ref": "#/$defs/nonNegativeInteger" }, "minContains": { "$ref": "#/$defs/nonNegativeInteger", "default": 1 }, "maxProperties": { "$ref": "#/$defs/nonNegativeInteger" }, "minProperties": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, "required": { "$ref": "#/$defs/stringArray" }, "dependentRequired": { "type": "object", "additionalProperties": { "$ref": "#/$defs/stringArray" } } }, "$defs": { "nonNegativeInteger": { "type": "integer", "minimum": 0 }, "nonNegativeIntegerDefault0": { "$ref": "#/$defs/nonNegativeInteger", "default": 0 }, "simpleTypes": { "enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ] }, "stringArray": { "type": "array", "items": { "type": "string" }, "uniqueItems": true, "default": [] } } } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.129098 asdf-3.4.0/asdf/_jsonschema/tests/0000755000175100001770000000000014653725331016421 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/tests/__init__.py0000644000175100001770000000000014653725311020516 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/tests/_helpers.py0000644000175100001770000000113614653725311020573 0ustar00runnerdockerfrom urllib.parse import urljoin def issues_url(organization, repository): return urljoin( "https://github.com/", f"{organization}/{repository}/issues/", ) ISSUES_URL = issues_url("asdf-format", "asdf") TEST_SUITE_ISSUES_URL = issues_url("json-schema-org", "JSON-Schema-Test-Suite") def bug(issue=None): message = "A known bug." if issue is not None: message += f" See {urljoin(ISSUES_URL, str(issue))}." return message def test_suite_bug(issue): return ( "A known test suite bug. " f"See {urljoin(TEST_SUITE_ISSUES_URL, str(issue))}." ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/tests/_suite.py0000644000175100001770000001567614653725311020300 0ustar00runnerdocker""" Python representations of the JSON Schema Test Suite tests. """ from functools import partial from pathlib import Path import json import os import re import subprocess import sys import unittest import attr from asdf._jsonschema.validators import _VALIDATORS import asdf._jsonschema def _find_suite(): root = os.environ.get("JSON_SCHEMA_TEST_SUITE") if root is not None: return Path(root) root = Path(asdf._jsonschema.__file__).parent / "json" if not root.is_dir(): # pragma: no cover raise ValueError( ( "Can't find the JSON-Schema-Test-Suite directory. " "Set the 'JSON_SCHEMA_TEST_SUITE' environment " "variable or run the tests from alongside a checkout " "of the suite." ), ) return root @attr.s(unsafe_hash=True) class Suite: _root = attr.ib(default=attr.Factory(_find_suite)) def _remotes(self): jsonschema_suite = self._root.joinpath("bin", "jsonschema_suite") remotes = subprocess.check_output( [sys.executable, str(jsonschema_suite), "remotes"], ) return json.loads(remotes.decode("utf-8")) def benchmark(self, runner): # pragma: no cover for name, Validator in _VALIDATORS.items(): self.version(name=name).benchmark( runner=runner, Validator=Validator, ) def version(self, name): return Version( name=name, path=self._root.joinpath("tests", name), remotes=self._remotes(), ) @attr.s(unsafe_hash=True) class Version: _path = attr.ib() _remotes = attr.ib() name = attr.ib() def benchmark(self, runner, **kwargs): # pragma: no cover for suite in self.tests(): for test in suite: runner.bench_func( test.fully_qualified_name, partial(test.validate_ignoring_errors, **kwargs), ) def tests(self): return ( test for child in self._path.glob("*.json") for test in self._tests_in( subject=child.name[:-5], path=child, ) ) def format_tests(self): path = self._path.joinpath("optional", "format") return ( test for child in path.glob("*.json") for test in self._tests_in( subject=child.name[:-5], path=child, ) ) def optional_tests_of(self, name): return self._tests_in( subject=name, path=self._path.joinpath("optional", name + ".json"), ) def to_unittest_testcase(self, *suites, **kwargs): name = kwargs.pop("name", "Test" + self.name.title().replace("-", "")) methods = { test.method_name: test.to_unittest_method(**kwargs) for suite in suites for tests in suite for test in tests } cls = type(name, (unittest.TestCase,), methods) try: cls.__module__ = _someone_save_us_the_module_of_the_caller() except Exception: # pragma: no cover # We're doing crazy things, so if they go wrong, like a function # behaving differently on some other interpreter, just make them # not happen. pass return cls def _tests_in(self, subject, path): for each in json.loads(path.read_text(encoding="utf-8")): yield ( _Test( version=self, subject=subject, case_description=each["description"], schema=each["schema"], remotes=self._remotes, **test, ) for test in each["tests"] ) @attr.s(unsafe_hash=True, repr=False) class _Test: version = attr.ib() subject = attr.ib() case_description = attr.ib() description = attr.ib() data = attr.ib() schema = attr.ib(repr=False) valid = attr.ib() _remotes = attr.ib() comment = attr.ib(default=None) def __repr__(self): # pragma: no cover return "".format(self.fully_qualified_name) @property def fully_qualified_name(self): # pragma: no cover return " > ".join( [ self.version.name, self.subject, self.case_description, self.description, ], ) @property def method_name(self): delimiters = r"[\W\- ]+" return "test_{}_{}_{}".format( re.sub(delimiters, "_", self.subject), re.sub(delimiters, "_", self.case_description), re.sub(delimiters, "_", self.description), ) def to_unittest_method(self, skip=lambda test: None, **kwargs): if self.valid: def fn(this): self.validate(**kwargs) else: def fn(this): with this.assertRaises(asdf._jsonschema.ValidationError): self.validate(**kwargs) fn.__name__ = self.method_name reason = skip(self) if reason is None or os.environ.get("JSON_SCHEMA_DEBUG", "0") != "0": return fn elif os.environ.get("JSON_SCHEMA_EXPECTED_FAILURES", "0") != "0": return unittest.expectedFailure(fn) else: return unittest.skip(reason)(fn) def validate(self, Validator, **kwargs): Validator.check_schema(self.schema) resolver = asdf._jsonschema.RefResolver.from_schema( schema=self.schema, store=self._remotes, id_of=Validator.ID_OF, ) # XXX: #693 asks to improve the public API for this, since yeah, it's # bad. Figures that since it's hard for end-users, we experience # the pain internally here too. def prevent_network_access(uri): raise RuntimeError(f"Tried to access the network: {uri}") resolver.resolve_remote = prevent_network_access validator = Validator(schema=self.schema, resolver=resolver, **kwargs) if os.environ.get("JSON_SCHEMA_DEBUG", "0") != "0": breakpoint() validator.validate(instance=self.data) def validate_ignoring_errors(self, Validator): # pragma: no cover try: self.validate(Validator=Validator) except asdf._jsonschema.ValidationError: pass def _someone_save_us_the_module_of_the_caller(): """ The FQON of the module 2nd stack frames up from here. This is intended to allow us to dynamically return test case classes that are indistinguishable from being defined in the module that wants them. Otherwise, trial will mis-print the FQON, and copy pasting it won't re-run the class that really is running. Save us all, this is all so so so so so terrible. """ return sys._getframe(2).f_globals["__name__"] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/tests/test_deprecations.py0000644000175100001770000002000314653725311022503 0ustar00runnerdockerfrom unittest import TestCase import importlib import subprocess import sys from asdf._jsonschema import FormatChecker, validators class TestDeprecations(TestCase): def test_validators_ErrorTree(self): """ As of v4.0.0, importing ErrorTree from asdf._jsonschema.validators is deprecated in favor of doing so from asdf._jsonschema.exceptions. """ with self.assertWarns(DeprecationWarning) as w: from asdf._jsonschema.validators import ErrorTree # noqa self.assertEqual(w.filename, __file__) self.assertTrue( str(w.warning).startswith( "Importing ErrorTree from asdf._jsonschema.validators is deprecated", ), ) def test_validators_validators(self): """ As of v4.0.0, accessing asdf._jsonschema.validators.validators is deprecated. """ with self.assertWarns(DeprecationWarning) as w: value = validators.validators self.assertEqual(value, validators._VALIDATORS) self.assertEqual(w.filename, __file__) self.assertTrue( str(w.warning).startswith( "Accessing asdf._jsonschema.validators.validators is deprecated", ), ) def test_validators_meta_schemas(self): """ As of v4.0.0, accessing asdf._jsonschema.validators.meta_schemas is deprecated. """ with self.assertWarns(DeprecationWarning) as w: value = validators.meta_schemas self.assertEqual(value, validators._META_SCHEMAS) self.assertEqual(w.filename, __file__) self.assertTrue( str(w.warning).startswith( "Accessing asdf._jsonschema.validators.meta_schemas is deprecated", ), ) def test_RefResolver_in_scope(self): """ As of v4.0.0, RefResolver.in_scope is deprecated. """ resolver = validators.RefResolver.from_schema({}) with self.assertWarns(DeprecationWarning) as w: with resolver.in_scope("foo"): pass self.assertEqual(w.filename, __file__) self.assertTrue( str(w.warning).startswith( "asdf._jsonschema.RefResolver.in_scope is deprecated ", ), ) def test_Validator_is_valid_two_arguments(self): """ As of v4.0.0, calling is_valid with two arguments (to provide a different schema) is deprecated. """ validator = validators.Draft7Validator({}) with self.assertWarns(DeprecationWarning) as w: result = validator.is_valid("foo", {"type": "number"}) self.assertFalse(result) self.assertEqual(w.filename, __file__) self.assertTrue( str(w.warning).startswith( "Passing a schema to Validator.is_valid is deprecated ", ), ) def test_Validator_iter_errors_two_arguments(self): """ As of v4.0.0, calling iter_errors with two arguments (to provide a different schema) is deprecated. """ validator = validators.Draft7Validator({}) with self.assertWarns(DeprecationWarning) as w: error, = validator.iter_errors("foo", {"type": "number"}) self.assertEqual(error.validator, "type") self.assertEqual(w.filename, __file__) self.assertTrue( str(w.warning).startswith( "Passing a schema to Validator.iter_errors is deprecated ", ), ) def test_Validator_subclassing(self): """ As of v4.12.0, subclassing a validator class produces an explicit deprecation warning. This was never intended to be public API (and some comments over the years in issues said so, but obviously that's not a great way to make sure it's followed). A future version will explicitly raise an error. """ with self.assertWarns(DeprecationWarning) as w: class Subclass(validators.Draft202012Validator): pass self.assertEqual(w.filename, __file__) self.assertTrue( str(w.warning).startswith("Subclassing validator classes is "), ) with self.assertWarns(DeprecationWarning) as w: class AnotherSubclass(validators.create(meta_schema={})): pass def test_FormatChecker_cls_checks(self): """ As of v4.14.0, FormatChecker.cls_checks is deprecated without replacement. """ self.addCleanup(FormatChecker.checkers.pop, "boom", None) with self.assertWarns(DeprecationWarning) as w: FormatChecker.cls_checks("boom") self.assertEqual(w.filename, __file__) self.assertTrue( str(w.warning).startswith("FormatChecker.cls_checks "), ) def test_draftN_format_checker(self): """ As of v4.16.0, accessing asdf._jsonschema.draftn_format_checker is deprecated in favor of Validator.FORMAT_CHECKER. """ with self.assertWarns(DeprecationWarning) as w: from asdf._jsonschema import draft202012_format_checker # noqa self.assertIs( draft202012_format_checker, validators.Draft202012Validator.FORMAT_CHECKER, ) self.assertEqual(w.filename, __file__) self.assertTrue( str(w.warning).startswith( "Accessing asdf._jsonschema.draft202012_format_checker is ", ), msg=w.warning, ) with self.assertWarns(DeprecationWarning) as w: from asdf._jsonschema import draft201909_format_checker # noqa self.assertIs( draft201909_format_checker, validators.Draft201909Validator.FORMAT_CHECKER, ) self.assertEqual(w.filename, __file__) self.assertTrue( str(w.warning).startswith( "Accessing asdf._jsonschema.draft201909_format_checker is ", ), msg=w.warning, ) with self.assertWarns(DeprecationWarning) as w: from asdf._jsonschema import draft7_format_checker # noqa self.assertIs( draft7_format_checker, validators.Draft7Validator.FORMAT_CHECKER, ) self.assertEqual(w.filename, __file__) self.assertTrue( str(w.warning).startswith( "Accessing asdf._jsonschema.draft7_format_checker is ", ), msg=w.warning, ) with self.assertWarns(DeprecationWarning) as w: from asdf._jsonschema import draft6_format_checker # noqa self.assertIs( draft6_format_checker, validators.Draft6Validator.FORMAT_CHECKER, ) self.assertEqual(w.filename, __file__) self.assertTrue( str(w.warning).startswith( "Accessing asdf._jsonschema.draft6_format_checker is ", ), msg=w.warning, ) with self.assertWarns(DeprecationWarning) as w: from asdf._jsonschema import draft4_format_checker # noqa self.assertIs( draft4_format_checker, validators.Draft4Validator.FORMAT_CHECKER, ) self.assertEqual(w.filename, __file__) self.assertTrue( str(w.warning).startswith( "Accessing asdf._jsonschema.draft4_format_checker is ", ), msg=w.warning, ) with self.assertWarns(DeprecationWarning) as w: from asdf._jsonschema import draft3_format_checker # noqa self.assertIs( draft3_format_checker, validators.Draft3Validator.FORMAT_CHECKER, ) self.assertEqual(w.filename, __file__) self.assertTrue( str(w.warning).startswith( "Accessing asdf._jsonschema.draft3_format_checker is ", ), msg=w.warning, ) with self.assertRaises(ImportError): from asdf._jsonschema import draft1234_format_checker # noqa ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/tests/test_exceptions.py0000644000175100001770000004630314653725311022217 0ustar00runnerdockerfrom unittest import TestCase import textwrap from asdf._jsonschema import exceptions from asdf._jsonschema.validators import _LATEST_VERSION class TestBestMatch(TestCase): def best_match_of(self, instance, schema): errors = list(_LATEST_VERSION(schema).iter_errors(instance)) best = exceptions.best_match(iter(errors)) reversed_best = exceptions.best_match(reversed(errors)) self.assertEqual( best._contents(), reversed_best._contents(), f"No consistent best match!\nGot: {best}\n\nThen: {reversed_best}", ) return best def test_shallower_errors_are_better_matches(self): schema = { "properties": { "foo": { "minProperties": 2, "properties": {"bar": {"type": "object"}}, }, }, } best = self.best_match_of(instance={"foo": {"bar": []}}, schema=schema) self.assertEqual(best.validator, "minProperties") def test_oneOf_and_anyOf_are_weak_matches(self): """ A property you *must* match is probably better than one you have to match a part of. """ schema = { "minProperties": 2, "anyOf": [{"type": "string"}, {"type": "number"}], "oneOf": [{"type": "string"}, {"type": "number"}], } best = self.best_match_of(instance={}, schema=schema) self.assertEqual(best.validator, "minProperties") def test_if_the_most_relevant_error_is_anyOf_it_is_traversed(self): """ If the most relevant error is an anyOf, then we traverse its context and select the otherwise *least* relevant error, since in this case that means the most specific, deep, error inside the instance. I.e. since only one of the schemas must match, we look for the most relevant one. """ schema = { "properties": { "foo": { "anyOf": [ {"type": "string"}, {"properties": {"bar": {"type": "array"}}}, ], }, }, } best = self.best_match_of(instance={"foo": {"bar": 12}}, schema=schema) self.assertEqual(best.validator_value, "array") def test_no_anyOf_traversal_for_equally_relevant_errors(self): """ We don't traverse into an anyOf (as above) if all of its context errors seem to be equally "wrong" against the instance. """ schema = { "anyOf": [ {"type": "string"}, {"type": "integer"}, {"type": "object"}, ], } best = self.best_match_of(instance=[], schema=schema) self.assertEqual(best.validator, "anyOf") def test_anyOf_traversal_for_single_equally_relevant_error(self): """ We *do* traverse anyOf with a single nested error, even though it is vacuously equally relevant to itself. """ schema = { "anyOf": [ {"type": "string"}, ], } best = self.best_match_of(instance=[], schema=schema) self.assertEqual(best.validator, "type") def test_if_the_most_relevant_error_is_oneOf_it_is_traversed(self): """ If the most relevant error is an oneOf, then we traverse its context and select the otherwise *least* relevant error, since in this case that means the most specific, deep, error inside the instance. I.e. since only one of the schemas must match, we look for the most relevant one. """ schema = { "properties": { "foo": { "oneOf": [ {"type": "string"}, {"properties": {"bar": {"type": "array"}}}, ], }, }, } best = self.best_match_of(instance={"foo": {"bar": 12}}, schema=schema) self.assertEqual(best.validator_value, "array") def test_no_oneOf_traversal_for_equally_relevant_errors(self): """ We don't traverse into an oneOf (as above) if all of its context errors seem to be equally "wrong" against the instance. """ schema = { "oneOf": [ {"type": "string"}, {"type": "integer"}, {"type": "object"}, ], } best = self.best_match_of(instance=[], schema=schema) self.assertEqual(best.validator, "oneOf") def test_oneOf_traversal_for_single_equally_relevant_error(self): """ We *do* traverse oneOf with a single nested error, even though it is vacuously equally relevant to itself. """ schema = { "oneOf": [ {"type": "string"}, ], } best = self.best_match_of(instance=[], schema=schema) self.assertEqual(best.validator, "type") def test_if_the_most_relevant_error_is_allOf_it_is_traversed(self): """ Now, if the error is allOf, we traverse but select the *most* relevant error from the context, because all schemas here must match anyways. """ schema = { "properties": { "foo": { "allOf": [ {"type": "string"}, {"properties": {"bar": {"type": "array"}}}, ], }, }, } best = self.best_match_of(instance={"foo": {"bar": 12}}, schema=schema) self.assertEqual(best.validator_value, "string") def test_nested_context_for_oneOf(self): """ We traverse into nested contexts (a oneOf containing an error in a nested oneOf here). """ schema = { "properties": { "foo": { "oneOf": [ {"type": "string"}, { "oneOf": [ {"type": "string"}, { "properties": { "bar": {"type": "array"}, }, }, ], }, ], }, }, } best = self.best_match_of(instance={"foo": {"bar": 12}}, schema=schema) self.assertEqual(best.validator_value, "array") def test_it_prioritizes_matching_types(self): schema = { "properties": { "foo": { "anyOf": [ {"type": "array", "minItems": 2}, {"type": "string", "minLength": 10}, ], }, }, } best = self.best_match_of(instance={"foo": "bar"}, schema=schema) self.assertEqual(best.validator, "minLength") reordered = { "properties": { "foo": { "anyOf": [ {"type": "string", "minLength": 10}, {"type": "array", "minItems": 2}, ], }, }, } best = self.best_match_of(instance={"foo": "bar"}, schema=reordered) self.assertEqual(best.validator, "minLength") def test_it_prioritizes_matching_union_types(self): schema = { "properties": { "foo": { "anyOf": [ {"type": ["array", "object"], "minItems": 2}, {"type": ["integer", "string"], "minLength": 10}, ], }, }, } best = self.best_match_of(instance={"foo": "bar"}, schema=schema) self.assertEqual(best.validator, "minLength") reordered = { "properties": { "foo": { "anyOf": [ {"type": "string", "minLength": 10}, {"type": "array", "minItems": 2}, ], }, }, } best = self.best_match_of(instance={"foo": "bar"}, schema=reordered) self.assertEqual(best.validator, "minLength") def test_boolean_schemas(self): schema = {"properties": {"foo": False}} best = self.best_match_of(instance={"foo": "bar"}, schema=schema) self.assertIsNone(best.validator) def test_one_error(self): validator = _LATEST_VERSION({"minProperties": 2}) error, = validator.iter_errors({}) self.assertEqual( exceptions.best_match(validator.iter_errors({})).validator, "minProperties", ) def test_no_errors(self): validator = _LATEST_VERSION({}) self.assertIsNone(exceptions.best_match(validator.iter_errors({}))) class TestByRelevance(TestCase): def test_short_paths_are_better_matches(self): shallow = exceptions.ValidationError("Oh no!", path=["baz"]) deep = exceptions.ValidationError("Oh yes!", path=["foo", "bar"]) match = max([shallow, deep], key=exceptions.relevance) self.assertIs(match, shallow) match = max([deep, shallow], key=exceptions.relevance) self.assertIs(match, shallow) def test_global_errors_are_even_better_matches(self): shallow = exceptions.ValidationError("Oh no!", path=[]) deep = exceptions.ValidationError("Oh yes!", path=["foo"]) errors = sorted([shallow, deep], key=exceptions.relevance) self.assertEqual( [list(error.path) for error in errors], [["foo"], []], ) errors = sorted([deep, shallow], key=exceptions.relevance) self.assertEqual( [list(error.path) for error in errors], [["foo"], []], ) def test_weak_keywords_are_lower_priority(self): weak = exceptions.ValidationError("Oh no!", path=[], validator="a") normal = exceptions.ValidationError("Oh yes!", path=[], validator="b") best_match = exceptions.by_relevance(weak="a") match = max([weak, normal], key=best_match) self.assertIs(match, normal) match = max([normal, weak], key=best_match) self.assertIs(match, normal) def test_strong_keywords_are_higher_priority(self): weak = exceptions.ValidationError("Oh no!", path=[], validator="a") normal = exceptions.ValidationError("Oh yes!", path=[], validator="b") strong = exceptions.ValidationError("Oh fine!", path=[], validator="c") best_match = exceptions.by_relevance(weak="a", strong="c") match = max([weak, normal, strong], key=best_match) self.assertIs(match, strong) match = max([strong, normal, weak], key=best_match) self.assertIs(match, strong) class TestErrorTree(TestCase): def test_it_knows_how_many_total_errors_it_contains(self): # FIXME: #442 errors = [ exceptions.ValidationError("Something", validator=i) for i in range(8) ] tree = exceptions.ErrorTree(errors) self.assertEqual(tree.total_errors, 8) def test_it_contains_an_item_if_the_item_had_an_error(self): errors = [exceptions.ValidationError("a message", path=["bar"])] tree = exceptions.ErrorTree(errors) self.assertIn("bar", tree) def test_it_does_not_contain_an_item_if_the_item_had_no_error(self): errors = [exceptions.ValidationError("a message", path=["bar"])] tree = exceptions.ErrorTree(errors) self.assertNotIn("foo", tree) def test_keywords_that_failed_appear_in_errors_dict(self): error = exceptions.ValidationError("a message", validator="foo") tree = exceptions.ErrorTree([error]) self.assertEqual(tree.errors, {"foo": error}) def test_it_creates_a_child_tree_for_each_nested_path(self): errors = [ exceptions.ValidationError("a bar message", path=["bar"]), exceptions.ValidationError("a bar -> 0 message", path=["bar", 0]), ] tree = exceptions.ErrorTree(errors) self.assertIn(0, tree["bar"]) self.assertNotIn(1, tree["bar"]) def test_children_have_their_errors_dicts_built(self): e1, e2 = ( exceptions.ValidationError("1", validator="foo", path=["bar", 0]), exceptions.ValidationError("2", validator="quux", path=["bar", 0]), ) tree = exceptions.ErrorTree([e1, e2]) self.assertEqual(tree["bar"][0].errors, {"foo": e1, "quux": e2}) def test_multiple_errors_with_instance(self): e1, e2 = ( exceptions.ValidationError( "1", validator="foo", path=["bar", "bar2"], instance="i1"), exceptions.ValidationError( "2", validator="quux", path=["foobar", 2], instance="i2"), ) exceptions.ErrorTree([e1, e2]) def test_it_does_not_contain_subtrees_that_are_not_in_the_instance(self): error = exceptions.ValidationError("123", validator="foo", instance=[]) tree = exceptions.ErrorTree([error]) with self.assertRaises(IndexError): tree[0] def test_if_its_in_the_tree_anyhow_it_does_not_raise_an_error(self): """ If a keyword refers to a path that isn't in the instance, the tree still properly returns a subtree for that path. """ error = exceptions.ValidationError( "a message", validator="foo", instance={}, path=["foo"], ) tree = exceptions.ErrorTree([error]) self.assertIsInstance(tree["foo"], exceptions.ErrorTree) def test_repr_single(self): error = exceptions.ValidationError( "1", validator="foo", path=["bar", "bar2"], instance="i1", ) tree = exceptions.ErrorTree([error]) self.assertEqual(repr(tree), "") def test_repr_multiple(self): e1, e2 = ( exceptions.ValidationError( "1", validator="foo", path=["bar", "bar2"], instance="i1"), exceptions.ValidationError( "2", validator="quux", path=["foobar", 2], instance="i2"), ) tree = exceptions.ErrorTree([e1, e2]) self.assertEqual(repr(tree), "") def test_repr_empty(self): tree = exceptions.ErrorTree([]) self.assertEqual(repr(tree), "") class TestErrorInitReprStr(TestCase): def make_error(self, **kwargs): defaults = dict( message="hello", validator="type", validator_value="string", instance=5, schema={"type": "string"}, ) defaults.update(kwargs) return exceptions.ValidationError(**defaults) def assertShows(self, expected, **kwargs): expected = textwrap.dedent(expected).rstrip("\n") error = self.make_error(**kwargs) message_line, _, rest = str(error).partition("\n") self.assertEqual(message_line, error.message) self.assertEqual(rest, expected) def test_it_calls_super_and_sets_args(self): error = self.make_error() self.assertGreater(len(error.args), 1) def test_repr(self): self.assertEqual( repr(exceptions.ValidationError(message="Hello!")), "", ) def test_unset_error(self): error = exceptions.ValidationError("message") self.assertEqual(str(error), "message") kwargs = { "validator": "type", "validator_value": "string", "instance": 5, "schema": {"type": "string"}, } # Just the message should show if any of the attributes are unset for attr in kwargs: k = dict(kwargs) del k[attr] error = exceptions.ValidationError("message", **k) self.assertEqual(str(error), "message") def test_empty_paths(self): self.assertShows( """ Failed validating 'type' in schema: {'type': 'string'} On instance: 5 """, path=[], schema_path=[], ) def test_one_item_paths(self): self.assertShows( """ Failed validating 'type' in schema: {'type': 'string'} On instance[0]: 5 """, path=[0], schema_path=["items"], ) def test_multiple_item_paths(self): self.assertShows( """ Failed validating 'type' in schema['items'][0]: {'type': 'string'} On instance[0]['a']: 5 """, path=[0, "a"], schema_path=["items", 0, 1], ) def test_uses_pprint(self): self.assertShows( """ Failed validating 'maxLength' in schema: {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10, 11: 11, 12: 12, 13: 13, 14: 14, 15: 15, 16: 16, 17: 17, 18: 18, 19: 19} On instance: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24] """, instance=list(range(25)), schema=dict(zip(range(20), range(20))), validator="maxLength", ) def test_str_works_with_instances_having_overriden_eq_operator(self): """ Check for #164 which rendered exceptions unusable when a `ValidationError` involved instances with an `__eq__` method that returned truthy values. """ class DontEQMeBro: def __eq__(this, other): # pragma: no cover self.fail("Don't!") def __ne__(this, other): # pragma: no cover self.fail("Don't!") instance = DontEQMeBro() error = exceptions.ValidationError( "a message", validator="foo", instance=instance, validator_value="some", schema="schema", ) self.assertIn(repr(instance), str(error)) class TestHashable(TestCase): def test_hashable(self): set([exceptions.ValidationError("")]) set([exceptions.SchemaError("")]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/tests/test_format.py0000644000175100001770000000737214653725311021331 0ustar00runnerdocker""" Tests for the parts of asdf._jsonschema related to the :kw:`format` keyword. """ from unittest import TestCase from asdf._jsonschema import FormatChecker, FormatError, ValidationError from asdf._jsonschema.validators import Draft4Validator BOOM = ValueError("Boom!") BANG = ZeroDivisionError("Bang!") def boom(thing): if thing == "bang": raise BANG raise BOOM class TestFormatChecker(TestCase): def test_it_can_validate_no_formats(self): checker = FormatChecker(formats=()) self.assertFalse(checker.checkers) def test_it_raises_a_key_error_for_unknown_formats(self): with self.assertRaises(KeyError): FormatChecker(formats=["o noes"]) def test_it_can_register_cls_checkers(self): original = dict(FormatChecker.checkers) self.addCleanup(FormatChecker.checkers.pop, "boom") with self.assertWarns(DeprecationWarning): FormatChecker.cls_checks("boom")(boom) self.assertEqual( FormatChecker.checkers, dict(original, boom=(boom, ())), ) def test_it_can_register_checkers(self): checker = FormatChecker() checker.checks("boom")(boom) self.assertEqual( checker.checkers, dict(FormatChecker.checkers, boom=(boom, ())), ) def test_it_catches_registered_errors(self): checker = FormatChecker() checker.checks("boom", raises=type(BOOM))(boom) with self.assertRaises(FormatError) as cm: checker.check(instance=12, format="boom") self.assertIs(cm.exception.cause, BOOM) self.assertIs(cm.exception.__cause__, BOOM) # Unregistered errors should not be caught with self.assertRaises(type(BANG)): checker.check(instance="bang", format="boom") def test_format_error_causes_become_validation_error_causes(self): checker = FormatChecker() checker.checks("boom", raises=ValueError)(boom) validator = Draft4Validator({"format": "boom"}, format_checker=checker) with self.assertRaises(ValidationError) as cm: validator.validate("BOOM") self.assertIs(cm.exception.cause, BOOM) self.assertIs(cm.exception.__cause__, BOOM) def test_format_checkers_come_with_defaults(self): # This is bad :/ but relied upon. # The docs for quite awhile recommended people do things like # validate(..., format_checker=FormatChecker()) # We should change that, but we can't without deprecation... checker = FormatChecker() with self.assertRaises(FormatError): checker.check(instance="not-an-ipv4", format="ipv4") def test_repr(self): checker = FormatChecker(formats=()) checker.checks("foo")(lambda thing: True) # pragma: no cover checker.checks("bar")(lambda thing: True) # pragma: no cover checker.checks("baz")(lambda thing: True) # pragma: no cover self.assertEqual( repr(checker), "", ) def test_duration_format(self): try: from asdf._jsonschema._format import is_duration # noqa: F401 except ImportError: # pragma: no cover pass else: checker = FormatChecker() self.assertTrue(checker.conforms(1, "duration")) self.assertTrue(checker.conforms("P4Y", "duration")) self.assertFalse(checker.conforms("test", "duration")) def test_uuid_format(self): checker = FormatChecker() self.assertTrue(checker.conforms(1, "uuid")) self.assertTrue( checker.conforms("6e6659ec-4503-4428-9f03-2e2ea4d6c278", "uuid"), ) self.assertFalse(checker.conforms("test", "uuid")) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/tests/test_jsonschema_test_suite.py0000644000175100001770000004346414653725311024445 0ustar00runnerdocker""" Test runner for the JSON Schema official test suite Tests comprehensive correctness of each draft's validator. See https://github.com/json-schema-org/JSON-Schema-Test-Suite for details. """ import sys from asdf._jsonschema.tests._helpers import bug from asdf._jsonschema.tests._suite import Suite import asdf._jsonschema SUITE = Suite() DRAFT3 = SUITE.version(name="draft3") DRAFT4 = SUITE.version(name="draft4") DRAFT6 = SUITE.version(name="draft6") DRAFT7 = SUITE.version(name="draft7") DRAFT201909 = SUITE.version(name="draft2019-09") DRAFT202012 = SUITE.version(name="draft2020-12") def skip(message, **kwargs): def skipper(test): if all(value == getattr(test, attr) for attr, value in kwargs.items()): return message return skipper def missing_format(Validator): def missing_format(test): # pragma: no cover schema = test.schema if ( schema is True or schema is False or "format" not in schema or schema["format"] in Validator.FORMAT_CHECKER.checkers or test.valid ): return return "Format checker {0!r} not found.".format(schema["format"]) return missing_format def complex_email_validation(test): if test.subject != "email": return message = "Complex email validation is (intentionally) unsupported." return skip( message=message, description="an invalid domain", )(test) or skip( message=message, description="an invalid IPv4-address-literal", )(test) or skip( message=message, description="dot after local part is not valid", )(test) or skip( message=message, description="dot before local part is not valid", )(test) or skip( message=message, description="two subsequent dots inside local part are not valid", )(test) is_narrow_build = sys.maxunicode == 2 ** 16 - 1 if is_narrow_build: # pragma: no cover message = "Not running surrogate Unicode case, this Python is narrow." def narrow_unicode_build(test): # pragma: no cover return skip( message=message, description=( "one supplementary Unicode code point is not long enough" ), )(test) or skip( message=message, description="two supplementary Unicode code points is long enough", )(test) else: def narrow_unicode_build(test): # pragma: no cover return if sys.version_info < (3, 9): # pragma: no cover message = "Rejecting leading zeros is 3.9+" allowed_leading_zeros = skip( message=message, subject="ipv4", description="invalid leading zeroes, as they are treated as octals", ) else: def allowed_leading_zeros(test): # pragma: no cover return def leap_second(test): message = "Leap seconds are unsupported." return skip( message=message, subject="time", description="a valid time string with leap second", )(test) or skip( message=message, subject="time", description="a valid time string with leap second, Zulu", )(test) or skip( message=message, subject="time", description="a valid time string with leap second with offset", )(test) or skip( message=message, subject="time", description="valid leap second, positive time-offset", )(test) or skip( message=message, subject="time", description="valid leap second, negative time-offset", )(test) or skip( message=message, subject="time", description="valid leap second, large positive time-offset", )(test) or skip( message=message, subject="time", description="valid leap second, large negative time-offset", )(test) or skip( message=message, subject="time", description="valid leap second, zero time-offset", )(test) or skip( message=message, subject="date-time", description="a valid date-time with a leap second, UTC", )(test) or skip( message=message, subject="date-time", description="a valid date-time with a leap second, with minus offset", )(test) TestDraft3 = DRAFT3.to_unittest_testcase( DRAFT3.tests(), DRAFT3.format_tests(), DRAFT3.optional_tests_of(name="bignum"), DRAFT3.optional_tests_of(name="non-bmp-regex"), DRAFT3.optional_tests_of(name="zeroTerminatedFloats"), Validator=asdf._jsonschema.Draft3Validator, format_checker=asdf._jsonschema.Draft3Validator.FORMAT_CHECKER, skip=lambda test: ( narrow_unicode_build(test) or missing_format(asdf._jsonschema.Draft3Validator)(test) or complex_email_validation(test) or skip( message=bug(), subject="ref", valid=False, case_description=( "$ref prevents a sibling id from changing the base uri" ), )(test) ), ) TestDraft4 = DRAFT4.to_unittest_testcase( DRAFT4.tests(), DRAFT4.format_tests(), DRAFT4.optional_tests_of(name="bignum"), DRAFT4.optional_tests_of(name="float-overflow"), DRAFT4.optional_tests_of(name="non-bmp-regex"), DRAFT4.optional_tests_of(name="zeroTerminatedFloats"), Validator=asdf._jsonschema.Draft4Validator, format_checker=asdf._jsonschema.Draft4Validator.FORMAT_CHECKER, skip=lambda test: ( narrow_unicode_build(test) or allowed_leading_zeros(test) or leap_second(test) or missing_format(asdf._jsonschema.Draft4Validator)(test) or complex_email_validation(test) or skip( message=bug(), subject="ref", case_description="Recursive references between schemas", )(test) or skip( message=bug(), subject="ref", case_description=( "Location-independent identifier with " "base URI change in subschema" ), )(test) or skip( message=bug(), subject="ref", case_description=( "$ref prevents a sibling id from changing the base uri" ), )(test) or skip( message=bug(), subject="id", description="match $ref to id", )(test) or skip( message=bug(), subject="id", description="no match on enum or $ref to id", )(test) or skip( message=bug(), subject="refRemote", case_description="base URI change - change folder in subschema", )(test) or skip( message=bug(), subject="ref", case_description=( "id must be resolved against nearest parent, " "not just immediate parent" ), )(test) ), ) TestDraft6 = DRAFT6.to_unittest_testcase( DRAFT6.tests(), DRAFT6.format_tests(), DRAFT6.optional_tests_of(name="bignum"), DRAFT6.optional_tests_of(name="float-overflow"), DRAFT6.optional_tests_of(name="non-bmp-regex"), Validator=asdf._jsonschema.Draft6Validator, format_checker=asdf._jsonschema.Draft6Validator.FORMAT_CHECKER, skip=lambda test: ( narrow_unicode_build(test) or allowed_leading_zeros(test) or leap_second(test) or missing_format(asdf._jsonschema.Draft6Validator)(test) or complex_email_validation(test) or skip( message=bug(), subject="refRemote", case_description="base URI change - change folder in subschema", )(test) ), ) TestDraft7 = DRAFT7.to_unittest_testcase( DRAFT7.tests(), DRAFT7.format_tests(), DRAFT7.optional_tests_of(name="bignum"), DRAFT7.optional_tests_of(name="cross-draft"), DRAFT7.optional_tests_of(name="float-overflow"), DRAFT7.optional_tests_of(name="non-bmp-regex"), Validator=asdf._jsonschema.Draft7Validator, format_checker=asdf._jsonschema.Draft7Validator.FORMAT_CHECKER, skip=lambda test: ( narrow_unicode_build(test) or allowed_leading_zeros(test) or leap_second(test) or missing_format(asdf._jsonschema.Draft7Validator)(test) or complex_email_validation(test) or skip( message=bug(), subject="refRemote", case_description="base URI change - change folder in subschema", )(test) or skip( message=bug(), subject="ref", case_description=( "$id must be resolved against nearest parent, " "not just immediate parent" ), )(test) ), ) TestDraft201909 = DRAFT201909.to_unittest_testcase( DRAFT201909.tests(), DRAFT201909.optional_tests_of(name="bignum"), DRAFT201909.optional_tests_of(name="cross-draft"), DRAFT201909.optional_tests_of(name="float-overflow"), DRAFT201909.optional_tests_of(name="non-bmp-regex"), DRAFT201909.optional_tests_of(name="refOfUnknownKeyword"), Validator=asdf._jsonschema.Draft201909Validator, skip=lambda test: ( skip( message="recursiveRef support isn't working yet.", subject="recursiveRef", case_description=( "$recursiveRef with no $recursiveAnchor in " "the initial target schema resource" ), description=( "leaf node does not match: recursion uses the inner schema" ), )(test) or skip( message="recursiveRef support isn't working yet.", subject="recursiveRef", description="leaf node matches: recursion uses the inner schema", )(test) or skip( message="recursiveRef support isn't working yet.", subject="recursiveRef", case_description=( "dynamic $recursiveRef destination (not predictable " "at schema compile time)" ), description="integer node", )(test) or skip( message="recursiveRef support isn't working yet.", subject="recursiveRef", case_description=( "multiple dynamic paths to the $recursiveRef keyword" ), description="recurse to integerNode - floats are not allowed", )(test) or skip( message="recursiveRef support isn't working yet.", subject="recursiveRef", description="integer does not match as a property value", )(test) or skip( message="recursiveRef support isn't working yet.", subject="recursiveRef", description=( "leaf node does not match: " "recursion only uses inner schema" ), )(test) or skip( message="recursiveRef support isn't working yet.", subject="recursiveRef", description=( "leaf node matches: " "recursion only uses inner schema" ), )(test) or skip( message="recursiveRef support isn't working yet.", subject="recursiveRef", description=( "two levels, integer does not match as a property value" ), )(test) or skip( message="recursiveRef support isn't working yet.", subject="recursiveRef", description="recursive mismatch", )(test) or skip( message="recursiveRef support isn't working yet.", subject="recursiveRef", description="two levels, no match", )(test) or skip( message="recursiveRef support isn't working yet.", subject="id", case_description=( "Invalid use of fragments in location-independent $id" ), )(test) or skip( message="dynamicRef support isn't fully working yet.", subject="defs", description="invalid definition schema", )(test) or skip( message="dynamicRef support isn't fully working yet.", subject="anchor", case_description="same $anchor with different base uri", )(test) or skip( message="Vocabulary support is still in-progress.", subject="vocabulary", description=( "no validation: invalid number, but it still validates" ), )(test) or skip( message=bug(), subject="ref", case_description=( "$id must be resolved against nearest parent, " "not just immediate parent" ), )(test) or skip( message=bug(), subject="refRemote", case_description="remote HTTP ref with nested absolute ref", )(test) ), ) TestDraft201909Format = DRAFT201909.to_unittest_testcase( DRAFT201909.format_tests(), name="TestDraft201909Format", Validator=asdf._jsonschema.Draft201909Validator, format_checker=asdf._jsonschema.Draft201909Validator.FORMAT_CHECKER, skip=lambda test: ( complex_email_validation(test) or allowed_leading_zeros(test) or leap_second(test) or missing_format(asdf._jsonschema.Draft201909Validator)(test) or complex_email_validation(test) ), ) TestDraft202012 = DRAFT202012.to_unittest_testcase( DRAFT202012.tests(), DRAFT202012.optional_tests_of(name="bignum"), DRAFT202012.optional_tests_of(name="cross-draft"), DRAFT202012.optional_tests_of(name="float-overflow"), DRAFT202012.optional_tests_of(name="non-bmp-regex"), DRAFT202012.optional_tests_of(name="refOfUnknownKeyword"), Validator=asdf._jsonschema.Draft202012Validator, skip=lambda test: ( narrow_unicode_build(test) or skip( message="dynamicRef support isn't fully working yet.", subject="dynamicRef", description="The recursive part is not valid against the root", )(test) or skip( message="dynamicRef support isn't fully working yet.", subject="dynamicRef", description="incorrect extended schema", case_description=( "$ref and $dynamicAnchor are independent of order - " "$defs first" ), )(test) or skip( message="dynamicRef support isn't fully working yet.", subject="dynamicRef", description="correct extended schema", case_description=( "$ref and $dynamicAnchor are independent of order - " "$defs first" ), )(test) or skip( message="dynamicRef support isn't fully working yet.", subject="dynamicRef", description="correct extended schema", case_description=( "$ref and $dynamicAnchor are independent of order - $ref first" ), )(test) or skip( message="dynamicRef support isn't fully working yet.", subject="dynamicRef", description="incorrect extended schema", case_description=( "$ref and $dynamicAnchor are independent of order - $ref first" ), )(test) or skip( message="dynamicRef support isn't fully working yet.", subject="dynamicRef", description=( "/then/$defs/thingy is the final stop for the $dynamicRef" ), )(test) or skip( message="dynamicRef support isn't fully working yet.", subject="dynamicRef", description=( "string matches /$defs/thingy, but the $dynamicRef " "does not stop here" ), )(test) or skip( message="dynamicRef support isn't fully working yet.", subject="dynamicRef", description=( "string matches /$defs/thingy, but the $dynamicRef " "does not stop here" ), )(test) or skip( message="dynamicRef support isn't fully working yet.", subject="dynamicRef", description="recurse to integerNode - floats are not allowed", )(test) or skip( message="dynamicRef support isn't fully working yet.", subject="defs", description="invalid definition schema", )(test) or skip( message="dynamicRef support isn't fully working yet.", subject="anchor", case_description="same $anchor with different base uri", )(test) or skip( message="Vocabulary support is still in-progress.", subject="vocabulary", description=( "no validation: invalid number, but it still validates" ), )(test) or skip( message=bug(), subject="ref", case_description=( "$id must be resolved against nearest parent, " "not just immediate parent" ), )(test) or skip( message=bug(), subject="refRemote", case_description="remote HTTP ref with nested absolute ref", )(test) ), ) TestDraft202012Format = DRAFT202012.to_unittest_testcase( DRAFT202012.format_tests(), name="TestDraft202012Format", Validator=asdf._jsonschema.Draft202012Validator, format_checker=asdf._jsonschema.Draft202012Validator.FORMAT_CHECKER, skip=lambda test: ( complex_email_validation(test) or allowed_leading_zeros(test) or leap_second(test) or missing_format(asdf._jsonschema.Draft202012Validator)(test) or complex_email_validation(test) ), ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/tests/test_types.py0000644000175100001770000001553714653725311021207 0ustar00runnerdocker""" Tests for the `TypeChecker`-based type interface. The actual correctness of the type checking is handled in `test_jsonschema_test_suite`; these tests check that TypeChecker functions correctly at a more granular level. """ from collections import namedtuple from unittest import TestCase from asdf._jsonschema import ValidationError, _validators from asdf._jsonschema._types import TypeChecker from asdf._jsonschema.exceptions import UndefinedTypeCheck, UnknownType from asdf._jsonschema.validators import Draft202012Validator, extend def equals_2(checker, instance): return instance == 2 def is_namedtuple(instance): return isinstance(instance, tuple) and getattr(instance, "_fields", None) def is_object_or_named_tuple(checker, instance): if Draft202012Validator.TYPE_CHECKER.is_type(instance, "object"): return True return is_namedtuple(instance) class TestTypeChecker(TestCase): def test_is_type(self): checker = TypeChecker({"two": equals_2}) self.assertEqual( ( checker.is_type(instance=2, type="two"), checker.is_type(instance="bar", type="two"), ), (True, False), ) def test_is_unknown_type(self): with self.assertRaises(UndefinedTypeCheck) as e: TypeChecker().is_type(4, "foobar") self.assertIn( "'foobar' is unknown to this type checker", str(e.exception), ) self.assertTrue( e.exception.__suppress_context__, msg="Expected the internal KeyError to be hidden.", ) def test_checks_can_be_added_at_init(self): checker = TypeChecker({"two": equals_2}) self.assertEqual(checker, TypeChecker().redefine("two", equals_2)) def test_redefine_existing_type(self): self.assertEqual( TypeChecker().redefine("two", object()).redefine("two", equals_2), TypeChecker().redefine("two", equals_2), ) def test_remove(self): self.assertEqual( TypeChecker({"two": equals_2}).remove("two"), TypeChecker(), ) def test_remove_unknown_type(self): with self.assertRaises(UndefinedTypeCheck) as context: TypeChecker().remove("foobar") self.assertIn("foobar", str(context.exception)) def test_redefine_many(self): self.assertEqual( TypeChecker().redefine_many({"foo": int, "bar": str}), TypeChecker().redefine("foo", int).redefine("bar", str), ) def test_remove_multiple(self): self.assertEqual( TypeChecker({"foo": int, "bar": str}).remove("foo", "bar"), TypeChecker(), ) def test_type_check_can_raise_key_error(self): """ Make sure no one writes: try: self._type_checkers[type](...) except KeyError: ignoring the fact that the function itself can raise that. """ error = KeyError("Stuff") def raises_keyerror(checker, instance): raise error with self.assertRaises(KeyError) as context: TypeChecker({"foo": raises_keyerror}).is_type(4, "foo") self.assertIs(context.exception, error) def test_repr(self): checker = TypeChecker({"foo": is_namedtuple, "bar": is_namedtuple}) self.assertEqual(repr(checker), "") class TestCustomTypes(TestCase): def test_simple_type_can_be_extended(self): def int_or_str_int(checker, instance): if not isinstance(instance, (int, str)): return False try: int(instance) except ValueError: return False return True CustomValidator = extend( Draft202012Validator, type_checker=Draft202012Validator.TYPE_CHECKER.redefine( "integer", int_or_str_int, ), ) validator = CustomValidator({"type": "integer"}) validator.validate(4) validator.validate("4") with self.assertRaises(ValidationError): validator.validate(4.4) with self.assertRaises(ValidationError): validator.validate("foo") def test_object_can_be_extended(self): schema = {"type": "object"} Point = namedtuple("Point", ["x", "y"]) type_checker = Draft202012Validator.TYPE_CHECKER.redefine( "object", is_object_or_named_tuple, ) CustomValidator = extend( Draft202012Validator, type_checker=type_checker, ) validator = CustomValidator(schema) validator.validate(Point(x=4, y=5)) def test_object_extensions_require_custom_validators(self): schema = {"type": "object", "required": ["x"]} type_checker = Draft202012Validator.TYPE_CHECKER.redefine( "object", is_object_or_named_tuple, ) CustomValidator = extend( Draft202012Validator, type_checker=type_checker, ) validator = CustomValidator(schema) Point = namedtuple("Point", ["x", "y"]) # Cannot handle required with self.assertRaises(ValidationError): validator.validate(Point(x=4, y=5)) def test_object_extensions_can_handle_custom_validators(self): schema = { "type": "object", "required": ["x"], "properties": {"x": {"type": "integer"}}, } type_checker = Draft202012Validator.TYPE_CHECKER.redefine( "object", is_object_or_named_tuple, ) def coerce_named_tuple(fn): def coerced(validator, value, instance, schema): if is_namedtuple(instance): instance = instance._asdict() return fn(validator, value, instance, schema) return coerced required = coerce_named_tuple(_validators.required) properties = coerce_named_tuple(_validators.properties) CustomValidator = extend( Draft202012Validator, type_checker=type_checker, validators={"required": required, "properties": properties}, ) validator = CustomValidator(schema) Point = namedtuple("Point", ["x", "y"]) # Can now process required and properties validator.validate(Point(x=4, y=5)) with self.assertRaises(ValidationError): validator.validate(Point(x="not an integer", y=5)) # As well as still handle objects. validator.validate({"x": 4, "y": 5}) with self.assertRaises(ValidationError): validator.validate({"x": "not an integer", "y": 5}) def test_unknown_type(self): with self.assertRaises(UnknownType) as e: Draft202012Validator({}).is_type(12, "some unknown type") self.assertIn("'some unknown type'", str(e.exception)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/tests/test_utils.py0000644000175100001770000000725314653725311021177 0ustar00runnerdockerfrom unittest import TestCase from asdf._jsonschema._utils import equal class TestEqual(TestCase): def test_none(self): self.assertTrue(equal(None, None)) class TestDictEqual(TestCase): def test_equal_dictionaries(self): dict_1 = {"a": "b", "c": "d"} dict_2 = {"c": "d", "a": "b"} self.assertTrue(equal(dict_1, dict_2)) def test_missing_key(self): dict_1 = {"a": "b", "c": "d"} dict_2 = {"c": "d", "x": "b"} self.assertFalse(equal(dict_1, dict_2)) def test_additional_key(self): dict_1 = {"a": "b", "c": "d"} dict_2 = {"c": "d", "a": "b", "x": "x"} self.assertFalse(equal(dict_1, dict_2)) def test_missing_value(self): dict_1 = {"a": "b", "c": "d"} dict_2 = {"c": "d", "a": "x"} self.assertFalse(equal(dict_1, dict_2)) def test_empty_dictionaries(self): dict_1 = {} dict_2 = {} self.assertTrue(equal(dict_1, dict_2)) def test_one_none(self): dict_1 = None dict_2 = {"a": "b", "c": "d"} self.assertFalse(equal(dict_1, dict_2)) def test_same_item(self): dict_1 = {"a": "b", "c": "d"} self.assertTrue(equal(dict_1, dict_1)) def test_nested_equal(self): dict_1 = {"a": {"a": "b", "c": "d"}, "c": "d"} dict_2 = {"c": "d", "a": {"a": "b", "c": "d"}} self.assertTrue(equal(dict_1, dict_2)) def test_nested_dict_unequal(self): dict_1 = {"a": {"a": "b", "c": "d"}, "c": "d"} dict_2 = {"c": "d", "a": {"a": "b", "c": "x"}} self.assertFalse(equal(dict_1, dict_2)) def test_mixed_nested_equal(self): dict_1 = {"a": ["a", "b", "c", "d"], "c": "d"} dict_2 = {"c": "d", "a": ["a", "b", "c", "d"]} self.assertTrue(equal(dict_1, dict_2)) def test_nested_list_unequal(self): dict_1 = {"a": ["a", "b", "c", "d"], "c": "d"} dict_2 = {"c": "d", "a": ["b", "c", "d", "a"]} self.assertFalse(equal(dict_1, dict_2)) class TestListEqual(TestCase): def test_equal_lists(self): list_1 = ["a", "b", "c"] list_2 = ["a", "b", "c"] self.assertTrue(equal(list_1, list_2)) def test_unsorted_lists(self): list_1 = ["a", "b", "c"] list_2 = ["b", "b", "a"] self.assertFalse(equal(list_1, list_2)) def test_first_list_larger(self): list_1 = ["a", "b", "c"] list_2 = ["a", "b"] self.assertFalse(equal(list_1, list_2)) def test_second_list_larger(self): list_1 = ["a", "b"] list_2 = ["a", "b", "c"] self.assertFalse(equal(list_1, list_2)) def test_list_with_none_unequal(self): list_1 = ["a", "b", None] list_2 = ["a", "b", "c"] self.assertFalse(equal(list_1, list_2)) list_1 = ["a", "b", None] list_2 = [None, "b", "c"] self.assertFalse(equal(list_1, list_2)) def test_list_with_none_equal(self): list_1 = ["a", None, "c"] list_2 = ["a", None, "c"] self.assertTrue(equal(list_1, list_2)) def test_empty_list(self): list_1 = [] list_2 = [] self.assertTrue(equal(list_1, list_2)) def test_one_none(self): list_1 = None list_2 = [] self.assertFalse(equal(list_1, list_2)) def test_same_list(self): list_1 = ["a", "b", "c"] self.assertTrue(equal(list_1, list_1)) def test_equal_nested_lists(self): list_1 = ["a", ["b", "c"], "d"] list_2 = ["a", ["b", "c"], "d"] self.assertTrue(equal(list_1, list_2)) def test_unequal_nested_lists(self): list_1 = ["a", ["b", "c"], "d"] list_2 = ["a", [], "c"] self.assertFalse(equal(list_1, list_2)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/tests/test_validators.py0000644000175100001770000022665714653725311022222 0ustar00runnerdockerfrom __future__ import annotations from collections import deque, namedtuple from contextlib import contextmanager from decimal import Decimal from io import BytesIO from unittest import TestCase, mock from urllib.request import pathname2url import json import os import sys import tempfile import unittest import warnings import attr from asdf._jsonschema import ( FormatChecker, TypeChecker, exceptions, protocols, validators, ) from asdf._jsonschema.tests._helpers import bug def fail(validator, errors, instance, schema): for each in errors: each.setdefault("message", "You told me to fail!") yield exceptions.ValidationError(**each) class TestCreateAndExtend(TestCase): def setUp(self): self.addCleanup( self.assertEqual, validators._META_SCHEMAS, dict(validators._META_SCHEMAS), ) self.meta_schema = {"$id": "some://meta/schema"} self.validators = {"fail": fail} self.type_checker = TypeChecker() self.Validator = validators.create( meta_schema=self.meta_schema, validators=self.validators, type_checker=self.type_checker, ) def test_attrs(self): self.assertEqual( ( self.Validator.VALIDATORS, self.Validator.META_SCHEMA, self.Validator.TYPE_CHECKER, ), ( self.validators, self.meta_schema, self.type_checker, ), ) def test_init(self): schema = {"fail": []} self.assertEqual(self.Validator(schema).schema, schema) def test_iter_errors_successful(self): schema = {"fail": []} validator = self.Validator(schema) errors = list(validator.iter_errors("hello")) self.assertEqual(errors, []) def test_iter_errors_one_error(self): schema = {"fail": [{"message": "Whoops!"}]} validator = self.Validator(schema) expected_error = exceptions.ValidationError( "Whoops!", instance="goodbye", schema=schema, validator="fail", validator_value=[{"message": "Whoops!"}], schema_path=deque(["fail"]), ) errors = list(validator.iter_errors("goodbye")) self.assertEqual(len(errors), 1) self.assertEqual(errors[0]._contents(), expected_error._contents()) def test_iter_errors_multiple_errors(self): schema = { "fail": [ {"message": "First"}, {"message": "Second!", "validator": "asdf"}, {"message": "Third"}, ], } validator = self.Validator(schema) errors = list(validator.iter_errors("goodbye")) self.assertEqual(len(errors), 3) def test_if_a_version_is_provided_it_is_registered(self): Validator = validators.create( meta_schema={"$id": "something"}, version="my version", ) self.addCleanup(validators._META_SCHEMAS.pop, "something") self.assertEqual(Validator.__name__, "MyVersionValidator") self.assertEqual(Validator.__qualname__, "MyVersionValidator") def test_repr(self): Validator = validators.create( meta_schema={"$id": "something"}, version="my version", ) self.addCleanup(validators._META_SCHEMAS.pop, "something") self.assertEqual( repr(Validator({})), "MyVersionValidator(schema={}, format_checker=None)", ) def test_long_repr(self): Validator = validators.create( meta_schema={"$id": "something"}, version="my version", ) self.addCleanup(validators._META_SCHEMAS.pop, "something") self.assertEqual( repr(Validator({"a": list(range(1000))})), ( "MyVersionValidator(schema={'a': [0, 1, 2, 3, 4, 5, ...]}, " "format_checker=None)" ), ) def test_repr_no_version(self): Validator = validators.create(meta_schema={}) self.assertEqual( repr(Validator({})), "Validator(schema={}, format_checker=None)", ) def test_dashes_are_stripped_from_validator_names(self): Validator = validators.create( meta_schema={"$id": "something"}, version="foo-bar", ) self.addCleanup(validators._META_SCHEMAS.pop, "something") self.assertEqual(Validator.__qualname__, "FooBarValidator") def test_if_a_version_is_not_provided_it_is_not_registered(self): original = dict(validators._META_SCHEMAS) validators.create(meta_schema={"id": "id"}) self.assertEqual(validators._META_SCHEMAS, original) def test_validates_registers_meta_schema_id(self): meta_schema_key = "meta schema id" my_meta_schema = {"id": meta_schema_key} validators.create( meta_schema=my_meta_schema, version="my version", id_of=lambda s: s.get("id", ""), ) self.addCleanup(validators._META_SCHEMAS.pop, meta_schema_key) self.assertIn(meta_schema_key, validators._META_SCHEMAS) def test_validates_registers_meta_schema_draft6_id(self): meta_schema_key = "meta schema $id" my_meta_schema = {"$id": meta_schema_key} validators.create( meta_schema=my_meta_schema, version="my version", ) self.addCleanup(validators._META_SCHEMAS.pop, meta_schema_key) self.assertIn(meta_schema_key, validators._META_SCHEMAS) def test_create_default_types(self): Validator = validators.create(meta_schema={}, validators=()) self.assertTrue( all( Validator({}).is_type(instance=instance, type=type) for type, instance in [ ("array", []), ("boolean", True), ("integer", 12), ("null", None), ("number", 12.0), ("object", {}), ("string", "foo"), ] ), ) def test_check_schema_with_different_metaschema(self): """ One can create a validator class whose metaschema uses a different dialect than itself. """ NoEmptySchemasValidator = validators.create( meta_schema={ "$schema": validators.Draft202012Validator.META_SCHEMA["$id"], "not": {"const": {}}, }, ) NoEmptySchemasValidator.check_schema({"foo": "bar"}) with self.assertRaises(exceptions.SchemaError): NoEmptySchemasValidator.check_schema({}) NoEmptySchemasValidator({"foo": "bar"}).validate("foo") def test_check_schema_with_different_metaschema_defaults_to_self(self): """ A validator whose metaschema doesn't declare $schema defaults to its own validation behavior, not the latest "normal" specification. """ NoEmptySchemasValidator = validators.create( meta_schema={"fail": [{"message": "Meta schema whoops!"}]}, validators={"fail": fail}, ) with self.assertRaises(exceptions.SchemaError): NoEmptySchemasValidator.check_schema({}) def test_extend(self): original = dict(self.Validator.VALIDATORS) new = object() Extended = validators.extend( self.Validator, validators={"new": new}, ) self.assertEqual( ( Extended.VALIDATORS, Extended.META_SCHEMA, Extended.TYPE_CHECKER, self.Validator.VALIDATORS, ), ( dict(original, new=new), self.Validator.META_SCHEMA, self.Validator.TYPE_CHECKER, original, ), ) def test_extend_idof(self): """ Extending a validator preserves its notion of schema IDs. """ def id_of(schema): return schema.get("__test__", self.Validator.ID_OF(schema)) correct_id = "the://correct/id/" meta_schema = { "$id": "the://wrong/id/", "__test__": correct_id, } Original = validators.create( meta_schema=meta_schema, validators=self.validators, type_checker=self.type_checker, id_of=id_of, ) self.assertEqual(Original.ID_OF(Original.META_SCHEMA), correct_id) Derived = validators.extend(Original) self.assertEqual(Derived.ID_OF(Derived.META_SCHEMA), correct_id) class TestValidationErrorMessages(TestCase): def message_for(self, instance, schema, *args, **kwargs): cls = kwargs.pop("cls", validators._LATEST_VERSION) cls.check_schema(schema) validator = cls(schema, *args, **kwargs) errors = list(validator.iter_errors(instance)) self.assertTrue(errors, msg=f"No errors were raised for {instance!r}") self.assertEqual( len(errors), 1, msg=f"Expected exactly one error, found {errors!r}", ) return errors[0].message def test_single_type_failure(self): message = self.message_for(instance=1, schema={"type": "string"}) self.assertEqual(message, "1 is not of type 'string'") def test_single_type_list_failure(self): message = self.message_for(instance=1, schema={"type": ["string"]}) self.assertEqual(message, "1 is not of type 'string'") def test_multiple_type_failure(self): types = "string", "object" message = self.message_for(instance=1, schema={"type": list(types)}) self.assertEqual(message, "1 is not of type 'string', 'object'") def test_object_with_named_type_failure(self): schema = {"type": [{"name": "Foo", "minimum": 3}]} message = self.message_for( instance=1, schema=schema, cls=validators.Draft3Validator, ) self.assertEqual(message, "1 is not of type 'Foo'") def test_minimum(self): message = self.message_for(instance=1, schema={"minimum": 2}) self.assertEqual(message, "1 is less than the minimum of 2") def test_maximum(self): message = self.message_for(instance=1, schema={"maximum": 0}) self.assertEqual(message, "1 is greater than the maximum of 0") def test_dependencies_single_element(self): depend, on = "bar", "foo" schema = {"dependencies": {depend: on}} message = self.message_for( instance={"bar": 2}, schema=schema, cls=validators.Draft3Validator, ) self.assertEqual(message, "'foo' is a dependency of 'bar'") def test_object_without_title_type_failure_draft3(self): type = {"type": [{"minimum": 3}]} message = self.message_for( instance=1, schema={"type": [type]}, cls=validators.Draft3Validator, ) self.assertEqual( message, "1 is not of type {'type': [{'minimum': 3}]}", ) def test_dependencies_list_draft3(self): depend, on = "bar", "foo" schema = {"dependencies": {depend: [on]}} message = self.message_for( instance={"bar": 2}, schema=schema, cls=validators.Draft3Validator, ) self.assertEqual(message, "'foo' is a dependency of 'bar'") def test_dependencies_list_draft7(self): depend, on = "bar", "foo" schema = {"dependencies": {depend: [on]}} message = self.message_for( instance={"bar": 2}, schema=schema, cls=validators.Draft7Validator, ) self.assertEqual(message, "'foo' is a dependency of 'bar'") def test_additionalItems_single_failure(self): message = self.message_for( instance=[2], schema={"items": [], "additionalItems": False}, cls=validators.Draft3Validator, ) self.assertIn("(2 was unexpected)", message) def test_additionalItems_multiple_failures(self): message = self.message_for( instance=[1, 2, 3], schema={"items": [], "additionalItems": False}, cls=validators.Draft3Validator, ) self.assertIn("(1, 2, 3 were unexpected)", message) def test_additionalProperties_single_failure(self): additional = "foo" schema = {"additionalProperties": False} message = self.message_for(instance={additional: 2}, schema=schema) self.assertIn("('foo' was unexpected)", message) def test_additionalProperties_multiple_failures(self): schema = {"additionalProperties": False} message = self.message_for( instance=dict.fromkeys(["foo", "bar"]), schema=schema, ) self.assertIn(repr("foo"), message) self.assertIn(repr("bar"), message) self.assertIn("were unexpected)", message) def test_const(self): schema = {"const": 12} message = self.message_for( instance={"foo": "bar"}, schema=schema, ) self.assertIn("12 was expected", message) def test_contains_draft_6(self): schema = {"contains": {"const": 12}} message = self.message_for( instance=[2, {}, []], schema=schema, cls=validators.Draft6Validator, ) self.assertEqual( message, "None of [2, {}, []] are valid under the given schema", ) def test_invalid_format_default_message(self): checker = FormatChecker(formats=()) checker.checks("thing")(lambda value: False) schema = {"format": "thing"} message = self.message_for( instance="bla", schema=schema, format_checker=checker, ) self.assertIn(repr("bla"), message) self.assertIn(repr("thing"), message) self.assertIn("is not a", message) def test_additionalProperties_false_patternProperties(self): schema = {"type": "object", "additionalProperties": False, "patternProperties": { "^abc$": {"type": "string"}, "^def$": {"type": "string"}, }} message = self.message_for( instance={"zebra": 123}, schema=schema, cls=validators.Draft4Validator, ) self.assertEqual( message, "{} does not match any of the regexes: {}, {}".format( repr("zebra"), repr("^abc$"), repr("^def$"), ), ) message = self.message_for( instance={"zebra": 123, "fish": 456}, schema=schema, cls=validators.Draft4Validator, ) self.assertEqual( message, "{}, {} do not match any of the regexes: {}, {}".format( repr("fish"), repr("zebra"), repr("^abc$"), repr("^def$"), ), ) def test_False_schema(self): message = self.message_for( instance="something", schema=False, ) self.assertEqual(message, "False schema does not allow 'something'") def test_multipleOf(self): message = self.message_for( instance=3, schema={"multipleOf": 2}, ) self.assertEqual(message, "3 is not a multiple of 2") def test_minItems(self): message = self.message_for(instance=[], schema={"minItems": 2}) self.assertEqual(message, "[] is too short") def test_maxItems(self): message = self.message_for(instance=[1, 2, 3], schema={"maxItems": 2}) self.assertEqual(message, "[1, 2, 3] is too long") def test_prefixItems_with_items(self): message = self.message_for( instance=[1, 2, "foo", 5], schema={"items": False, "prefixItems": [{}, {}]}, ) self.assertEqual(message, "Expected at most 2 items, but found 4") def test_minLength(self): message = self.message_for( instance="", schema={"minLength": 2}, ) self.assertEqual(message, "'' is too short") def test_maxLength(self): message = self.message_for( instance="abc", schema={"maxLength": 2}, ) self.assertEqual(message, "'abc' is too long") def test_pattern(self): message = self.message_for( instance="bbb", schema={"pattern": "^a*$"}, ) self.assertEqual(message, "'bbb' does not match '^a*$'") def test_does_not_contain(self): message = self.message_for( instance=[], schema={"contains": {"type": "string"}}, ) self.assertEqual( message, "[] does not contain items matching the given schema", ) def test_contains_too_few(self): message = self.message_for( instance=["foo", 1], schema={"contains": {"type": "string"}, "minContains": 2}, ) self.assertEqual( message, "Too few items match the given schema " "(expected at least 2 but only 1 matched)", ) def test_contains_too_few_both_constrained(self): message = self.message_for( instance=["foo", 1], schema={ "contains": {"type": "string"}, "minContains": 2, "maxContains": 4, }, ) self.assertEqual( message, "Too few items match the given schema (expected at least 2 but " "only 1 matched)", ) def test_contains_too_many(self): message = self.message_for( instance=["foo", "bar", "baz"], schema={"contains": {"type": "string"}, "maxContains": 2}, ) self.assertEqual( message, "Too many items match the given schema (expected at most 2)", ) def test_contains_too_many_both_constrained(self): message = self.message_for( instance=["foo"] * 5, schema={ "contains": {"type": "string"}, "minContains": 2, "maxContains": 4, }, ) self.assertEqual( message, "Too many items match the given schema (expected at most 4)", ) def test_exclusiveMinimum(self): message = self.message_for( instance=3, schema={"exclusiveMinimum": 5}, ) self.assertEqual( message, "3 is less than or equal to the minimum of 5", ) def test_exclusiveMaximum(self): message = self.message_for(instance=3, schema={"exclusiveMaximum": 2}) self.assertEqual( message, "3 is greater than or equal to the maximum of 2", ) def test_required(self): message = self.message_for(instance={}, schema={"required": ["foo"]}) self.assertEqual(message, "'foo' is a required property") def test_dependentRequired(self): message = self.message_for( instance={"foo": {}}, schema={"dependentRequired": {"foo": ["bar"]}}, ) self.assertEqual(message, "'bar' is a dependency of 'foo'") def test_minProperties(self): message = self.message_for(instance={}, schema={"minProperties": 2}) self.assertEqual(message, "{} does not have enough properties") def test_maxProperties(self): message = self.message_for( instance={"a": {}, "b": {}, "c": {}}, schema={"maxProperties": 2}, ) self.assertEqual( message, "{'a': {}, 'b': {}, 'c': {}} has too many properties", ) def test_oneOf_matches_none(self): message = self.message_for(instance={}, schema={"oneOf": [False]}) self.assertEqual( message, "{} is not valid under any of the given schemas", ) def test_oneOf_matches_too_many(self): message = self.message_for(instance={}, schema={"oneOf": [True, True]}) self.assertEqual(message, "{} is valid under each of True, True") def test_unevaluated_items(self): schema = {"type": "array", "unevaluatedItems": False} message = self.message_for(instance=["foo", "bar"], schema=schema) self.assertIn( message, "Unevaluated items are not allowed ('bar', 'foo' were unexpected)", ) def test_unevaluated_items_on_invalid_type(self): schema = {"type": "array", "unevaluatedItems": False} message = self.message_for(instance="foo", schema=schema) self.assertEqual(message, "'foo' is not of type 'array'") def test_unevaluated_properties_invalid_against_subschema(self): schema = { "properties": {"foo": {"type": "string"}}, "unevaluatedProperties": {"const": 12}, } message = self.message_for( instance={ "foo": "foo", "bar": "bar", "baz": 12, }, schema=schema, ) self.assertEqual( message, "Unevaluated properties are not valid under the given schema " "('bar' was unevaluated and invalid)", ) def test_unevaluated_properties_disallowed(self): schema = {"type": "object", "unevaluatedProperties": False} message = self.message_for( instance={ "foo": "foo", "bar": "bar", }, schema=schema, ) self.assertEqual( message, "Unevaluated properties are not allowed " "('bar', 'foo' were unexpected)", ) def test_unevaluated_properties_on_invalid_type(self): schema = {"type": "object", "unevaluatedProperties": False} message = self.message_for(instance="foo", schema=schema) self.assertEqual(message, "'foo' is not of type 'object'") class TestValidationErrorDetails(TestCase): # TODO: These really need unit tests for each individual keyword, rather # than just these higher level tests. def test_anyOf(self): instance = 5 schema = { "anyOf": [ {"minimum": 20}, {"type": "string"}, ], } validator = validators.Draft4Validator(schema) errors = list(validator.iter_errors(instance)) self.assertEqual(len(errors), 1) e = errors[0] self.assertEqual(e.validator, "anyOf") self.assertEqual(e.validator_value, schema["anyOf"]) self.assertEqual(e.instance, instance) self.assertEqual(e.schema, schema) self.assertIsNone(e.parent) self.assertEqual(e.path, deque([])) self.assertEqual(e.relative_path, deque([])) self.assertEqual(e.absolute_path, deque([])) self.assertEqual(e.json_path, "$") self.assertEqual(e.schema_path, deque(["anyOf"])) self.assertEqual(e.relative_schema_path, deque(["anyOf"])) self.assertEqual(e.absolute_schema_path, deque(["anyOf"])) self.assertEqual(len(e.context), 2) e1, e2 = sorted_errors(e.context) self.assertEqual(e1.validator, "minimum") self.assertEqual(e1.validator_value, schema["anyOf"][0]["minimum"]) self.assertEqual(e1.instance, instance) self.assertEqual(e1.schema, schema["anyOf"][0]) self.assertIs(e1.parent, e) self.assertEqual(e1.path, deque([])) self.assertEqual(e1.absolute_path, deque([])) self.assertEqual(e1.relative_path, deque([])) self.assertEqual(e1.json_path, "$") self.assertEqual(e1.schema_path, deque([0, "minimum"])) self.assertEqual(e1.relative_schema_path, deque([0, "minimum"])) self.assertEqual( e1.absolute_schema_path, deque(["anyOf", 0, "minimum"]), ) self.assertFalse(e1.context) self.assertEqual(e2.validator, "type") self.assertEqual(e2.validator_value, schema["anyOf"][1]["type"]) self.assertEqual(e2.instance, instance) self.assertEqual(e2.schema, schema["anyOf"][1]) self.assertIs(e2.parent, e) self.assertEqual(e2.path, deque([])) self.assertEqual(e2.relative_path, deque([])) self.assertEqual(e2.absolute_path, deque([])) self.assertEqual(e2.json_path, "$") self.assertEqual(e2.schema_path, deque([1, "type"])) self.assertEqual(e2.relative_schema_path, deque([1, "type"])) self.assertEqual(e2.absolute_schema_path, deque(["anyOf", 1, "type"])) self.assertEqual(len(e2.context), 0) def test_type(self): instance = {"foo": 1} schema = { "type": [ {"type": "integer"}, { "type": "object", "properties": {"foo": {"enum": [2]}}, }, ], } validator = validators.Draft3Validator(schema) errors = list(validator.iter_errors(instance)) self.assertEqual(len(errors), 1) e = errors[0] self.assertEqual(e.validator, "type") self.assertEqual(e.validator_value, schema["type"]) self.assertEqual(e.instance, instance) self.assertEqual(e.schema, schema) self.assertIsNone(e.parent) self.assertEqual(e.path, deque([])) self.assertEqual(e.relative_path, deque([])) self.assertEqual(e.absolute_path, deque([])) self.assertEqual(e.json_path, "$") self.assertEqual(e.schema_path, deque(["type"])) self.assertEqual(e.relative_schema_path, deque(["type"])) self.assertEqual(e.absolute_schema_path, deque(["type"])) self.assertEqual(len(e.context), 2) e1, e2 = sorted_errors(e.context) self.assertEqual(e1.validator, "type") self.assertEqual(e1.validator_value, schema["type"][0]["type"]) self.assertEqual(e1.instance, instance) self.assertEqual(e1.schema, schema["type"][0]) self.assertIs(e1.parent, e) self.assertEqual(e1.path, deque([])) self.assertEqual(e1.relative_path, deque([])) self.assertEqual(e1.absolute_path, deque([])) self.assertEqual(e1.json_path, "$") self.assertEqual(e1.schema_path, deque([0, "type"])) self.assertEqual(e1.relative_schema_path, deque([0, "type"])) self.assertEqual(e1.absolute_schema_path, deque(["type", 0, "type"])) self.assertFalse(e1.context) self.assertEqual(e2.validator, "enum") self.assertEqual(e2.validator_value, [2]) self.assertEqual(e2.instance, 1) self.assertEqual(e2.schema, {"enum": [2]}) self.assertIs(e2.parent, e) self.assertEqual(e2.path, deque(["foo"])) self.assertEqual(e2.relative_path, deque(["foo"])) self.assertEqual(e2.absolute_path, deque(["foo"])) self.assertEqual(e2.json_path, "$.foo") self.assertEqual( e2.schema_path, deque([1, "properties", "foo", "enum"]), ) self.assertEqual( e2.relative_schema_path, deque([1, "properties", "foo", "enum"]), ) self.assertEqual( e2.absolute_schema_path, deque(["type", 1, "properties", "foo", "enum"]), ) self.assertFalse(e2.context) def test_single_nesting(self): instance = {"foo": 2, "bar": [1], "baz": 15, "quux": "spam"} schema = { "properties": { "foo": {"type": "string"}, "bar": {"minItems": 2}, "baz": {"maximum": 10, "enum": [2, 4, 6, 8]}, }, } validator = validators.Draft3Validator(schema) errors = validator.iter_errors(instance) e1, e2, e3, e4 = sorted_errors(errors) self.assertEqual(e1.path, deque(["bar"])) self.assertEqual(e2.path, deque(["baz"])) self.assertEqual(e3.path, deque(["baz"])) self.assertEqual(e4.path, deque(["foo"])) self.assertEqual(e1.relative_path, deque(["bar"])) self.assertEqual(e2.relative_path, deque(["baz"])) self.assertEqual(e3.relative_path, deque(["baz"])) self.assertEqual(e4.relative_path, deque(["foo"])) self.assertEqual(e1.absolute_path, deque(["bar"])) self.assertEqual(e2.absolute_path, deque(["baz"])) self.assertEqual(e3.absolute_path, deque(["baz"])) self.assertEqual(e4.absolute_path, deque(["foo"])) self.assertEqual(e1.json_path, "$.bar") self.assertEqual(e2.json_path, "$.baz") self.assertEqual(e3.json_path, "$.baz") self.assertEqual(e4.json_path, "$.foo") self.assertEqual(e1.validator, "minItems") self.assertEqual(e2.validator, "enum") self.assertEqual(e3.validator, "maximum") self.assertEqual(e4.validator, "type") def test_multiple_nesting(self): instance = [1, {"foo": 2, "bar": {"baz": [1]}}, "quux"] schema = { "type": "string", "items": { "type": ["string", "object"], "properties": { "foo": {"enum": [1, 3]}, "bar": { "type": "array", "properties": { "bar": {"required": True}, "baz": {"minItems": 2}, }, }, }, }, } validator = validators.Draft3Validator(schema) errors = validator.iter_errors(instance) e1, e2, e3, e4, e5, e6 = sorted_errors(errors) self.assertEqual(e1.path, deque([])) self.assertEqual(e2.path, deque([0])) self.assertEqual(e3.path, deque([1, "bar"])) self.assertEqual(e4.path, deque([1, "bar", "bar"])) self.assertEqual(e5.path, deque([1, "bar", "baz"])) self.assertEqual(e6.path, deque([1, "foo"])) self.assertEqual(e1.json_path, "$") self.assertEqual(e2.json_path, "$[0]") self.assertEqual(e3.json_path, "$[1].bar") self.assertEqual(e4.json_path, "$[1].bar.bar") self.assertEqual(e5.json_path, "$[1].bar.baz") self.assertEqual(e6.json_path, "$[1].foo") self.assertEqual(e1.schema_path, deque(["type"])) self.assertEqual(e2.schema_path, deque(["items", "type"])) self.assertEqual( list(e3.schema_path), ["items", "properties", "bar", "type"], ) self.assertEqual( list(e4.schema_path), ["items", "properties", "bar", "properties", "bar", "required"], ) self.assertEqual( list(e5.schema_path), ["items", "properties", "bar", "properties", "baz", "minItems"], ) self.assertEqual( list(e6.schema_path), ["items", "properties", "foo", "enum"], ) self.assertEqual(e1.validator, "type") self.assertEqual(e2.validator, "type") self.assertEqual(e3.validator, "type") self.assertEqual(e4.validator, "required") self.assertEqual(e5.validator, "minItems") self.assertEqual(e6.validator, "enum") def test_recursive(self): schema = { "definitions": { "node": { "anyOf": [{ "type": "object", "required": ["name", "children"], "properties": { "name": { "type": "string", }, "children": { "type": "object", "patternProperties": { "^.*$": { "$ref": "#/definitions/node", }, }, }, }, }], }, }, "type": "object", "required": ["root"], "properties": {"root": {"$ref": "#/definitions/node"}}, } instance = { "root": { "name": "root", "children": { "a": { "name": "a", "children": { "ab": { "name": "ab", # missing "children" }, }, }, }, }, } validator = validators.Draft4Validator(schema) e, = validator.iter_errors(instance) self.assertEqual(e.absolute_path, deque(["root"])) self.assertEqual( e.absolute_schema_path, deque(["properties", "root", "anyOf"]), ) self.assertEqual(e.json_path, "$.root") e1, = e.context self.assertEqual(e1.absolute_path, deque(["root", "children", "a"])) self.assertEqual( e1.absolute_schema_path, deque( [ "properties", "root", "anyOf", 0, "properties", "children", "patternProperties", "^.*$", "anyOf", ], ), ) self.assertEqual(e1.json_path, "$.root.children.a") e2, = e1.context self.assertEqual( e2.absolute_path, deque( ["root", "children", "a", "children", "ab"], ), ) self.assertEqual( e2.absolute_schema_path, deque( [ "properties", "root", "anyOf", 0, "properties", "children", "patternProperties", "^.*$", "anyOf", 0, "properties", "children", "patternProperties", "^.*$", "anyOf", ], ), ) self.assertEqual(e2.json_path, "$.root.children.a.children.ab") def test_additionalProperties(self): instance = {"bar": "bar", "foo": 2} schema = {"additionalProperties": {"type": "integer", "minimum": 5}} validator = validators.Draft3Validator(schema) errors = validator.iter_errors(instance) e1, e2 = sorted_errors(errors) self.assertEqual(e1.path, deque(["bar"])) self.assertEqual(e2.path, deque(["foo"])) self.assertEqual(e1.json_path, "$.bar") self.assertEqual(e2.json_path, "$.foo") self.assertEqual(e1.validator, "type") self.assertEqual(e2.validator, "minimum") def test_patternProperties(self): instance = {"bar": 1, "foo": 2} schema = { "patternProperties": { "bar": {"type": "string"}, "foo": {"minimum": 5}, }, } validator = validators.Draft3Validator(schema) errors = validator.iter_errors(instance) e1, e2 = sorted_errors(errors) self.assertEqual(e1.path, deque(["bar"])) self.assertEqual(e2.path, deque(["foo"])) self.assertEqual(e1.json_path, "$.bar") self.assertEqual(e2.json_path, "$.foo") self.assertEqual(e1.validator, "type") self.assertEqual(e2.validator, "minimum") def test_additionalItems(self): instance = ["foo", 1] schema = { "items": [], "additionalItems": {"type": "integer", "minimum": 5}, } validator = validators.Draft3Validator(schema) errors = validator.iter_errors(instance) e1, e2 = sorted_errors(errors) self.assertEqual(e1.path, deque([0])) self.assertEqual(e2.path, deque([1])) self.assertEqual(e1.json_path, "$[0]") self.assertEqual(e2.json_path, "$[1]") self.assertEqual(e1.validator, "type") self.assertEqual(e2.validator, "minimum") def test_additionalItems_with_items(self): instance = ["foo", "bar", 1] schema = { "items": [{}], "additionalItems": {"type": "integer", "minimum": 5}, } validator = validators.Draft3Validator(schema) errors = validator.iter_errors(instance) e1, e2 = sorted_errors(errors) self.assertEqual(e1.path, deque([1])) self.assertEqual(e2.path, deque([2])) self.assertEqual(e1.json_path, "$[1]") self.assertEqual(e2.json_path, "$[2]") self.assertEqual(e1.validator, "type") self.assertEqual(e2.validator, "minimum") def test_propertyNames(self): instance = {"foo": 12} schema = {"propertyNames": {"not": {"const": "foo"}}} validator = validators.Draft7Validator(schema) error, = validator.iter_errors(instance) self.assertEqual(error.validator, "not") self.assertEqual( error.message, "'foo' should not be valid under {'const': 'foo'}", ) self.assertEqual(error.path, deque([])) self.assertEqual(error.json_path, "$") self.assertEqual(error.schema_path, deque(["propertyNames", "not"])) def test_if_then(self): schema = { "if": {"const": 12}, "then": {"const": 13}, } validator = validators.Draft7Validator(schema) error, = validator.iter_errors(12) self.assertEqual(error.validator, "const") self.assertEqual(error.message, "13 was expected") self.assertEqual(error.path, deque([])) self.assertEqual(error.json_path, "$") self.assertEqual(error.schema_path, deque(["then", "const"])) def test_if_else(self): schema = { "if": {"const": 12}, "else": {"const": 13}, } validator = validators.Draft7Validator(schema) error, = validator.iter_errors(15) self.assertEqual(error.validator, "const") self.assertEqual(error.message, "13 was expected") self.assertEqual(error.path, deque([])) self.assertEqual(error.json_path, "$") self.assertEqual(error.schema_path, deque(["else", "const"])) def test_boolean_schema_False(self): validator = validators.Draft7Validator(False) error, = validator.iter_errors(12) self.assertEqual( ( error.message, error.validator, error.validator_value, error.instance, error.schema, error.schema_path, error.json_path, ), ( "False schema does not allow 12", None, None, 12, False, deque([]), "$", ), ) def test_ref(self): ref, schema = "someRef", {"additionalProperties": {"type": "integer"}} validator = validators.Draft7Validator( {"$ref": ref}, resolver=validators.RefResolver("", {}, store={ref: schema}), ) error, = validator.iter_errors({"foo": "notAnInteger"}) self.assertEqual( ( error.message, error.validator, error.validator_value, error.instance, error.absolute_path, error.schema, error.schema_path, error.json_path, ), ( "'notAnInteger' is not of type 'integer'", "type", "integer", "notAnInteger", deque(["foo"]), {"type": "integer"}, deque(["additionalProperties", "type"]), "$.foo", ), ) def test_prefixItems(self): schema = {"prefixItems": [{"type": "string"}, {}, {}, {"maximum": 3}]} validator = validators.Draft202012Validator(schema) type_error, min_error = validator.iter_errors([1, 2, "foo", 5]) self.assertEqual( ( type_error.message, type_error.validator, type_error.validator_value, type_error.instance, type_error.absolute_path, type_error.schema, type_error.schema_path, type_error.json_path, ), ( "1 is not of type 'string'", "type", "string", 1, deque([0]), {"type": "string"}, deque(["prefixItems", 0, "type"]), "$[0]", ), ) self.assertEqual( ( min_error.message, min_error.validator, min_error.validator_value, min_error.instance, min_error.absolute_path, min_error.schema, min_error.schema_path, min_error.json_path, ), ( "5 is greater than the maximum of 3", "maximum", 3, 5, deque([3]), {"maximum": 3}, deque(["prefixItems", 3, "maximum"]), "$[3]", ), ) def test_prefixItems_with_items(self): schema = { "items": {"type": "string"}, "prefixItems": [{}], } validator = validators.Draft202012Validator(schema) e1, e2 = validator.iter_errors(["foo", 2, "bar", 4, "baz"]) self.assertEqual( ( e1.message, e1.validator, e1.validator_value, e1.instance, e1.absolute_path, e1.schema, e1.schema_path, e1.json_path, ), ( "2 is not of type 'string'", "type", "string", 2, deque([1]), {"type": "string"}, deque(["items", "type"]), "$[1]", ), ) self.assertEqual( ( e2.message, e2.validator, e2.validator_value, e2.instance, e2.absolute_path, e2.schema, e2.schema_path, e2.json_path, ), ( "4 is not of type 'string'", "type", "string", 4, deque([3]), {"type": "string"}, deque(["items", "type"]), "$[3]", ), ) def test_contains_too_many(self): """ `contains` + `maxContains` produces only one error, even if there are many more incorrectly matching elements. """ schema = {"contains": {"type": "string"}, "maxContains": 2} validator = validators.Draft202012Validator(schema) error, = validator.iter_errors(["foo", 2, "bar", 4, "baz", "quux"]) self.assertEqual( ( error.message, error.validator, error.validator_value, error.instance, error.absolute_path, error.schema, error.schema_path, error.json_path, ), ( "Too many items match the given schema (expected at most 2)", "maxContains", 2, ["foo", 2, "bar", 4, "baz", "quux"], deque([]), {"contains": {"type": "string"}, "maxContains": 2}, deque(["contains"]), "$", ), ) def test_contains_too_few(self): schema = {"contains": {"type": "string"}, "minContains": 2} validator = validators.Draft202012Validator(schema) error, = validator.iter_errors(["foo", 2, 4]) self.assertEqual( ( error.message, error.validator, error.validator_value, error.instance, error.absolute_path, error.schema, error.schema_path, error.json_path, ), ( ( "Too few items match the given schema " "(expected at least 2 but only 1 matched)" ), "minContains", 2, ["foo", 2, 4], deque([]), {"contains": {"type": "string"}, "minContains": 2}, deque(["contains"]), "$", ), ) def test_contains_none(self): schema = {"contains": {"type": "string"}, "minContains": 2} validator = validators.Draft202012Validator(schema) error, = validator.iter_errors([2, 4]) self.assertEqual( ( error.message, error.validator, error.validator_value, error.instance, error.absolute_path, error.schema, error.schema_path, error.json_path, ), ( "[2, 4] does not contain items matching the given schema", "contains", {"type": "string"}, [2, 4], deque([]), {"contains": {"type": "string"}, "minContains": 2}, deque(["contains"]), "$", ), ) def test_ref_sibling(self): schema = { "$defs": {"foo": {"required": ["bar"]}}, "properties": { "aprop": { "$ref": "#/$defs/foo", "required": ["baz"], }, }, } validator = validators.Draft202012Validator(schema) e1, e2 = validator.iter_errors({"aprop": {}}) self.assertEqual( ( e1.message, e1.validator, e1.validator_value, e1.instance, e1.absolute_path, e1.schema, e1.schema_path, e1.relative_schema_path, e1.json_path, ), ( "'bar' is a required property", "required", ["bar"], {}, deque(["aprop"]), {"required": ["bar"]}, deque(["properties", "aprop", "required"]), deque(["properties", "aprop", "required"]), "$.aprop", ), ) self.assertEqual( ( e2.message, e2.validator, e2.validator_value, e2.instance, e2.absolute_path, e2.schema, e2.schema_path, e2.relative_schema_path, e2.json_path, ), ( "'baz' is a required property", "required", ["baz"], {}, deque(["aprop"]), {"$ref": "#/$defs/foo", "required": ["baz"]}, deque(["properties", "aprop", "required"]), deque(["properties", "aprop", "required"]), "$.aprop", ), ) class MetaSchemaTestsMixin: # TODO: These all belong upstream def test_invalid_properties(self): with self.assertRaises(exceptions.SchemaError): self.Validator.check_schema({"properties": 12}) def test_minItems_invalid_string(self): with self.assertRaises(exceptions.SchemaError): # needs to be an integer self.Validator.check_schema({"minItems": "1"}) def test_enum_allows_empty_arrays(self): """ Technically, all the spec says is they SHOULD have elements, not MUST. (As of Draft 6. Previous drafts do say MUST). See #529. """ if self.Validator in { validators.Draft3Validator, validators.Draft4Validator, }: with self.assertRaises(exceptions.SchemaError): self.Validator.check_schema({"enum": []}) else: self.Validator.check_schema({"enum": []}) def test_enum_allows_non_unique_items(self): """ Technically, all the spec says is they SHOULD be unique, not MUST. (As of Draft 6. Previous drafts do say MUST). See #529. """ if self.Validator in { validators.Draft3Validator, validators.Draft4Validator, }: with self.assertRaises(exceptions.SchemaError): self.Validator.check_schema({"enum": [12, 12]}) else: self.Validator.check_schema({"enum": [12, 12]}) def test_schema_with_invalid_regex(self): with self.assertRaises(exceptions.SchemaError): self.Validator.check_schema({"pattern": "*notaregex"}) def test_schema_with_invalid_regex_with_disabled_format_validation(self): self.Validator.check_schema( {"pattern": "*notaregex"}, format_checker=None, ) class ValidatorTestMixin(MetaSchemaTestsMixin, object): def test_it_implements_the_validator_protocol(self): self.assertIsInstance(self.Validator({}), protocols.Validator) def test_valid_instances_are_valid(self): schema, instance = self.valid self.assertTrue(self.Validator(schema).is_valid(instance)) def test_invalid_instances_are_not_valid(self): schema, instance = self.invalid self.assertFalse(self.Validator(schema).is_valid(instance)) def test_non_existent_properties_are_ignored(self): self.Validator({object(): object()}).validate(instance=object()) def test_it_creates_a_ref_resolver_if_not_provided(self): self.assertIsInstance( self.Validator({}).resolver, validators.RefResolver, ) def test_it_delegates_to_a_ref_resolver(self): ref, schema = "someCoolRef", {"type": "integer"} resolver = validators.RefResolver("", {}, store={ref: schema}) validator = self.Validator({"$ref": ref}, resolver=resolver) with self.assertRaises(exceptions.ValidationError): validator.validate(None) def test_evolve(self): ref, schema = "someCoolRef", {"type": "integer"} resolver = validators.RefResolver("", {}, store={ref: schema}) validator = self.Validator(schema, resolver=resolver) new = validator.evolve(schema={"type": "string"}) expected = self.Validator({"type": "string"}, resolver=resolver) self.assertEqual(new, expected) self.assertNotEqual(new, validator) def test_evolve_with_subclass(self): """ Subclassing validators isn't supported public API, but some users have done it, because we don't actually error entirely when it's done :/ We need to deprecate doing so first to help as many of these users ensure they can move to supported APIs, but this test ensures that in the interim, we haven't broken those users. """ with self.assertWarns(DeprecationWarning): @attr.s class OhNo(self.Validator): foo = attr.ib(factory=lambda: [1, 2, 3]) _bar = attr.ib(default=37) validator = OhNo({}, bar=12) self.assertEqual(validator.foo, [1, 2, 3]) new = validator.evolve(schema={"type": "integer"}) self.assertEqual(new.foo, [1, 2, 3]) self.assertEqual(new._bar, 12) def test_it_delegates_to_a_legacy_ref_resolver(self): """ Legacy RefResolvers support only the context manager form of resolution. """ class LegacyRefResolver: @contextmanager def resolving(this, ref): self.assertEqual(ref, "the ref") yield {"type": "integer"} resolver = LegacyRefResolver() schema = {"$ref": "the ref"} with self.assertRaises(exceptions.ValidationError): self.Validator(schema, resolver=resolver).validate(None) def test_is_type_is_true_for_valid_type(self): self.assertTrue(self.Validator({}).is_type("foo", "string")) def test_is_type_is_false_for_invalid_type(self): self.assertFalse(self.Validator({}).is_type("foo", "array")) def test_is_type_evades_bool_inheriting_from_int(self): self.assertFalse(self.Validator({}).is_type(True, "integer")) self.assertFalse(self.Validator({}).is_type(True, "number")) def test_it_can_validate_with_decimals(self): schema = {"items": {"type": "number"}} Validator = validators.extend( self.Validator, type_checker=self.Validator.TYPE_CHECKER.redefine( "number", lambda checker, thing: isinstance( thing, (int, float, Decimal), ) and not isinstance(thing, bool), ), ) validator = Validator(schema) validator.validate([1, 1.1, Decimal(1) / Decimal(8)]) invalid = ["foo", {}, [], True, None] self.assertEqual( [error.instance for error in validator.iter_errors(invalid)], invalid, ) def test_it_returns_true_for_formats_it_does_not_know_about(self): validator = self.Validator( {"format": "carrot"}, format_checker=FormatChecker(), ) validator.validate("bugs") def test_it_does_not_validate_formats_by_default(self): validator = self.Validator({}) self.assertIsNone(validator.format_checker) def test_it_validates_formats_if_a_checker_is_provided(self): checker = FormatChecker() bad = ValueError("Bad!") @checker.checks("foo", raises=ValueError) def check(value): if value == "good": return True elif value == "bad": raise bad else: # pragma: no cover self.fail("What is {}? [Baby Don't Hurt Me]".format(value)) validator = self.Validator( {"format": "foo"}, format_checker=checker, ) validator.validate("good") with self.assertRaises(exceptions.ValidationError) as cm: validator.validate("bad") # Make sure original cause is attached self.assertIs(cm.exception.cause, bad) def test_non_string_custom_type(self): non_string_type = object() schema = {"type": [non_string_type]} Crazy = validators.extend( self.Validator, type_checker=self.Validator.TYPE_CHECKER.redefine( non_string_type, lambda checker, thing: isinstance(thing, int), ), ) Crazy(schema).validate(15) def test_it_properly_formats_tuples_in_errors(self): """ A tuple instance properly formats validation errors for uniqueItems. See #224 """ TupleValidator = validators.extend( self.Validator, type_checker=self.Validator.TYPE_CHECKER.redefine( "array", lambda checker, thing: isinstance(thing, tuple), ), ) with self.assertRaises(exceptions.ValidationError) as e: TupleValidator({"uniqueItems": True}).validate((1, 1)) self.assertIn("(1, 1) has non-unique elements", str(e.exception)) def test_check_redefined_sequence(self): """ Allow array to validate against another defined sequence type """ schema = {"type": "array", "uniqueItems": True} MyMapping = namedtuple("MyMapping", "a, b") Validator = validators.extend( self.Validator, type_checker=self.Validator.TYPE_CHECKER.redefine_many( { "array": lambda checker, thing: isinstance( thing, (list, deque), ), "object": lambda checker, thing: isinstance( thing, (dict, MyMapping), ), }, ), ) validator = Validator(schema) valid_instances = [ deque(["a", None, "1", "", True]), deque([[False], [0]]), [deque([False]), deque([0])], [[deque([False])], [deque([0])]], [[[[[deque([False])]]]], [[[[deque([0])]]]]], [deque([deque([False])]), deque([deque([0])])], [MyMapping("a", 0), MyMapping("a", False)], [ MyMapping("a", [deque([0])]), MyMapping("a", [deque([False])]), ], [ MyMapping("a", [MyMapping("a", deque([0]))]), MyMapping("a", [MyMapping("a", deque([False]))]), ], [deque(deque(deque([False]))), deque(deque(deque([0])))], ] for instance in valid_instances: validator.validate(instance) invalid_instances = [ deque(["a", "b", "a"]), deque([[False], [False]]), [deque([False]), deque([False])], [[deque([False])], [deque([False])]], [[[[[deque([False])]]]], [[[[deque([False])]]]]], [deque([deque([False])]), deque([deque([False])])], [MyMapping("a", False), MyMapping("a", False)], [ MyMapping("a", [deque([False])]), MyMapping("a", [deque([False])]), ], [ MyMapping("a", [MyMapping("a", deque([False]))]), MyMapping("a", [MyMapping("a", deque([False]))]), ], [deque(deque(deque([False]))), deque(deque(deque([False])))], ] for instance in invalid_instances: with self.assertRaises(exceptions.ValidationError): validator.validate(instance) class AntiDraft6LeakMixin: """ Make sure functionality from draft 6 doesn't leak backwards in time. """ def test_True_is_not_a_schema(self): with self.assertRaises(exceptions.SchemaError) as e: self.Validator.check_schema(True) self.assertIn("True is not of type", str(e.exception)) def test_False_is_not_a_schema(self): with self.assertRaises(exceptions.SchemaError) as e: self.Validator.check_schema(False) self.assertIn("False is not of type", str(e.exception)) @unittest.skip(bug(523)) def test_True_is_not_a_schema_even_if_you_forget_to_check(self): resolver = validators.RefResolver("", {}) with self.assertRaises(Exception) as e: self.Validator(True, resolver=resolver).validate(12) self.assertNotIsInstance(e.exception, exceptions.ValidationError) @unittest.skip(bug(523)) def test_False_is_not_a_schema_even_if_you_forget_to_check(self): resolver = validators.RefResolver("", {}) with self.assertRaises(Exception) as e: self.Validator(False, resolver=resolver).validate(12) self.assertNotIsInstance(e.exception, exceptions.ValidationError) class TestDraft3Validator(AntiDraft6LeakMixin, ValidatorTestMixin, TestCase): Validator = validators.Draft3Validator valid: tuple[dict, dict] = ({}, {}) invalid = {"type": "integer"}, "foo" def test_any_type_is_valid_for_type_any(self): validator = self.Validator({"type": "any"}) validator.validate(object()) def test_any_type_is_redefinable(self): """ Sigh, because why not. """ Crazy = validators.extend( self.Validator, type_checker=self.Validator.TYPE_CHECKER.redefine( "any", lambda checker, thing: isinstance(thing, int), ), ) validator = Crazy({"type": "any"}) validator.validate(12) with self.assertRaises(exceptions.ValidationError): validator.validate("foo") def test_is_type_is_true_for_any_type(self): self.assertTrue(self.Validator({"type": "any"}).is_valid(object())) def test_is_type_does_not_evade_bool_if_it_is_being_tested(self): self.assertTrue(self.Validator({}).is_type(True, "boolean")) self.assertTrue(self.Validator({"type": "any"}).is_valid(True)) class TestDraft4Validator(AntiDraft6LeakMixin, ValidatorTestMixin, TestCase): Validator = validators.Draft4Validator valid: tuple[dict, dict] = ({}, {}) invalid = {"type": "integer"}, "foo" class TestDraft6Validator(ValidatorTestMixin, TestCase): Validator = validators.Draft6Validator valid: tuple[dict, dict] = ({}, {}) invalid = {"type": "integer"}, "foo" class TestDraft7Validator(ValidatorTestMixin, TestCase): Validator = validators.Draft7Validator valid: tuple[dict, dict] = ({}, {}) invalid = {"type": "integer"}, "foo" class TestDraft201909Validator(ValidatorTestMixin, TestCase): Validator = validators.Draft201909Validator valid: tuple[dict, dict] = ({}, {}) invalid = {"type": "integer"}, "foo" class TestDraft202012Validator(ValidatorTestMixin, TestCase): Validator = validators.Draft202012Validator valid: tuple[dict, dict] = ({}, {}) invalid = {"type": "integer"}, "foo" class TestLatestValidator(TestCase): """ These really apply to multiple versions but are easiest to test on one. """ def test_ref_resolvers_may_have_boolean_schemas_stored(self): ref = "someCoolRef" schema = {"$ref": ref} resolver = validators.RefResolver("", {}, store={ref: False}) validator = validators._LATEST_VERSION(schema, resolver=resolver) with self.assertRaises(exceptions.ValidationError): validator.validate(None) class TestValidatorFor(TestCase): def test_draft_3(self): schema = {"$schema": "http://json-schema.org/draft-03/schema"} self.assertIs( validators.validator_for(schema), validators.Draft3Validator, ) schema = {"$schema": "http://json-schema.org/draft-03/schema#"} self.assertIs( validators.validator_for(schema), validators.Draft3Validator, ) def test_draft_4(self): schema = {"$schema": "http://json-schema.org/draft-04/schema"} self.assertIs( validators.validator_for(schema), validators.Draft4Validator, ) schema = {"$schema": "http://json-schema.org/draft-04/schema#"} self.assertIs( validators.validator_for(schema), validators.Draft4Validator, ) def test_draft_6(self): schema = {"$schema": "http://json-schema.org/draft-06/schema"} self.assertIs( validators.validator_for(schema), validators.Draft6Validator, ) schema = {"$schema": "http://json-schema.org/draft-06/schema#"} self.assertIs( validators.validator_for(schema), validators.Draft6Validator, ) def test_draft_7(self): schema = {"$schema": "http://json-schema.org/draft-07/schema"} self.assertIs( validators.validator_for(schema), validators.Draft7Validator, ) schema = {"$schema": "http://json-schema.org/draft-07/schema#"} self.assertIs( validators.validator_for(schema), validators.Draft7Validator, ) def test_draft_201909(self): schema = {"$schema": "https://json-schema.org/draft/2019-09/schema"} self.assertIs( validators.validator_for(schema), validators.Draft201909Validator, ) schema = {"$schema": "https://json-schema.org/draft/2019-09/schema#"} self.assertIs( validators.validator_for(schema), validators.Draft201909Validator, ) def test_draft_202012(self): schema = {"$schema": "https://json-schema.org/draft/2020-12/schema"} self.assertIs( validators.validator_for(schema), validators.Draft202012Validator, ) schema = {"$schema": "https://json-schema.org/draft/2020-12/schema#"} self.assertIs( validators.validator_for(schema), validators.Draft202012Validator, ) def test_True(self): self.assertIs( validators.validator_for(True), validators._LATEST_VERSION, ) def test_False(self): self.assertIs( validators.validator_for(False), validators._LATEST_VERSION, ) def test_custom_validator(self): Validator = validators.create( meta_schema={"id": "meta schema id"}, version="12", id_of=lambda s: s.get("id", ""), ) schema = {"$schema": "meta schema id"} self.assertIs( validators.validator_for(schema), Validator, ) def test_custom_validator_draft6(self): Validator = validators.create( meta_schema={"$id": "meta schema $id"}, version="13", ) schema = {"$schema": "meta schema $id"} self.assertIs( validators.validator_for(schema), Validator, ) def test_validator_for_jsonschema_default(self): self.assertIs(validators.validator_for({}), validators._LATEST_VERSION) def test_validator_for_custom_default(self): self.assertIs(validators.validator_for({}, default=None), None) def test_warns_if_meta_schema_specified_was_not_found(self): with self.assertWarns(DeprecationWarning) as cm: validators.validator_for(schema={"$schema": "unknownSchema"}) self.assertEqual(cm.filename, __file__) self.assertEqual( str(cm.warning), "The metaschema specified by $schema was not found. " "Using the latest draft to validate, but this will raise " "an error in the future.", ) def test_does_not_warn_if_meta_schema_is_unspecified(self): with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") validators.validator_for(schema={}, default={}) self.assertFalse(w) def test_validator_for_custom_default_with_schema(self): schema, default = {"$schema": "mailto:foo@example.com"}, object() self.assertIs(validators.validator_for(schema, default), default) class TestValidate(TestCase): def assertUses(self, schema, Validator): result = [] with mock.patch.object(Validator, "check_schema", result.append): validators.validate({}, schema) self.assertEqual(result, [schema]) def test_draft3_validator_is_chosen(self): self.assertUses( schema={"$schema": "http://json-schema.org/draft-03/schema#"}, Validator=validators.Draft3Validator, ) # Make sure it works without the empty fragment self.assertUses( schema={"$schema": "http://json-schema.org/draft-03/schema"}, Validator=validators.Draft3Validator, ) def test_draft4_validator_is_chosen(self): self.assertUses( schema={"$schema": "http://json-schema.org/draft-04/schema#"}, Validator=validators.Draft4Validator, ) # Make sure it works without the empty fragment self.assertUses( schema={"$schema": "http://json-schema.org/draft-04/schema"}, Validator=validators.Draft4Validator, ) def test_draft6_validator_is_chosen(self): self.assertUses( schema={"$schema": "http://json-schema.org/draft-06/schema#"}, Validator=validators.Draft6Validator, ) # Make sure it works without the empty fragment self.assertUses( schema={"$schema": "http://json-schema.org/draft-06/schema"}, Validator=validators.Draft6Validator, ) def test_draft7_validator_is_chosen(self): self.assertUses( schema={"$schema": "http://json-schema.org/draft-07/schema#"}, Validator=validators.Draft7Validator, ) # Make sure it works without the empty fragment self.assertUses( schema={"$schema": "http://json-schema.org/draft-07/schema"}, Validator=validators.Draft7Validator, ) def test_draft202012_validator_is_chosen(self): self.assertUses( schema={ "$schema": "https://json-schema.org/draft/2020-12/schema#", }, Validator=validators.Draft202012Validator, ) # Make sure it works without the empty fragment self.assertUses( schema={ "$schema": "https://json-schema.org/draft/2020-12/schema", }, Validator=validators.Draft202012Validator, ) def test_draft202012_validator_is_the_default(self): self.assertUses(schema={}, Validator=validators.Draft202012Validator) def test_validation_error_message(self): with self.assertRaises(exceptions.ValidationError) as e: validators.validate(12, {"type": "string"}) self.assertRegex( str(e.exception), "(?s)Failed validating '.*' in schema.*On instance", ) def test_schema_error_message(self): with self.assertRaises(exceptions.SchemaError) as e: validators.validate(12, {"type": 12}) self.assertRegex( str(e.exception), "(?s)Failed validating '.*' in metaschema.*On schema", ) def test_it_uses_best_match(self): schema = { "oneOf": [ {"type": "number", "minimum": 20}, {"type": "array"}, ], } with self.assertRaises(exceptions.ValidationError) as e: validators.validate(12, schema) self.assertIn("12 is less than the minimum of 20", str(e.exception)) class TestRefResolver(TestCase): base_uri = "" stored_uri = "foo://stored" stored_schema = {"stored": "schema"} def setUp(self): self.referrer = {} self.store = {self.stored_uri: self.stored_schema} self.resolver = validators.RefResolver( self.base_uri, self.referrer, self.store, ) def test_it_does_not_retrieve_schema_urls_from_the_network(self): ref = validators.Draft3Validator.META_SCHEMA["id"] with mock.patch.object(self.resolver, "resolve_remote") as patched: with self.resolver.resolving(ref) as resolved: pass self.assertEqual(resolved, validators.Draft3Validator.META_SCHEMA) self.assertFalse(patched.called) def test_it_resolves_local_refs(self): ref = "#/properties/foo" self.referrer["properties"] = {"foo": object()} with self.resolver.resolving(ref) as resolved: self.assertEqual(resolved, self.referrer["properties"]["foo"]) def test_it_resolves_local_refs_with_id(self): schema = {"id": "http://bar/schema#", "a": {"foo": "bar"}} resolver = validators.RefResolver.from_schema( schema, id_of=lambda schema: schema.get("id", ""), ) with resolver.resolving("#/a") as resolved: self.assertEqual(resolved, schema["a"]) with resolver.resolving("http://bar/schema#/a") as resolved: self.assertEqual(resolved, schema["a"]) def test_it_retrieves_stored_refs(self): with self.resolver.resolving(self.stored_uri) as resolved: self.assertIs(resolved, self.stored_schema) self.resolver.store["cached_ref"] = {"foo": 12} with self.resolver.resolving("cached_ref#/foo") as resolved: self.assertEqual(resolved, 12) def test_it_can_construct_a_base_uri_from_a_schema(self): schema = {"id": "foo"} resolver = validators.RefResolver.from_schema( schema, id_of=lambda schema: schema.get("id", ""), ) self.assertEqual(resolver.base_uri, "foo") self.assertEqual(resolver.resolution_scope, "foo") with resolver.resolving("") as resolved: self.assertEqual(resolved, schema) with resolver.resolving("#") as resolved: self.assertEqual(resolved, schema) with resolver.resolving("foo") as resolved: self.assertEqual(resolved, schema) with resolver.resolving("foo#") as resolved: self.assertEqual(resolved, schema) def test_it_can_construct_a_base_uri_from_a_schema_without_id(self): schema = {} resolver = validators.RefResolver.from_schema(schema) self.assertEqual(resolver.base_uri, "") self.assertEqual(resolver.resolution_scope, "") with resolver.resolving("") as resolved: self.assertEqual(resolved, schema) with resolver.resolving("#") as resolved: self.assertEqual(resolved, schema) def test_custom_uri_scheme_handlers(self): def handler(url): self.assertEqual(url, ref) return schema schema = {"foo": "bar"} ref = "foo://bar" resolver = validators.RefResolver("", {}, handlers={"foo": handler}) with resolver.resolving(ref) as resolved: self.assertEqual(resolved, schema) def test_cache_remote_on(self): response = [object()] def handler(url): try: return response.pop() except IndexError: # pragma: no cover self.fail("Response must not have been cached!") ref = "foo://bar" resolver = validators.RefResolver( "", {}, cache_remote=True, handlers={"foo": handler}, ) with resolver.resolving(ref): pass with resolver.resolving(ref): pass def test_cache_remote_off(self): response = [object()] def handler(url): try: return response.pop() except IndexError: # pragma: no cover self.fail("Handler called twice!") ref = "foo://bar" resolver = validators.RefResolver( "", {}, cache_remote=False, handlers={"foo": handler}, ) with resolver.resolving(ref): pass def test_if_you_give_it_junk_you_get_a_resolution_error(self): error = ValueError("Oh no! What's this?") def handler(url): raise error ref = "foo://bar" resolver = validators.RefResolver("", {}, handlers={"foo": handler}) with self.assertRaises(exceptions.RefResolutionError) as err: with resolver.resolving(ref): self.fail("Shouldn't get this far!") # pragma: no cover self.assertEqual(err.exception, exceptions.RefResolutionError(error)) def test_helpful_error_message_on_failed_pop_scope(self): resolver = validators.RefResolver("", {}) resolver.pop_scope() with self.assertRaises(exceptions.RefResolutionError) as exc: resolver.pop_scope() self.assertIn("Failed to pop the scope", str(exc.exception)) def sorted_errors(errors): def key(error): return ( [str(e) for e in error.path], [str(e) for e in error.schema_path], ) return sorted(errors, key=key) @attr.s class ReallyFakeRequests: _responses = attr.ib() def get(self, url): response = self._responses.get(url) if url is None: # pragma: no cover raise ValueError("Unknown URL: " + repr(url)) return _ReallyFakeJSONResponse(json.dumps(response)) @attr.s class _ReallyFakeJSONResponse: _response = attr.ib() def json(self): return json.loads(self._response) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_jsonschema/validators.py0000644000175100001770000011125414653725311020003 0ustar00runnerdocker""" Creation and extension of validators, with implementations for existing drafts. """ from __future__ import annotations from collections import deque from collections.abc import Mapping, Sequence from functools import lru_cache from operator import methodcaller from urllib.parse import unquote, urldefrag, urljoin, urlsplit from warnings import warn import contextlib import json import reprlib import typing import warnings import attr from asdf._jsonschema import ( _format, _legacy_validators, _types, _utils, _validators, exceptions, ) _UNSET = _utils.Unset() _VALIDATORS: dict[str, typing.Any] = {} _META_SCHEMAS = _utils.URIDict() _VOCABULARIES: list[tuple[str, typing.Any]] = [] def __getattr__(name): if name == "ErrorTree": warnings.warn( "Importing ErrorTree from asdf._jsonschema.validators is deprecated. " "Instead import it from asdf._jsonschema.exceptions.", DeprecationWarning, stacklevel=2, ) from asdf._jsonschema.exceptions import ErrorTree return ErrorTree elif name == "validators": warnings.warn( "Accessing asdf._jsonschema.validators.validators is deprecated. " "Use asdf._jsonschema.validators.validator_for with a given schema.", DeprecationWarning, stacklevel=2, ) return _VALIDATORS elif name == "meta_schemas": warnings.warn( "Accessing asdf._jsonschema.validators.meta_schemas is deprecated. " "Use asdf._jsonschema.validators.validator_for with a given schema.", DeprecationWarning, stacklevel=2, ) return _META_SCHEMAS raise AttributeError(f"module {__name__} has no attribute {name}") def validates(version): """ Register the decorated validator for a ``version`` of the specification. Registered validators and their meta schemas will be considered when parsing :kw:`$schema` keywords' URIs. Arguments: version (str): An identifier to use as the version's name Returns: collections.abc.Callable: a class decorator to decorate the validator with the version """ def _validates(cls): _VALIDATORS[version] = cls meta_schema_id = cls.ID_OF(cls.META_SCHEMA) _META_SCHEMAS[meta_schema_id] = cls return cls return _validates def _id_of(schema): """ Return the ID of a schema for recent JSON Schema drafts. """ if schema is True or schema is False: return "" return schema.get("$id", "") def _store_schema_list(): if not _VOCABULARIES: package = _utils.resources.files(__package__) for version in package.joinpath("schemas", "vocabularies").iterdir(): for path in version.iterdir(): vocabulary = json.loads(path.read_text()) _VOCABULARIES.append((vocabulary["$id"], vocabulary)) return [ (id, validator.META_SCHEMA) for id, validator in _META_SCHEMAS.items() ] + _VOCABULARIES def create( meta_schema, validators=(), version=None, type_checker=_types.draft202012_type_checker, format_checker=_format.draft202012_format_checker, id_of=_id_of, applicable_validators=methodcaller("items"), ): """ Create a new validator class. Arguments: meta_schema (collections.abc.Mapping): the meta schema for the new validator class validators (collections.abc.Mapping): a mapping from names to callables, where each callable will validate the schema property with the given name. Each callable should take 4 arguments: 1. a validator instance, 2. the value of the property being validated within the instance 3. the instance 4. the schema version (str): an identifier for the version that this validator class will validate. If provided, the returned validator class will have its ``__name__`` set to include the version, and also will have `asdf._jsonschema.validators.validates` automatically called for the given version. type_checker (asdf._jsonschema.TypeChecker): a type checker, used when applying the :kw:`type` keyword. If unprovided, a `asdf._jsonschema.TypeChecker` will be created with a set of default types typical of JSON Schema drafts. format_checker (asdf._jsonschema.FormatChecker): a format checker, used when applying the :kw:`format` keyword. If unprovided, a `asdf._jsonschema.FormatChecker` will be created with a set of default formats typical of JSON Schema drafts. id_of (collections.abc.Callable): A function that given a schema, returns its ID. applicable_validators (collections.abc.Callable): A function that given a schema, returns the list of applicable validators (validation keywords and callables) which will be used to validate the instance. Returns: a new `asdf._jsonschema.protocols.Validator` class """ # preemptively don't shadow the `Validator.format_checker` local format_checker_arg = format_checker @attr.s class Validator: VALIDATORS = dict(validators) META_SCHEMA = dict(meta_schema) TYPE_CHECKER = type_checker FORMAT_CHECKER = format_checker_arg ID_OF = staticmethod(id_of) schema = attr.ib(repr=reprlib.repr) resolver = attr.ib(default=None, repr=False) format_checker = attr.ib(default=None) def __init_subclass__(cls): warnings.warn( ( "Subclassing validator classes is not intended to " "be part of their public API. A future version " "will make doing so an error, as the behavior of " "subclasses isn't guaranteed to stay the same " "between releases of asdf._jsonschema. Instead, prefer " "composition of validators, wrapping them in an object " "owned entirely by the downstream library." ), DeprecationWarning, stacklevel=2, ) def __attrs_post_init__(self): if self.resolver is None: self.resolver = RefResolver.from_schema( self.schema, id_of=id_of, ) @classmethod def check_schema(cls, schema, format_checker=_UNSET): Validator = validator_for(cls.META_SCHEMA, default=cls) if format_checker is _UNSET: format_checker = Validator.FORMAT_CHECKER validator = Validator( schema=cls.META_SCHEMA, format_checker=format_checker, ) for error in validator.iter_errors(schema): raise exceptions.SchemaError.create_from(error) def evolve(self, **changes): # Essentially reproduces attr.evolve, but may involve instantiating # a different class than this one. cls = self.__class__ schema = changes.setdefault("schema", self.schema) NewValidator = validator_for(schema, default=cls) for field in attr.fields(cls): if not field.init: continue attr_name = field.name # To deal with private attributes. init_name = attr_name if attr_name[0] != "_" else attr_name[1:] if init_name not in changes: changes[init_name] = getattr(self, attr_name) return NewValidator(**changes) def iter_errors(self, instance, _schema=None): if _schema is not None: warnings.warn( ( "Passing a schema to Validator.iter_errors " "is deprecated and will be removed in a future " "release. Call validator.evolve(schema=new_schema)." "iter_errors(...) instead." ), DeprecationWarning, stacklevel=2, ) else: _schema = self.schema if _schema is True: return elif _schema is False: yield exceptions.ValidationError( f"False schema does not allow {instance!r}", validator=None, validator_value=None, instance=instance, schema=_schema, ) return scope = id_of(_schema) if scope: self.resolver.push_scope(scope) try: for k, v in applicable_validators(_schema): validator = self.VALIDATORS.get(k) if validator is None: continue errors = validator(self, v, instance, _schema) or () for error in errors: # set details if not already set by the called fn error._set( validator=k, validator_value=v, instance=instance, schema=_schema, type_checker=self.TYPE_CHECKER, ) if k not in {"if", "$ref"}: error.schema_path.appendleft(k) yield error finally: if scope: self.resolver.pop_scope() def descend(self, instance, schema, path=None, schema_path=None): for error in self.evolve(schema=schema).iter_errors(instance): if path is not None: error.path.appendleft(path) if schema_path is not None: error.schema_path.appendleft(schema_path) yield error def validate(self, *args, **kwargs): for error in self.iter_errors(*args, **kwargs): raise error def is_type(self, instance, type): try: return self.TYPE_CHECKER.is_type(instance, type) except exceptions.UndefinedTypeCheck: raise exceptions.UnknownType(type, instance, self.schema) def is_valid(self, instance, _schema=None): if _schema is not None: warnings.warn( ( "Passing a schema to Validator.is_valid is deprecated " "and will be removed in a future release. Call " "validator.evolve(schema=new_schema).is_valid(...) " "instead." ), DeprecationWarning, stacklevel=2, ) self = self.evolve(schema=_schema) error = next(self.iter_errors(instance), None) return error is None if version is not None: safe = version.title().replace(" ", "").replace("-", "") Validator.__name__ = Validator.__qualname__ = f"{safe}Validator" Validator = validates(version)(Validator) return Validator def extend( validator, validators=(), version=None, type_checker=None, format_checker=None, ): """ Create a new validator class by extending an existing one. Arguments: validator (asdf._jsonschema.protocols.Validator): an existing validator class validators (collections.abc.Mapping): a mapping of new validator callables to extend with, whose structure is as in `create`. .. note:: Any validator callables with the same name as an existing one will (silently) replace the old validator callable entirely, effectively overriding any validation done in the "parent" validator class. If you wish to instead extend the behavior of a parent's validator callable, delegate and call it directly in the new validator function by retrieving it using ``OldValidator.VALIDATORS["validation_keyword_name"]``. version (str): a version for the new validator class type_checker (asdf._jsonschema.TypeChecker): a type checker, used when applying the :kw:`type` keyword. If unprovided, the type checker of the extended `asdf._jsonschema.protocols.Validator` will be carried along. format_checker (asdf._jsonschema.FormatChecker): a format checker, used when applying the :kw:`format` keyword. If unprovided, the format checker of the extended `asdf._jsonschema.protocols.Validator` will be carried along. Returns: a new `asdf._jsonschema.protocols.Validator` class extending the one provided .. note:: Meta Schemas The new validator class will have its parent's meta schema. If you wish to change or extend the meta schema in the new validator class, modify ``META_SCHEMA`` directly on the returned class. Note that no implicit copying is done, so a copy should likely be made before modifying it, in order to not affect the old validator. """ all_validators = dict(validator.VALIDATORS) all_validators.update(validators) if type_checker is None: type_checker = validator.TYPE_CHECKER if format_checker is None: format_checker = validator.FORMAT_CHECKER return create( meta_schema=validator.META_SCHEMA, validators=all_validators, version=version, type_checker=type_checker, format_checker=format_checker, id_of=validator.ID_OF, ) Draft3Validator = create( meta_schema=_utils.load_schema("draft3"), validators={ "$ref": _validators.ref, "additionalItems": _validators.additionalItems, "additionalProperties": _validators.additionalProperties, "dependencies": _legacy_validators.dependencies_draft3, "disallow": _legacy_validators.disallow_draft3, "divisibleBy": _validators.multipleOf, "enum": _validators.enum, "extends": _legacy_validators.extends_draft3, "format": _validators.format, "items": _legacy_validators.items_draft3_draft4, "maxItems": _validators.maxItems, "maxLength": _validators.maxLength, "maximum": _legacy_validators.maximum_draft3_draft4, "minItems": _validators.minItems, "minLength": _validators.minLength, "minimum": _legacy_validators.minimum_draft3_draft4, "pattern": _validators.pattern, "patternProperties": _validators.patternProperties, "properties": _legacy_validators.properties_draft3, "type": _legacy_validators.type_draft3, "uniqueItems": _validators.uniqueItems, }, type_checker=_types.draft3_type_checker, format_checker=_format.draft3_format_checker, version="draft3", id_of=_legacy_validators.id_of_ignore_ref(property="id"), applicable_validators=_legacy_validators.ignore_ref_siblings, ) Draft4Validator = create( meta_schema=_utils.load_schema("draft4"), validators={ "$ref": _validators.ref, "additionalItems": _validators.additionalItems, "additionalProperties": _validators.additionalProperties, "allOf": _validators.allOf, "anyOf": _validators.anyOf, "dependencies": _legacy_validators.dependencies_draft4_draft6_draft7, "enum": _validators.enum, "format": _validators.format, "items": _legacy_validators.items_draft3_draft4, "maxItems": _validators.maxItems, "maxLength": _validators.maxLength, "maxProperties": _validators.maxProperties, "maximum": _legacy_validators.maximum_draft3_draft4, "minItems": _validators.minItems, "minLength": _validators.minLength, "minProperties": _validators.minProperties, "minimum": _legacy_validators.minimum_draft3_draft4, "multipleOf": _validators.multipleOf, "not": _validators.not_, "oneOf": _validators.oneOf, "pattern": _validators.pattern, "patternProperties": _validators.patternProperties, "properties": _validators.properties, "required": _validators.required, "type": _validators.type, "uniqueItems": _validators.uniqueItems, }, type_checker=_types.draft4_type_checker, format_checker=_format.draft4_format_checker, version="draft4", id_of=_legacy_validators.id_of_ignore_ref(property="id"), applicable_validators=_legacy_validators.ignore_ref_siblings, ) Draft6Validator = create( meta_schema=_utils.load_schema("draft6"), validators={ "$ref": _validators.ref, "additionalItems": _validators.additionalItems, "additionalProperties": _validators.additionalProperties, "allOf": _validators.allOf, "anyOf": _validators.anyOf, "const": _validators.const, "contains": _legacy_validators.contains_draft6_draft7, "dependencies": _legacy_validators.dependencies_draft4_draft6_draft7, "enum": _validators.enum, "exclusiveMaximum": _validators.exclusiveMaximum, "exclusiveMinimum": _validators.exclusiveMinimum, "format": _validators.format, "items": _legacy_validators.items_draft6_draft7_draft201909, "maxItems": _validators.maxItems, "maxLength": _validators.maxLength, "maxProperties": _validators.maxProperties, "maximum": _validators.maximum, "minItems": _validators.minItems, "minLength": _validators.minLength, "minProperties": _validators.minProperties, "minimum": _validators.minimum, "multipleOf": _validators.multipleOf, "not": _validators.not_, "oneOf": _validators.oneOf, "pattern": _validators.pattern, "patternProperties": _validators.patternProperties, "properties": _validators.properties, "propertyNames": _validators.propertyNames, "required": _validators.required, "type": _validators.type, "uniqueItems": _validators.uniqueItems, }, type_checker=_types.draft6_type_checker, format_checker=_format.draft6_format_checker, version="draft6", id_of=_legacy_validators.id_of_ignore_ref(), applicable_validators=_legacy_validators.ignore_ref_siblings, ) Draft7Validator = create( meta_schema=_utils.load_schema("draft7"), validators={ "$ref": _validators.ref, "additionalItems": _validators.additionalItems, "additionalProperties": _validators.additionalProperties, "allOf": _validators.allOf, "anyOf": _validators.anyOf, "const": _validators.const, "contains": _legacy_validators.contains_draft6_draft7, "dependencies": _legacy_validators.dependencies_draft4_draft6_draft7, "enum": _validators.enum, "exclusiveMaximum": _validators.exclusiveMaximum, "exclusiveMinimum": _validators.exclusiveMinimum, "format": _validators.format, "if": _validators.if_, "items": _legacy_validators.items_draft6_draft7_draft201909, "maxItems": _validators.maxItems, "maxLength": _validators.maxLength, "maxProperties": _validators.maxProperties, "maximum": _validators.maximum, "minItems": _validators.minItems, "minLength": _validators.minLength, "minProperties": _validators.minProperties, "minimum": _validators.minimum, "multipleOf": _validators.multipleOf, "not": _validators.not_, "oneOf": _validators.oneOf, "pattern": _validators.pattern, "patternProperties": _validators.patternProperties, "properties": _validators.properties, "propertyNames": _validators.propertyNames, "required": _validators.required, "type": _validators.type, "uniqueItems": _validators.uniqueItems, }, type_checker=_types.draft7_type_checker, format_checker=_format.draft7_format_checker, version="draft7", id_of=_legacy_validators.id_of_ignore_ref(), applicable_validators=_legacy_validators.ignore_ref_siblings, ) Draft201909Validator = create( meta_schema=_utils.load_schema("draft2019-09"), validators={ "$recursiveRef": _legacy_validators.recursiveRef, "$ref": _validators.ref, "additionalItems": _validators.additionalItems, "additionalProperties": _validators.additionalProperties, "allOf": _validators.allOf, "anyOf": _validators.anyOf, "const": _validators.const, "contains": _validators.contains, "dependentRequired": _validators.dependentRequired, "dependentSchemas": _validators.dependentSchemas, "enum": _validators.enum, "exclusiveMaximum": _validators.exclusiveMaximum, "exclusiveMinimum": _validators.exclusiveMinimum, "format": _validators.format, "if": _validators.if_, "items": _legacy_validators.items_draft6_draft7_draft201909, "maxItems": _validators.maxItems, "maxLength": _validators.maxLength, "maxProperties": _validators.maxProperties, "maximum": _validators.maximum, "minItems": _validators.minItems, "minLength": _validators.minLength, "minProperties": _validators.minProperties, "minimum": _validators.minimum, "multipleOf": _validators.multipleOf, "not": _validators.not_, "oneOf": _validators.oneOf, "pattern": _validators.pattern, "patternProperties": _validators.patternProperties, "properties": _validators.properties, "propertyNames": _validators.propertyNames, "required": _validators.required, "type": _validators.type, "unevaluatedItems": _legacy_validators.unevaluatedItems_draft2019, "unevaluatedProperties": _validators.unevaluatedProperties, "uniqueItems": _validators.uniqueItems, }, type_checker=_types.draft201909_type_checker, format_checker=_format.draft201909_format_checker, version="draft2019-09", ) Draft202012Validator = create( meta_schema=_utils.load_schema("draft2020-12"), validators={ "$dynamicRef": _validators.dynamicRef, "$ref": _validators.ref, "additionalItems": _validators.additionalItems, "additionalProperties": _validators.additionalProperties, "allOf": _validators.allOf, "anyOf": _validators.anyOf, "const": _validators.const, "contains": _validators.contains, "dependentRequired": _validators.dependentRequired, "dependentSchemas": _validators.dependentSchemas, "enum": _validators.enum, "exclusiveMaximum": _validators.exclusiveMaximum, "exclusiveMinimum": _validators.exclusiveMinimum, "format": _validators.format, "if": _validators.if_, "items": _validators.items, "maxItems": _validators.maxItems, "maxLength": _validators.maxLength, "maxProperties": _validators.maxProperties, "maximum": _validators.maximum, "minItems": _validators.minItems, "minLength": _validators.minLength, "minProperties": _validators.minProperties, "minimum": _validators.minimum, "multipleOf": _validators.multipleOf, "not": _validators.not_, "oneOf": _validators.oneOf, "pattern": _validators.pattern, "patternProperties": _validators.patternProperties, "prefixItems": _validators.prefixItems, "properties": _validators.properties, "propertyNames": _validators.propertyNames, "required": _validators.required, "type": _validators.type, "unevaluatedItems": _validators.unevaluatedItems, "unevaluatedProperties": _validators.unevaluatedProperties, "uniqueItems": _validators.uniqueItems, }, type_checker=_types.draft202012_type_checker, format_checker=_format.draft202012_format_checker, version="draft2020-12", ) _LATEST_VERSION = Draft202012Validator class RefResolver: """ Resolve JSON References. Arguments: base_uri (str): The URI of the referring document referrer: The actual referring document store (dict): A mapping from URIs to documents to cache cache_remote (bool): Whether remote refs should be cached after first resolution handlers (dict): A mapping from URI schemes to functions that should be used to retrieve them urljoin_cache (:func:`functools.lru_cache`): A cache that will be used for caching the results of joining the resolution scope to subscopes. remote_cache (:func:`functools.lru_cache`): A cache that will be used for caching the results of resolved remote URLs. Attributes: cache_remote (bool): Whether remote refs should be cached after first resolution """ def __init__( self, base_uri, referrer, store=None, cache_remote=True, handlers=(), urljoin_cache=None, remote_cache=None, ): store = store or {} if urljoin_cache is None: urljoin_cache = lru_cache(1024)(urljoin) if remote_cache is None: remote_cache = lru_cache(1024)(self.resolve_from_url) self.referrer = referrer self.cache_remote = cache_remote self.handlers = dict(handlers) self._scopes_stack = [base_uri] self.store = _utils.URIDict(_store_schema_list()) self.store.update(store) self.store.update( (schema["$id"], schema) for schema in store.values() if isinstance(schema, Mapping) and "$id" in schema ) self.store[base_uri] = referrer self._urljoin_cache = urljoin_cache self._remote_cache = remote_cache @classmethod def from_schema(cls, schema, id_of=_id_of, *args, **kwargs): """ Construct a resolver from a JSON schema object. Arguments: schema: the referring schema Returns: `RefResolver` """ return cls(base_uri=id_of(schema), referrer=schema, *args, **kwargs) # noqa: B026, E501 def push_scope(self, scope): """ Enter a given sub-scope. Treats further dereferences as being performed underneath the given scope. """ self._scopes_stack.append( self._urljoin_cache(self.resolution_scope, scope), ) def pop_scope(self): """ Exit the most recent entered scope. Treats further dereferences as being performed underneath the original scope. Don't call this method more times than `push_scope` has been called. """ try: self._scopes_stack.pop() except IndexError: raise exceptions.RefResolutionError( "Failed to pop the scope from an empty stack. " "`pop_scope()` should only be called once for every " "`push_scope()`", ) @property def resolution_scope(self): """ Retrieve the current resolution scope. """ return self._scopes_stack[-1] @property def base_uri(self): """ Retrieve the current base URI, not including any fragment. """ uri, _ = urldefrag(self.resolution_scope) return uri @contextlib.contextmanager def in_scope(self, scope): """ Temporarily enter the given scope for the duration of the context. .. deprecated:: v4.0.0 """ warnings.warn( "asdf._jsonschema.RefResolver.in_scope is deprecated and will be " "removed in a future release.", DeprecationWarning, stacklevel=3, ) self.push_scope(scope) try: yield finally: self.pop_scope() @contextlib.contextmanager def resolving(self, ref): """ Resolve the given ``ref`` and enter its resolution scope. Exits the scope on exit of this context manager. Arguments: ref (str): The reference to resolve """ url, resolved = self.resolve(ref) self.push_scope(url) try: yield resolved finally: self.pop_scope() def _find_in_referrer(self, key): return self._get_subschemas_cache()[key] @lru_cache() # noqa: B019 def _get_subschemas_cache(self): cache = {key: [] for key in _SUBSCHEMAS_KEYWORDS} for keyword, subschema in _search_schema( self.referrer, _match_subschema_keywords, ): cache[keyword].append(subschema) return cache @lru_cache() # noqa: B019 def _find_in_subschemas(self, url): subschemas = self._get_subschemas_cache()["$id"] if not subschemas: return None uri, fragment = urldefrag(url) for subschema in subschemas: target_uri = self._urljoin_cache( self.resolution_scope, subschema["$id"], ) if target_uri.rstrip("/") == uri.rstrip("/"): if fragment: subschema = self.resolve_fragment(subschema, fragment) self.store[url] = subschema return url, subschema return None def resolve(self, ref): """ Resolve the given reference. """ url = self._urljoin_cache(self.resolution_scope, ref).rstrip("/") match = self._find_in_subschemas(url) if match is not None: return match return url, self._remote_cache(url) def resolve_from_url(self, url): """ Resolve the given URL. """ url, fragment = urldefrag(url) if not url: url = self.base_uri try: document = self.store[url] except KeyError: try: document = self.resolve_remote(url) except Exception as exc: raise exceptions.RefResolutionError(exc) return self.resolve_fragment(document, fragment) def resolve_fragment(self, document, fragment): """ Resolve a ``fragment`` within the referenced ``document``. Arguments: document: The referent document fragment (str): a URI fragment to resolve within it """ fragment = fragment.lstrip("/") if not fragment: return document if document is self.referrer: find = self._find_in_referrer else: def find(key): yield from _search_schema(document, _match_keyword(key)) for keyword in ["$anchor", "$dynamicAnchor"]: for subschema in find(keyword): if fragment == subschema[keyword]: return subschema for keyword in ["id", "$id"]: for subschema in find(keyword): if "#" + fragment == subschema[keyword]: return subschema # Resolve via path parts = unquote(fragment).split("/") if fragment else [] for part in parts: part = part.replace("~1", "/").replace("~0", "~") if isinstance(document, Sequence): # Array indexes should be turned into integers try: part = int(part) except ValueError: pass try: document = document[part] except (TypeError, LookupError): raise exceptions.RefResolutionError( f"Unresolvable JSON pointer: {fragment!r}", ) return document def resolve_remote(self, uri): """ Resolve a remote ``uri``. If called directly, does not check the store first, but after retrieving the document at the specified URI it will be saved in the store if :attr:`cache_remote` is True. Arguments: uri (str): The URI to resolve Returns: The retrieved document .. _requests: https://pypi.org/project/requests/ """ scheme = urlsplit(uri).scheme result = self.handlers[scheme](uri) if self.cache_remote: self.store[uri] = result return result _SUBSCHEMAS_KEYWORDS = ("$id", "id", "$anchor", "$dynamicAnchor") def _match_keyword(keyword): def matcher(value): if keyword in value: yield value return matcher def _match_subschema_keywords(value): for keyword in _SUBSCHEMAS_KEYWORDS: if keyword in value: yield keyword, value def _search_schema(schema, matcher): """Breadth-first search routine.""" values = deque([schema]) while values: value = values.pop() if not isinstance(value, dict): continue yield from matcher(value) values.extendleft(value.values()) def validate(instance, schema, cls=None, *args, **kwargs): """ Validate an instance under the given schema. >>> from asdf._jsonschema.validators import validate >>> validate([2, 3, 4], {"maxItems": 2}) # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... ValidationError: [2, 3, 4] is too long :func:`~asdf._jsonschema.validators.validate` will first verify that the provided schema is itself valid, since not doing so can lead to less obvious error messages and fail in less obvious or consistent ways. If you know you have a valid schema already, especially if you intend to validate multiple instances with the same schema, you likely would prefer using the `asdf._jsonschema.protocols.Validator.validate` method directly on a specific validator (e.g. ``Draft20212Validator.validate``). Arguments: instance: The instance to validate schema: The schema to validate with cls (asdf._jsonschema.protocols.Validator): The class that will be used to validate the instance. If the ``cls`` argument is not provided, two things will happen in accordance with the specification. First, if the schema has a :kw:`$schema` keyword containing a known meta-schema [#]_ then the proper validator will be used. The specification recommends that all schemas contain :kw:`$schema` properties for this reason. If no :kw:`$schema` property is found, the default validator class is the latest released draft. Any other provided positional and keyword arguments will be passed on when instantiating the ``cls``. Raises: `asdf._jsonschema.exceptions.ValidationError`: if the instance is invalid `asdf._jsonschema.exceptions.SchemaError`: if the schema itself is invalid .. rubric:: Footnotes .. [#] known by a validator registered with `asdf._jsonschema.validators.validates` """ if cls is None: cls = validator_for(schema) cls.check_schema(schema) validator = cls(schema, *args, **kwargs) error = exceptions.best_match(validator.iter_errors(instance)) if error is not None: raise error def validator_for(schema, default=_UNSET): """ Retrieve the validator class appropriate for validating the given schema. Uses the :kw:`$schema` keyword that should be present in the given schema to look up the appropriate validator class. Arguments: schema (collections.abc.Mapping or bool): the schema to look at default: the default to return if the appropriate validator class cannot be determined. If unprovided, the default is to return the latest supported draft. """ DefaultValidator = _LATEST_VERSION if default is _UNSET else default if schema is True or schema is False or "$schema" not in schema: return DefaultValidator if schema["$schema"] not in _META_SCHEMAS: if default is _UNSET: warn( ( "The metaschema specified by $schema was not found. " "Using the latest draft to validate, but this will raise " "an error in the future." ), DeprecationWarning, stacklevel=2, ) return _META_SCHEMAS.get(schema["$schema"], DefaultValidator) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_node_info.py0000644000175100001770000002536214653725311015445 0ustar00runnerdockerimport re from collections import namedtuple from .schema import load_schema from .treeutil import get_children def _filter_tree(info, filters): """ Keep nodes in tree which pass the all of the filters. Mutates the tree. """ filtered_children = [] for child in info.children: if _filter_tree(child, filters): filtered_children.append(child) info.children = filtered_children return len(info.children) > 0 or all(f(info.node, info.identifier) for f in filters) def create_tree(key, node, identifier="root", filters=None, refresh_extension_manager=False): """ Create a `NodeSchemaInfo` tree which can be filtered from a base node. Parameters ---------- key : str The key to look up. node : dict The asdf tree to search. filters : list of functions A list of functions that take a node and identifier and return True if the node should be included in the tree. preserve_list : bool If True, then lists are preserved. Otherwise, they are turned into dicts. refresh_extension_manager : bool If `True`, refresh the extension manager before looking up the key. This is useful if you want to make sure that the schema data for a given key is up to date. """ filters = [] if filters is None else filters schema_info = NodeSchemaInfo.from_root_node( key, identifier, node, refresh_extension_manager=refresh_extension_manager, ) if len(filters) > 0 and not _filter_tree(schema_info, filters): return None return schema_info def collect_schema_info( key, path, node, identifier="root", filters=None, preserve_list=True, refresh_extension_manager=False, ): """ Collect from the underlying schemas any of the info stored under key, relative to the path Parameters ---------- key : str The key to look up. path : str or None A dot-separated path to the parameter to find the key information on. If None return full dictionary. node : dict The asdf tree to search. filters : list of functions A list of functions that take a node and identifier and return True if the node should be included in the tree. preserve_list : bool If True, then lists are preserved. Otherwise, they are turned into dicts. refresh_extension_manager : bool If `True`, refresh the extension manager before looking up the key. This is useful if you want to make sure that the schema data for a given key is up to date. """ schema_info = create_tree( key, node, identifier=identifier, filters=[] if filters is None else filters, refresh_extension_manager=refresh_extension_manager, ) info = schema_info.collect_info(preserve_list=preserve_list) if path is not None: for path_key in path.split("."): info = info.get(path_key, None) if info is None: return None return info def _get_extension_manager(refresh_extension_manager): from ._asdf import AsdfFile, get_config from .extension import ExtensionManager af = AsdfFile() if refresh_extension_manager: config = get_config() af._extension_manager = ExtensionManager(config.extensions) return af.extension_manager _SchemaInfo = namedtuple("SchemaInfo", ["info", "value"]) class SchemaInfo(_SchemaInfo): """ A class to hold the schema info and the value of the node. Parameters ---------- info : dict The schema info. value : object The value of the node. """ def __repr__(self): return f"{self.info}" class NodeSchemaInfo: """ Container for keyed information collected from a schema about a node of an ASDF file tree. This contains node alongside the parent and child nodes of that node in the ASDF file tree. Effectively this means that each of these "node" objects represents the a subtree of the file tree rooted at the node in question alongside methods to access the underlying schemas for the portions of the ASDF file in question. This is used for a variety of general purposes, including: - Providing the long descriptions for nodes as described in the schema. - Assisting in traversing an ASDF file like trees, to search nodes. - Providing a way to pull static information about an ASDF file which has been stored within the schemas for that file. Parameters ---------- key : str The key for the information to be collected from the underlying schema(s). parent : NodeSchemaInfo The parent node of this node. None if this is the root node. identifier : str The identifier for this node in the ASDF file tree. node : any The value of the node in the ASDF file tree. depth : int The depth of this node in the ASDF file tree. recursive : bool If this node has already been visited, then this is set to True. Default is False. visible : bool If this node will be made visible in the output. Default is True. children : list List of the NodeSchemaInfo objects for the children of this node. This is a leaf node if this is empty. schema : dict The portion of the underlying schema corresponding to the node. """ def __init__(self, key, parent, identifier, node, depth, recursive=False, visible=True): self.key = key self.parent = parent self.identifier = identifier self.node = node self.depth = depth self.recursive = recursive self.visible = visible self.children = [] self.schema = None @classmethod def traversable(cls, node): """ This method determines if the node is an instance of a class that supports introspection by the info machinery. This determined by the presence of a __asdf_traverse__ method. """ return hasattr(node, "__asdf_traverse__") @property def visible_children(self): return [c for c in self.children if c.visible] @property def parent_node(self): if self.parent is not None: return self.parent.node return None @property def info(self): if self.schema is not None: return self.schema.get(self.key, None) return None def get_schema_for_property(self, identifier): subschema = self.schema.get("properties", {}).get(identifier, None) if subschema is not None: return subschema subschema = self.schema.get("properties", {}).get("patternProperties", None) if subschema: for key in subschema: if re.search(key, identifier): return subschema[key] return {} def set_schema_for_property(self, parent, identifier): """Extract a subschema from the parent for the identified property""" self.schema = parent.get_schema_for_property(identifier) def set_schema_from_node(self, node, extension_manager): """Pull a tagged schema for the node""" tag_def = extension_manager.get_tag_definition(node._tag) schema_uri = tag_def.schema_uris[0] schema = load_schema(schema_uri) self.schema = schema @classmethod def from_root_node(cls, key, root_identifier, root_node, schema=None, refresh_extension_manager=False): """ Build a NodeSchemaInfo tree from the given ASDF root node. Intentionally processes the tree in breadth-first order so that recursively referenced nodes are displayed at their shallowest reference point. """ extension_manager = _get_extension_manager(refresh_extension_manager) current_nodes = [(None, root_identifier, root_node)] seen = set() root_info = None current_depth = 0 while True: next_nodes = [] for parent, identifier, node in current_nodes: if (isinstance(node, (dict, tuple)) or cls.traversable(node)) and id(node) in seen: info = NodeSchemaInfo(key, parent, identifier, node, current_depth, recursive=True) parent.children.append(info) else: info = NodeSchemaInfo(key, parent, identifier, node, current_depth) if root_info is None: root_info = info if parent is not None: if parent.schema is not None and not cls.traversable(node): info.set_schema_for_property(parent, identifier) parent.children.append(info) seen.add(id(node)) if cls.traversable(node): t_node = node.__asdf_traverse__() if hasattr(node, "_tag") and isinstance(node._tag, str): try: info.set_schema_from_node(node, extension_manager) except KeyError: # if _tag is not a valid tag, no schema will be found # and a KeyError will be raised. We don't raise the KeyError # (or another exception) here as the node (object) might # be using _tag for a non-ASDF purpose. pass else: t_node = node if parent is None: info.schema = schema for child_identifier, child_node in get_children(t_node): next_nodes.append((info, child_identifier, child_node)) if len(next_nodes) == 0: break current_nodes = next_nodes current_depth += 1 return root_info def collect_info(self, preserve_list=True): """ Collect the information from the NodeSchemaInfo tree, and return it as nested dict. Parameters ---------- preserve_list : bool If True, then lists are preserved. Otherwise, they are turned into dicts. """ if preserve_list and isinstance(self.node, (list, tuple)) and self.info is None: info = [c_info for child in self.visible_children if len(c_info := child.collect_info(preserve_list)) > 0] else: info = { child.identifier: c_info for child in self.visible_children if len(c_info := child.collect_info(preserve_list)) > 0 } if self.info is not None: info[self.key] = SchemaInfo(self.info, self.node) return info ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.137098 asdf-3.4.0/asdf/_tests/0000755000175100001770000000000014653725331014267 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/__init__.py0000644000175100001770000000112614653725311016376 0ustar00runnerdockerimport numpy as np RNG = np.random.default_rng(619) def create_small_tree(): x = np.arange(0, 10, dtype=float) return { "science_data": x, "subset": x[3:-3], "skipping": x[::2], "not_shared": np.arange(10, 0, -1, dtype=np.uint8), } def create_large_tree(): # These are designed to be big enough so they don't fit in a # single block, but not so big that RAM/disk space for the tests # is enormous. x = RNG.normal(size=(256, 256)) y = RNG.normal(size=(16, 16, 16)) return { "science_data": x, "more": y, } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.137098 asdf-3.4.0/asdf/_tests/_block/0000755000175100001770000000000014653725331015520 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/_block/__init__.py0000644000175100001770000000000014653725311017615 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/_block/test_callback.py0000644000175100001770000000231414653725311020663 0ustar00runnerdockerimport pytest from asdf._block.callback import DataCallback from asdf._block.manager import ReadBlocks def test_default_attribute(): class Data: def __init__(self, value): self.data = value blks = ReadBlocks([Data("a"), Data("b")]) cbs = [DataCallback(0, blks), DataCallback(1, blks)] assert cbs[0]() == "a" assert cbs[1]() == "b" def test_attribute_access(): class Foo: def __init__(self, attr, value): setattr(self, attr, value) blks = ReadBlocks([Foo("a", "foo"), Foo("a", "bar")]) cb = DataCallback(0, blks) assert cb(_attr="a") == "foo" def test_weakref(): class Data: def __init__(self, value): self.data = value blks = ReadBlocks([Data("a"), Data("b")]) cb = DataCallback(0, blks) del blks with pytest.raises(OSError, match="Attempt to read block data from missing block"): cb() def test_reassign(): class Data: def __init__(self, value): self.data = value blks = ReadBlocks([Data("a"), Data("b")]) cb = DataCallback(0, blks) assert cb() == "a" blks2 = ReadBlocks([Data("c"), Data("d")]) cb._reassign(1, blks2) assert cb() == "d" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/_block/test_external.py0000644000175100001770000000147514653725311020760 0ustar00runnerdockerimport numpy as np import pytest import asdf from asdf._block import external def test_cache(tmp_path): efn = tmp_path / "test.asdf" arr = np.arange(3, dtype="uint8") asdf.AsdfFile({"data": arr}).write_to(efn) cache = external.ExternalBlockCache() base_uri = f"{tmp_path.as_uri()}/" data = cache.load(base_uri, "test.asdf") np.testing.assert_array_equal(data, arr) assert cache.load(base_uri, "test.asdf") is data assert cache.load(base_uri, "#") is external.UseInternal assert cache.load(base_uri, "") is external.UseInternal @pytest.mark.parametrize("uri", ["test.asdf", "foo/test.asdf"]) @pytest.mark.parametrize("index", [0, 1, 100]) def test_relative_uri_for_index(uri, index): match = f"test{index:04d}.asdf" assert external.relative_uri_for_index(uri, index) == match ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/_block/test_io.py0000644000175100001770000003047214653725311017544 0ustar00runnerdockerimport io import mmap import numpy as np import pytest from asdf import constants, generic_io from asdf._block import io as bio from asdf._block.exceptions import BlockIndexError def test_checksum(tmp_path): my_array = np.arange(0, 64, dtype=" allocated_size data = np.ones(30, dtype="uint8") raw_fd = io.BytesIO() fd = generic_io.get_file(raw_fd, mode="rw") with pytest.raises(RuntimeError, match="Block used size.*"): bio.write_block(fd, data, allocated_size=0) assert fd.tell() == 0 def test_fd_not_seekable(): data = np.ones(30, dtype="uint8") raw_fd = io.BytesIO() fd = generic_io.get_file(raw_fd, mode="rw") bio.write_block(fd, data) raw_fd.seek(0) fd = generic_io.get_file(raw_fd, mode="rw") seekable = lambda: False # noqa: E731 fd.seekable = seekable _, _, _, d = bio.read_block(fd) np.testing.assert_array_equal(d, data) with pytest.raises(ValueError, match="write_block received offset.*"): bio.write_block(fd, data, offset=0) def test_compressed_block(): data = np.ones(30, dtype="uint8") fd = generic_io.get_file(io.BytesIO(), mode="rw") write_header = bio.write_block(fd, data, compression="zlib") assert write_header["compression"] == b"zlib" _, _, _, rdata = bio.read_block(fd, offset=0) np.testing.assert_array_equal(rdata, data) def test_stream_block(): data = np.ones(10, dtype="uint8") fd = generic_io.get_file(io.BytesIO(), mode="rw") write_header = bio.write_block(fd, data, stream=True) assert write_header["flags"] & constants.BLOCK_FLAG_STREAMED # now write extra data to file extra_data = np.ones(10, dtype="uint8") fd.write_array(extra_data) _, _, _, rdata = bio.read_block(fd, offset=0) assert rdata.size == 20 assert np.all(rdata == 1) def test_read_from_closed(tmp_path): fn = tmp_path / "test.blk" data = np.ones(10, dtype="uint8") with generic_io.get_file(fn, mode="w") as fd: bio.write_block(fd, data, stream=True) with generic_io.get_file(fn, mode="rw") as fd: _, _, _, callback = bio.read_block(fd, offset=0, lazy_load=True) with pytest.raises(OSError, match="ASDF file has already been closed. Can not get the data."): callback() @pytest.mark.parametrize("data", [np.ones(10, dtype="f4"), np.ones((3, 3), dtype="uint8")]) def test_invalid_data(data): fd = generic_io.get_file(io.BytesIO(), mode="rw") with pytest.raises(ValueError, match="Data must be of.*"): bio.write_block(fd, data, stream=True) @pytest.mark.parametrize( "options", [ (0, 10, 5, [5, 0]), (0, 10, 3, [9, 6, 3, 0]), (0, 10, 10, [0]), (0, 10, 6, [6, 0]), (0, 10, 11, [0]), (0, 10, 4096, [0]), ], ) def test_candidate_offsets(options): min_offset, max_offset, size, targets = options for offset, target in zip(bio._candidate_offsets(min_offset, max_offset, size), targets): assert offset == target def generate_block_index_file(fn, values=None, offset=0): if values is None: values = [1, 2, 3] with generic_io.get_file(fn, "w") as f: f.write(b"\0" * offset) bio.write_block_index(f, values) def test_find_block_index(tmp_path): offset = 42 fn = tmp_path / "test" generate_block_index_file(fn, offset=offset) with generic_io.get_file(fn, "r") as fd: assert bio.find_block_index(fd) == offset def test_find_block_index_on_boundry(tmp_path): fn = tmp_path / "test" with generic_io.get_file(fn, "w") as fd: block_size = fd.block_size # put pattern across a block boundary offset = block_size - (len(constants.INDEX_HEADER) // 2) generate_block_index_file(fn, offset=offset) with generic_io.get_file(fn, "r") as fd: assert bio.find_block_index(fd) == offset def test_missing_block_index(tmp_path): fn = tmp_path / "test" with open(fn, "w") as f: f.write("\0" * 4096) with generic_io.get_file(fn, "r") as fd: assert bio.find_block_index(fd) is None def test_less_than_min_offset_block_index(tmp_path): fn = tmp_path / "test" offset = 26 min_offset = 42 generate_block_index_file(fn, offset=offset) with generic_io.get_file(fn, "r") as fd: assert bio.find_block_index(fd, min_offset) is None def test_greater_than_max_offset_block_index(tmp_path): fn = tmp_path / "test" offset = 72 max_offset = 42 generate_block_index_file(fn, offset=offset) with generic_io.get_file(fn, "r") as fd: assert bio.find_block_index(fd, 0, max_offset) is None def test_read_block_index(tmp_path): fn = tmp_path / "test" values = [1, 2, 3] generate_block_index_file(fn, values=values, offset=0) with generic_io.get_file(fn, "r") as fd: assert bio.read_block_index(fd) == values def test_read_block_index_with_offset(tmp_path): fn = tmp_path / "test" values = [1, 2, 3] offset = 42 generate_block_index_file(fn, values=values, offset=offset) with generic_io.get_file(fn, "r") as fd: assert bio.read_block_index(fd, offset) == values def test_read_block_index_pre_seek(tmp_path): fn = tmp_path / "test" values = [1, 2, 3] offset = 42 generate_block_index_file(fn, values=values, offset=offset) with generic_io.get_file(fn, "r") as fd: fd.seek(offset) assert bio.read_block_index(fd) == values def test_read_block_index_no_header(tmp_path): fn = tmp_path / "test" values = [1, 2, 3] generate_block_index_file(fn, values=values, offset=0) with generic_io.get_file(fn, "r") as fd: fd.seek(len(constants.INDEX_HEADER)) with pytest.raises(BlockIndexError, match="Failed to read block index.*"): assert bio.read_block_index(fd) == values def test_read_block_index_invalid_yaml(): bs = io.BytesIO(constants.INDEX_HEADER + b"][") with generic_io.get_file(bs, "r") as fd: with pytest.raises(BlockIndexError, match="Failed to parse block index as yaml"): bio.read_block_index(fd) def test_read_block_index_valid_yaml_invalid_contents(): bs = io.BytesIO(constants.INDEX_HEADER + b"['a', 'b']") with generic_io.get_file(bs, "r") as fd: with pytest.raises(BlockIndexError, match="Invalid block index"): bio.read_block_index(fd) def test_write_block_index_with_offset(tmp_path): fn = tmp_path / "test" offset = 50 with generic_io.get_file(fn, "w") as fd: fd.write(b"\0" * 100) fd.seek(0) bio.write_block_index(fd, [1, 2, 3], offset=offset) with generic_io.get_file(fn, "r") as fd: assert bio.find_block_index(fd) == offset ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/_block/test_key.py0000644000175100001770000000344014653725311017720 0ustar00runnerdockerimport copy from asdf._block.key import Key # a blank class for testing class Foo: pass def test_unique_per_object(): seen = set() for _i in range(10): bk = Key(Foo()) assert bk not in seen seen.add(bk) def test_unique_same_object(): seen = set() f = Foo() for _i in range(10): bk = Key(f) assert bk not in seen seen.add(bk) def test_matches_obj(): f = Foo() bk = Key(f) assert bk._matches_object(f) def test_undefined_no_match(): bk = Key() assert not bk._matches_object(Foo()) def test_is_valid(): f = Foo() bk = Key(f) assert bk._is_valid() del f assert not bk._is_valid() def test_same_class(): f = Foo() bk = Key(f) del f f2 = Foo() assert not bk._is_valid() assert not bk._matches_object(f2) def test_undefined(): k = Key() assert not k._is_valid() def test_equal(): key_value = 42 f = Foo() k1 = Key(f, key_value) k2 = Key(f, key_value) assert k1 == k2 def test_key_mismatch_not_equal(): f = Foo() k1 = Key(f) k2 = Key(f) assert k1 != k2 def test_obj_not_equal(): f = Foo() k = Key(f) assert k != f def test_undefined_not_equal(): key_value = 42 k1 = Key(_key=key_value) k2 = Key(_key=key_value) assert k1 != k2 def test_deleted_object_not_equal(): key_value = 42 f = Foo() k1 = Key(f, key_value) k2 = Key(f, key_value) del f assert k1 != k2 def test_copy(): f = Foo() k1 = Key(f) k2 = copy.copy(k1) assert k1 == k2 def test_copy_undefined_not_equal(): k1 = Key() k2 = copy.copy(k1) assert k1 != k2 def test_copy_deleted_object_not_equal(): f = Foo() k1 = Key(f) k2 = copy.copy(k1) del f assert k1 != k2 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/_block/test_manager.py0000644000175100001770000000560214653725311020544 0ustar00runnerdockerimport numpy as np import pytest import asdf from asdf._block import manager from asdf._block.options import Options def test_set_streamed_block_via_options(): options = manager.OptionsStore(manager.ReadBlocks()) arr1 = np.arange(10, dtype="uint8") arr2 = np.arange(5, dtype="uint8") options.set_options(arr1, Options("streamed")) with pytest.raises(ValueError, match=r"Can not add second streaming block"): options.set_options(arr2, Options("streamed")) del arr1 options.set_options(arr2, Options("streamed")) def test_set_streamed_block_via_manager(): af = asdf.AsdfFile() m = af._blocks class Foo: pass arr = np.arange(10, dtype="uint8") obj = Foo() m.set_streamed_write_block(arr, obj) # setting again with the same data is ok m.set_streamed_write_block(arr, obj) # using a different array is not allowed arr2 = np.arange(3, dtype="uint8") with pytest.raises(ValueError, match="Can not add second streaming block"): m.set_streamed_write_block(arr2, obj) # a different object is ok as long as the array matches obj2 = Foo() m.set_streamed_write_block(arr, obj2) def test_load_external_internal(tmp_path): fn = tmp_path / "test.asdf" asdf.AsdfFile({"arr": np.arange(10, dtype="uint8")}).write_to(fn) with asdf.open(fn) as af: m = af._blocks np.testing.assert_array_equal(m._load_external("#"), m.blocks[0].data) def test_write_no_uri(tmp_path): fn = tmp_path / "test.asdf" asdf.AsdfFile({"arr": np.arange(10, dtype="uint8")}).write_to(fn) with asdf.open(fn) as af: m = af._blocks with pytest.raises(ValueError, match=r"Can't write external blocks.*"): m._write_external_blocks() def test_write_outside_context(tmp_path): fn = tmp_path / "test.asdf" asdf.AsdfFile({"arr": np.arange(10, dtype="uint8")}).write_to(fn) with asdf.open(fn) as af: m = af._blocks with pytest.raises(OSError, match=r"write called outside of valid write_context"): m.write(False, False) def test_update_outside_context(tmp_path): fn = tmp_path / "test.asdf" asdf.AsdfFile({"arr": np.arange(10, dtype="uint8")}).write_to(fn) with asdf.open(fn) as af: m = af._blocks with pytest.raises(OSError, match=r"update called outside of valid write_context"): m.update(0, False, False) def test_input_compression(tmp_path): fn = tmp_path / "test.asdf" af = asdf.AsdfFile({"arr": np.arange(10, dtype="uint8")}) af.set_array_compression(af["arr"], "zlib") af.write_to(fn) with asdf.open(fn) as af: assert af.get_array_compression(af["arr"]) == "zlib" af.set_array_compression(af["arr"], "bzp2") assert af.get_array_compression(af["arr"]) == "bzp2" af.set_array_compression(af["arr"], "input") assert af.get_array_compression(af["arr"]) == "zlib" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/_block/test_options.py0000644000175100001770000000722614653725311020631 0ustar00runnerdockerimport copy import pytest from asdf._block.options import Options from asdf.config import config_context valid_storage_types = ["internal", "external", "streamed", "inline"] valid_default_storage_types = [st for st in valid_storage_types if st != "streamed"] valid_compression_types = [None, "zlib", "bzp2", "lz4", ""] invalid_storage_types = ["foo", "bar"] invalid_compression_types = ["input", "foo"] @pytest.mark.parametrize("storage", valid_storage_types) def test_set_storage_init(storage): o = Options(storage) assert o.storage_type == storage @pytest.mark.parametrize("storage", valid_default_storage_types) def test_default_storage_init(storage): with config_context() as cfg: cfg.all_array_storage = storage o = Options() assert o.storage_type == storage @pytest.mark.parametrize("storage", valid_storage_types) def test_set_storage_attr(storage): # start with a different storage type o = Options("internal" if storage == "external" else "external") o.storage_type = storage assert o.storage_type == storage @pytest.mark.parametrize("compression", valid_compression_types) def test_set_compression_attr(compression): o = Options("internal") o.compression = compression # allow "" to become None, both are falsey assert o.compression == compression if compression else not o.compression @pytest.mark.parametrize("compression", valid_compression_types) def test_set_compression_init(compression): o = Options("internal", compression) # allow "" to become None, both are falsey assert o.compression == compression if compression else not o.compression def test_set_compression_kwargs_attr(): o = Options("internal") o.compression_kwargs = {"foo": 1} assert o.compression_kwargs == {"foo": 1} def test_set_compression_kwargs_init(): o = Options("internal", compression_kwargs={"foo": 1}) assert o.compression_kwargs == {"foo": 1} def test_default_compression(): o = Options("internal") assert o.compression is None @pytest.mark.parametrize("invalid_storage", invalid_storage_types) def test_invalid_storage_type_init(invalid_storage): with pytest.raises(ValueError, match="array_storage must be one of.*"): Options(invalid_storage) @pytest.mark.parametrize("invalid_storage", invalid_storage_types) def test_invalid_storage_attr(invalid_storage): o = Options("internal") with pytest.raises(ValueError, match="array_storage must be one of.*"): o.storage_type = invalid_storage @pytest.mark.parametrize("invalid_compression", invalid_compression_types) def test_invalid_compression_attr(invalid_compression): o = Options("internal") with pytest.raises(ValueError, match="Invalid compression.*"): o.compression = invalid_compression @pytest.mark.parametrize("invalid_compression", invalid_compression_types) def test_invalid_compression_init(invalid_compression): with pytest.raises(ValueError, match="Invalid compression.*"): Options("internal", invalid_compression) @pytest.mark.parametrize("storage", valid_storage_types) @pytest.mark.parametrize("compression", valid_compression_types) @pytest.mark.parametrize("compression_kwargs", [None, {"foo": 1}]) def test_copy(storage, compression, compression_kwargs): o = Options(storage, compression, compression_kwargs) o2 = copy.copy(o) assert o2 is not o assert o2.storage_type == storage # allow "" to become None, both are falsey assert o2.compression == compression if compression else not o2.compression # allow None to become {}, both are falsey assert o2.compression_kwargs == compression_kwargs if compression_kwargs else not o2.compression_kwargs ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/_block/test_reader.py0000644000175100001770000001571114653725311020376 0ustar00runnerdockerimport contextlib import io import mmap import os import numpy as np import pytest from asdf import constants, generic_io, util from asdf._block import io as bio from asdf._block.reader import read_blocks from asdf.exceptions import AsdfBlockIndexWarning, AsdfWarning @contextlib.contextmanager def gen_blocks( fn=None, n=5, size=10, padding=0, padding_byte=b"\0", with_index=False, block_padding=False, streamed=False ): offsets = [] if fn is not None: with generic_io.get_file(fn, mode="w") as fd: pass def check(blocks): assert len(blocks) == n for i, blk in enumerate(blocks): assert blk.data.size == size assert np.all(blk.data == i) with generic_io.get_file(fn or io.BytesIO(), mode="rw") as fd: fd.write(padding_byte * padding) for i in range(n): offsets.append(fd.tell()) fd.write(constants.BLOCK_MAGIC) data = np.ones(size, dtype="uint8") * i bio.write_block(fd, data, stream=streamed and (i == n - 1), padding=block_padding) if with_index and not streamed: bio.write_block_index(fd, offsets) fd.seek(0) yield fd, check # test a few paddings to test read_blocks checking 4 bytes while searching for the first block @pytest.mark.parametrize("lazy_load", [True, False]) @pytest.mark.parametrize("memmap", [True, False]) @pytest.mark.parametrize("with_index", [True, False]) @pytest.mark.parametrize("validate_checksums", [True, False]) @pytest.mark.parametrize("padding", [0, 3, 4, 5]) @pytest.mark.parametrize("streamed", [True, False]) def test_read(tmp_path, lazy_load, memmap, with_index, validate_checksums, padding, streamed): fn = tmp_path / "test.bin" n = 5 size = 10 with gen_blocks(fn=fn, n=n, size=size, padding=padding, with_index=with_index, streamed=streamed) as (fd, check): r = read_blocks(fd, memmap=memmap, lazy_load=lazy_load, validate_checksums=validate_checksums) if lazy_load and with_index and not streamed: assert r[0].loaded assert r[-1].loaded for blk in r[1:-1]: assert not blk.loaded # getting the header should load the block blk.header assert blk.loaded else: for blk in r: assert blk.loaded if memmap: for blk in r: base = util.get_array_base(blk.data) assert isinstance(base.base, mmap.mmap) check(r) if lazy_load: # if lazy loaded, each call to data should re-read the data assert r[0].data is not r[0].data else: assert r[0].data is r[0].data # getting cached_data should always return the same array assert r[0].cached_data is r[0].cached_data def test_read_invalid_padding(): with gen_blocks(padding=1, padding_byte=b"\1") as (fd, check): with pytest.raises(OSError, match="Invalid bytes.*"): check(read_blocks(fd)) def test_read_post_padding_null_bytes(): with gen_blocks(padding=1) as (fd, check): fd.seek(0, os.SEEK_END) # acceptable to have <4 bytes after the last block fd.write(b"\x00" * 3) fd.seek(0) check(read_blocks(fd)) def test_read_post_padding_non_null_bytes(): with gen_blocks(padding=1) as (fd, check): fd.seek(0, os.SEEK_END) # acceptable to have <4 bytes after the last block fd.write(b"\x01" * 3) fd.seek(0) with pytest.warns(AsdfWarning, match=r"Read invalid bytes.*"): check(read_blocks(fd)) @pytest.mark.parametrize("invalid_block_index", [0, 1, -1, "junk"]) def test_invalid_block_index(tmp_path, invalid_block_index): fn = tmp_path / "test.bin" with gen_blocks(fn=fn, with_index=True) as (fd, check): # trash the block index offset = bio.find_block_index(fd) assert offset is not None if invalid_block_index == "junk": # trash the whole index fd.seek(-4, 2) fd.write(b"junk") else: # mess up one entry of the index block_index = bio.read_block_index(fd, offset) block_index[invalid_block_index] += 4 fd.seek(offset) bio.write_block_index(fd, block_index) fd.seek(0) # when the block index is read, only the first and last blocks # are check, so any other invalid entry should result in failure if invalid_block_index in (0, -1): with pytest.warns(AsdfBlockIndexWarning, match="Invalid block index contents"): check(read_blocks(fd, lazy_load=True)) elif invalid_block_index == "junk": # read_blocks should fall back to reading serially with pytest.warns(AsdfBlockIndexWarning, match="Failed to read block index"): check(read_blocks(fd, lazy_load=True)) else: with pytest.raises(ValueError, match="Header size.*"): check(read_blocks(fd, lazy_load=True)) def test_invalid_block_in_index_with_valid_magic(tmp_path): fn = tmp_path / "test.bin" with gen_blocks(fn=fn, with_index=True, block_padding=1.0) as (fd, check): offset = bio.find_block_index(fd) assert offset is not None block_index = bio.read_block_index(fd, offset) # move the first block offset to the padding before # the second block with enough space to write # valid magic (but invalid header) block_index[0] = block_index[1] - 6 fd.seek(block_index[0]) fd.write(constants.BLOCK_MAGIC) fd.write(b"\0\0") fd.seek(offset) bio.write_block_index(fd, block_index) fd.seek(0) with pytest.warns(AsdfBlockIndexWarning, match="Invalid block index contents"): check(read_blocks(fd, lazy_load=True)) def test_closed_file(tmp_path): fn = tmp_path / "test.bin" with gen_blocks(fn=fn, with_index=True) as (fd, check): blocks = read_blocks(fd, lazy_load=True) blk = blocks[1] with pytest.raises(OSError, match="Attempt to load block from closed file"): blk.load() @pytest.mark.parametrize("validate_checksums", [True, False]) def test_bad_checksum(validate_checksums): buff = io.BytesIO( constants.BLOCK_MAGIC + b"\x000" # header size = 2 + b"\0\0\0\0" # flags = 4 + b"\0\0\0\0" # compression = 4 + b"\0\0\0\0\0\0\0\0" # allocated size = 8 + b"\0\0\0\0\0\0\0\0" # used size = 8 + b"\0\0\0\0\0\0\0\0" # data size = 8 + b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" # invalid checksum = 16 ) with generic_io.get_file(buff, mode="r") as fd: if validate_checksums: with pytest.raises(ValueError, match=".* does not match given checksum"): read_blocks(fd, lazy_load=False, validate_checksums=validate_checksums)[0].data else: read_blocks(fd, lazy_load=False, validate_checksums=validate_checksums)[0].data ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/_block/test_store.py0000644000175100001770000000626614653725311020275 0ustar00runnerdockerfrom unittest.mock import patch import pytest from asdf._block.key import Key from asdf._block.store import Store # a blank class for testing class Foo: pass def test_store_by_obj(): f = Foo() v = 42 s = Store() s.assign_object(f, v) assert s.lookup_by_object(f) == v def test_get_missing_by_obj(): f = Foo() s = Store() assert s.lookup_by_object(f) is None def test_store_by_key(): f = Foo() v = 42 s = Store() k = Key(f) s.assign_object(k, v) assert s.lookup_by_object(k) == v def test_get_by_key(): f = Foo() v = 42 s = Store() k = Key(f) s.assign_object(k, v) assert s.lookup_by_object(f) == v def test_get_missing_key(): f = Foo() s = Store() k = Key(f) assert s.lookup_by_object(k) is None def test_get_missing_key_same_obj(): f = Foo() v = 42 s = Store() k = Key(f) s.assign_object(k, v) k2 = Key(f) assert s.lookup_by_object(k2) is None def test_get_existing_default(): f = Foo() v = 42 s = Store() s.assign_object(f, v) assert s.lookup_by_object(f, 26) == v def test_get_missing_default(): f = Foo() v = 42 s = Store() assert s.lookup_by_object(f, v) == v def test_set_same_object(): f = Foo() v = 42 s = Store() s.assign_object(f, 26) s.assign_object(f, v) assert s.lookup_by_object(f) == v def test_invalid_key_assign_object(): s = Store() k = Key() with pytest.raises(ValueError, match="Invalid key used for assign_object"): s.assign_object(k, 42) def test_set_same_key(): f = Foo() s = Store() k = Key(f) v = 42 s.assign_object(k, 26) s.assign_object(k, v) assert s.lookup_by_object(k) == v def test_get_memory_reused(): f = Foo() s = Store() v = 42 s.assign_object(f, v) fid = id(f) del f f2 = Foo() def mock_id(obj): if obj is f2: return fid return id(obj) with patch("asdf._block.store.id", mock_id): assert s.lookup_by_object(f2) is None def test_set_memory_reused(): f = Foo() s = Store() v = 42 s.assign_object(f, v) fid = id(f) del f f2 = Foo() def mock_id(obj): if obj is f2: return fid return id(obj) with patch("asdf._block.store.id", mock_id): nv = 26 s.assign_object(f2, nv) assert s.lookup_by_object(f2) is nv def test_cleanup(): f = Foo() s = Store() k = Key(f) s.assign_object(s, 42) s.assign_object(k, 26) del f s._cleanup() assert s.lookup_by_object(k, None) is None def test_keys_for_value(): s = Store() data = { Foo(): 42, Foo(): 26, Foo(): 42, Foo(): 11, } data_by_value = {} for o, v in data.items(): s.assign_object(o, v) data_by_value[v] = [*data_by_value.get(v, []), o] for v, objs in data_by_value.items(): objs = set(objs) returned_objects = set() for k in s.keys_for_value(v): assert k._is_valid() obj = k._ref() returned_objects.add(obj) assert objs == returned_objects del returned_objects, objs ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/_block/test_writer.py0000644000175100001770000000777214653725311020460 0ustar00runnerdockerimport numpy as np import pytest import asdf._block.io as bio from asdf import constants, generic_io from asdf._block import reader, writer @pytest.mark.parametrize("lazy", [True, False]) @pytest.mark.parametrize("index", [True, False]) @pytest.mark.parametrize("padding", [True, False, 0.1, 0.9]) @pytest.mark.parametrize("compression", [None, b"zlib"]) @pytest.mark.parametrize("stream", [True, False]) @pytest.mark.parametrize("seekable", [True, False]) def test_write_blocks(tmp_path, lazy, index, padding, compression, stream, seekable): data = [np.ones(10, dtype=np.uint8), np.zeros(5, dtype=np.uint8), None] if lazy: blocks = [writer.WriteBlock(lambda bd=d: bd, compression=compression) for d in data] else: blocks = [writer.WriteBlock(d, compression=compression) for d in data] if stream: streamed_block = writer.WriteBlock(np.ones(15, dtype=np.uint8)) else: streamed_block = None fn = tmp_path / "test.bin" with generic_io.get_file(fn, mode="w") as fd: if not seekable: fd.seekable = lambda: False writer.write_blocks(fd, blocks, padding=padding, streamed_block=streamed_block, write_index=index) with generic_io.get_file(fn, mode="r") as fd: if index and not stream: assert bio.find_block_index(fd) is not None else: assert bio.find_block_index(fd) is None fd.seek(0) read_blocks = reader.read_blocks(fd) if stream: assert len(read_blocks) == (len(data) + 1) else: assert len(read_blocks) == len(data) for r, d in zip(read_blocks, data): if d is None: assert r.data.size == 0 else: np.testing.assert_array_equal(r.data, d) if compression is not None: assert r.header["compression"] == compression if padding: assert r.header["allocated_size"] > r.header["used_size"] if stream: read_stream_block = read_blocks[-1] np.testing.assert_array_equal(read_stream_block.data, streamed_block.data) assert read_stream_block.header["flags"] & constants.BLOCK_FLAG_STREAMED def _raise_illegal_seek(): raise OSError("Illegal seek") @pytest.mark.parametrize("stream", [True, False]) @pytest.mark.parametrize("index", [True, False]) @pytest.mark.parametrize("tell", [0, None, _raise_illegal_seek]) def test_non_seekable_files_with_odd_tells(tmp_path, stream, index, tell): """ Some non-seekable files have odd 'tell' results. See: https://github.com/asdf-format/asdf/issues/1545 https://github.com/asdf-format/asdf/issues/1542 These can produce invalid block indices which should not be written to the ASDF file. """ data = [np.ones(10, dtype=np.uint8), np.zeros(5, dtype=np.uint8), None] blocks = [writer.WriteBlock(d) for d in data] if stream: streamed_block = writer.WriteBlock(np.ones(15, dtype=np.uint8)) else: streamed_block = None fn = tmp_path / "test.bin" with generic_io.get_file(fn, mode="w") as fd: fd.seekable = lambda: False if callable(tell): fd.tell = tell else: fd.tell = lambda: tell writer.write_blocks(fd, blocks, streamed_block=streamed_block, write_index=index) with generic_io.get_file(fn, mode="r") as fd: assert bio.find_block_index(fd) is None fd.seek(0) read_blocks = reader.read_blocks(fd) if stream: assert len(read_blocks) == (len(data) + 1) else: assert len(read_blocks) == len(data) for r, d in zip(read_blocks, data): if d is None: assert r.data.size == 0 else: np.testing.assert_array_equal(r.data, d) if stream: read_stream_block = read_blocks[-1] np.testing.assert_array_equal(read_stream_block.data, streamed_block.data) assert read_stream_block.header["flags"] & constants.BLOCK_FLAG_STREAMED ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/_helpers.py0000644000175100001770000000346414653725311016447 0ustar00runnerdockerimport warnings import numpy as np import asdf __all__ = [ "assert_tree_match", ] def assert_tree_match(old_tree, new_tree): """ Assert that two ASDF trees match. Parameters ---------- old_tree : ASDF tree new_tree : ASDF tree """ seen = set() ignore_keys = {"asdf_library", "history"} def recurse(old, new): if id(old) in seen or id(new) in seen: return seen.add(id(old)) seen.add(id(new)) if isinstance(old, dict) and isinstance(new, dict): assert {x for x in old if x not in ignore_keys} == {x for x in new if x not in ignore_keys} for key in old: if key not in ignore_keys: recurse(old[key], new[key]) elif isinstance(old, (list, tuple)) and isinstance(new, (list, tuple)): assert len(old) == len(new) for a, b in zip(old, new): recurse(a, b) elif all([isinstance(obj, (np.ndarray, asdf.tags.core.NDArrayType)) for obj in (old, new)]): with warnings.catch_warnings(): # The oldest deps job tests against versions of numpy where this # testing function raised a FutureWarning but still functioned # as expected warnings.filterwarnings("ignore", category=FutureWarning) if old.dtype.fields: if not new.dtype.fields: msg = "arrays not equal" raise AssertionError(msg) for f in old.dtype.fields: np.testing.assert_array_equal(old[f], new[f]) else: np.testing.assert_array_equal(old.__array__(), new.__array__()) else: assert old == new recurse(old_tree, new_tree) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.141098 asdf-3.4.0/asdf/_tests/_regtests/0000755000175100001770000000000014653725331016266 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/_regtests/test_1013.py0000644000175100001770000000305414653725311020263 0ustar00runnerdockerimport numpy as np import asdf def test_control_array_storage_in_to_yaml_tree_methods(tmp_path): """ controlling array storage in to_yaml_tree methods https://github.com/asdf-format/asdf/issues/1013 """ class FooType: def __init__(self, data): self.data = data class FooConverter: tags = ["asdf://somewhere.org/tag/foo-1.0.0"] types = [FooType] def to_yaml_tree(self, obj, tag, ctx): if obj.data.ndim < 2: ctx._blocks._set_array_storage(obj.data, "inline") return {"data": obj.data} def from_yaml_tree(self, obj, tag, ctx): return FooType(obj["data"]) class FooExtension: converters = [FooConverter()] tags = ["asdf://somewhere.org/tag/foo-1.0.0"] extension_uri = "asdf://somewhere.org/extensions/foo-1.0.0" with asdf.config_context() as cfg: cfg.add_extension(FooExtension()) fn = tmp_path / "test.asdf" for shape in [3, (3, 3)]: arr = np.zeros(shape) n_blocks = 0 if arr.ndim == 1 else 1 af = asdf.AsdfFile({"foo": FooType(arr)}) assert af.get_array_storage(arr) == "internal" af.write_to(fn) # make sure write_to doesn't change the settings outside of the # writing context assert af.get_array_storage(arr) == "internal" with asdf.open(fn) as af: np.testing.assert_array_equal(af["foo"].data, arr) assert len(af._blocks.blocks) == n_blocks ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/_regtests/test_1334.py0000644000175100001770000000070514653725311020271 0ustar00runnerdockerimport numpy as np import asdf def test_memmap_view_access_after_close(tmp_path): """ Accessing a view of a memmap after the asdf file is closed results in a segfault https://github.com/asdf-format/asdf/issues/1334 """ a = np.ones(10, dtype="uint8") fn = tmp_path / "test.asdf" asdf.AsdfFile({"a": a}).write_to(fn) with asdf.open(fn, copy_arrays=False) as af: v = af["a"][:5] assert np.all(v == 1) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/_regtests/test_1505.py0000644000175100001770000000072514653725311020273 0ustar00runnerdockerimport numpy as np import asdf def test_update_fails_after_write_to(tmp_path): """ Calling update after write_to fails https://github.com/asdf-format/asdf/issues/1505 """ fn1 = tmp_path / "test1.asdf" fn2 = tmp_path / "test2.asdf" tree = {"a": np.zeros(3), "b": np.ones(3)} af = asdf.AsdfFile(tree) af.write_to(fn1) with asdf.open(fn1, mode="rw") as af: af["a"] = None af.write_to(fn2) af.update() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/_regtests/test_1523.py0000644000175100001770000000131514653725311020267 0ustar00runnerdockerimport numpy as np import asdf def test_update_corrupts_stream_data(tmp_path): """ update corrupts stream data https://github.com/asdf-format/asdf/issues/1523 """ fn = tmp_path / "stream.asdf" s = asdf.Stream([3], np.uint8) asdf.AsdfFile({"s": s}).write_to(fn) with open(fn, "rb+") as f: f.seek(0, 2) f.write(b"\x01\x02\x03") with asdf.open(fn) as af: np.testing.assert_array_equal(af["s"], [[1, 2, 3]]) with asdf.open(fn, mode="rw") as af: af["a"] = np.arange(1000) af.update() np.testing.assert_array_equal(af["s"], [[1, 2, 3]]) with asdf.open(fn) as af: np.testing.assert_array_equal(af["s"], [[1, 2, 3]]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/_regtests/test_1525.py0000644000175100001770000000147714653725311020302 0ustar00runnerdockerimport numpy as np import pytest import asdf @pytest.mark.parametrize("copy_arrays", [True, False]) def test_external_blocks_always_lazy_loaded_and_memmapped(tmp_path, copy_arrays): """ External blocks are always lazy loaded and memmapped https://github.com/asdf-format/asdf/issues/1525 """ fn = tmp_path / "test.asdf" arr = np.arange(10) af = asdf.AsdfFile({"arr": arr}) af.set_array_storage(arr, "external") af.write_to(fn) with asdf.open(fn, copy_arrays=copy_arrays) as af: # check that block is external source = af["arr"]._source assert isinstance(source, str) # check if block is memmapped if copy_arrays: assert not isinstance(af["arr"].base, np.memmap) else: assert isinstance(af["arr"].base, np.memmap) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/_regtests/test_1526.py0000644000175100001770000000151614653725311020275 0ustar00runnerdockerimport os import numpy as np import asdf def test_rewrite_file_with_unaccessed_external_blocks_fails(tmp_path): """ Rewriting a file with external blocks fails if arrays are not first accessed https://github.com/asdf-format/asdf/issues/1526 """ arrs = [np.arange(3) + i for i in range(3)] af = asdf.AsdfFile({"arrs": arrs}) [af.set_array_storage(a, "external") for a in arrs] dns = [] for i in range(2): dn = tmp_path / f"d{i}" if not os.path.exists(dn): os.makedirs(dn) dns.append(dn) fns = [dn / "test.asdf" for dn in dns] # write to d0 af.write_to(fns[0]) with asdf.open(fns[0]) as af2: af2["arrs"][0] = 42 # write to d1 af2.write_to(fns[1]) assert len(os.listdir(dns[0])) == 4 assert len(os.listdir(dns[1])) == 3 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/_regtests/test_1530.py0000644000175100001770000000216414653725311020270 0ustar00runnerdockerimport numpy as np import asdf def test_update_with_memmapped_data_can_make_view_data_invalid(tmp_path): """ Calling update with memmapped data can create invalid data in memmap views https://github.com/asdf-format/asdf/issues/1530 A view of a memmapped array can return invalid data or segfault after an update """ fn = tmp_path / "test.asdf" a = np.zeros(10, dtype="uint8") b = np.ones(10, dtype="uint8") ov = a[:3] af = asdf.AsdfFile({"a": a, "b": b}) af.write_to(fn) with asdf.open(fn, mode="rw", copy_arrays=False) as af: va = af["a"][:3] np.testing.assert_array_equal(a, af["a"]) np.testing.assert_array_equal(b, af["b"]) np.testing.assert_array_equal(va, ov) af["c"] = "a" * 10000 af.update() np.testing.assert_array_equal(a, af["a"]) np.testing.assert_array_equal(b, af["b"]) # the view of 'a' taken above ('va') keeps the original memmap open # and is not a valid view of af['a'] (as this now differs from the # af['a'] used to generate the view). assert not np.all(va == ov) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/_regtests/test_1538.py0000644000175100001770000000065014653725311020276 0ustar00runnerdockerimport numpy as np import asdf def test_unable_to_read_empty_inline_array(tmp_path): """ ASDF unable to read empty inline array https://github.com/asdf-format/asdf/issues/1538 """ fn = tmp_path / "test.asdf" a = np.array([]) af = asdf.AsdfFile({"a": a}) af.set_array_storage(a, "inline") af.write_to(fn) with asdf.open(fn) as af: np.testing.assert_array_equal(af["a"], a) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/_regtests/test_1539.py0000644000175100001770000000100614653725311020273 0ustar00runnerdockerimport io import pytest import asdf @pytest.mark.xfail(reason="Fix will require more major changes to generic_io") def test_invalid_seek_and_read_from_closed_memoryio(): """ Seek and read from closed MemoryIO https://github.com/asdf-format/asdf/issues/1539 """ b = io.BytesIO() b.write(b"\0" * 10) b.seek(0) f = asdf.generic_io.get_file(b) f.close() with pytest.raises(IOError, match="I/O operation on closed file."): f.read_into_array(10) assert b.tell() == 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/_regtests/test_1540.py0000644000175100001770000000100414653725311020261 0ustar00runnerdockerimport numpy as np import asdf def test_writes_but_fails_to_read_inline_structured_array(tmp_path): """ ASDF writes but fails to read inline structured array https://github.com/asdf-format/asdf/issues/1540 """ x = np.array((0, 1.0, [2, 3]), dtype=[("MINE", "i1"), ("f1", " defragment_size with asdf.open(tmp_path / "original.defragment.asdf") as ff: assert_tree_match(ff.tree, tree) assert len(ff._blocks.blocks) == 2 def test_defragment_zlib(tmp_path): _test_defragment(tmp_path, "zlib") def test_defragment_bzp2(tmp_path): _test_defragment(tmp_path, "bzp2") def test_defragment_lz4(tmp_path): pytest.importorskip("lz4") _test_defragment(tmp_path, "lz4") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/commands/test_diff.py0000644000175100001770000000546514653725311020421 0ustar00runnerdockerimport io import pytest from asdf.commands import diff, main def _assert_diffs_equal(test_data_path, filenames, result_file, minimal=False, ignore=None): iostream = io.StringIO() file_paths = [test_data_path / name for name in filenames] diff(file_paths, minimal=minimal, iostream=iostream, ignore=ignore) iostream.seek(0) result_path = test_data_path / result_file with open(result_path) as handle: assert handle.read() == iostream.read() def test_diff(test_data_path): filenames = ["frames0.asdf", "frames1.asdf"] result_file = "frames.diff" _assert_diffs_equal(test_data_path, filenames, result_file, minimal=False) def test_diff_minimal(test_data_path): filenames = ["frames0.asdf", "frames1.asdf"] result_file = "frames_minimal.diff" _assert_diffs_equal(test_data_path, filenames, result_file, minimal=True) @pytest.mark.parametrize( ("result_file", "ignore"), [ ("frames_ignore_asdf_library.diff", ["asdf_library"]), ("frames_ignore_reference_frame.diff", ["frames[*].reference_frame"]), ("frames_ignore_both.diff", ["asdf_library", "frames[*].reference_frame"]), ], ) def test_diff_ignore(test_data_path, result_file, ignore): filenames = ["frames0.asdf", "frames1.asdf"] _assert_diffs_equal(test_data_path, filenames, result_file, minimal=False, ignore=ignore) def test_diff_ndarray(test_data_path): filenames = ["ndarray0.asdf", "ndarray1.asdf"] result_file = "ndarrays.diff" _assert_diffs_equal(test_data_path, filenames, result_file, minimal=False) def test_diff_ndarray_in_list(test_data_path): filenames = ["ndarray_in_list0.asdf", "ndarray_in_list1.asdf"] result_file = "ndarray_in_list.diff" _assert_diffs_equal(test_data_path, filenames, result_file, minimal=False) def test_diff_block(test_data_path): filenames = ["block0.asdf", "block1.asdf"] result_file = "blocks.diff" _assert_diffs_equal(test_data_path, filenames, result_file, minimal=False) def test_diff_simple_inline_array(test_data_path): filenames = ["simple_inline_array0.asdf", "simple_inline_array1.asdf"] result_file = "simple_inline_array.diff" _assert_diffs_equal(test_data_path, filenames, result_file, minimal=False) @pytest.mark.filterwarnings("ignore:unclosed file .*") def test_file_not_found(test_data_path): # Try to open files that exist but are not valid asdf filenames = ["frames.diff", "blocks.diff"] with pytest.raises( RuntimeError, match=r"Does not appear to be a ASDF file.", ): diff([test_data_path / name for name in filenames], False) def test_diff_command(test_data_path): filenames = ["frames0.asdf", "frames1.asdf"] path_strings = [str(test_data_path / name) for name in filenames] assert main.main_from_args(["diff", *path_strings]) == 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/commands/test_edit.py0000644000175100001770000002343114653725311020427 0ustar00runnerdockerimport os import re from contextlib import contextmanager import numpy as np import pytest from numpy.testing import assert_array_equal import asdf from asdf import constants from asdf._block import io as bio from asdf.commands import main RNG = np.random.default_rng(42) @pytest.fixture(params=asdf.versioning.supported_versions) def version(request): return request.param @pytest.fixture() def create_editor(tmp_path): """ Fixture providing a function that generates an editor script. """ def _create_editor(pattern, replacement): if isinstance(pattern, str): pattern = pattern.encode("utf-8") if isinstance(replacement, str): replacement = replacement.encode("utf-8") editor_path = tmp_path / "editor.py" content = f"""import re import sys with open(sys.argv[1], "rb") as file: content = file.read() content = re.sub({pattern!r}, {replacement!r}, content, flags=(re.DOTALL | re.MULTILINE)) with open(sys.argv[1], "wb") as file: file.write(content) """ with editor_path.open("w") as file: file.write(content) return f"python3 {editor_path}" return _create_editor @contextmanager def file_not_modified(path): """ Assert that a file was not modified during the context. """ original_mtime = os.stat(path).st_mtime_ns yield assert os.stat(path).st_mtime_ns == original_mtime @pytest.fixture() def mock_input(monkeypatch): """ Fixture providing a function that mocks the edit module's built-in input function. """ @contextmanager def _mock_input(pattern, response): called = False def _input(prompt=None): nonlocal called called = True assert prompt is not None assert re.match(pattern, prompt) return response with monkeypatch.context() as m: m.setattr("builtins.input", _input) yield assert called, "input was not called as expected" return _mock_input @pytest.fixture(autouse=True) def _default_mock_input(monkeypatch): """ Fixture that raises an error when the program requests unexpected input. """ def _input(prompt=None): msg = f"Received unexpected request for input: {prompt}" raise AssertionError(msg) monkeypatch.setattr("builtins.input", _input) def test_no_blocks(tmp_path, create_editor, version): file_path = str(tmp_path / "test.asdf") with asdf.AsdfFile(version=version) as af: af["foo"] = "bar" af.write_to(file_path) os.environ["EDITOR"] = create_editor(r"foo: bar", "foo: baz") assert main.main_from_args(["edit", file_path]) == 0 with asdf.open(file_path) as af: assert af["foo"] == "baz" def test_no_blocks_increase_size(tmp_path, create_editor, version): file_path = str(tmp_path / "test.asdf") with asdf.AsdfFile(version=version) as af: af["foo"] = "bar" af.write_to(file_path) new_value = "a" * 32768 os.environ["EDITOR"] = create_editor(r"foo: bar", f"foo: {new_value}") # With no blocks, we can expand the existing file, so this case # shouldn't require confirmation from the user. assert main.main_from_args(["edit", file_path]) == 0 with asdf.open(file_path) as af: assert af["foo"] == new_value def test_no_blocks_decrease_size(tmp_path, create_editor, version): file_path = str(tmp_path / "test.asdf") original_value = "a" * 32768 with asdf.AsdfFile(version=version) as af: af["foo"] = original_value af.write_to(file_path) os.environ["EDITOR"] = create_editor(f"foo: {original_value}", "foo: bar") assert main.main_from_args(["edit", file_path]) == 0 with asdf.open(file_path) as af: assert af["foo"] == "bar" def confirm_valid_block_index(file_path): # make sure the block index is valid with asdf.generic_io.get_file(file_path, "r") as f: block_index_offset = bio.find_block_index(f) assert block_index_offset is not None block_index = bio.read_block_index(f, block_index_offset) for block_offset in block_index: f.seek(block_offset) assert f.read(len(constants.BLOCK_MAGIC)) == constants.BLOCK_MAGIC def test_with_blocks(tmp_path, create_editor, version): file_path = str(tmp_path / "test.asdf") array1 = RNG.normal(size=100) array2 = RNG.normal(size=100) with asdf.AsdfFile(version=version) as af: af["array1"] = array1 af["array2"] = array2 af["foo"] = "bar" af.write_to(file_path) os.environ["EDITOR"] = create_editor(r"foo: bar", "foo: baz") assert main.main_from_args(["edit", file_path]) == 0 with asdf.open(file_path) as af: assert af["foo"] == "baz" assert_array_equal(af["array1"], array1) assert_array_equal(af["array2"], array2) confirm_valid_block_index(file_path) def test_with_blocks_increase_size(tmp_path, create_editor, version, mock_input): file_path = str(tmp_path / "test.asdf") array1 = RNG.normal(size=100) array2 = RNG.normal(size=100) with asdf.AsdfFile(version=version) as af: af["array1"] = array1 af["array2"] = array2 af["foo"] = "bar" af.write_to(file_path) new_value = "a" * 32768 os.environ["EDITOR"] = create_editor(r"foo: bar", f"foo: {new_value}") # Abort without updating the file with mock_input(r"\(c\)ontinue or \(a\)bort\?", "a"), file_not_modified(file_path): assert main.main_from_args(["edit", file_path]) == 1 # Agree to allow the file to be rewritten with mock_input(r"\(c\)ontinue or \(a\)bort\?", "c"): assert main.main_from_args(["edit", file_path]) == 0 with asdf.open(file_path) as af: assert af["foo"] == new_value assert_array_equal(af["array1"], array1) assert_array_equal(af["array2"], array2) confirm_valid_block_index(file_path) def test_with_blocks_decrease_size(tmp_path, create_editor, version): file_path = str(tmp_path / "test.asdf") original_value = "a" * 32768 array1 = RNG.normal(size=100) array2 = RNG.normal(size=100) with asdf.AsdfFile(version=version) as af: af["array1"] = array1 af["array2"] = array2 af["foo"] = original_value af.write_to(file_path) os.environ["EDITOR"] = create_editor(f"foo: {original_value}", "foo: bar") assert main.main_from_args(["edit", file_path]) == 0 with asdf.open(file_path) as af: assert af["foo"] == "bar" assert_array_equal(af["array1"], array1) assert_array_equal(af["array2"], array2) confirm_valid_block_index(file_path) def test_no_changes(tmp_path, create_editor, version): file_path = str(tmp_path / "test.asdf") with asdf.AsdfFile(version=version) as af: af["foo"] = "bar" af.write_to(file_path) os.environ["EDITOR"] = create_editor(r"non-existent-string", "non-existent-string") with file_not_modified(file_path): assert main.main_from_args(["edit", file_path]) == 0 def test_update_asdf_standard_version(tmp_path, create_editor, version, mock_input): file_path = str(tmp_path / "test.asdf") with asdf.AsdfFile(version=version) as af: af["foo"] = "bar" af.write_to(file_path) os.environ["EDITOR"] = create_editor(r"^#ASDF_STANDARD .*?$", "#ASDF_STANDARD 999.999.999") with file_not_modified(file_path), mock_input(r"\(c\)ontinue editing or \(a\)bort\?", "a"): assert main.main_from_args(["edit", file_path]) == 1 def test_update_yaml_version(tmp_path, create_editor, version, mock_input): file_path = str(tmp_path / "test.asdf") with asdf.AsdfFile(version=version) as af: af["foo"] = "bar" af.write_to(file_path) os.environ["EDITOR"] = create_editor(r"^%YAML 1.1$", "%YAML 1.2") with file_not_modified(file_path), mock_input(r"\(c\)ontinue editing or \(a\)bort\?", "a"): assert main.main_from_args(["edit", file_path]) == 1 def test_bad_yaml(tmp_path, create_editor, version, mock_input): file_path = str(tmp_path / "test.asdf") with asdf.AsdfFile(version=version) as af: af["foo"] = "bar" af.write_to(file_path) os.environ["EDITOR"] = create_editor(r"foo: bar", "foo: [") with file_not_modified(file_path), mock_input(r"\(c\)ontinue editing or \(a\)bort\?", "a"): assert main.main_from_args(["edit", file_path]) == 1 def test_validation_failure(tmp_path, create_editor, version, mock_input): file_path = str(tmp_path / "test.asdf") with asdf.AsdfFile(version=version) as af: af["array"] = np.arange(100) af.write_to(file_path) os.environ["EDITOR"] = create_editor(r"byteorder: .*?$", "byteorder: med") with file_not_modified(file_path), mock_input(r"\(c\)ontinue editing, \(f\)orce update, or \(a\)bort\?", "a"): assert main.main_from_args(["edit", file_path]) == 1 with mock_input(r"\(c\)ontinue editing, \(f\)orce update, or \(a\)bort\?", "f"): assert main.main_from_args(["edit", file_path]) == 0 with open(file_path, "rb") as f: content = f.read() assert b"byteorder: med" in content def test_asdf_open_failure(tmp_path, create_editor, version, mock_input): file_path = str(tmp_path / "test.asdf") with asdf.AsdfFile(version=version) as af: af["foo"] = "bar" af.write_to(file_path) os.environ["EDITOR"] = create_editor(r"^#ASDF .*?$", "#HJKL 1.0.0") with file_not_modified(file_path), mock_input(r"\(c\)ontinue editing or \(a\)bort\?", "a"): assert main.main_from_args(["edit", file_path]) == 1 def test_non_asdf_file(tmp_path): file_path = str(tmp_path / "test.asdf") with open(file_path, "w") as f: f.write("Dear diary...") with file_not_modified(file_path): assert main.main_from_args(["edit", file_path]) == 1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/commands/test_exploded.py0000644000175100001770000000333514653725311021307 0ustar00runnerdockerimport numpy as np import asdf from asdf import AsdfFile from asdf._tests._helpers import assert_tree_match from asdf.commands import main def test_explode_then_implode(tmp_path): x = np.arange(0, 10, dtype=float) tree = { "science_data": x, "subset": x[3:-3], "skipping": x[::2], "not_shared": np.arange(10, 0, -1, dtype=np.uint8), } path = tmp_path / "original.asdf" ff = AsdfFile(tree) # Since we're testing with small arrays, force all arrays to be stored # in internal blocks rather than letting some of them be automatically put # inline. ff.write_to(path, all_array_storage="internal") with asdf.open(path) as af: assert len(af._blocks.blocks) == 2 result = main.main_from_args(["explode", str(path)]) assert result == 0 files = [p.name for p in tmp_path.iterdir()] assert "original.asdf" in files assert "original_exploded.asdf" in files assert "original_exploded0000.asdf" in files assert "original_exploded0001.asdf" in files assert "original_exploded0002.asdf" not in files # compare file sizes of original and exploded files original_size = (tmp_path / "original.asdf").stat().st_size exploded_size = (tmp_path / "original_exploded.asdf").stat().st_size assert original_size > exploded_size path = tmp_path / "original_exploded.asdf" result = main.main_from_args(["implode", str(path)]) assert result == 0 with asdf.open(tmp_path / "original_exploded_all.asdf") as af: assert_tree_match(af.tree, tree) assert len(af._blocks.blocks) == 2 def test_file_not_found(tmp_path): path = tmp_path / "original.asdf" assert main.main_from_args(["explode", str(path)]) == 2 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/commands/test_extension.py0000644000175100001770000000111414653725311021510 0ustar00runnerdockerimport pytest from asdf.commands import find_extensions from asdf.versioning import supported_versions @pytest.mark.parametrize("summary", [True, False]) @pytest.mark.parametrize("tags_only", [True, False]) def test_parameter_combinations(summary, tags_only): # Just confirming no errors: find_extensions(summary, tags_only) @pytest.mark.parametrize("standard_version", supported_versions) def test_builtin_extension_included(capsys, standard_version): find_extensions(True, False) captured = capsys.readouterr() assert f"core-{standard_version}" in captured.out ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/commands/test_info.py0000644000175100001770000000161214653725311020432 0ustar00runnerdockerimport pytest from asdf.commands import main # The test file we're using here contains objects whose schemas # have been dropped from the ASDF Standard. We should select # a new file once the locations of schemas are more stable. @pytest.mark.filterwarnings("ignore::asdf.exceptions.AsdfConversionWarning") def test_info_command(capsys, test_data_path): file_path = test_data_path / "frames0.asdf" assert main.main_from_args(["info", str(file_path)]) == 0 captured = capsys.readouterr() assert "root" in captured.out assert "frames" in captured.out original_len = len(captured.out.split("\n")) assert main.main_from_args(["info", "--max-rows", str(original_len - 5), str(file_path)]) == 0 captured = capsys.readouterr() assert "root" in captured.out assert "frames" in captured.out new_len = len(captured.out.split("\n")) assert new_len < original_len ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/commands/test_main.py0000644000175100001770000000065214653725311020426 0ustar00runnerdockerimport pytest from asdf.commands import main def test_help(): # Just a smoke test, really main.main_from_args(["help"]) def test_invalid_command(): with pytest.raises(SystemExit) as e: main.main([]) assert e.value.code == 2 with pytest.raises(SystemExit) as e: main.main(["foo"]) if isinstance(e.value, int): assert e.value == 2 else: assert e.value.code == 2 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/commands/test_tags.py0000644000175100001770000000103414653725311020433 0ustar00runnerdockerimport io import pytest from asdf import AsdfFile from asdf.commands import list_tags @pytest.mark.parametrize("display_classes", [True, False]) def test_parameter_combinations(display_classes): # Just confirming no errors: list_tags(display_classes) def test_all_tags_present(): iostream = io.StringIO() list_tags(iostream=iostream) iostream.seek(0) tags = {line.strip() for line in iostream.readlines()} af = AsdfFile() for tag in af.extension_manager._converters_by_tag: assert tag in tags ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/commands/test_to_yaml.py0000644000175100001770000000156214653725311021147 0ustar00runnerdockerimport numpy as np import asdf from asdf import AsdfFile from asdf._tests._helpers import assert_tree_match from asdf.commands import main def test_to_yaml(tmp_path): x = np.arange(0, 10, dtype=float) tree = { "science_data": x, "subset": x[3:-3], "skipping": x[::2], "not_shared": np.arange(10, 0, -1, dtype=np.uint8), } path = tmp_path / "original.asdf" ff = AsdfFile(tree) ff.write_to(path) with asdf.open(path) as ff2: assert len(ff2._blocks.blocks) == 2 result = main.main_from_args(["to_yaml", str(path)]) assert result == 0 files = [p.name for p in tmp_path.iterdir()] assert "original.asdf" in files assert "original.yaml" in files with asdf.open(tmp_path / "original.yaml") as ff: assert_tree_match(ff.tree, tree) assert len(list(ff._blocks.blocks)) == 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/conftest.py0000644000175100001770000000274114653725311016470 0ustar00runnerdockerimport importlib.resources import pytest from asdf import config, schema from . import create_large_tree, create_small_tree from .httpserver import HTTPServer @pytest.fixture() def small_tree(): return create_small_tree() @pytest.fixture() def large_tree(): return create_large_tree() @pytest.fixture(autouse=True) def _restore_default_config(): yield config._global_config = config.AsdfConfig() config._local = config._ConfigLocal() @pytest.fixture(autouse=True) def _clear_schema_cache(): """ Fixture that clears schema caches to prevent issues when tests use same URI for different schema content. """ yield schema._load_schema.cache_clear() schema._load_schema_cached.cache_clear() @pytest.fixture() def httpserver(request): """ The returned ``httpserver`` provides a threaded HTTP server instance. It serves content from a temporary directory (available as the attribute tmpdir) at randomly assigned URL (available as the attribute url). * ``tmpdir`` - path to the tmpdir that it's serving from (str) * ``url`` - the base url for the server """ server = HTTPServer() yield server server.finalize() @pytest.fixture() def test_data_path(): return importlib.resources.files("asdf") / "_tests" / "data" @pytest.fixture(params=[True, False], ids=["lazy", "not-lazy"]) def with_lazy_tree(request): with config.config_context() as cfg: cfg.lazy_tree = request.param yield ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1722788569.141098 asdf-3.4.0/asdf/_tests/core/0000755000175100001770000000000014653725331015217 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/core/__init__.py0000644000175100001770000000000014653725311017314 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1450982 asdf-3.4.0/asdf/_tests/core/_converters/0000755000175100001770000000000014653725331017550 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/core/_converters/__init__.py0000644000175100001770000000000014653725311021645 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/core/_converters/test_complex.py0000644000175100001770000000351114653725311022626 0ustar00runnerdockerimport re import pytest import asdf from asdf.testing import helpers def make_complex_asdf(string): yaml = f""" a: !core/complex-1.0.0 {string} """ return helpers.yaml_to_asdf(yaml) @pytest.mark.parametrize( "invalid", [ "3 + 4i", "3+-4i", "3-+4i", "3i+4i", "X3+4iX", "3+X4i", "3+4", "3i+43+4z", "3.+4i", "3+4.i", "3e-4.0+4i", "3+4e4.0i", "", ], ) def test_invalid_complex(invalid): with pytest.raises(asdf.ValidationError), asdf.open(make_complex_asdf(invalid)): pass @pytest.mark.parametrize( "valid", [ "3+4j", "(3+4j)", ".3+4j", "3+.4j", "3e10+4j", "3e-10+4j", "3+4e10j", "3.0+4j", "3+4.0j", "3.0+4.0j", "3+4e-10j", "3+4J", "3+4i", "3+4I", "inf", "inf+infj", "inf+infi", "infj", "infi", "INFi", "INFI", "3+infj", "inf+4j", ], ) def test_valid_complex(valid): with asdf.open(make_complex_asdf(valid)) as af: assert af.tree["a"] == complex(re.sub(r"[iI]$", r"j", valid)) @pytest.mark.parametrize( "valid", ["nan", "nan+nanj", "nan+nani", "nanj", "nani", "NANi", "NANI", "3+nanj", "nan+4j"], ) def test_valid_nan_complex(valid): with asdf.open(make_complex_asdf(valid)): pass def test_roundtrip(tmp_path): values = { "a": 0 + 0j, "b": 1 + 1j, "c": -1 + 1j, "d": -1 - 1j, } fn = tmp_path / "test.asdf" asdf.AsdfFile({"values": values}).write_to(fn) with asdf.open(fn) as af: result = af["values"] assert len(values) == len(result) for key, value in values.items(): assert result[key] == value ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/core/_converters/test_constant.py0000644000175100001770000000033414653725311023010 0ustar00runnerdockerfrom asdf.tags.core import Constant from asdf.testing import helpers def test_constant(): constant = Constant("gardener") result = helpers.roundtrip_object(constant) assert result.value == constant.value ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/core/_converters/test_external_reference.py0000644000175100001770000000047014653725311025020 0ustar00runnerdockerfrom asdf.tags.core.external_reference import ExternalArrayReference from asdf.testing.helpers import roundtrip_object def test_roundtrip_external_array(tmp_path): ref = ExternalArrayReference("./nonexistent.fits", 1, "np.float64", (100, 100)) result = roundtrip_object(ref) assert result == ref ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/core/_converters/test_tree.py0000644000175100001770000000430514653725311022120 0ustar00runnerdockerimport datetime import asdf from asdf.tags.core import AsdfObject, ExtensionMetadata, HistoryEntry, Software, SubclassMetadata from asdf.testing import helpers def test_asdf_object(): asdf_object = AsdfObject({"foo": "bar"}) result = helpers.roundtrip_object(asdf_object) assert result == asdf_object def test_extension_metadata(): metadata = ExtensionMetadata( extension_class="foo.extension.FooExtension", extension_uri="http://foo.biz/extensions/foo-1.0.0", software=Software(name="FooSoft", version="1.5"), ) result = helpers.roundtrip_object(metadata) assert result == metadata def test_extension_metadata_extra_properties(): yaml = """ metadata: !core/extension_metadata-1.0.0 extension_class: foo.extension.FooExtension software: !core/software-1.0.0 name: FooSoft version: "1.5" extension_uri: http://foo.biz/extensions/foo-1.0.0 extra: property """ buff = helpers.yaml_to_asdf(yaml) with asdf.open(buff) as af: assert af["metadata"].extension_class == "foo.extension.FooExtension" assert af["metadata"].software["name"] == "FooSoft" assert af["metadata"].software["version"] == "1.5" assert af["metadata"].extension_uri == "http://foo.biz/extensions/foo-1.0.0" assert af["metadata"]["extra"] == "property" def test_software(): software = Software( name="FooSoft", version="1.5.0", author="The Foo Developers", homepage="http://nowhere.org", extra="property", ) result = helpers.roundtrip_object(software) assert result == software def test_history_entry(tmp_path): history_entry = HistoryEntry( description="Some history happened here", time=datetime.datetime.now(), software=[Software(name="FooSoft", version="1.5.0")], extra="property", ) fn = tmp_path / "test.asdf" asdf.AsdfFile({"obj": history_entry}).write_to(fn) with asdf.open(fn) as af: assert af["obj"] == history_entry def test_subclass_metadata(): subclass_metadata = SubclassMetadata(name="SomeCoolSubclass") result = helpers.roundtrip_object(subclass_metadata) assert result == subclass_metadata ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1450982 asdf-3.4.0/asdf/_tests/core/tests/0000755000175100001770000000000014653725331016361 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/core/tests/__init__.py0000644000175100001770000000000014653725311020456 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/core/tests/test_integration.py0000644000175100001770000000207714653725311022321 0ustar00runnerdockerimport pytest import yaml import asdf from asdf._core._integration import get_extensions, get_json_schema_resource_mappings @pytest.mark.parametrize( "uri", [ "http://json-schema.org/draft-04/schema", ], ) def test_get_resource_mappings(uri): mappings = get_json_schema_resource_mappings() mapping = next(m for m in mappings if uri in m) assert mapping is not None assert uri.encode("utf-8") in mapping[uri] def test_get_extensions(): extensions = get_extensions() extension_uris = {e.extension_uri for e in extensions} # No duplicates assert len(extension_uris) == len(extensions) resource_extension_uris = set() resource_manager = asdf.get_config().resource_manager for resource_uri in resource_manager: if resource_uri.startswith("asdf://asdf-format.org/core/manifests/core-"): resource_extension_uris.add(yaml.safe_load(resource_manager[resource_uri])["extension_uri"]) # Make sure every core manifest has a corresponding extension assert resource_extension_uris == extension_uris ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1490982 asdf-3.4.0/asdf/_tests/data/0000755000175100001770000000000014653725331015200 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/__init__.py0000644000175100001770000000000014653725311017275 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/block0.asdf0000644000175100001770000023505314653725311017217 0ustar00runnerdocker#ASDF 1.0.0 #ASDF_STANDARD 1.1.0 %YAML 1.1 %TAG ! tag:stsci.edu:asdf/ --- !core/asdf-1.0.0 asdf_library: !core/software-1.0.0 {author: Space Telescope Science Institute, homepage: 'http://github.com/spacetelescope/asdf', name: asdf, version: 1.2.2.dev870} foobar: !core/ndarray-1.0.0 source: 0 datatype: uint64 byteorder: little bizbaz: green shape: [9000] ... ÓBLK08€8€8€’Ù­ÙžZàv/$‡ŸGt·®æ? ³]çÞ?Xkßrå?ÚŽ?õ¡è?­ŠrÓ“êä?X¸âc^ï?Ó]j7*ðá?pÉnÒ')é?¨pD/±?“5§Ò?æ{G¸8š?x_\¼|í?Èf¾^â°?w‡zö^á?Tƒ¥¿?ðnmÆÆÖ?HìS?'¢Í?Ê`髎î?ÂÍàŽÞ?¦v\Å"á?(Vë_\×?ðM_ûÏÄ?@@´êºUÀ?ìÆj˜NgØ?P!H¡?€#Þµ™?­ÒNéë?µ QÂç”ç?ŒFü{¼?ËŒÞ2ï?@ J/'¥¯?ãÆoé„Ñ?XjŽ—Hª»?sG¨'²Àê?L/Ý"­ƒÛ?㾉Ðùç?ˆ*@7|]í? ¸[6 ¥?±“6L™ïï?[ÉPïxç?è?Üw1ü¡`È?€Q³"uݺ?NÕ?¸.æ? mªìRÁ?% ˬ?yå?ÌÖ—q*½Õ?* ‘‚í?à„†ŠRä?èWcR\š³?ųM3@Ø?|Æ{š.$ê?zþãùt‰é?²“ m·Þ?ü¢Î©g<à?Rï) Û?X,¨´Kà?×ÜýQµ¢ê?°äŒo‹¹Ù?Æ`5‘Ãï?æÉNôwí?a©µæŸê?ØGBû¿?2ê$zðNâ?s°Ÿö§üë?‘¬.Ø6Íå?Ûß_»Í5ì?8¸þÿúç¸?G³ÔÓ?Êç?Õ0§ªUìâ?ÜJÂöçþã?„»<€Àá?x»ØÏÁï½?x`« >½?*µ–I†Õ?…¦ ÛÁóê?á‹1¿þæ?îÆŸX—Ùî?rê`Ëùzä?ËÛ¢-Aã?Ì©ëp;Ì?˜5ìÞ?¡ „Kî·é?Ú¯5K%í?°¡Û¬UÎ?,Ô8ø³ëã?Éi§'ñÚ?ºÂs¥AÖ?1eóU¥ã?µx&2,…? tÍh+#ä?G­avµÊ?{â×ÞšNï?Ä"2 >Ö?bz˜xxê?JDË'Aç?HÍ-ý¼?´vÐZ‰æ? IÀ‰é#Î?Ð4Ü㯧?«$"sm+ä?ŒÇÙ·RãÓ?«à%Ðá?È´'†OØÝ? æ¼W®¹?“šËÃf@ç?™ê<#à?´xçV‡zÂ?6X(<ÖGî?x=g›¾Ï?Áf¢Š æ?ûƒ]Må?è¾¢/â?ÌáK' À?¶ÒÞßW0á?@꿤?`,ùÍ¥¸?0ºD!Áæã?ÆyjÎ?¡GŠlé?÷uò[Îæ?Êj´Så?‚ǾÁ0Ó?7[ðo<Ô?Ü2EoƒæÆ?vPš§±/à?¦ÈH‘" â?¤e=°×Í?5½:þš-î?`³.Ÿß¤? Œc_í€Û?£xÔ,d1é?îkÖÕÔ×?jxiAE€æ?yê$Âå?à §Õê?È @ӻŴ?+Ë•×íé?¸¹lÉQã?'HJÕž²î?.},‹.©Ð?´Mãf< í?vÀJ¤I´Ô?+‘N¿¾í?ˆÛ\xØJÌ?“²=' æ?NƒNÙ7Þ?r0ŽÒÌþß?Ñs[ á?›¥‘CWà?94¦‰˜Ç?»pÍÒIMà?@.íµ”Â?À ~ë5sˆ?<,è}ÅÛ?€úô*5®?¿É}lï?NIÊ¢Ñ×?3öWnw»?u÷·Ù„¬æ?ÌJ²1TÏ?™KƒüWè?è=÷¦Š¹Ø?އs¤0»Ü?‡yR $Æ?…±ÁOä?Sx°­]í??ߣ,^à?¬(ÖÒ³¢ç?ÈÀ²6ôuÊ?à!Ê 6Ô§?ÍWQD0Ãé?@·1ã?Y´O^ðã?žóaXðy?À4S Åí¦?ˆ¼ÄêÐ?Zkë6â?b£I×J‚Ñ?­_Ó@¦Qç? :ÚXóë?øj f:"º?ºTÝκÜ?±ù=»^ˆâ?¦ì˜ïé?›ú=É´)é?Šy›6à?°â”oÍNß?p£lqÁ'¿?8‘ŽïÚ?)·Híèîê? íx±€Ò?œñó¦tdÕ?ìúÈZÊNÈ?xÀüÅK+ê?¤¢g°Ö?@¨(É»?W 7ùrÝã?ÿ ÷á·4í?[”™ã@%é?%Îô4äà?)íZ¯`Fç?ò“ÕÂyè?[¬Ë°´ë?*c@­’á?n·ËWP|ç?+HkìÔ4â?.Í‹r½ÓÚ?²¹Óç×?à·òðËÈ¿?|“áJä?eçú¦é?UhÂæê?Œo7ÆÇ3Ë?`ÿOC“ä?_¡cOÃ?n—X`D5é?Ìzè]y„à?t5“xýçÎ?œ/wÁÒÇ?š+îöá?œÆ„Ú&ÿÍ?QïR"yæ?^Á*¡º<Õ?t·áiÎ?2¬†kÙ?&X©Ø?G<«Á_ã?z&Mê–Ö?¯¶T®»ì?ÄÙú:7&é?¢ßÀÜbø×?;â@$Àå?ð7+€CÔÔ?ï¢*4ß?pȉË$º?–‰†2Ñ?à„ä/‘ä?ô|±p­^Ý?ö’Ȧ©³Ó?ºz2SûÑ?øÐ¨PƒkÒ?SúzòÙÌä?ÀW•0‰=Ì?qîàÔ‹.â?L]¸ƒì÷Ê?Øub¬ØS¾?jc-Í=Hæ?¤¤¡¸Í?óÁee³?Z“«EœÕÔ?f¨ƒOï?hFªóq%Ç?5…^ZwÆ?8XNÁëüï?¶Á±>&ÉÓ?ðº\û¹? nªRÝ9¦?ž:ëƒ Cé?úr–å?FúÛ.àØ?­iÌÃ)Rá?€b‘•² ì?4*ª9€sÂ?¬+ êÝ?×´ã*0ï?0ÒçEeÄÍ?ÀnÕâÇ‹?8oôt7QÐ?õÅ?:üÉî?ðÀØÚSÒÕ?àD¼9ÖÓ?²c:ÏÓä?š|ëÊeyÒ?böÍáòTÓ?Å*×ú\ç?:À÷E.ä?öUiíÑ?(ew¯±Ð?)c§‹—´î?Ò¸i {Ô?4tŽÆ¼âá?^µpîÕ^ß?óÔ[ XRç?È—ñ{øç?½Ã;|{á?wõ‡}ÁNæ? tµ¿NP‘?Ø4×4$Õ? lK”‡æª? ¶^¾î?$sLúÑmÞ?Vâ<ìä? ÑI)Btá?ÆNŽeî?þ.ÛÀ3ê?à{'X?ÛvÇ\¯ä?Rq1Îêï?$zgñþà?\ôKµ¥Ð?ºGþHb¥è?ÂIUÇ’Yï? cZ6Ѷ?`nýÉÜÑ?̈üíòØ?þÀ»l€Ò?ÃÃ^Zä?=ÀÁCÛEà?ô~JÏÂÉÕ?}ý_!ê?¦ªÎÈÀí?Ч­Áø«?jœ§ í?ÒA$ãà?8¦h*±É?¨lz-~ºà?XÒ‘ž‘î?V&ÌIQ[à?Èò΄àÁ?¶%ªÉÙ?F Uã¨Ü?*0¯l8ë?µ½ƒgjIì?NßQûÆæâ?Ï7ãXö‡é?úÛTì·?FÉx$š-Ø?ÀaUt\Ø?<MBÄß?ص7,*É? ic$ÖõÏ?’˜Oä,Vã?ѵ;í"™å?¢aÉʉ‡ï?o‰é®¢à?Nuet‘üÝ?EÓ³8ká? ÿ(¾¹òà?£>ªOêÖá?»¿XÎjì?oþµ—UÎæ?¯f"%p«è?a è_øç?<—I‚€vÂ?ªéGã?Üazé”^Æ?dRʵê?@9’p@kª?ä<‹vÿkÔ?Œ¢â ?šÄ€ÄAê?Û^]Î?ç?Ï‘!ŒQ‚á?SóȈnè?†•i¿üë?ÿu„‰Zºã?ìW­fÓ–Ô?¨.Ƶ0Ì?¿Äã} ä?8’.D©Ã?5 (ZAî?ó ‡×šæ?þ…¬Æå?è¡]£© Ê?rÐt#ÃTç?[‹¢¾ fî?bIz½vì?0Éï:“hÑ?Äø8 h±á?# ?´Šï?`8Ù(JÞë?X‚bhÍFÞ?þ£äZ¼Ñ?žß°÷ºØ?sp_£"ä?ÙËмÉ?lnºCç?»ƒƒjæ?0òàßÙ¤?R¡X*ëÛ?‚ƒ™ÌþïÞ?n;s¿Ø?8”YòÍíÙ?$‡)j«Å?õñ2i?´®w„ŒzÖ?Ä!ä^€_Ð?ü÷ƒë?ê’>˜€Ý?`&\-Í|¬?t @ßð¿Ö?X…üõ¯dÌ?€;¶œ#ûš?Aù‚Øu-é?Àà"Ò›Ó?ˆg^Ú}Ãî?¤€N%åÐ?x‘Ltв?Šôï&ú=Ð?$‚‹•îê?›2á ³êì?o ä&è?ÄV_øÂ?ƒˆ¥\ä?6Ç•| Õ?%ñĶSì?šåè]£:á?4¾X‘‰Ç?0ˆëý\ï?{&»Ì€¶í?øõ²pÑ?àfXÈÑ?¼ç­â%×?`•0±;‰”?‹o“ à?Îuñ"éÊÒ?É..Ëéê?|R¿¼QÒ?L,×KuÔ?îgíÑ ëÞ?¨Ã6ŸÓÌÈ?`&ëè…JË?”Ú¢óæÍ?GéðÌšä?怸Áè?dÍŠ¼ÀÐê? þc¶.?xd¼xð¡Ú?!Q,·S°ê?waè2!Ç?@ëâö$%Í?f»}Ë Ñ?ÐÛó-½Z¼?8ÿËHø·?H ¤ÀÀßÞ?øÐ¥†¾MÃ?Då¯ìòä?Ø#¯Ô?x-ìFcÈ?Pü¸Œì¸?àsæý [Æ?8)˜7XÂ?ák|þˆâ?P)õw"ÕÔ?|ßäVÑ?€xwø“ý{?Ry/­Å¨á?n1`2þà?À,[Út€?^ù HmÑ?fYÇÕÅí?wÌ3Ƭä?€)_ï‘‹Ô?Øw'æ,î?à¶N¸®º?¾¾<^NØ?wsÍÞÇôí?X(6êþ4¶?HÝÖ¥ÄÎ?x[Ëò¡¤Ú?l1š­Ç?9&{(hÙ?èÞ¬†Ù¼?¸:РÆÖ?êÂ6·ÂÒ?*{un_yê?:)^<ì­ã?˜™ eh9Â?i7¨^ì?ʺF˜á?Ffo yë?b'hˆÛ?d¿ƒ;)9Þ?UÉQ Ú·?r1CSç?„ñ9R‘Ã?K¼6!¾?wþ3l?Âà™z¯ é?ʯXÐ?l¿“j_¡ß?ÙJ(¹³ê?‚¤”Lx]Ñ?m1ȆFÐ?Ôã 8Ï€è?©sáøé?€êF“ Ap?¦î­V~Þ? ú°o@ì?3¥ÍlòÏå?`²“†Wœ?(p'õ ×?e¼‡;Щì?`UJ]Ùì?Rb~‚æà?防Pø.è?^v`®Û?Y˜ºþK˜à?A¼¸~Tòá?CË¢ Þyè? †”îËÞ?¨›}Ÿ¼[Ù?lwu6È\Û?8æÊµ.Ê?„öKÕ,Ì?¶¾‹ÿýÙ?s¼³C‡á? jZ¥ÉÊ?§¾HáÚç?>'x³õä?àÕù’~8Ú?×kB5!ëì?¸I' ÉEÅ?Xcbè?l÷ÉüÃÞï?€Ö.? ?Šæ<è¹?Ôàj pÃÈ?àôð…›?<)¥¿šì?¤§òÇÐÁ?Î+Å#ûNë?ò3O;uuÞ?J™½1ß?B1š•>(í?iƒ˜ÙÔä?Èc0Ó Ù?Ž™.qÇöÐ?îœ,ÿN×?žr'ÐHØ?Ó:׺ñé?vMÓÀúÕ?ü=º\H Ó?¨áoH.)à?™4s*‚vå?²üQ}ÌÔ?˜¦;_W“ï?hVÃSø»?.£ÅN"¸í?*MVöÛæ?VàfœFì?æÅåU7Æé?Њ)g(×?há4^kÍÄ?»è?¾åæsÆØ?›ý_9Ð_ï?&‰L èóé?8 #å¹?Ò¯I%ÌÚÑ?«[iñå?Ó5oÒÆê?]?% ³@ê?Xç”Õ,Ø?X˜GÜsæ?[Ì‘±¸î?N@YTÝAÔ?ωCgJäá?¢oÉQÇ? hvϰ’?LÖêk¸Ç?r¯cÓaùê?ØÈ_ïL“¼?éåïEÙ?˜ gâ´?ëµsºè?¬ùJ‡qïì?ÜÁôã¸Ñ?XRÖ×fI¿?p³l´âã?hWÒ^ª¥Ê?Œà@)ß?ˆ²-ü‡Â?í›ý*²æ?pÎä@Á¤?¸q_.Ý?û‰ PÍ?ŒJã›7¯ç?Úí&/ìðë?&äºêÑØ?çbÓÉžé?$Å“Ôhë?Oø2ä?P‰i¥îä?H±A-Sæ?½³-;ã?…Ì7|'í?N®Æ’Ú?È6>Yï?nX‘ SÑ? &é:“Ä?.ðæ…Ùë?ä®ÃV×3à?úÚÁ•?@FÜÔNˆÂ?xÍrXFì?<ÆP^þ˜é?ÖqýécÝ?n‘S}Axì?2QOð÷ï?‚ªq˜xç?åõ¸àËé?À¶DLêá?µ”È‘îùí?á ù^ç?©5(í?À|?£^lž?‹!¢_{–î?ÌIÖïÑÀ?Vî¢ù:“Ð?Â|¹N£±ä?ïoãgðfä?ÓAzßVë?àÉ?å½XÃ?Û‡UmÒà?(µ@¢q¹Í? v[KÄÞ?««BÉÕåï?{ˆU«SÃè?ÔSyþë?%t#°î?Þr[y†…à?>9ºÂ~ä?C†ÕÈr±â?P+çJïFÖ?^ÔõJž0Þ?õ½ä¼?ç?zX¥ïè?ZހѳÚ?TÃÉ”jÛ?/¯÷é?¨aövÿÑ?j=:E¨é?l»cbtÂà?à¦9yq°?‘˜ø‡{â?gÓue€?`Á§ý舿?0šd'Î?¬nIÐ?Ë>¥JØ?ô„¿L:ê?¹íظv‘ã?È4ÐÉ:Ó?(EHr6{Ó?œ1¦fÌÿâ?`³sCË?¡]ÈëÞæ?X¿}ˆÖ?)Û„ûÐÕë?h7³ÉiçÀ?bOBëòì?Ù­¤)åà?;ÃgEHí?|øó%G,Ñ?*v½yÈ×?͉3Ó?"(žè?áú³Å‚&á?̳F·RË?pˆ¤üò±?NÆz¼‰â?áŸú¨ŽÙæ?€K ”>س?ËNðþúî?HxŠø`Ú?aÙ …Â?0gO"Š[·?Šè\ñÓ?d®z+Ù? Œ|ÎOÀ?ýÙA߃Ð?kx }sá?¬*„¯Må?7$cz _è?û¼QúªÍå?äŠf¬«ï?Ï0Zõâ?’Ç8_ªÝ? 8 oƒ?<¥Ìi‘Ì?  ~9Êã?Œ„†ýFÅ?Ä¡d>öã?ò£‹©'Çí?Tñ1ú"Ô?à—»3 «?þïVÒà? »9çòÙ?ø³)p³?pJhO÷¸À?SìãD"}ê?0þ—dä)®?/Œ"uèå?01Ê„Ù?pY[væ°?“ÿºé?«èÒjÏ?–ffé?Ë?“¿â-è?v+,/iéá?æ JBêÛ?àfìÕ•?8T×/â,Þ?f›å¿ñuß?÷«v`¼?ÆSüàãdÛ?F¨nÐJë?¹~…ÄL!ä?¢ (*ÿè?Ðɳÿæ?öqM¯¬í?¼Ÿ£šÝ?d$®5‰8À?L ã^³y? °¬7cÎ?¶.÷¹,å?´°„cbáï? ”R7[æ?Ì؃à:Á? okXí?Ì |%ŽºÕ? s¥ßÜ‹Ó?Tš˜ƒÍ?j\0 Íä?ÂÏ68ì?ùèç}Òé?nÏ*šhøâ?Þê$ƹà? ÚþâÂÚ?j·ºø„×?Öã‹Ë …Ù?ËEë%.ì?¼ÿ)5ÓäÒ?¤6×ñÛ?›wMcª¿?ä'½ƒÅ?pÑÏ2ä?„|  ·cÉ?ŽÑ[Âñ¥Ô?z!ù‰€Ü?ÝVCfûæ?RÆ1#'ýå?P@`Jæ?ëåÝgóå?èR®”¤AÐ?ˆÄÍ _Ú?ªnïúÕÖ??¯HbGøç?¶ðRëDî?äþØcí?0=Ä»ë?0ÒP—ŠQî? >zö…é¼?#YÕË®â?nÿÍ>°dÖ?6¨–âb¯Ú?葆]G°?„Eõ]„¹è?ü3Ó¹cWÀ?ŒÚÕf‹™Ü?ãî?|z ¾^Ç?‰©m°z±?ú2‡ï?Bf¥¥ýå?ˆÊ”Q+Ü?—…#5ˆlæ?ÇRŒkMî?HUĉ ê?C‰Ä3½î?hæx?a@ƒãÒ¾?Ð6 #)¡?…Ê‘Ä?ŸæP2'°?.Ý’[ÊÕ?ê +±œê?Ïm‹Ýè?@ q2‡Â?ðø8Ì~öÓ?D¬žø Íâ?üV%%À?8§ó½F¸?°—ù Þ?ÊâèÞ?pzÏŽë¨?M>›¼éÇí?™®~ïé?` n Š4©?øØºe˜Â?ø“ú³Y•Ð?ø·&?3ß?›Ï-Íç?·æ…ñ‡(ê?4æ•I<Û?ö臖œžß?ãæ”vÖÕê?1µ2OvÑì?ZsÐU°Ô?ð­uFwý°?ÿSÊÎç?ÅÚI™µ?ˆÓ!Ù?Ù~qÕî?®6)´Kè?Ð’˜àm¸ê?Â\êãèí?¤‚“•"Då?Ä+³~Ù?J‘ÑkcÞ?çúÌÍ?,©ÚuË?¢®¦[¸ç?©*ÐÁ¾á?ð1OLHAª?¯Ø”øöaã?/îÆã?yªÉšLÎâ?ÊHHÍÁ^Ô?䕿ˆKÓ?‘û÷sà?ÔJ>wnê?°H2úêæ?íc(¬aá?(FâŽÀ²¼?;z!ïõyå?=$uiJµà?‚¡×ý^?&×)“,#è?ø%ãì½ÎÊ?ú­ëÔ?Þ8N=aÒ? …\þZç?cÚÁÀ­“î?¶Ì8‹Ò?wjí©‘ï?<×-Î_©é?äy° ¾äÖ?¬,ýÆ&‘Ø?ìÚ-#à¸Ã?õ–—Båbë?‹úˆý5ä?ñc˜IYì?±%»¼žå?ÄÊ´öyßÌ?døìÔ~é?P²¼9'IÞ?ø…À(ƒè¾?Æâ¶,2:ä?Ú©næzÕ×?êýñ<¾ë?Ô3@õœÀ?xˆ_áxÊ?é ±[òôà?À y£¸Iß?!ÿ@Û° é?µ šiì?>·{äCï?hê%÷AgÌ?r×zž—Ô?x±©… È?LºÀÈ0Þ? ¡ƒEŠfÂ? ïçt¦¨×?,0»£ƒÛÝ?húºœ¥Ô?p߈Ճ,æ?%+²Û”å?Íh•É‹[á?~ùÿ05Ò?@\†¿ î? ”ÎE9ì?€8ä­ü`Þ?0¹üâWB©?Œ¿½ئÒ?ôdûs Å?ª*N¬?íå? ûe„2”?dL¯¬Ã´É?ñ@ìÚSâ?åíï‰!ã?bx£ñÍã?Úðü“,è? ’¾ÒÕ?ÖÄ8§¸SÔ?Öeq iî?P5SÙ߬?›‚ˇãç?ŽŒÏ™2¥Ð?/v…_Rã?þ¤êÝ«ì?¨à+í8È?ŽR]@í?2ý&ŒÚ?­h0óÝî?ЛòØg]½?@Q9 墡?Œ<¸¶pQÇ?&uÐa¢ØØ?ºj­§Õ?¤X4D‹Î?$ Òë¸9à?¹…ûô²?°Biµ‹“¼?G&™õhœá?†êúº£é?dP_àšÓß?€¥äaÜÒˆ?ôŒòž-Aß?à>ü ]¨?ü¼¢Kþ Ç?ƒ &­­›è?I@˜~Óã?TO»Éfã?×|´¤ã?±g yP´?zÔÇb·ç? ÄûXç?æ?À‹İã?‚%¦©¢ß?Kå> –ê?º¯SûCPÕ?>ù*”ã?¯È?X/[á?ðQÃÖ k¤?ø€]r“QÂ?Và¥gÐ?àቷBÒ?ÈŸ³0ÓÊ?ˆ–7Ó>Û?XÃÝÛ¢Ôê?£!ß?õ­é?²ÞO²Ó?–¦w9å?TÓju=Æ?Ð|©ñcÁ?ñ°y±…˜æ?J±{|‡mÕ?ºÖ½¯ñ&é?~é‹ã›Â×?`Œ[Ó@@À?œ‡ŽóHÄÖ?À·ŠM¸Fš?pZN ô#?ÙÀÿªá?„ø±ƒÑÊ?;>)â8Ø?øÐF(wK¿?0?b3¸ÖÉ?Ü,‰†Ëí?m¼Ö­Ÿà?¶\P9cåÓ?Î…oî’'í?X:Qô>0Ø?¬®íD»­Ê?ßSOÑ“ê?L Ø|´ÛÐ?&Gà=¥Òç?ò|¬(Ãå?¬³ ôyß?Ô˜Žç‰Ü?®KfÞv×?cþ 3xÕï?¶cT†éÑ?L|i"ØÒØ?ÄÛ½Z¶É?¸CŒ&Ê?~^?$¶9í?p¾ ßÖfã?€9(/K·?#à—/?_á?Òm¶Þ–å?kç5ŽQæ?G*Öf¢jé?Só°öÕ/í?Ô)¡Ê±Ü?ˆ|BÍ,#Å?-?näÚ­ï?Tæ´GíBê?Ð:tfD £?" Wcüå?ñz„Èdºê?L9>Û“å?hTÀЫç?æ:£ãOÛ?HöD~iÄ?òWL Åá?ìŠjбÛ?t\qŒ+&Ô?+hìÃvHç? kÏ´È–Â?Âæ„D!î?2Î?À$2Ó?R‹Ä'è?¨š*0àß?]–‘ŽtÑî?T•ܲç4Í?šà›ö?Ý?k–X§’ë?p-&Û±?áù.}{·?À–Œ»q9Æ?<´'_¾9ï?µípÇDaç?ö¤–¥“>Þ?!§y¤î?Ê7ûæ[“Ó?xØPŠàÆ?4¹°P'ÁÝ?Œ>I2¾êÜ?¨E÷Ù¡¼?ÒrÊ·Õ?ÐðFcÉë?¬P¼Æž›Ï?z ³ª÷ä?PJÁÊ(Á?ØÎ„s‰á?;DQoå?rábhÏùÞ?4â»mØÁ?¬›¸}Ÿ0ä? ’ƒ?LÜÞ?Žƒˆ¨é?ÜZ>ÊT-Ñ?Ô3…„µ²Í?°]ÿeÂNï?i†8ZQá?@®úÇfæ?˜•ò±ëÆÚ?}¶´Ýåï?ˆê~Í·Ê? ž |ÃÆÓ?ÇÈØ^[ï?ŒêÌzãË?G…§dQ–?|©ÓÍà?eâÖnÒ?À•ö¼qÒ?^ŠrÛhwä?l¬bœÒ¿é?ÿÜÁ?æ®Sð'ä?ßFæ—Óç?²«In‡—Ö?^K¤ià?8·)H"ià?6o0*»­ä?Äë_éZÔ?Ó-6pì?€±1H½’É?`–3-6¹±?2,®ÁÒrÔ?¢N¡âÜä?bt®þ– Ù?|d5KƒÜ?Y*À©æ?Ò¥”$3 Ö?6O9?BÛÓ?AM(½Zìæ?@‰ õÍ­?÷oœXºðæ?c>¸ƒöé?ü¹ï*Jë?5knÕé?p¡õ=sP¦?®ëÎçÚ?ƒ.ç7NÎâ?°Íé«ä4Ú?ô9:>pê?ô׶пB×?ÐP"L8ªí?Ya®2ôÙ?tŽZ 'Ã?…¤€|$©î?èÁ_1NÚ?h¾~r—á?þÄìÒ?Áˆrò£Aæ? ² —‘ÍÖ?”™åW ë?šH*!Ø?;©i8Øc?2:ŽÂQýÛ?ärIç?¦á„XñÜ?`{ðÀKøâ?$›²A@à?ÈîEò$Lµ?ls\ؾtÆ?ä;sÎÔÛ?èÝHDˆÏ?©d–Áwå?4ð~¸ÀEÙ?¸Á÷)öÓ?wgY¡¯`á?Ƭ¨±Ñ°Ú?4.ì»Ò?XÛX«Æ?¿o**‰è?Œë¹ŸÊ?—O4Ÿˆî? „_x¼’?FöŽ=ã?‘Õnãfï?û)èÛÌï?rä‹ï¸Ð?`k¿Á¤e±?÷ÓR3Æê?À}i îGÀ?ÐIÛ{w­?Ö0b0Åï?:ô…hüfÒ?¤”Ì €Â?Ã&ä*´¸?jL0èÙ?èKfD¾?8ÌÖÔ¿©º? )A.4¹Ê?ȪBÄ„Hé?´uØøÙ é?½µ mœ¹í?`0X´ ¨?ÃgÝÈÚkì?Ääö{0ÃÍ?R1ù¶oä?ôšĘÒÚ?¨²nûFKÛ? ÇFë?3£¨žçå?]—håå?‚µ¸/Ø?ÉÖãñúöá?Xþ 0„ À?0~™Ìé7ê?ûj¬–žá?.K6OÍÔ?ýÃs‚Ò‡?œUâÂ?—šbŒOGá?Ø!ÔùÞ³?llEDÛÑ?ØÓÞ >G¶?î;¯¨þt?ÌÛœ;×ÓÚ?ð¸SAKÃ?N|†’Kí?À¿Ö¦.4†?ã"ùëõä?<h=Íà?ÀW 7ö•¥?ØtJ‰y³?è¤í)Qæ?Òâ\*YÖ?œ¶‡§ÃrÝ?ÇvCàmê?îDVÒ ×?˜ðe 'Uà?J®º.ç?Þ¥4Òm5ä?@’ذæå?'‹»; Ê?lªÏB™«Í?â­3.ýë?kJêl¶på?Ú¸d•Õ?>Ç!tx©Þ?\ÝáÌoë?ƒÊ”3ënå?|_ŠTk]ï?$˜BÃCâ?æÀéa¾cî?°f º†Ý?`!‡1™ë?#)™î?$”B Ú?É+—Í¢"è?¼ É)XÀ?êœS;ï?ˆÏìkíµß?ÀL÷Û²êÙ?çC’i í?@0r4/!‚?ä yèçë?€ç~—£†Ø?†äyÊwÓÞ?àôwΑÒ?×ö‚òzè?6§—ÞÚã?ºèž.“²Ù?XŠñp#»?º"L€,¿å?89F:F³?lâŸÙÍ Ñ?©Qÿpá?žÙ¢ ”sÛ?hŽr=sÛ?1æãÙ0õî?,ŸNp/Í×? kQ¡*?°µ”ª›Ï?-jº*£ï?é˜{,@ûà??Ü–r´ï?qUÖ€Û?˜¹BUVѱ?Ðl6 äa¥?¸T;‡´1Ö?\ð¸~Ç?àð+¢îÞ?Ø ÜYØÕ?A4ÿ_×?®eGž"ß?Îí¤WÛ?3Q‹Úâ?ýÜŸ.åâ?±ØîE©sê?lÎ×ÐÄ?8Äp¿`½?&íÒ RþÚ?$v…ƒ^bÂ? #pï5íÖ?€ZÃd‹?|c\?=Ç?%’xÔ±?4Dt6ÙÌ?€Á{õu?ÈXÎ áÐ?ÚZCÑ?¨'™§.Ǽ?”ÖÁ‘E­ë?ÚX Îýè?6ÿ.æ?x<аizÝ?öÁ© È,Ò?EðB aá?¸$ù™'Ûæ?À—%ûèL±?~ñÁ-Î×?„¼Ú6æ›Â?”y«kÇ¿Å?׿°ªéõì?U‡w«‡î?+0TZ©é?9Ê’@à?ÛÒ8쌦â?Ø cvÝ(è?Ç$7m×êì? qY9ëÝ?Œk¹’Ç?H#ã&¯S½?\ÿ~Ò¨Ì?Ô5…¶RZÒ?›¹Ñ¬äy?Çþì¬Hâ?³0RÔqå?~ÿlÛÚ?öo‚ÛÓóÙ?À¤O¡£Ý?€€zйnÐ?Àã»M¢„í?Ð$dФÉ?T^oRhÝ?DÙ4$8²ë?¹}ØBu¦è?µÊ*Ê¢î?x87‹‡Ï?LiÿKié?–¾o{†¬Ó?(6KÊyªÑ?(èeíÇ?(¬è¸¾¤ï?Ènšõ˜°?a$öûºÊ?Àg+é¸î‡?^È1Ð.;ì?Œ¶~7ÌB×?8 ¶iCÕ?~uLAŠÚ?"»× Ü?œL1ý¯Ø?EÉ” ˆí?ÝìyÎí?LЩÌ?ÄgrYAÅ?ŠH¤‰ºXÔ?›•èé Wá?œBë&Î?pš±vÜ¥?Äuà{"ê?îˆOl#ÐÝ?õ¼ý»¶â? °ô°›žÌ?КkȾ?zÿ 7~™ä?PŒÆÂ€ç?û·]qO·ê?þÍ´©Õ?ÆRñ Û?îÖ?G£ŸàPé?ŽþÍ/ŒÖÚ?Ü¥7?³ë?á´˜:Ÿå?´ÂVHá?]'41£žì?<Ûrô¢Ä?‹Õ[ç?Š—OÜ}Û?[ürj$ï?Ì£.7—ýÖ?PµqikÏ?&/}êuã?˜6‡ #´¾?J©±¾ûåæ?¤¤g¬÷î? Dû¶UœÄ?ŠŽˆÉûè?J³ûǰÍà?6°©¥›îÛ?¸{T)žß?¼õ,t„ç?äŽÀµ˜ä?”7ÒúÇoÎ? ¨ †JÐ?ƤÔM6µ?dhQ¾â?MÀÊë?³GŒ6rDæ?L°ÎKЉÁ?`±ýPÖ?6|ÁK"³Ù? ˜ZÒN²Æ?×ꃣãï? 4ê0ŸK‘?‡ˆÍ‰_ûç?ò½äŸ;çï?R.ã#Œî?8¨Šæ?•á3±é?Ô‡ÿ£îËâ?4qÞõÈ?J$楞Õ?ž­ë©}Ó?TôÁê.ëä?Xå_ ²Ž·?#²©¢-ç?Úq«sÔ¤ß?Ò¢ý?¶Ö?Àò–°Í>Ö?‚úð|þÖ?ÚzIâvå?²W¦u±Tâ?|»{Ù~4Ó?lÞ:ç4È?+YÑx×?L@/ܧ3Ç?Ó@9¸ ê?È_@gÜ?.9P†Îç?PñéD¹?†i«å?"Þ[%Sè?·¥pwÄè?Èåk‹‘ݾ?@–)Ó,îÃ?`ø[}¾ž?è·X64À?2ƒRl5=à?À+ž°}Â?Ä? &/%á?n…,ë?bMœÏé¸é?xl2þ‚8ß?î!nû`gÑ?Û'½ Šè?ûeIàíç?ô»x5Foí?‡ú@­(è?tܽð¬¢Ê?°% JÄ?9^ •þâ?)–Ÿç½î?€*¥·? "rö¸^ê?žB[†òè?@!6칿?ð…ü¶Èå? Ü5òbµ?€NR}ªÖ?†TéqÜ?ʉÃÜþAæ?d/ª(×Ô?w¸Ós©ä?Ä —`}ê?äwk=ºë?8&z'S—Ð?d3ÁzÄ?âçˆ %é?\¸ –ó“à?× ?×pï?ì çQ4Ê?%´’ƒ>€î?eo"W’â?¼Ô:þ­Ë?¼Jº;Å ê?P ‡GÖ?öñy‰Qã?!mòˆå? 4Eå$×?„f¬ >¶Ñ?£™;þ–Ì?cG+üÊ?†¼©)FÔ?¼ú4ÚÓ\Ã?2òœ° ýá?ˆCÖ§ð·Ð?E—Ôš.Ñ?¢_…·ì­ï?TD~Æe«Þ? œÀ^Œê?œó~ÂÊ’Ä?“ñÁNŒç?°«c<Æä?Ê{¶Øï?ô”+ˆÕ?}>§±då?¸™÷#MŒé?”Á w¢°Ü?ü8 ;ùoÝ?&:l–pé?h²5ΧËï?§žríÚí?ñVZ¥_ì?˜½¹D\Æ?ô&ªz\ç?´|–9fä?ÖÕåÉ«í?Î&¬³÷Ñ?à…K=-^»?@t ¸²¬?‘6\jôé?àŠè•¾?T”!a1!í?YöXÝ?0þ57± Ú?ú­þbÍ—Õ?x…Ñ0Yƒá?; ‰H£íä?¿ÇÑÒ!ç?ì¿Þ“+Ñ?4]u1Šà?É'òÓ#š?ºU)•×iê?Ëvižgå?²À(Ëe²Ó?ÆÈPõká? «J%]•™?ºíJ0Õ?L,Í£4Â?dK^ÍÅ?x€{‡EEä?ª:tÀûnÓ?ðdàôþ~¸?aKšvÛ?„•ÙÛ£½Ý?@ãÀešÄ?@˜­8=θ?¡#˜,á?ðDD4gÊ?º}­bÔ?ðŸ;JÊŽç?¬ÂÆ‹Qtì?æÏƒö>Ó?,`“±œÝ?R=j™ÒHç? (¸¹¾­?A!dÛ?æþ.(¦Ú?$¼JTÙoÜ?ÈÙh¸ÛÜ? "728"ä?h¡_ìiIÔ?|êídÐ?07I¿Ã?p¨lÌLO¹?¬êm)î’Ý?Xh¡Tüë?p Š‚ iË?#D&u ±è?ŽàÅä²Aí?p šO±Ü?Ø` ;Iº?k½{ï‹‹ï?,øžŸ¿íà?L{Ѷ#êÚ? =5àå?ƺ ”æ?ߌ‡ ê?´|ËMÞÇ?Œ1šs1Õ?ª‚öý*ïè?Q ‰Š8tâ?Xö gÍyÂ?žd@ǼgÖ?Àšâ’˜t”?|nFÅ16à?[Ò‚j)è?zé-á? á'Qóß?h(ûËôüä?@;¡PàQ¾?¨¹ÍçÓ?âoÒ|ÊÑà?|ãyÅEÙ?êÉŠ¶ã?Ä÷ž_¦à?Hõ«Š¢½?‹jø~‘â? ^JÊBdì?žìU9¯ Õ?Ô¾Ÿkyï?+÷ÄÔ| é?~O°y–æ?œ-%ÿ«ß?Å'<Ô?êS{Yë?§KÒó€æì?Bš*Ý=ß?“K'‡æ?HŸM'Ø??Ï6ᬽã?K½Â”$à?DémU[@Ä?(œ7í½?;nap>Äà?Í^U½râ?¦dÛÛÀ;Ý?X(ºK[íÏ?<ïdülé?ôE h É?¬âÅtúÉË?#¦‹ K±ë?07aŦ?‘TbÕå?bV:¸¿]Ò?ELASìóç?Å&ˆúÝì?hn´éøï?hÞ9 óÍ?” §p!Â?M¿ÿ\A“ï?úšÕ—Ö?+C‡G¾xî?ÖþÙí?_" \óå?Ú±Ñçè?ö=¯ÐÆDÚ?p³EŒîÙ?ª$µ*:Ý?ý‡ Bê¹ï?†›èùxðí?Á–æ“9-î?ì,ߢxAê?#ùò½õ+à?ô¼ë—uVÇ?À‰—Ÿ?(Ú? L49³Æž?ü\¤+Jï?ÐÂR|çá? RGŸø¡?+ãxÿqë?Bm‚Sîä?¨'p:À?HPeç?@8Hbd¬’?=ômì–è?<“… u®î?'ÿæ ‡æ?ºÀñR¼ä?6+ÚŒ„âé?Hš xË?m•óøJ„?`Ú¤…7®×?2a;ƹç?HžxZ;Ú?¼^;Ñ-Á×?.0{ÃÍÚ?@y‡K¥å?ñç©F¯Üì?éªöé?¢¾Ï6Š,ã?ë÷ *çî??±«6DÀâ?~솃G;Õ?€ ºöí[}?ö ¡Ú¹¢å?ž{% ܵé? ˜ _jKÖ?^)°–å?S\™ê?2¥8ѹ?p}ëÁÊà?TbÜ2‹0Þ?6q|!ɲÞ?ž×ßbCÙ?+*ü*È?®€æ¼ŠÊß?Kxh#+¶ã? ŒivæAÓ?6ÀâäNnë?Å8¦RWá?ÔuĹs|é?tJ¶†é¿?óK„£Óå?\¤º¨îžÜ?|owúþ…Ï?åð]Ø÷íà?øëð:ËîÜ?¸:Çåñâ?ö}ÄXÒÓ?áyßí+æ?ÎÛ£ÙÕgã?”¿™‰ÞSÞ?ô{xÈÅÓ?ÕÕ(¢ë?ûÌvìwë?¼kÍŽë?L±à°"Æà?æe M›<ç?˜ …r~Ü?úÙ“‹¸LÖ? ý@ bµ?z´Ð‘keç?&×¾2œ]Ý?E—€‹âì?Ò ¿Â?ÌÁ{wWßÅ?fZc‚£šÔ?<ÊRK’˜â?Æ•Çê?L½njÿaÜ?lÜÁšÒÑ?CùìÜ»êë?à‹ùUSÁ°?P‰÷Ë?g‚Bììí?`üìÒä²?’¼s3¨?¸…åŽwå?ˆ{Ë«Íï?€)`~%Œ?ƒê(.@ã?xƒ—8q”Ï?`–g¿ýñ¡?J¹ÃBÚÙ?(d»‘ —ß?‹ô§ì?hPÇc¶?V@EîyÉÙ?w+ÎÓ¢…?¤Ä2æÓÍÆ?€vÌŽ2V~?`×0ë™?²N֘ʩß?¸tȹ¢·?.÷yö«×?¹ötuì?,;¯Tí?ß[ÂPXÑ?Æ®J ±¼?@-ÂÄ?DTsqz£Ù?Nh¨qêç?rÇžx#Ñ?@8ÖÒ`º?°&óÂ?€F·«Ëdã?æ¦G‹Ø?°ºÛføÑ?^“Ø79Ù?À´‚Þv¨’?N‰â’æë?\ª´î?æ?RÙvÙ?"ÁJOä|ê?ªtOGÁ?É?3bO‹ï?4ëD4[Ô?ìOözùë?_Ë'Huæ?pÙ‘Ùèí?<Âë¦1 Ê?µ`ºÀÓá?”(¹èk»Ä?fdô"ÁZí?dpeYØè×?Rí’ÆÄrÛ?:ñµÔ?€ D¬³a¬?ù‰´g›¨â?e×p½ê?Ð%•9Pß?HH-hXå?Zå!rï?0hÖŸí¼î?N®Þ½z›Ð?])y)Wæ?åÕšEê?pÀKü1°?>Â>¥PNå?ýzÀURî?äE;g1=Þ?œkÿ¨Úè? ÛšµO$ª?PûjüYIµ?&6™“¼ï?¼‰ž¢Ì?pæ²MÕ?˜•ýsËÎ?¬¨USå?Ãè¤vå?0‘#[¿ãê?BæHBäÔ?ÙM~ÿÚ´ã?K>¨c¯)ç?fx·ÂÔ?EU0†µ]é?¤©äçÌPê?õðõÏÏ?”œ%ÝZ“æ?@ŸÜéç¼Ì?*# üÐÝ?¸ÇS§¬ç?0?Ôc‘§°?N9*²Ö?jzÎú–ë?,ÝÔæ×?PÉçlò¾î?ØDiÁ“Ø?@àHûÄ$È?¬†Åÿ6àÔ?¥ãY…÷sí?(3{ßd‰¿?­±MN"æé?äTÂ˨ýê?ZG¤Çå?ºNÃvúé?©$V^´è?<ƒþhÍÙà?šÀé;Kšç?ÊoŒ4 ë?Æ%&÷¡Zã?ð¸×¬ê;ä?.¶nõ¼ì?œå·U.–ã?D-lYO¨ì?p_N,:,¹?eŽz³Lé?¦D­ÆîÚ?5æ~¯äë?´Ÿ["Á? AqççÏí?X˜ ±¡·?)3Æ¿Lëç?v¨ŸÀÙ:Ü?†7Ëy"{?ŒO9C°À?΂=ü`›Õ?êVÒöÚJÜ?ôëc³[¤á? ~JXJà²?¼øÊ’ðwÞ?,1 Zë–é?Dn3[ Ï?`|`ê¿Üß?³vÂeCê?^?Õ#¢@Þ?xXÖ¼±W»?²Æ;5ré?Pf…›…°?H„ I¯ZÈ?È6:ÆÈß?`KdЦß?púrâÎ? ±U‘;˜?ÿœYH÷ß?|·ªˆ°?°‰¦ýdÇ?Øé[” ‡º?žªAŸÚ?nTvgJÔ?n«´\uÓ? â €+þä?áæÙNÆ0ê?w9kÉ>î?¢øD½jwë?•v…- ã?²¼.í·oá? 9òê‹æ?€çpµm7x?¾ÛE¤¼Ð?Í¿6Ô?Lo8ƒÅÐ?¿©Ñ|Šë?À > ”ª?FX›Ìvs×?²6¨õ¿àÐ?`§cÔÝÁ?Z©iÕÊ|ë?\‚”†Iá?pbTÎ4«?Ð1OÖ¼ì?Ü£L1Oí?ˆÈÒH”à?”£\¡‘*À?JQ_1•ì?|RáY=nÅ? sûqÑ?Ð÷:EŒÍ?®Éóråì?º(ý~ì?õKë|é?P#qþ{†§?Ž÷'”òÔ?NƇ•%uÓ?ø1éËÝJÖ?=Ï¡Š*à?¶`cã?+”ñ¾Lä?èå€þyê?fËÈm<Ö?”ŠÖwÿå?/øBàuÕá?Ÿ(§|1á?û~Îæú€á?÷J<Üé?ÐDd-øÃ?hò²H sÇ?Bª®'èá?¼qÿh¢Àé? sÏ#ý#î?Îo ŠtÁè?2qúµcÑ?°i~²J#ª?ƒžûÅáî?  q@¥?'Z«'жì?¢`á4$Øç?íDÃéKê?ì}¶¨À?€ñ‹á>»?PJ… t¯?9 ƒK?àF‚ƒäÒ?¦äWÕúÕ?a‰tæ?[T¼GOê?€|¬oÅ?à'á—N§?³°•пê?s†¯¦ªå?_„ÕWLîæ?x@…ìoã?èšçÐ Â?@Šžo Ïž?¨6A‹“]Ü?x8*]ÂRº?BÔ¸’në?X!RÞ˜„Ê?Z—ü!à?Ûl Zšì?ⓨ\ cÞ? ß:Eá? 6RxÔ?ˆï{SÚå?›Ð«3&è?Ržž[Ó?ð’°Ú?]ç?WQ+áæ?šÝƒa«óÙ?öò¥HêÔ?mrreiIâ?¸¹\6É?¨'17¸?”´¾jÞî? Ér|£ä?4¾7±à? hL3Æ?„S!€ÝÝ?¦î$…äÀÚ? öŠqÙ–?û÷Ɔo?”¯_æå×?—ðóyÔä?­¹Ôèä?½0²ôî?$rnOÚ?Q‘w«ÊÙå?n·ÐQÕøè?ékƒæÐ?]Ô ÿà«è?¦­a"»ã?ºUpÍ€`ã?~*ì'Û?ÚY,פÛï?T¦Ø²Ñæ?ªp”«E×?0$®Þk&ê?™Òçd•å?îž¡ž0õÖ?›@ß7¯å?íàV8Ññä?ük_Gk$é?Ð{T;2¬¸?d0b ¤ÂÉ?Þªcî?Rfº…ê?ó.ª¶û{à?†;ó„æ?6LÊ#Ü?h"mza Ö?€¼ø‡p„?œÚ³K­Ó?`Ý`•ÃM”?Hß°>âÀÎ?†½í­ûé?R²MŽß7Ö?ðq޲?Àa$R'·”?tȉ®Ã?ÍrñßÞê?Bì²<Ágï?9¥3™ç?¤bã¹i Ñ?L-)³,â?s4%†òÜë?è™úIîÃ?ìÓÒL²Ù?‚üOÝÂç?ö*Ög½ä?`ðŠ{({Æ?2Šh²‡™Ù?þ¦AQ&mÞ?è1Ë¡õÑ»?Åö¤†c¦ê?ðmc*¹÷Ô?˜ÀKF޵?.9I:™Ð?Þ¼‡­ã?e1®?„â?ذ¼F3¢ç?.qŒƒéVí?.¥¨F3à?R…fï? p áp®?d4„UFˆÙ?:îY²öKí?Èe‹±Œ!ë?‹Lm;å?ìeŒÄ?„a<»¤TÉ?,Åúæ?RàrŽ•ä?øKÐÖXÂÃ?!JpO®Uï?à)¾â(»?¼ù«ÔUß?q…™\í?(ªêâ¥;ï?Ö‹QÔÅØ?Óc¹Ãî?ÂÖñÓ?Æá»À?p—ÕN±?mÓ ~~ê?¸Ê«·è?*†ï zxä?6¡Yàà?d( ²ÚÈ?¨æ°².ä?áo)ÿïï?Ѐ£Uº¬è?ì…\ÝÇà?È\âóöÜ?±{ŸØÌ`ä? ø Ód‰é?2;±Ñ0ê?õÿÎx9 â?®Ð´¶HÒ?€Þ ’Y€?” fÄ.]Ý?Îî͘H Ü?þ\óSç°é?c2îûZá?Ö›ýÝŽê?pÕš+cä? D3ìÓÚ?Z&ÆakØ?ÄbAá«Èè?Mmëµä?pCæl‹»?LÆ8—°Á?z5j™µâ?ÈôdäÊP»?ZØÆÚì?('cT¥Ê?­:"ßvõå?©›¸È/ìî?¨H_æ“{Ï?|. R¼:à?0‡Ç%µ?}¾ZÃuì?üL¶Lë?8©‹M— Ô?Û¨>B`ç?öוéîØ?„’¶JPÃÜ?ãöõ¸â?P¢ñN¿Ñ±?GCôÍ?X™†Í2Ð?*i÷Ÿ×©Ö?[îÊw‡Ë? YÅÊ}=™?Æf t$ï?Bémø•Þ?@TÕËÁî?ùëꇜä?`~{nH ?7‡øë?8³‚¥[¸?µCN­ä?Y²eYÖ‚æ?º ›…²¹×?‘ÌeÜä?æ·‚›u?6WÖp!Ié?u7T Vå?€šŸÝ“Î?ÁÁ-I>Ô?”œwm­sã?øK1˦·?Lp>o×?°ß–>¡?ŠBÜ Çî?€äV Fôt?†öÖ혇Ò?ðm¥ÁwÊ?ú?c±•™Ý?XLE=êÜ?!½ÂÏè?Ô¨øüñXÎ?â]”T¿ÌÑ?N§™Ò?:ã©(Eà?x„_Ü5Õ? sŒÈ¬æ?â÷/*aÜ?úsîJfžÓ?P"Å~ì…Ê?Ö6N… å?àG)­°f¶?ö7åµUä? ž’]>áí?`{¾u#DÝ?õ"ßÍwQè?€›áq%ž?0Uy§lØ?l¿8ÇuÛ?~^R¾M6Þ? iµ‚Õ¾¬?é/‘<›˜?x?²¾ÅƒÍ?]’vƒð2í?®i–•è“Ù?®«h–«$ê? ½ª6‘ïÖ?€±ƒÊ'ÚÝ?.Aë ô\Ô?ÐÐ]ê]pË? 4 ¼Í?/ÜRMÇœé?½é³¼?½ï?¬åͦ7Á?"£Ùü£Ô?|§Í¬î?ã8Ïyè?ºÛ‘/&í?â1´p?Qã?TiȇyìÕ?Þ—ì“E¶Ô?âq¨wí?0ÀÞëè³?·J=zLê?XˆåüÀD¸?ÚJÊß¹m?ñ5¸ ‡¯å?ô)GÌŠê? 1ݵ—÷ê?šžV¹mè?pæ2GžÕ?ÏØ~â°â?–ZÏó°á?~lÜÆß?L2ôîc’è?¸SϹ•¼?è°ºµõ Ô?Ó¿bŒúÞè?p u§,žâ?µCì¼åè?a滕ßé?Z—~yÑ?1Þ:ê?”4»ŸÉ?jüàS [Ô?ùêI•*â?æ™ã®?Ô`ÉлÞß?ÆÒ"mÎeç?)*Ï Éæ?ü!9·¤Zê?äín ¼cï?Ð"©ÓÐ?ièb¬ëíí?œO*£iä?v˜ÞÎ{Û?ÀJœQŽÝ?ÆŠMÖÕé?£Å™A†nï?,Óî,~©Õ?ˆ3 Þ¯Ó?¹,:¨Û#ç?ïî£ð8<ê?ï{´´Neê?£l$¶è?$1›~KÓ?z£ÓpzaØ?¸ÊÞÕ?V+ñ;@YÐ?¸;ÒI(HÏ?‚d6oKá?¾‹:>³¼ê?yêÍ0Ÿøé?a4gñŽhå?ÍÖ9‚ÈVç?P7`—iÃ?rùéÀÖØ?ÎÉ*›ÉÓ?lÇ„Ž¥Ñ?Ô­<ŠZ¬á?Êq ¡æ?†²S¡?0æ?œ2[Ÿ5Á?÷yÐÒßá?¯»xS4ä?òVn¿ Ö?@)îaÚI“?\÷õ‘¯kè?H1]¬³à?©Kí…<æ?†zo­Ö¢í?ú2&…c÷Ø?l\0&BÁ?ë7üã?"H~î? ä"7@?Õ?„XºYŠ Ð?Pª£´vÞ?3œ³}úï? A®b¾Í?Ì(%°Jƒç?”}9Àtåì?ÇÔ­iÉGä?$‚hUðÄ?Y”XŽYêå?à‘Otu® ?ÏÓƒ<^ë?E>žÂÓe?¤“õK‰¾?Ød‡4Ý?´¢Ú`úê?˜¥o žÝ?•gÁ*á?£ðGc{'ì?èèDJ‚ìè?êwÖÁcœí? q+U?>{XÀâÆî? Šá´ªÿÚ?~”³ó£ç?\« º›É?”½¨œ‰Ò?œMï?){,ÃÈ?„5Õ˯é?Ìz +LÔß?*.ÁS¡#Ñ?ê¨N»ðî?Èjä"ñ–Ó?q\=é8Žç?P3øxR¸Í?‹Ëê~-¥?„8:TòžÀ?”Û¼“¹Þ?€¿õõ鋟?<—(D©Ó?ƒhÄ(Aã?óM¶Zé?ÓIÝëæ?ÇІçì?Ñåƒ öÛî?p¦éÑ}·È?(3Ó-r×¼?Dn-q¯}Î? t¨€ðnœ?î8¦)÷6à?üÜÙÄžÝ? k€†o¥?ýÿ·¯Ù“å?ä_ýùQ;Õ?Š'øæÑà?4Ô±~Î?ssGÜ?¸üµÊouÄ?F,¸ÞYÑ?ì¡1¡³Ò?x*Ro28Ð?ø,¸°éÙ?BÉäW}Ö?ž"3Æ•â?æµÝÖ?0\7— üß?]ïCŸ{Ð?`Ö¶òé—¥?ó hí?à@¯æÄÞ?‚ ïh‡Ô?­.ð‘,ê?ÿÆ`Œ£ï?°2ÿPxòÔ?ºº†Öh´?C2Ç(ý†ç?*ïñFÒá?2o9æzŒ×?·Œ¿º?„êȆFí?ôä#WðcÒ?ä-ô/OƒÏ?rÈ¥Wyvã?Ð>10U¿?€¨-r¦RÄ?j°Èe¡ÓÔ?tø :"Â?ð/¹â:Z ?…ñKÕ‚ùá?z’ûÒnã?€øÁìƒúÆ?ü2iHæ?Kþ8d¡iâ?‚ž ‚Šï?Îý#Ýrï?ö'y|Cß?Ÿ×LMEã?¥þúxk ?P‚ÒIx«?püW¤ùê?âþã"Óç?†ðøêˆßï?Ý®õ0Íðè?²»‰²Šë?àÆ ?÷Ï?¤RŽÙŽÇ?]ð¿ ¼úç?bmP.͹è?J} …¨Ø?‰Ií?tŽâ?\“lxíÇ?d5Ú‰ bÁ?ÑE¯þ™¿ä?ÈgÎ(Ü;Ç?¢TÑÁ è?&ÿÓ3šNß?Cå5Ù?À¼M¸íˆ?æîžÌ?xp,5 À?4E;ŸßaÓ?ð®Û|µ«?*?Q ¢`í?¶ìF…Gãí?ˆÑ!&^eÛ?Ø«½P’ë?8—@B&”Û?Ô1±$wÊ?Çê…g)6ê?T M³ÍÒ?ȯÔüŠÑ³?’°àGÚ?ƒ ƒyWå?Ù -¬Êè?@¦¥D$é–? „ùé?ç?„„MDW–È?É/`ÍÕì?¦Ÿžéð´â?””mÄ Ç?PÅ ¦Ë~¿?Øžxʾ?­ †Ty|ê? I9ûbXÅ?ô2Ÿ|¹—Ñ?£ÅÝÛií? j¨€î?SU…äí¸è?ìñ§òY\Ý?Òâºð|†×?Páz(˜ã?Ÿ•BT°?V{rÀaîé?3NÕ¦}ç?`WÁ|-Û?p`¿ÀÖ?¡éA ìì?£I‡å?h‚j„¶?Cƒ0ÆPàï?d?ÃDË¢ì?ƒ.ï þÓ?D«ãE`(ç?P ¯pC»¼?V´N9|è?ò–8BŸªë?ÞGê?à’ñ!Ý?ÃØÛXíˆé?„ ¸ü²æ?Æ£R£"ÁÑ?ã ¬09¡î?kÑCŠwÖâ?ö„ì~æ,î?ü}Md®â?Î{…Ñ£×Õ?€¿èTGwŸ? ÑëÝzî?™?ªD:ï?ÕÊ“W8Úí?h[õË1÷ï?ªÇõA%ä?Ê­e^CÕ?‰ŠÌVòä?\€TV]Ú? ¢ÓäuT§? xG_•ï?î|7ºGë?þ±‡t¦†ç?Vžš†z3Ó?Èéÿ^°ã?ä,/½µæ?IÅümî?:Ø©ô»´é?¢_ZH‡ á?˜ ‘Cz ¼?8û$V¥ž²?‘iÞ7Àá?CÉT:Û?7ùy×uZà?pj©\¹êå?š Sú¨Ü?š _âÂä?‡9ÇBh`ç?€¼S¤@÷ê?L8¢ G í?!Š ¶ÐPå?È×ojÍÅ?äü<èì?ãp û[Ùí?Û$­†Ddè?)IˆL™Çë? ñnCy—¿? 1&é?õ º~å?[õº(§èã?Ô"é•@ÝÓ?p†ëˆ1ç?]>Aå¤è?Xªzÿ±ç?Óå'±Ð?«ÓÁ/Þ”â?j %ðV à?0zçHá±?ºU”ׯÚÐ?8Lþooî?§nHy#ìë?S,¸ˆ÷Šæ?€ç9­K?乆k2è?ø¶lÞ´?£—îßà?WNãTnLï?:­i´é Ù?pø{L§¾?詵4ŸOã?¤šv®è?€âq̼®?m2ç1ųá?&¡uœ’à?ptaЅ¶?Åú:é?ã@w•§è?vÔ˜Q/gì?%V5!Ôã?tdšÕÖ?(äædã?àýØÅ«8Õ?îÅV-è?˜ª‰U‘ª?—ž)?¢Dé?$øeä|)Ò?ä*ßg¤©É?øÆ/sÆÖ?m·ÙÖ7vâ?pÆ—'vâ?ü:Ñÿ“Âè?Æ7¦ ÓRã?´ÐÚR)í?¸Ò¬6S…î?¤ “Ò£ñï?žÿF—Læ?–ñÔ@Hå?´ü4so«ê?ÄªŠœ Ö?véöÜ5]Ñ?¸°º-¬ê?0M²FѾµ?˜–ñKFxµ?¬èp$|Çá?ø†œp¶?7b¶@\¯í?gñ›kÌfí?nÉè?p€_Ý?Ûe¶*Œß?wÜ@ã ñá?@v# šã?ˆ¶y,c¾?P°Š9ÊÚß? nùç?Ãkk,Jà?©P3pié?&–•°Ô?dI°ÞÆÇ?‚îÄ×¢QØ?ÔšÈzÃvÙ?æ ~Ðb?2g¤«æ?Jx¦·’æ? …:ØÚÉ? A\’‰é? z†bU¶¹?Ü!Eä—]Ö?ØjزjWå?Ü?°ÇÐØê? §Ïx"ã?D„÷2Ã?2-º³Ó?ú՛Ͷé?€ÞÈæ¿?¦$Y1â?Bªá¤2&Û?Ü¡aI/Þ?ºnb<¯•Û?©3+¬Êç?…uÆÄå?¿»¦'Žè?pþÁ¿-ò¥?ã÷Ï2ã?„€ÖSÂÆ?(K™^hVæ?‘œ<(ã?.P¤ºã?ºP îî›í?ÅRQvÊÏ?oÁPÞ;¬é?â :5pì?7Bd$ã?ÆÈù¨nšÚ?4 Õ™Ò?¶Xû¿t¸Ý?.ŽâKšï?þ‡ÛÔ?ÁÿÆ¡àÒä?`¢»Ô`€Ç?\øÙð?Ã?<°Ü2ŸÓ?]R‘ºÓqà?âHTxæ? Â4{€¥?¸pÓÎÚré?;Ïãs1Œä?ÿO*F7í?Pcp.‘ˆ·?,_j·˜?ç?TE _Ï?ÉÚ{¯ì?УLï• ª?¼”£ç‡#Ö?Znv7´fÞ?6ýJ›Ô©Õ?ŸSxò·ã?‚±çgÜ?ƒ¬Ô1”è? G:?¤DŽPv×?.7‰²©£ß?ÉE§ Êê?“6G\§å?ÈG†ŸÊ?P¸üÀÏ­?Zœ T0æ?"ác[p¨Ò?Â,ߨ[oå?Í¢NL¥øä?°rË´á©?w÷‹Èù à?ȉ{Že¾?r´°Â¿§Ü?Ô8œ‘Së?ÜBL°N[é?NŽIõCì?é¬hº@ç?(RÒÛE&Ù?ª5Îvü·Ò?ÌÜí ¹Ü?V nÙ?¢¸`+ÊÒ?c}ƒÀä?± ³Èmë?à¶2„›w¨?ÙT¼”Û?W0‚Ìžé?ÆÁºÄM†×?zÿué•ç?è¿âpß? $nTã?•úuÉî?èù?xî›Í?Hå¿Ö¼?d\ñ@r`ä?¬a3¼Ñ?¸hNþ'å?]Ev‚S®é?н†Çä?„ö¦Î Ç? ¤x ¥?áè#äÏê?jŠ=ê®Àç? >›½!„á?,Ž«ÕÊ?fHDîÞ?,4õ÷ÃÁ?ßö'é?Eµ'ö~?øÆ€ÍÔ²?\‘;!™Ùß?l‹]¬=Á?¤£,tž\Ì?²!Øô¬é?ë¥ dÙ?[Ê °¬ç?ǨӱPé?ªd¿Ý?Úb'"€pÙ? 4Ö˜ú¡˜?H„‰î›Ýâ? мyö´Í?»ðÀÖâ?¦(#¿Ü?üp«Ü§Á?‚žWP0à?’ƒÊT~‚ç?Ó×¥1ªÛ?øªŽGI Ø?D]Ðí?óÙ^æÁé?„O‰ÐЀ×?š$NÔ /Ý? •Ácq”?Åù¤µ¨í?½Ü fÄ]ã?±IªðŸøæ?hWSm Ö?ƒ2—‘|å?ž~ù›‡Oà?‚=‰üíë?ÂùÿmËÇë?ÜKå¹'Û?†êºÕ?3½hV¡Èâ?@±+»?àl""½=Ÿ?ˆ )šÑ?}" ÄsMï?J¼KQ®îÑ?` ‰vPòÕ?T£Ô¯ Õ?èE´Äo»?JƘ"ú´ï?Øt†ñ`E±?±Å-å?À­Ð&×¼?\ŒðFbÀ?꺅\óß? tŒ@f¬Ÿ?ƒLc‚&æ?ZÃsþŒá?Hí‹ì Jà?‹¡áO²â?¬ÙØjßÁ?À_:Í]²¸?fÍMiàç?(WÈñ¥¸?°hR‰ Û¹?¤åÖ¹ÿWÙ?ÌjÑX•â?¤wÃ’Ð?¯Ì©2aä?,w4ËÜ£ê?B¥¸ê'æî?ŠnìC[–á?‡ÿÞ“€ì?`‚Ëe®?¡]N=‚à?·þÏk¯`á?„];VãÌ?mÖhAï?8žÖø¡Ó?¾z‘”ÊÜ?´¬‡ó¹jé?“ROÁZ5ì?àJhl> Ó?€óGb•ã?÷rÞ?pÛnA:ÆÂ?î´x5Ïâ?‡D¨vüäà? ÿ0¼3³?zµ2óØ?H˺ ýÕ?_B¬J†â?û ‚Öƒ»ã?’m½næ?ˆ¤š÷’ ·?ÉÄþÙp³è?°†+$_µ?¬µà:8ûÇ?þe÷zÉöè?~ÛÝtèå? .úÇF?dGö}^aÜ?õ1ÐK¢Öà?J -Æÿá?lQþS Ï?æaÉLÖè?ÖWÖ®fí?à"®ºÌUÑ?d¡“ƒ…Û?îâ]"êë?©@3–Ç? ‹Ô¨÷\Æ?\AÈÒŒŽÅ?¼e¶Á?Ì€:â]Ó?Ü=a¾³¡Ì?rãyÑÀÙ?÷ÌW1ï?É<¾ó«ì?ç\ò×J¨î?α ùGÚ?°•ÍÝ`Ç?X†ß '€±?öÃ7è§ Ö?>³u+æ?u½¼§vê?³ž-ûwì?XÏ=ê ÿÄ?xºìÐ?¥=ä­#é?˜ ó‘Hç?Æ\C{«?xº¾Õí7¶?O£‚IŽ?$´;*[4Ü?¥a<±Óä?~ÌéÑOÛ?¸AS¿l´?Ë×’§¾ä?O5\¬í?Ö.êqä?Q%ų2Î?ÐOR²·´?êðñÝ"¹?d/ó/zÛÍ?ˆ±Ú»?@b†ÿî+Î? ç±¹é{Ý?ä7rI;ðï?h×ÞDz? >ß;Iúµ?¨‘ú®»ýâ?$i°ž­è?`ý‰ã?Ü„Å÷Ð?¬Î|Èp°ã?¨ï×]IÊ?©&½kî?}Øi?å?ön”:_Ý? `jí?E–?¢{Lœë?±6ŒK.èî?ö¹yõÐÒÝ?à­Âeaª?°Ä/~‚+é?ȨU(ûøÂ?\èéNCÏ?/Ðcò»ºä?°œÎÚ¬ ¡?Qð!ëÓ?0ö_BÜ »?&âf‚wä?Œß46>ÝÇ?rB ô¡zÒ?Ô*ü:K’Ï?À¹/ˆôj„?¤§kÔ=ªÝ?0üé©ÏS«?ë>ÉpÏ4å?=(·©ë?¦¸~r$Ø?Â~tLÚ‚è?r ä¿ÆÔ?ˆlç?–îÌó}í?ÈœoÅÎ?‚¼È)¯ë?‘Óú#1ï?vµ¤¼µÐä? 9SŠÊ?t¿@©ƒì?™>ÊobIí?ÞÀœ.å?† *OÄzÔ?§)[žŽî?ÌÀ*°êŒî?.ý÷Nä}è?Fž¹œ}è?8ZF>xýà?1‰±®Äç?†ÃÑÔLá?8§Wæ?$tE§sÅ?cjjé?ÒíŽÐÚ?¨ò‘! Û?” ™ÚÈní?Qá˜]Œäí?2L³Í®Eå?øÕ‹µ·à?VBï zï?4¯ÉÃä?t3„Ê3Pè?nTè¦Ó•â?p±ý(tß?R ëFçFÚ?ï×jê?°~1έ?§×aé? Ì%µg‹Ï?JÃ9×?÷ýs,ñìì?¾w9åç?°w¯Ðýº?ÃÇ]½Ñì?À²—@ E®?Œó3ûöTË?]< ‰°î?d*-«º­å?èSDŽ‘ê?õ7¾¬º<â?­‰t¦¼ê? S3@åwß?$Œà Nã?§y\ Yå?`Lt¨ÎÀ?Øi¦½àÎ?µÎi"kòë?nÖ d]Ò?wy¡Èê?5†ÙxUá?k ’£ÆIå?°ß® Û? ”‡æ5å?ð\7nÓ˜§?lVú'5×?ê¹äÝ3ß?@Pœp‘h¿?#+·{Úá?¦¢£„õûÚ?*–Àl-Ò?:q¬f¤6ê?PuÔß\úÊ?@9¬%i”Î? Õ“ë)Ãé?ÈΠ{jgÏ?Ñå§A—'ï?ß0ò;¨â?œ7s•/næ?ã5ÇLKƒè?°2m­Ü?>Ì Ò×?ÌšÂãê?ˆß«Çw«Õ?f“1~XÉÐ?öË·ñw&î?€–΂ðÙ?J? 5Sä?//¬©Œá?c—_ 7ê?8oa Þ?V [e§p×?­•0dåê?uÎ=Ÿ±¢ê?– òE _Ö?õú‘£6ç?´-¯I´Â?eÀMÎjfå?>Ä\"7ß?ñ‘¦+ã?X›syÌÊ?Ñ–på»â? u^oÕùÕ?ºË‹ÇMë? ɈÐÝ?:VŠá?­²(·Þ?Q¤E(Šî?Í89Ihì?†ŒŽ%ÖÑ?hž6¿¦Ã?n¶ÏG=3Þ?jp9ëØ?ée@=§yè? ‹¡„âºì?é$Èá3á?AÃÆ~³æ?½Ÿ àÌXã?ø¿+]$²À?²j0HÚ?ÆK™žX?øØZs—Ð? ?Ú„3Ù?`~g$µ?c¶³æ4í?>d=î?¡l×ι®å?l¦jîIÝ?ïOg¡Tä?p\óh!¸? ?r6Øá?`A£¸B©?x2xÛuÞ?´.|gf—Õ?c÷‚“ÿà?˜“Ø*å?ºyŠÁËŽÕ?2¥Eµ hí?êпè§)ç?TQ€¡ÌÃ?ÊX²ö•Ú?ë3‰/í?1·¼ü­Hå?”Ð-EKÞë?wƒ¼õê?Vd!o`Û?üVμzèÂ?ËY.—;ã?¨ë£>ªç?ð÷² ¨¿?ý»fúOìà?”¬ÒEMä?°Ò·ÊôL×?@/ÒLÜ?ôy‚ïÅÑ?éMZ¨¼Öâ?1æ‰ÄÃ?Ûð%Bí?+k’aè?@`A‚‚?îãDïé?ŒA0'e¨Æ?è¸Iþ0yÝ?LÚôiÑéË?IK:ò€ç?à¢l‘ؤ?’ÞV;ªï?Bº­¥ iã?¿ “~9í?«˜ ZÇê?ÊúÄZå´Þ?LhµVaÚ?à¢/ÔrþÒ?„na€aÌ?Ze`f¬ÄÛ?îúŒ4ï?Pñ@§ÄÚ?pdº;¸³?´îÞ.ë?Óî‚–Oì?Ø@Ò™Ö?ðµ…Äz”¨?hQÚ¸É? hÞÀ“(ª?6ô}äIé?0°›§?±Þ«oÒà?,ÞÈÑáÎ?)J.µƒªì?òMå©â?…›=Šë? Ä'L9ñÅ?PHˆ²Ÿ¾?ÜóŠ„g Ï? 0 ˜NÑ?wCÑŠX_æ?={ÉÅÃé?oß8оÃç?ðµûŽ<ß?[ÑÚ‡Cï? |éý­è?âÉw£Ží?rƒÓ€¯Q×?X‚÷è˜TÙ?è˜Ç{†é?w$NvR×ê?x|io Ï?€å&Ï “×?Öȱ,Ö?m–¢î4â?dúåNKä?üÎñkÕ? ¥_Øa:ã?ÀSæc¡’?G¾1Ûî?‘Ô¼ââ×?Ä}Ü:Â?l@õu“?Î5fÈçoâ?4­Ó[GaØ?‰çù7l(â?ÇFÎÔ—ï?˜»)Ã?ÝXXh‰gã?{*‘I§ì?é~±¤öì?®ÇF<ùÜ?ú)ÿENéä?fH'o4â?€/ÈÜWä?ʤE|£ê?ÈG)!5Ò?ëÆ'»Çä?hêBõTãç?š ¢5)žê?Ð ÍàÚÚç?~~÷ßÕ?§~âŸYYà?ÉUЏæ?04Z[!Æ?~D¢ã îÔ?Î(ë/¿å?CF|:H®ë?f¬ßuÔ?äȉúÏâÔ?ä¶çî wß?³ù¸|×? ²5AÌé?øG’¨ ·? í»oò’?Š®£±§ôç?n¦Ë¼Î©á?35J ¨¯ä?Xªšî{eÆ?n‹C¾á?:sap.ªî? ÃÍ÷ì? o’ ™©Æ?½ZRÎß?4Y0‚Ý?^TëT“ã?]1ÔÈhè?u ÏàÉ?­êrá? »¦ì?ÚÔ ® ï?ÄäŒpÑ?¨y>TêQÑ?ÌÇ9fÉ?¨zï.Ó?ŽRðã‡í?øô¤=¸?x’¡ìÞê?䯹F°ÏÀ?´#RÕÔÚ?.v,¢BÇØ?â ÚÝôã?Ó+ik¿ã?Õ´7ÀŸgç?B­“Þáà?”2Ňð§×?8¬8Ÿ½î?(kñFÔÃ?Ø®ø¨Aê?h|a{¸·?¦Sˆs´?;õ¥£èê?às•ÙàR¢?%6F0é?€šÙ¡Ü¢?z_ñbmÛ?ÏÚž€Ã–à?_`Nvä?îŸï™ß?Ø(4ï4ß?*‡3€gEß?ðØ £÷¶?Û¦•f$ä?4QùrÉæ?Ðý,Öj-ï? ãÖ?T·ÉN4@Í?vïXBEÕ?Hª$µ+î?¨°rïÀq°?d ò9ŒÍ?ƨ˜å?6ªØ©àÑ?vÉXÿýÚ?ØuúÚ9÷ä?¸]|ƒùSÈ?•xü©õhë?2~00]‰Ø?E>?Lˆî?˜JÜ›vë?±Šo IOì?5–ûûsí?ȾA²Tã?oCìM¼ç? i)2•D›?FÀ0Øßî?µ±¨`nkå?¼3!ÈæÞ?u’'S׿?pòïjØ?——Q6®Œè?Üäq&KKâ?Ür©d˜Cä?ÀõyÌ?—ŽSD°á? #8øq(»?(ãÕ¤É:É?.„ ¦¹?6l°Gn—î?óî3yÙä?¿a-W¹ä?E^â›hë?š†ú$SîÖ?T’™å|kë?¨ÒZ¯Eüé?ô¶gbåÂ?x®‚RÚ=Ö?ŒF`šÃûÁ?°¢4èmº?à k¢yÌÝ?D–Wg0úÛ?p23þzãÂ?ÊÀƒÑyî?Ó2iF­ æ?U{¬¤NÛ?šÍôÐÒ?ž_«‰øè?%Œ«H¼"é?ÆAÅs ´ê?$jx[½Ð??#E,Š…ë?kþû+âæ?߀”ØÈ¸î?¤É,¨¿vÈ?ô .hÂ8Ô?õu ^Ö?c|ÇÎ9˜ç?ôîÕèöùÒ?[¬€BG‚î?˜¹Oשß?4Iüx/œÅ?0 ˜ž Kà?È(V7Áâ?:ŸëT óÓ?äpŒÑ¨ß?úhÞ?rj$›d›?ÀòÿIT‰â?ޏ×uß?|ðH1Ö×?‡oÚD¸¤?²ó® äãÑ?¬¥-° ²Þ? jã@*Ú?,‡k¯í¦?ðmé„&!®?nå’±ôß?ðúÁåC¾?žAÎp7ì?8Qƒâ?îþ3¨Éæ?C)YÔ¨ï?@ër/¹?@bñ|‘?DfÖs#Èé?XÓpâsÂ?øjpKˆ½?ˆܨüÚ?ÿrNŽzâ?}Àsy!få?e ìɸÑ?ä`é&lRÉ?xgƒÔ¿?ŽrWiä?‹a[YÅé?Lm®Wí?Ð;´ûdz?Ä r/Þ?J›Àr.î?°o¢ Ý?aÛáŒvèæ?¿œ=ž>Ñé?¼¶Õ½Ý ï?À/ná†?ÖnÄsr5ä?J¬=áÄÒ?8ÌøÓ?BÑ BÑÞ?€É»˜…? øI²õÎË?¨GBIç?ß-Î=õì?7ÝuÙEË?6 ŸâwS×?0ˆ9õ¯7ä?‡ I»?ÃÔ챜æ?Ä1’œ–AÏ?°5ÝŸ!õÎ?à´M&Ôÿµ?&>’à?•q؈"ä?ý’»xyæ?†ßŒ†›¼ä?¼`Ü„>€Ö?%'Zë?ž=ùÌ«ëï?<‰Œb3¡ê?LQ]âß¶È?pÊ,4ÒÕ®?¸S¸‘AýÑ?,©ÆÊ¥Ë?´õ›Ð§!ã?î¨ì€Nê?;^«•{å?+öb™æ?·tã?À1^¯S‡?d<ÙìAi×?TÃYfaß?<°úÉœÜ?H³@‰ÿä?žxüDí?úC 5Ú%Û?ÊfÈ& ³é? +ÓÀu½?k|·áƒï?„ÿÝÀÚsß?ô¯"–Ï Â?zÁCt¬ûÓ?˜k&Ö âå?~3×£Bî?×±PŒc¢à?ÕƒAþMá?¼ÞtìrØ?ŠFƒ’Ò?ê–"òA%í?ñNžKþë?^ìuî?/åŠ(`è?vC’øËÖ?Š S¥×®Ù?ðÔ³^Œû»?Bî`Y4iÕ?jß>E¤:ì? y± ·Ê?Bª™FÉç?é‡z}Ûtæ?h<ç\¥Î?x P¦_Æ?è JPî?·Ç.§fá?ù|× ïgè?cÛ•ÂtÒ?´j½<=æØ?Ú=90Ø/é?Di¶é``Í?6LÃD¶é?Lj¶Š/3Ñ?Ð5K–\(¬?\DZŧÔ?À}¬0¡Õ?ú ÿ®î?TÓxgàÆ?,Li¾/lë?–Á½µòì?ìMËÝ~Ê?ÃSr–Zíí?µ²š/Dä?·Ê`b­í?ÇuÚ 3ä?®î™«²¹ä?aÅ™,íë?+G©zì?jbÝË¥5ì?¶|*­õ¦×?Œž óCÞ?°1¦%: Å?èùÊ4«­?ÌÂÙ%ÕÃ?üA2cÇ?TÑŠA€é?L^׬ÎÍØ?ç•!ÞÄ*ë?tMnÎ_ëÅ?¸qáwô-´?&ÿ¶ åâ?¿Ãˆ¸»à?@fIþº?4h<. Óæ?òA*‡Mã?äÀ¶Ü˜Ó?˜(ñƒùçí?D|°0’ãÝ?¼é` oÐ?B/þ8²\Þ?Šªädvöß?%BªeÛë?ä`1›« ë?–:c÷ðæ?¦¯âåå?L~,ø‘Ú?Ø'I¢”Ë?>êËÔ?•Á·»¬Ëí?èèœQ½yÃ?ŒSôÊ\ãÏ?Ø2›,›†Ä? c·ÅsY‘?CGLêí[é?àÜþØ6Ö¾?ïûzí?pNÝÇ¿?\6X”±Ý?u3AüÆ<à?HÜH/6Ð?Ø‹¬?ÙÓÛ?@þT½aÑ?ØÎú¤W!¿?ޏ¬û!Îá?Ìâdžz‘Ä?”X()uhä?D³f’¸Òà?V™ .C%á?ŒõØššî?Ô²øÄ"Ý?„)˜šŠÕ?ýH‡âÀ?È…4¢°Æ?HËÙSk¸?P +ø(áÂ?ôìŠÉ@|Ê?s¯žˆõé?üX6aÌDÚ?64d"[í?€^9m¥“?0`<ô;Â?BÎAå¥Ö?T®ÕI`ÍÁ?}µïôDëê?°K•Þ? ê?‚Ø4®¥?Ý?ŽNr¥•Þ?òÅß–3â?fÝÁž3Vá?Sêú®ö{å?çX±¥è½??§õF%)ï?ò4çFñï×?üC O{ùç?*/gÁúÓ?cÜ Ù˜î?„ÖE¨‚Ìí?Nô€bÏá?6ˆ‹wäØ?æFd¬ß?îúø¹üXÙ? ÉÙ7Îê?¥d’”â?$4\Uªã?HÛ8 \&ã?æ 4Ò¹HØ?`mùRcç·?¤sÚƒgÜÝ?ZÑeɾè?8LÞ‡Ô?æÀÚá?àY­”­ÕÜ?¢!”böˆé?Êvä Äáç?ÿ¿§}%Ýî?ý1 Û.éå?gÑÏw}Ðç?~ʆ!m]Ò?¾p?6å?@å;qx•?”¹@†'âÐ?©»8èkà?عà©ÍÆè?‰Uÿ<µ?‘f,MŠ×í?2;ß< ní? L¬û¦à?ÀißTqY–?'Æúúä?61¹Ù>×?h-ÛÏAgÔ?p ÿIjت?PO(N6Þ¿?˜N%¬´?ë®ô=-¼ê?¨\ª•­º³?äÌ“‰í@ê?¶‰P/•éä?æAþrJSë?jN7ÜgLí?:#!ºÏ°Ù?©ãy’)Mì? RßF_sž?ð[脘´?Ϲ3/Iöç?w ¥Ä^iç?ýÅä(Ÿé?Èþö‘e8É?GK5ü‰Òí?Û¼‚#Lã?˜8ÃÜ?ÁG2ß·é?/9ã á?"¾úÿ* ã?x®è‘Cxç?ð‚yNÆ™Ñ?`q9 Ð?ç>ã‰BÉë?fÝÂ"Äë?… àrâë?Ñ5oÝcÃ?\¾Û¥aAé?cºeQLæ?¯ r…KÕ?QyI{ÊRå?"N®3‹í?Ðké{Òå¯??ßþéç?~æêºêÐ?Õ"Àü/î?Ðaª/ ä?´õàjÝ?ØÈB€À¹?v§&¿­:ä?B’Ç`fÔ?fá÷¶ÕyÞ?¸šËáã±?U;oDí?ÀÖV`fœ?€Ë<,¡¯´?;•Ÿ &Áæ?ût/öðé?"|(”—ªÜ?Æ\®é}Â?t ¨¬Óä?"ºÀ~&ä?ÆgíèPÀÖ?ùš$ ïë?ÔžTÀ×ä?„^ܰݘÊ?8ÇÇâ+Ø?óýw jµè?ì×£—E‡Ï?‚¡YÀˆ×?>´Ìl å?äÝ’{‹Â?Úýõ•èˆâ? Ê[áõâ?Øúiú¥ðÈ?L}(‚¶LÙ? (XÀØ<å?œpoO¶â?ÐÊá´Þ½Ú?,õ–X7Äç?ºùU8\Uç?ó 60µÿí?ô‡=3¤2ä?Š%¡éá?ÁYð®¢á?N “…W=Ý?)¾Öa/æ?€sï?x¾ž0FÞ? Jd”©ç?Mf2 g§ï?¢ê! ªì?©ÜOðÜ?q6 ¿iå?ù⚸Þ)ç?„ÍúcŽÛ?8üŽÛxÂÛ?æk{üaß?è{a?œþ±?†§#mê?™Â†§oèí?SîO–€Xì?ÐCÎÏÖä?E\›qé?â)â%)×?Šìái«…Ø?cˆñİÙ?ÚŠ TGã?ĦÜòäÚ?ÉÛ\0Œå?”7!.ÏbÃ?0ŸØ3rïª?à6E(¸»Ö?H׫‰ Û?èSÔŸÂ\í?#axN?†ï?<†——uVÁ?@j&!é?Ƥ0åï?;bŒc½?ð"¨ðû¿?ÔMðÿ{Î?Ö¶þ{ˆDÙ?OÖqטüé?®îŠv¼ä?È8ê7î¹?6F3Å2³Þ?ô1øìá¦Å?0HݰË?DÉ<÷×Ë?X\ ô³?³3m¨ôÑ?Û:Sã?×fÒvLýê?:³VäÕ?0\-EæîÁ?vÜ(<â?Ò¨pÿà?©ýæ/Ó?pŽ„ÀK«?I«ø Íà?•+<Àïí?ˆO†©âÇ?dd¾Ucà?¬› ú±Â?†±d'KÉÛ?[è!®‘ã?¢ ÆŠ‰í?Ôö!l¨é?ªŽîª*í?pǹwì É?†Ê¥„ç?¢Ì숻­?(nŸx²?(!’šêC¶?t;49¿IÊ?|)³˜ÊÅ?ª(ß{°9Ð?'ÔùÀ ¶? ˜Y‘] Ø?½r Ï„í?Ü>ØèÐï?ËâºÞé?6 Í?0vž¸?›bıå? I A{ÂÜ?Š/úUëÕ?Òz¡³`Ñ?jÌ­î Fß?8+LÓf¾? üäæ?FÁĆí?-Ðm膪å?Gÿh„X-á?ÅjÍüÊãå?ðuŒð5Õ?—œñ[=È?&¬4[:ß?×z‹šÂé?[*ºîýâ?Û#¸àÕë?+  ê?ˆ`=YúpÈ?L5¬+ë?×v‡0ë?êÝâÁƒEì?œ¶ŠƒÏ?¦Wm›¿ã?}>âµ9é?iù ¯ž?5ã¬á?¾ûÚ‡©¡Ò?ø·M²&“µ?ñŒ4Ñë?ì…dÁnã?Ä:Ñ?Õ[“ŸNÍä?þ¡ûP¼ Ø?´ŸóêiÇ?ÊáqÙ?êM ¨ñ@Ù?2ýÝ«‚„Ø?î2À‡ÚÔ?d®ï!Ù?€vÁ\îp?ƒƒ?|¥ç?¹UãK!0æ?ÀMË~: “?]ãu×É?2.)UÓ?$w»I-á?ã@+¦5ç?‚˜EÛ@í?ž®Éùž¨è?yKShZÿî?`#pÚ~ë? %Q°Ð&á?ÃÃýÀ¹í?~’bkÌ?„gû›Í?êÖ•¦dÑ?PŽmR³?‰h#Ž&óæ?âÍ1·5hå?ŠTwa~ÛÔ? mêø¬? vä}ŠÌ?0ŽíaL=£?ã ,þå±?_þ;€Ãá?Õ$JÕ)ùç?DºV³óÓ?/±0ªoØ?ÄëÇŽË´Î?5xÕyCCå?ÀK zȉ?q‹cvÒá?¤‚«ijì?MÞsœUé?`3@íØ?€àæ&Ÿ½?Ø€D³a9³?Áµ"ˆÀê?8{}-ÎÊ?f÷auÒî?ÀÀ—@#„•?ô@ ¾ê?Ø9Fvp=Ä?ê²hD,à?ü‡@Ú—-Ü?8L?š²Ÿ>B ê?ƒ<ðÈŸç?€nµ• ’?0nÄÐ-°½?˜›YèÙ<Ô?,V-AL¬ê?M¸]ŠÓê?2K9ö;~î?$VÏMæ¼Í?;Keýuàî?ø0‰7þè?¤Ì¶Ý?ò ±ªÌæ?X=Î{¨Ð?‚Ý_?{à?i%ç¾Mäã?Ù…Ñ€Éjä?ˆ_4¼ Öä?©Ü?[„¾©ÙAï?\ÏoŠîÏÁ?âò—žK¢ß?2ܧãNÞ?°­øèÙáì?¸¦Ô,Ö?äz£dMÄ?î̬S\–ê?R>ä¦+ê?i*9HÝ?ÇÙ…fÕ?Z‡­XúïÖ?™!S²B¶è?¥&|ó=î?²z:Ø—?u×Þ'¦á?>Õ6 Ô×?ÐòŠa¢°?ö5v2ÚØ?ŠÜÀåM+Ñ?É1ój"ê?¼P@Êç?ã lñ†žä? ˆc[†yé?™îÇ·5cì?UQ°‹Âè?ÆËè¾ï Ñ?Àô³™ïZØ?§Ë+E\…á?…äãxÁ?HþN}&ÆÁ?Õoƒ§?^xwÐsë?Ùt.+oè?(OS3“ŒÔ?À«8úr@†?úMŽQî?âô.kªì?G3pÖà/ì?@ ˆ6Od›?ëûiAâ?-àðþçé? àÍÎàà?^ÉQ ElÓ?àÊ \z¸?\Ú?qaÒ?pð•8­Dä?–ŸýÀÿé?5޶ÕÚÜ?x5Çu¼ÅÅ? JMm{Èì?Д9Ù»É?8¡–Ú?M&w|Vî?sîšßí?@OAˆß€?‚ª§Ÿ™:Ö?Œ½0­ýIÊ?n»Õ›Øç?ªm>@„ˆé? sFňÆ?°´ùœŽGÐ?fçƒDp£î?ªýP÷‚²è?ÀzÈ?} ”?ðÍ…Ð\Ã?žY½_Ö?|R<ì5tÖ?2"ߪç?Ú*ìëÒÑ?a°Q$é?´ø#ëÎ?T5¢Çñ•Ï?týæé‚2É?¨ÇžX«h³?]áI»è?Žæ¤=è§å?b€âçoÖ?Ý>_ßÉÐç?é"ƒ àê?Ÿ‘û½y_â?G_ ßvà?˜Qe¡$ì?L<*0°ÂÜ?†6Ã6–Û?œg a1ïÚ?UùzHâoà?îÉmýøÚ?øD2]Èwã?â}õÀqXà?~ýU£jÖ?6ÄšÏ×ää?ÊbÚ0Cç?ÂJò7Õ?ä­ÿ56à?\dr§BòÒ?|¨­öá å?¶À†-=ì?Gt]h6ƒ?øÈ ·EŠé?VqÕÖ?FÊ™*ìá?Š|®¼éè?¼Ä¯Í'î?[´²±à?rÎn€2æ?êQþX+í? FñŠ£ê?± ²9Ö‰è?ü€‡„WÞ?$˜@’Xbã?öI ûhªÚ?*$ü8‚(Õ? Ú‰ÑLÁ? ^š´ìjž?Ö÷/;oÝ?’hõt, ê?Öy_>Óà?¬®‘Ê vÎ?¶KúÏFqè?+…Ž0Ö±ä?þÖ01Zqà?¢àŠ}b3ç?˜ ²Âí?_ƒp‚¶åã?wÂùƒkÌ?*-[ó¢T?:@:*åí?ä†é(ô½ç?úyÀ,ÑÝ?l ö©òSÍ?äSÿ#÷ß?¢AÓ Ð?>k‡OÅØ?ˆxGâé?àAèøÈkÅ?It¢ûÙ?«¯TNHï?€yþbä“?H÷ö¬¶,ë?õ³X™ï?+¼Q§Ù?@¢Ý…dÞ?¬Àzl ã?謯“kä?Ý^è&ûÜë?k¿õâ<æ?Ülë?±ŒÐ?ú’ZÝ?ý²¥ˆcâ?²§cª`Ú?`rÂä?¶%&©yÑÙ?Ž…Œ¸ƒzÖ?d`®Ÿ|Ðã?ÊB+¬±Ø? ðŽi ì?D‘ör­2Â?È/àðbâÊ?@¯Mö‚?Àâ]L5¶´?dŽ“’ÃéÆ?ØÂà®"ã?ÛfyTüç?ïñ÷_‚å?„%e—úß?Hœf—óÛ?•\YŠ®ç?º'[Ù\÷Þ?ØÍ×—+ÓÀ?ä1øÜHÛØ? ÐEøÏOï?ˆ÷¼eä?lº}A¯yå?ûs6¿ˆè?FC—ûçÚ?¡WEÜá?bCŒÚŽLì?fsÀí?бQp<Ë?x ðõ¢Ü?÷}GgNá?ttÅ£fÓ?`O–Y~­?¶"Ö\GZß?Øè«bv ´?.ÅʤwÚ?Fm˜9UsÕ?ࢶ¯ðÐÀ?þpS·U4Õ?üõ—ìxÇØ?Ø3ÙYdKæ?¤âIÃÉä?„—˜'ð™ì?Xóiâ°Þ?ô¦ÓqZÉ?ýaw.ï¼á?‹é³WÍjà?šwDçÂLæ?-)8ß9™ï?Šå5¾Wâá?¨ÂU=Aî?7¢7ö(ßà?Ò›®TÄé?HÁôú¡³?àÃsǸPÑ?Jˆ<:°×?Ïõã Ñï?ųÊÚQâã?|áýzì?6Ð7yáµâ?]IêF Qè?‚••é*Þ?ÄΟ9×Í?àN[ª!P™?ô}õÎX[Ø? c{±A À?03nT…'Ð?¢wÚÙ›qæ?dõË~.Ô?¾¤[I!¾Ñ?@’—¥¿o…?ÑEDýSEã?N·õöúè?Æ”-…*Œï?Ÿº÷¸GŸâ?g¤¨ ¼à?ÌÚÿœž®Þ?{Ž0áÓŠæ?âQ%|¼Ù?ƒê‹‘°ï?§ã! yÒï? Û&P ´?<+QÂn3Ã?ÞEIÇTí? U¨ßö²×?*}aÝÍÜ?¹o³:Úë?œ2¹ð€Á?#M6¢ç?ǧ_‘%à?‚NÍâ?“'u‘±ï?Ehœ³äí?h§a#=Ó?Ê|¶"5‹Ô?äl9#ê?–¯àÑ’hÔ?JÈ­Ó?^Aqæ-ÇÚ?M¥èžë?»þ8~þIã?0jêëé?P"±ãî«?µ¾Á8ßà?ÞyÏêâ?Ðj{V¦?ô#gÕ ¡é?Þ}ʧê? k.îû*§?7?-º÷ê?aY…"yà?å¢nŸNuì?j ?83¡#ä»À?/Ú¯ y%í?|T jÙ Ê?@*õÚ¥³?Z»ÿàš+Ø?&•E¤ì?¢å‚±Ó?@¾ZGÏÂ?Ø,ݹ:g°?¬ÆÊcÅÁ?n5½¨‘¼è?˜l5‰ëÿÀ?45®ß£×?Àñn$Á?Ç~B&î?{/¶ñ–±æ?0Uu¡ÔZï?©Þ&‰ë>ë?˜UËKÏÜ?8¸äߥî?¶ˆXj›¢?D¸âžé?Ü^5*ò“é?œ€£<Ä?XXñŒÇ?¸lð§Mƺ?ž¼! /á?¹û¤2ê?­rà?…*οf?Þ"™/í?˾cXb^í?œ9¢Ÿ1Ä?W9'†‰?N|5èæå?›±qÁ»?rÚÖéãÜ?.? ¯›ÎÝ?ˆ´¿ÍÖÛï?”hb3}žÉ?DÕweúŽì?4̨þãgÃ?¸v¿ ”¶?0¤«öçå?‚ >Ê lç?,šÜ€4¾í?®4ǨÈÔ?«ßÀrý)æ? }"4·˜å?I (Hšç?wÚúÍ?‚:¼@=,Ý?¯WÝ“±Ù?˜óB(0ºÙ?DÔäN€|è?š7ÖgåÝ?@Þr¡Ãí?{¬Ôekæ?@zN2ç?„ÌA¨ù¢Ú?zÄTzÂÞ?(=ï§Ø?zíýÌßìÛ?½GÖ3f+ã?4µZêù‘ç?Gçý[ã¦?@*]f—ƒç?ªÉ:Êz¥Ù?þ,‹¹æé?xr]C¾?ŒµežJòÅ?-k‹Ý¡à?€’,ݸ0í?`׉_EÎ?T½ò….Î?3ùʆLÊ?R«5‹X–ê?¦šÒ—Vß?åîMXë{ä?À¢CQ%ˆ‰?¨ü3Jé?×ÄeÔJCà?† ¶U*#Ú?3S¹5{Lê?ò"cù,[â?wððT_Xí?ZJ¥J ã?¼%‚‹\*Á?˜#©§Öëà?üÃQ£«á?Æ–îqè?)Ããú|äè?޶…M;¤Ö?)×#Á’vå?&$Ð1H®Ó?Æ(z8…Ï?ε‘Fáâ?xÝÐä?è8N2Ú?¶“)tÔ?L2*OréÔ?HÇïï²æ?h¹ƒ*³Å?ôí8&3Ý??›Õ,ÑCè?6ôßNÉÐ?¼S!óºÆ?uš‘b8í?ÑÂ÷M5¦ì?tY&õ¡æï?"ò&5¶Õî?€¦íÀØ6‹?ä8PÉ×?<]ìO®?_8çœÑ?ÄJã-ÈÞ?¢ÓÝ áÐ?ZøÛ0ß?A!Dbê?hQÈõ¡Þ?'¢Û'°Ûì?ÊNTñ3Ñß?0äÆÓ?⑘ÆWJØ?™ûŒÔ°æ?›ö*ûî?¬­=©ûë?”«´>"ì?¢í kÏ×? ÑÆµžˆÑ?Ð߯`Íì?ìÙYx­6á?( ¸ä$ à?¨²‰R2|Å?̱Ç;3­è?³þ-™O~æ?ÐøQt–ÈÔ?ö!ÕqGÞ?ÀaYÄ{.Ú?¨r¯îÜ”é?¥¹ÏWï?"#%Æë?p}{ZQ+»?XJ%JDŒÃ?ªЮºRÖ?L2=wKî?À¿£f°;º?0ñ4q·¶?V¬ƒ)ë?—&zÉ6ë?$7˜*åEÁ?0Dé—†Ê?„–•ŒÜ?,¼ µÜÌ?xƒÇbþÇ?°.ƒHdÍ«?TD&Ù4ˆÒ?@×GØ:™¶?ó4»ÕÍâ?À4¬²6Ð?RÎâ®Øë?Åò/Ë?è ¨Ì#â?=³¸t‚á?éªhxÕgã?„gˆ^‰Í? +pà?&÷ò½ à?&X¨ÓzÏà?‰d)šÛ"í?Ø}Î1ûÃ?öJn5)Þ?ðjl@{º?¦3¼"ùÝ?ŠrþSµõá?IÅûÅôkâ?  K=Ñê?à [¨Ì·?{KÎJ6Çï?ù6º½à?µ=¿ÛŸë?Qç"E½?0Tžù#¿?0´ÚA˜Õ?èØŸsM2ß?yªñ•ìå? ù^*õZÐ?Z‚;ºeå?írV¯á?øÐÂBÎÔ?¡l;$ä?pÍ?™Ò?iªÁVä?d«÷¯ôß?HȎРâ¼?BŽ­&aáÕ?Uµ­:qî?$Ùæ0óã?dëT2Zuå?p4V›mÉè?æ«’“Äè?TÀ‘ȤÐ?ÎNÊná?0)n#´?,MÐ Óç?Á,‚ÑUæ?ôæ­+ªjÉ?¸=v` ë?4蔯Õ?s¨«k¢è?>ðítûº×?¬i,;7æÆ?ßN}”¼.ê?ÿïj¦÷ã?\;ˆ×ÕÅ? x0+º?>>¬¼XSÒ?B=a2Ò?4Å(NZæ?Õ`Fäæì?¼’4’ÄÝ?\PÌÎøCÕ? ¢-aÀmÓ?l‚Òĺì?–üáÓKç?ưèX'Èê?öjÑÕpÐ?žCý¤^î?  ¼Þ Ä?og%èšä?¤]€â£'ï?ÌÏÖ¿É:Á?€õ”ÈcÍ|?ìhÝIì?p²ÀûEÃ?@l„6èé?.wx…0óá?oÞÚÈ®à?°DŽ?Ò^Ë?3èXŠçïá?ã·~þŒÖ?ÊúpV,ää? Ú.î1·Å?Ë6ÊÂÅ'á?W‰ªÅ[å?'¬ñ&æ? Ö,ΙÇ?Hù m•GÃ?ä³t<ê5ç?=eÁëKÎå?VÚ“Ó,\ë?´Èo“Ü?`â{RDª?Pcbv'¸?p}H¿3¨?æ1ðH{.æ?m8ˆ»LÎâ?¼Z ?ŒÑ?Ÿ®%è3“á?ÙŸÇŸä?)aøâ?_J‘ãa?5Më€*ê?º­5zÚî?l9ë5-Í?²W²Ê/b?Ð#”–zY·?mÔZŠ©ì? ôRg£Á?Ø•uhuÑ?ÄÉåNÐøØ?p^3ošô¼?¾ÑŒ³PÔ?@¤¶Nò·?$áV"¡qË?(Cï›”@Ó?ø¹¡®1?ýDÝøÇ?Öí%:Q(å?´Y«F½î?Bâã=¨ê?x³\ïÈæ?‰3Û„B{á?à¯øh0F“?He˜Bš¿? à?7êj?ÌjsN |Ú?€PwÅõ¿?H<—i²?$ßý–TÓ? žH¹è?¯ñ³á?€ÙÒêë|´??þŠì? Šz…çé?Pö3æWÞÙ? ÿ-W¶–é?È»ËjóÃá?°"Q"ÿ\ç?èˆüp·ÔÍ?^Ýžm¯Þ?@$•‡~ÆË?´Pœ›D[Ã?ÈTNžÞÇ?ôÄ Ô}úë?0°’’/—®?fÑr’Sâ?4ŠXÛMôÕ?Ð6s= ‹Þ?ÈÚ‹g ¿?2öó£ˆzã?ìøMÇêEÏ?è¥GÐÂç?±Îsaé?ªÎà?Iª9“þ’ï?d§vioê?¸fñ{TÈ?^pzJ[kÞ?]Ñ3'÷ï?¨i­wìÕË?8ô\]¡OÈ?t| •V·Ù?†žºè5Ù?X®{¬ï?èe7¹]ƒÚ?ÒÜ,Ñ6mç? B£\4<â?˜€¶ &Î??1æq\`ï?6;j4ë?¸¯Ðªéœæ? Ï’ ™ï?âf#øš€á?8-2;'Õ?|DJ.°*à?l¿;Y™Ù?xFt¥¹ê?¾R­ó Õ?¨EÅG{´É?˜Rú@›Ý?9_-4.æ?tp¬<5È?àô9wnc˜?[Ќ͎¹â?P‘S¿.ùÔ?§§^Òîßé?¼~3‚ÔÜ?˜^0mÉØ? M @PÂ?\¾Ü:` Ô?&Â(*Ñ?€XQ¸¼?7SÒ÷xâ?Äç¼È-jÍ?zÒU_š-Û?4›ŒŸÃ?C;xüæ?ȼ­’GcÉ?DÅÀÛFÍ?gïñßç?‘Q&¨è?8Þ°Ö80¿?!¦+)}ä?”Z±&é?v‚Ž˜öâ?¯½ éDî?IF'^%Çî?Èͽ~‘ã?È-Òî°'î?°h¢I¿\à?Ö7A×¢î? dÖ?Üe-í¨eÚ?Ðùs4_ß²?H€‰/Íá?T5)Ò†ôç?®ÄB)ÑÒ?Μ èé?c Œ¨Èè?Š"ÈÏOöÖ?ÒàírCà?úˆKü“µç?8P¥#{0°?ÑN:Oíí?‰ßy­ëúê?Ö¨í Ò?ø_Úª¥ä?G¨Imá?bülBÞ*à?êÅPРÛ?\áÏDä?ÞŽº¾Ù?dBþ“uvË?mЙñÓ?(ðYÅYMé?SÍLòœâ?–<ƒkiøê?•êZHá?)ž}­¢î?…@÷ ;;â?ظ—nèå?Ååžéwê?7õß lã?ˆ¼Ï•FÖ?p%­"¼;µ?ð\ $Pôà?ÎW@â?`“K&êÄ?wQl¯÷›ã?,­œWñAË?bŒ7–§ Ú?ÐÊ!çÝ?ŸÃJË4\æ?Cðdš sé?8S >rÔ½?€÷Ü>ù¨?æj{h[Þ? àq…à?ÈG$œ{Ý?6B®’cèØ?’Xüo¸4Ò?”Õlí?þ4¹&.ì?`EU7ÿÕ?𘼔»? ‰©W·Aè? É+^Ö¹Ý?,`'òî:Â? |Ö¶à?êeÒè?Ô,,|æÝ?QÂêÞéÀì?Ðû xà…á?taU%:ì?Ì-¬þå?Rw¥ðºÛ?F•R‰á?h/Êj>ë?ì»yC£Sä?ràÿ&­ÿâ?’& …wæ?§ç•„ÇZé? ¨³%(Àå?äK|µFôÕ?çѦ{³ è?ú°M­TÝ?4Bã‘Ò?ð!>1 ¼?˜M5{µ?Ü’B†˜â?øz›Ÿ{´à?öÁ#èÁã?È1 ÷,Ò?‘MȤ¸¶è?‘@!ùí?øé´C´È?ôMÚµÆ6ì?¦Š„Ý?€£3Ï…?øÕõp÷à?“êè(ðï?ŒÄj´:é?”DHMŽÌÑ?Z¿µîÒ?\Ìâ1í?`Þp:vŽÉ?WXýÂ?’†I¿ï?øàB:¿?(ìV†¹?òò¹=£?ä?Œ—0,IÅÚ?Û§¯<á?Èç©LÚ±? ˜ÛÓÄŸ? ÿŸKǵ?(²4C?Â?€Áp-©®ä?Ùä€|¼ë?™12ôâ?lÎâhDóÑ?– ÏVÓ?ΗFÕiç?6üÑ1|Ö?ĶPºÓÒ?"]‹:'Ò?àÍc‰“m»?Ö6V½3Nà?P{Î׿È?Ôc›sýûË?ßÛ>?£â?æea”øÁì?8„€•¡Ù?é¬Iæ­?bYZXÜ?®GKÉß?œq¾ˆ¡Áî?xMgü µ?`¸ß4Ã? ;oI rä?xËÜLí?’™Übœí?yAÀ‘î¨ì?¶Z ÝòÕ?xß5ù¿‡º?ŠE~[ðÓ?¸FèŽTõÔ?í2MNá\ì?LKÑ`w±?鿼~í´?@‘ýé¸VÛ?ÙóžzUæ?DÄú‚±¡Ë?žÃ‚ÉÑÜ?‹aU­ç?Nӡذæ? pƒ±Jï?˜0%d´?ywq[“°ã?DÄZ®= Ë?©°itƒê?TÜsŸaÈ?mÐj˜Aí?ÇÑžâê?܈©\”%È?‡ë=ä±´?%ÒI—ß°?r=¸ôÛ×?°K 4ÿ‹¬?B± ]­ÂÒ?NŸÛøÊÔ?ÐÜMYª®?,¸ô@ªÇ×?Лr[P°?J\»2ýJ×?]KÌP2ï?qK©2†·à?¼U+”‘.â?o×Þ?­¡Íuï?ÒÕ1þÜ?e4ëf¸µà?œÚMÿk•È?²©gyÖÍî?Ð*èK¢Èª?¹nk*ã?>M®N5là?þ£´Ôjæà?ZÍÎù<Ø?âR_›‘ºè? ƒÊæ?Ù Â’²³ì?sOPi¾¾ì?7Äòß;ê?v‘æ«oâ?ÎØt eâ?d&Ë™€²à?&,H*€xß?™û Ñæ?ð˨ËÔAÜ?2l£&‰Û?Ê(v\ˆî?”Y ¢ÖœË?Ôªƒ’ã?–$à®F;Ó?Î Šlâ?o<îÈ#–æ?´ÀZØË?, Ít%9ï?›A‹í? ü%"áùÉ?¤I¸2{»ß?¿JQ§â?æ~(Ïèrì?ÇâZþá?¼öP€RRæ?öžK:Rì?Z ¯œÀå?Šõb1§\Ú?944 ãï?ãé(ð¬üé?¬¼˜Èë?Z šc¦”é?0§bŽË?høÚ–`²? úˆJŠuë?9ô&yà?k]2Ou¬ë?¨»eqTØ?2%Äíç?ì>œÂzÏ?(nœÃ? ÐOûÙ¤â?˜«I±°Ù¹?Ä—-Ë6Ó?é!?¯Iì?9Ô´øÊ?®Æ §¼Û?À½ÖÁ¥ˆ?Ø_tð«¡ê?ñ'GJ¬á?ÂÁôKî?4»Ý:œ0É?”>>‰k¯?úõõÎöí?‡Ð’|=Nä?®$ÿ¦*Ü?xµäÝæÊ?kU­qî?8{Zòº Ö?e›´“å?ÝïTw®ã? ,/kAæ?`ý|iÏž?æò¯väÈè?Q7UÌÐî?¶.Í…3ë?@Ý‘‡ Ûˆ?Ï%Þ*Óë?ôzK¾IÁ?f"Ë~¼ò×?”¤¦êRÌ?Ȇw‹…“Á?6?³{¹ì?+fÊ“Lœê?aˆ6 Ù?Êq?\Û?ÐzªÖñÀ?`RÈÑê/Ø?sÏöÙ?ÇË俸æï?ÏÞÞ?8}ÑÉ ä?Uw©cï?ðì9(VðÁ?%óUÀê?,OĦØèÀ?4Q"HÊÐÆ?€Ÿ€·\|?Èí ¼‰þä?…¯¾]OEâ?QéBN æ?)›aËíHà?ð™þKýž ?QOþL°ï?p%Q”¹ê·?Íûjåâ?P9P?L ¢?4þ¾!ï+Ä?iíaÚcê?F>TX)ÄÙ?j2»¾¶Ú?à½gà`ÉÀ?¦dŸ,!â?¥Ê¢?ç?‹áå]¥)é?à>îùÂF˜?ÑxÌ”7ß?ƒyo¥ifá?Fùœý²Ú?H?¬zÄà?wø÷°à?1Â'å–9ç? GŒÝ£Ô?%ÿgrÎ2è?f ïÃöÅÖ?âûä8SÞ?î=´ŒÒåæ?Ø„’8ÐÆß?}ûã?truÉÀØ?æùrò¢ê?h¡]}ìà?„Q½W.Ç?&lÄ”DÔ?0¡n¡ó¬?ôñ[þçé?\øˆ/5Zæ?ãÕ Ì?ëF„›)°é?`xEw¼(ê?¶fdÀCÛ?4TÌÚYÆ?\YÊ7Ó?Qÿóß”í?oçY_ê?´°aÁæÆ?³Lw.(Ë?É£Ôødí?ì`_(®Å?$7l#¾°î?˜ùÕÑ?5 êŒçÌê?ØâëËÒ<Ã?êì;džüí?¨ó1Žå:Þ?¢í´š^_à?vJLÂÀ‚í?¾¯T|®í?F{~¬MGÒ?ÆžOèà?q¹¶ë8eï?ÜÁ –iÄ?& :Çsè?0pþTbé?À¾ªØi?•l”Wäì?`°g·?´?´†Ýƒößã?RH´Ç›ÞÒ?!t-f¦µ?¹õÀù’è?¬øÔòL,ß?~_~îÛ¸Ö?:ؤgÜ?¸5ð4²ÓÚ?ÖbÛë?¿QV÷é?nSÏàÝ? œÕnÄœ?/®E‡»%á?ø_„á…¾È?粜$^ í?HSÍXrÞ?Pâ³ìÀEå?ð/Iå?¬#3éÂkÞ?¤ˆSä°Î?|¸–ÊYÖÒ?|Ýpe7ÒÛ?Ð}Êïí?æì§+DÖ?äbNl®á?±KÏŸÐþê?²ö>Òâç?€ì› æí?iÓTôæ?¹ãȪ©å?ý©àGí?zEûä?–qŒ(?ýè?ÚôñŒòÃí?(b÷¦Šâ?¬ÚT ñÎ?³†óJàë?„>‡<ìÓ?$Öʬþ‹ë?ÄÍ:~}zÔ?P’&:¼Ì?žè£Øºã? €ìžkÅå?`‰¥óìAÕ?`„X3kÅ?øÛ؉ã?¾>¿UMà?èuŠà?sÖø–Yá?ôdZ~ðÍ?öÁ‰©âÂé? û ßkè?h–~¦[‡ï?À êÀ_â?srQxB›æ?‚¦œË,Ræ?$ﺶ!Å?ðÑå¯?³ Szaï?IuÓ=æ8à?¸Âªľë?ÄR„l3[Ü? 4ד¢×?üxsFmå?HU…g OÃ?hAð‘™ñ±?«€ßHÜÒ?šÛ Ûéè?sfë­†i? êÐW² ?Ã1¦—>è?Ú/þ‰EÂä?”?Ö!eß?Ø´•·¦BÇ?ƒ»\~ðã?ŒÅz¨Õ?0/_¶ž—µ?¨/ ."Ô?t–¹8Gé?=þÅ\áà?.d`oNvÚ?€T‹Ûv~{?i^Ü¢y·é?oðwƒýî?_Òš¿Yá?h׫ÛÎØÄ?ægyE˜¥é?¸Z[wµP½?j¬ÓÉäë?¿#–‹›íï?¦j1c†Ð?$PõöCGÑ?X‘ì‹éçË?Ñ„ŠäÖâï?hÌhZñç?Ö¹cÐàÌå?€5W·|´?˜`Ç«dÞå?¥'Ì–›â?Kybèä?­;ßžRì?Xðý„™?RöC2‹*×?TªkÁvÓ?6}\‹Ø?£¥L#¶«?¨AÒç‰Ì?FµæÎ$Oá?DFÏô;Ú?¿⨎×?·l9l_ì?ˆž_æbÐ?²ÓGÂüÙ?·çQîë?P–<*ë?ãsÀõç?‹ó‚âªã?L¾Û?€Nâ?].’#×?þãSÛÔ?"ë€Å?d¬…Ö7âÉ?ú €°œÛ?¼›Aé={ë?`&'Þ¥æœ?­ˆ‡ ßî?cžj¶?Ö“×¹@Ø?úƒ?Cô#ì?P1 Ýò¼?Ãà#I— ê?£‡Á`v¸?^0åd5ÒÔ? uEº•¡?•»€© Cä?US´(Ûã?¤Ò.Ô¢Å?¸göx;¼?€e²/’™?¢Š*aCæ?X»mµÍ?ÚüÍv÷{Ö?Ë^¨ZÞÝ?Õv†KÌÿä?=`×U_På?µÐÙôðä?ÞV¤âšÔ?ˆíâ¿Þ?g__´Òí?H3[f³?ß¿ô'ã?N¶á«?¬gâà KÕ?œfVÛ?‚aòRN±Ø? NQ –«?Æ#K_VZÑ?¦zH.N)ì?ày•¿ª¤?npù¨I™í?²È^øÆ7æ?•}É—Ô›æ?œ b;æ?d?æVçå?`«xQ÷ƒœ?dxçÿøYÞ?È‚ì°@½æ?N(BˆÐ§Ò?‚‘°qãÓ?òa·êêé?€(m¹?jø~{nØ?’ùÒËôÓ?PÆÃ½žm¹?0m|UÕ¡?rðzðaë? ´ÓâÕ?¼‚€­¥ï?L€£T3é?ßø£,î?~j #Ù?z ½·ÑØ?Ê9¾{A[è?,´]x¹í? DjT–{è?T&ùá?ÀÈv Ø,•?d°l¬ÄÛÓ?ÄÉâ«y•Í?ï¯>§–ì?n[q°üÓ?å@¥@ …ì?JL÷Ð?ÏÚu&®Ð?\ñdD"Ì?8¦ÄüÒáÅ?ز*Åí¶?çÎ&„Á?¨W›,v¦Ã?7¨•¸ ä?Œ¾ê&ì?ƒª½?Ïâ?0¶ÈwTË?0ÿìúøç?Ìå6sdÃ?ôão°)Ñ?VZF ‘p×?í×:x„Ôæ?MµŸh~í?9L§›N]à?6 Á侑î?ÔzœqÓ»á?{øä? @‡¬¾æ?¾]°EÒfä?÷I>=$ì?ˆñ*;Ú¹?ȾÁdº²?Ä3ƒó„î?wÆË)Aì? Ð¿| è?Í`‰û›ƒè?(Ǧ¿^²?ñºægâ?H" ¨B ê?ñ»ÒàÔLà?Ð5(+޵?òó²ígØ?ÕäÛ‡L¡ë?üàO¿*Í?äÈ©AÐ?DÓüâ?,ÇMÏÞÚ?D–ö"B~Ê?ÐåcdQµ?™ m‹±ì?ˆ€”碶?o"9‡ã?04^d £?s3};)æ?5Þ¡Ä­â?àîäB¢?òô¢kõ_Û?ö]Iéìæ?$Ü1í‡ZÇ?´6 e Mã? /ýXrä?¦%š9Þ?tuÞá@UÈ?mâè?Ä{㾃Å?)7W“ç?ØËïd=°?ú$cï_ï?€ÖS½Íì?»¢ËÎæ?øGH{Ì×?¾8jˆÕ?K©+PE¹è?uX<ÃÏá?<§›åu—Â?@‹l z—š? v{¢œ*Ð?òOÊë5Û?à䉦bÙ?´s#à`Sß?`øšÏ£?nz6ÛÛ?ìJÎÝ|ï?ß¼¶GÙÏï? M®rÓXÕ?ÇlƒÔ¯®î?ÿ©T–Îç?šÿ(Ó?¾òP £è?ÞÙd˜Šâ?¤Z)^6MÖ?v›ï³¬à?µcY*Ð?-ÊqŠé?ltf cÆÓ?Ö1ÍõWÄá?x‘ùÔâã?.? ¸ ÅÓ?Œ@P®oÐ?€ÀDQò ?PHGHb·?XÃàÜãŸÏ?Õ3ÞuÈÑå?ußÏÇà?}…Ê·ç?€1Ç”=˶?óóbÔÃí?Ž`šˆ«î?È[\¥òî?ÐîH¯$ä? †¿©Ý-è?Äé€?·ã?ÀšY¹å?€{kË (‹?Ä^5 :lÊ?vËG9¿rÓ?ú3žþ (Ò?°Ñ}Y£ž²?jkS@ ×?.\Üïš…Ñ?Y¨Z?˜ê?ž-—·`2Ý?¤Í¦Û?V•à ¯mà?Àâh›»ô¾?„–®×'É?ªqZ[<Ó?”fi.ðã?&hX÷…Ý?¼è.«Í?ú}‘!ˆî?LZ¡¦vsË?ˆ3.××­Õ?¸Q› ÃéÇ?@_% Î?Êí¾ èá?ò…UÀ!õì?»[ÐáyÓ?tÓ{åû£Ê?@=*©UMŠ?¬bZÆWÕ?,#à™°”æ?Ç›8AaÖî?âVrþtöë?7†|!Tï?†ØÜá3Ùã?´2†«r¹í?q“]#Qá?æ¢PN¯“å?Û×ÚXÄê?˜ÕqUÀ…Ô?­±Z4­‰ì?žTŽ%Å?6µ¥‘PÙ?`³˜I‡‚™?Öp‰»áFä?¤+ݯšm?FÂcºÆ‚à?~À¶Éëì?–ì®Q¹ç?¬Âª`/á?/LþÐ?ü?IÃî+è? dÛÜ5Õ?u߆L'è?fzÔ÷ÀÔ?…øL‘¥«í?X%sŠƒåÃ?sØC%¼é?Ó¢eÓÑIä?¼Ñ!±²Rã?ä¼ncç?ð¢,3à?ZšJšë?„l*HÉã?|Øâ¹!Ê?ôNŸÖ?%~œYòÎ?\ -Ž›LÈ?Êx¸Qå?¡o·Õ‹á?H&?gº?"À@£³Ñ?Î_ü:”ÔÐ?œV:ÛÌè?bᯑ–ï?¬f;â*Æ?Gaöp€ì?Ù¯Ó> Ðè?f]zh¶ä?Z¬„àå?¯Gj$ì?kعbŸ¿æ?û¾±hyã?„' öUè?Ž•Ú|–Ú?ƒÞô~Í£à?Ø£ï¢1ê?¸ã0¬më?à[¢ôï¼?8jy:‹Ø?\KKþ—å?Z2˵Ù?„Ò0Ý~{Ð?æ…^ê0-Ó?à)½>Õ ä?]f°Îã?X?mGŸå?\õ4vþÎ?„6}wJâ?¥ö‘ÉOá?ð<<†òÓ?jâ&ðCè?@@ÖŸ¬?8à×E ï?Ä®˜ï)Ü?Áviì\æ?¸Q©^œ¶?Dº‘À]Ü?V;8Þ®Fí?ºÓŒ¤9hÙ?dcb7ëà?@ú°xGØÌ?áÎþIïï?þXŠ»à?šÖ,vOÝ?ÕváÀ)é??êX„å?)çÝZW3ã?&¢·—Ç?8¹[Ÿp¸³?Œ:o¤ÌŸÎ?Äáp&øàÙ?>â…(¶«Ô? Ù'—è?=-Üä?À„3ŸPŽ?¼JÍ* ]Ø?£1ž=>â?âhÚJ‚wì?r ã8‹ è?øØÆÕ‹Ü?Ì6pʼnIÙ?6†Õ4ú§å?C( w¿²ä?¨;‰ù ÿ?t(ý€¾£Á?´Óô€'.Ú?.¸V£â‘?ÂX ÆùØ?Ö…`ÔåVÝ?Râ(Ó.ï?cÌEþ6í?/ ?ç¼æ?’†Ø…É\á?Öm+ÇH×?è;“eR/ï?œÎ ÝiØ?ËÀ]>Ðã?êê£S-â?Ú—™èë}Þ?Ä'ë÷ÿKÈ?ƒ1ìo»?êî=@äÔï?´³Ê3äÔ?LsBÃkÞ?úìŸÄ.?è?`º%JÇ­?º0!1DCÐ?`<Ùj” š?–šI9¡Zí?`é!•Yí²? y쎬Ì?Ùi¿ðº;ë?ékû‡Xíè?@”+33…Æ?Å9øÌ†zî?ݘÞ®î?•š%·ž·î?øm=ž¡ôØ?þˆáù>‚Ñ?¸pgÞã?1x_­ç?*ö£'´á?Ôœ'Ïd*Ò?J¯âØóq×?X5ôÙ¬>å?¾VÓ`°Ð?¬r)) È?X%nýµâ?'òös—î?´&Æ—ûçÔ?¬‡oíÉ?8’ ˆ™rï?¨ò^žQ!×?àÚÇ÷kÖ?@*8âU@à?°"(4ÒÖ? Ùm踦?Ú6cè?”uÃ^ÀÀ?Xì<Ìœ-ã?(ÜŽû~nÝ? 9ØO(á?àN£„Ç¿?…=ó„•°ë?ÅO<(í?ˆÀŒþÂÀ?dVmøÿ|Ý?>1‚ø·ß?àg*@ð½?âiC÷Ä÷ï?Š>âõ‚×?ï§³QŒã?Âb‚/ÿÖ?LTÄýhÔ?V¶3L_ôâ?à`« Æ«?lrçØªÐ?¸VÈYÏÇë?úýéLÂï?Bƒjñùí?„€$ÔŒóÃ?Ž‹™ž÷Ø?ô×âÈ?žÂGScäë?r› #‹ï?ˆO¤uƒ×?o|½#Ïå?Ä•- މÀ?HµÃLî Æ?¬fA[©À?LúÚÂî?I9rõ¼zæ?uÝ0¿Mhå?QFTñíá?æ™,ʬ/Ý?Ü»…˜²Â?¬¼ÕCÄÄ?9Ô(a\öæ?@œµ3ˆ’?roïgÒ?ºP乨ŒÜ?>´»Û?³Á6Öì?ô{ˆ<Î?ê"AŒ£ÿÙ?îÏ#A&æ?»y¶M®ä?v 5­5ùØ?`9ß?f ?‹š}x•Yé?ä8«?p×?ØiÃ?¨# ¯¡?H®w]¥‹å?`ý”vÎlÒ?€û•bBݪ?Šü½MýÙ?°Ìƒ"Ø?˜!óúCä?X†šBÙ÷Ø?¸í†tFßÖ?þ ±=hå?2øä.<ÙÚ?’§Þ<ìÑ?:ÔY€Ù?ž!qäQê?Pï3Bìr®?{ ‘’9â?êìK%£è?Øôœ²?[5SCÚî? ÝŠ¿ žì?š÷Úö¤¡Ù?èJÑ Pâ³?°¾C‘°?ÍÚ_¸^ß?Ü©¤:zê?°¨Ú4 θ?°â-´¿æ?øÿ\íX«ñÄ?ô‚J˜ÜJì?t$ÐNR†Õ?Ù£.U”Ûí?N\±¿Bë?ÄxT)(ß?&´Äaî?¬à4ñ˜Ã?<Íß$øªë?ôÜsT·Ô?K…TÇÇÀî?¬ÎOêí?Îê@ 2ß?˜Ì¨jÜÒ?pÊ<ªÎ¦Þ?Ù¥·ÒRé?ÈÖú¨CðÃ? ó?Û“ÐÜ?rNkwµýã?ÐIü±6ÃÃ?Õ\1K‹ä?¶sCzË?z2¬‹ò»×?ðL™2žL¡?¤ KÍâ?*ÛÝxd-ß?V¿·#ß?¢yÍóé?´“YÝX«Ö?í±=-â?¶¹·ÂÞ?b˪`&Ú?ŒÇê´®ÏÆ?ôg§C;]í?IFÊlÙä?²…7ç…¾?¬]× ˜Õ?À‘‘ÊÍ?VžQMŽÛ?ó¼^ÚTœå?¬D,éSXÕ?›¯y°O´?<Éö6\åÎ?·n&Þ…“?ë_J¢Jæ?îý&¾ å?îÕ,åMè?ÌņÙ?Qä…†|é?€;Ä€Þ‚?Jø¿#¿ ß? %ÙÉH©?ˆôÝ—Ñ?ÞÎãbhÕ?°÷”zçM¦?pfØ¢ç?ôtŒš6±Å?Mã|&£Ùä?‰_»TIZì?ÈÑùüì•ã?¼™|¦ÔÔ?„ñÃQ^áÊ?%qH‹Øæ?Bð&aCÐ?¦IáNØ?ð²Ë[Ëb¡?„@, ‡ýë?o¬7Ä•é?X: u9Á?¼-Wå|uâ?ž/È%ë?²S7ßè?{‘ãëÖå?ðgÎÕPÁ?(Ùä¡%É?kÛsßÀ?¢ñÊŸà?1fNĉnì?;Àðnvñì?CûfWë?ÈÛ£÷[©Û?*$1 l€Ý?|3NUImÕ?¹3‰à„å?9.dœ¹ï?Ïzl´ë?쓃•ì?€ÁŒðzq?|7£ÐQXÎ?Þ£?JÕ×?¼ hé9Å? 5¼0Ýûè?ð-Ù‚Ù?øKãÕ†¶?–%é“:²ä?‚iüøe)Û?UµÎþÙ?ÓOXìä'à?ÓÑ^g|9î? ‰ÊMä1¯?3à!gs?H+´´+å?eRÏÅ[tè?„A. 3þÉ?¬U¤#6Ýä?Ãö!ï æ?û>Cr†=ì?èÞuY£º?®ïÈR,ÊÓ?¬ÛpŽŸè? úÿ7/Ïë?¼;¯Õ^–ä?ž”fͬé?g?¨L§ì?vÈ" ©œÖ? ¸ÍpÌ¡?rÇ]Ïá3é?M/µe>Ò?PÜðj…ð ?kÇ0Æ%áå?‚  §šÖ?¨\ÍÑp¶?Yê5ßÑ‹î?“‘Ôûlé?f(è'þâ? 5Í#{[¶?uòåÙç?F$Uà&æ?èU¬¬Æ?€«ú~¹?ñQ^Sží?hÇ^u8Ó×?Òýé•OáÕ?jñKήÕ?d c6 òÂ?¥“z”þï?ªÔ4Ñ—‡Ð?×ø%LÕæ?Ø“ßÖ`oÛ?¤þI¯È?dšì†Ö?6÷ú+(ìï?qZò&çæ?TLòNOã?aØÃ>eì?y#Tmïç?tÛA¡â?¥$vÚ?ð^øL?Cß?8^®ºì?“§þÝæà?¼°Â®;×? ƒßº™ì?w«Ð†Âlé?ÔåXÒÏê?úLk—\Ø?+É ~k¯é?àú²LfEã?!Ìö<ç?xLyk¡fß?úï%¼ÀÔ?n©­u²rï?8×HÄè?­"$\~™å?àsÐÀw¬?húnùqã?ìh€iZQï?nû¯î Ò?Mvदê?åûî7ï?`2ÀDu¾?ü–! ñÌÙ?V]@'¥˜æ?OÊ)qãìà?˜²¾Å °?ÛŽÜÓ«v? :%=ÿ’?·¸KÖˆÉî?§ŠvC âë?­CŠ´ï?Òž³=ï?ê±’æî?süùLÉ?‹îlµ§Žæ?:¯ô Îòç?6»r„Åmî?zYOIÖÇß?ÔU5>•Ã?~9ôy+ì?>9ØÞÐ?H¨\$ 'Â?«ß0ÑŒ÷ì?=3ëo´ï?”ZŒûê?ïãB@"5ë?mÏhš_â?(ÑÕ?0nçê„Úç?Y\ÐÀŠÁí?u1µÑªæâ?R$H`‚Ù?€Ïÿj´?¿g’ ’å?¤ÇÔÙ?}`Ñ÷³ì?zY³þ²?Þ?ȱ®iÿrÍ?ŠáºÍ $ß?ú6rT‹xì?®Ó®²È´á?þAEW×?ØAïÓ/Ã?úVP0¥'×?P/ƲiÀ?ðd[?<>›í‘3Å?6AàîÛdà?ϪM5×ç?øø÷ÉsAÑ?áù¡€Û…à? \áò Ã?6d+Zâ?Êïü%Lï?j·¥—GÝ?‹Ri¬˜Jï? ð‡Ìª“å?Ô”{LÅ?àOcLN|?.Òvž¼#Ñ?õ™NA ï?ünR ;oç?ÎOâyÈÛ?Ëp”*åµé?ù”e{Vç?ê°LÿŠxÕ?3N¨Z,èì?`4;d¨ýŸ?0@ÿ©•Í?°Œ—«z©?:„µ€¹ê?J OÄfå?ÒŸ§yêÆ?€«©š? Õ¾2åå?øLm¤?™l¥ùÁ²å?ÝÖjnàâ?L-ˤ"°Ö?FîsÌÞàÓ?¸ÈZ¹&n·?·,ù½'Uã?HT9å:YÆ?$Û^“¯î?"š,©Ïuì?RâðŠåÒ?Z§Wêí?^îç¶â?ÈÕQÚR¸?C7ôíð%ã?¿g3D(Ý?¸ô¯‚/ç?up–¬˜ß?âÙ=rß?zëZ³ÍÞ? ”:_~IÊ?ýÚp |ï?týáÃèEÐ?t|ï»;§å?àßþ™Ï?0­¥ºÆÜ?Êp98æ?€<’‰âŠ?6¦@6áï?O³r1í?€Ó#Û?’™¬DXÛç?úWþ£~>Ù?ê—±.ºUÛ?“Ý߀qî?åæP«~ì?L‹XåIËÍ?k#…ì?rÒq™¾Ó?$TµÞ?êS+dÛ?‚™hQÏÝ?”#…TQ—Æ?·ÎßMãÜà?u mÿ›¾é?tÇÈAî?Òä éßÒ?”Ùe™ná?Œc¯ˆEÌ?´¨^zôã?ÁrWÛõ’â?ÊÑÿšÒµá?¬»&÷³ï? <š·S„Þ? Äƒƒ|Tä?åÑ r¢í?X_D¿(kà?%óg$ê?l—™Y%Žß?ÐvïMŠzÆ?€\_`ü´›?PsIL®?<±SY®¢ë?Ve#F…NÜ?<‡É˜Öy×?¸€W$·›´?AÆ}j‰ê?ôHÁÑ?7­íÙô‡?ƒ×r—°ì?7¿æá·æ?€µW¬Ç?¸§ãP\¿?-¢—ø0ç?þų•æ?O¬_²8ðæ?ç{ð9ÓVë?h?r{Mµ?°k.dë?…2ô»tw?à¢@÷§+Ø?î¤ü•ŽÜ?GF Œù¬ï?4C¸)¦’í?n¢sˆÇ*ë?ßÓ¥j­®ä?ªgÓ?Ô;çôÃå?VÉï~}×ß?æªçÃŽÍÖ?Ø zPyºï?ØÏkÖ÷¶?jE³ÍLÆë?ŒïêÏ÷Ç?. kÂ¥Ó?A-Œbzä?¼.k<Ÿ+Þ?Ô9í7‰ØÌ?Hi“ ¾?‹™ôU—é? .§Hï?Ì`Ì5âØ?Kªò@„xë?€EW'R…?¥ÍÁ–ô+ë? ¸’Ä9Ú¼?M_åMBê?¾—bXÊ?S«¥Z‘°?]¿Î߃áâ?",Yæ?6žÍЉÓ?äôpº»{é?4ƒ¹ÅBÑÀ?0¬÷ÛÖÀ?ôÛ2åê? …5©žè?{<æRíÆ?°T\\–ßÜ?º×ÎD¶Â?à\SÄÁî?¯qöÍq^ä?v•]Ù?æZVýw ß?Î/ÖÙÃ?H¸xiK§Ô?ÒsuBTì?pÀüaÝ?q̈ ¡ê?æ²Ôºöî?0ÚiÅV'Î?‚C›kÄ&ë?Ò\YÉYùï?>1Læ'ä?}¯mhì?™´ÝÛ¼ä?$ªS¸uÄÐ?ÐŒUޤ²?Cy¢K"ã?,Û ÿ¥Óî?êåã¼øã?hG3Žÿ¸¼?T=-' ˆÖ?X9+æóö³?x,á£çØ?2y'ÙÓ?hžä§rê?[¶JÿÈÛ?^(ùD¾ÀÒ?^4ß)“Ú?Ðé—Y1ï?.ÒÓ] œã?ð’Ð!eÏ?¸Þ½Êè?MIßíæ?þ†>ŠÑ?ð \Uþóï?¢ù›Ì}zÞ?RGŠjÍî?еÕ²ž×?Q¯²9u¸í?ÚÖ5•Ô?xY£Ç?è³/¬)‹½?âîARî?dA¨ÚãÎ?þcÆpeÕ?³³ßtžÉé?KâUòÌYã?3c…¿æ?¶£™Ã<]á?¬3x‹×?¥ßü¸ùÌà?PÜw©¼¢?ÛÌ!â’ï?w–l‡ì?.2ÃÂyOâ?ª8jà36×?À—ñÖû‰¬?y©ù49 ë?qe]( í?Cô#”Šé?æÍ'€eç?4Žsu0’è?ûÜï…Ñé?l ztªÑ?@16ið•Î?¡fŽ®œßã?mvÖꥼî?„Öñüýß?àlá*™»?ìŤ°Qã?Nœ¬Íiáé?NG±=õà??é?m’?Ad3¶Q™å?ÞݪÿÂ_Þ?ÇÅá™â?M×á¸Ìê?\=çvuÐ?Ûl‚Ÿã?À)8 Ï ?¹ÈnÓ½oä?ìj7„VÉ?gBn‰uÛ??Z®sÛßã?À ®‚?Ú#ÏlxÜ?ŠEþeÔZì?m¨N—Mè?~ÀÎJší?HYÈõáÔ?â¦M°&ìí?N= ÑV"Ò?n~¿–Oªï?.ò‘ *Ð?Faž…=ê?a¯ùùeÐ?§œ& D·é?®«@e ðã?ŸËJä˜ç?¨¸%¿uy¿?ȯ›9Â?Ôß\ä?`åm÷aÁ­?\üÃÀ˜ã?‚ç?ÐÙ? PÝm…±Ò?«[ÁÁùrè?ê ùòï“×?0öx>k¾ª?ŸÀ¤S•Ïé?Â5\ò7ÂÜ?£ «·¤wì?_ÖŽ·—Òæ?\a0˜øÁ? õÓó!Ø?Ù§[î?TŠgŸâ¨æ?óIP|.±í?ÄÓ”Ö?£áÎ^×è?L¤õ²íï?þ¥áFÇÖ? Ú§««é?¤™'‚7Äê?1#Ÿ­Šå?€ `íÜ‚?”ˆx{`pÆ?˜G·ãê?DxeT÷Þ?>—×ßãÝ?F§Øwó6×?Óg{ëèÓ?÷[÷öhµ? ºgÚè?ÀJÉ›”Ñ?>0ŸƒJ/Û?P.ÙS3LÔ?€d;<*÷ç?ØQeØÓ`Ó? Ë{ÜYß·?(/ZÃî?vؤï÷Zî?w›%ÊäÖ?ÀÌ%žW4ƒ?pO5 íË?ÀñÝÔ ¨â?°Œ«O¥?'•ø,94ç?ãÊãw‹Øî?<Ôx­³?Z(__!Ö?xEÇt¤]ã?¤‰FcGß?õ°~?Fâ?4ŠevŸÌ?à{Ö'É?ÆXîõä?0ž!dÜì?ËHŸ¶Ðá?F#a5×Gî?†Ò ׳?‡Ø`„ ùâ?¿‹¢â?ŠPü ÈœÔ?:ù?Ù?¸K7øËÉ?jã0EÕ­î?ŸR:”Ýã?Pñ”±#ÿ»?Øî£Wï?@èË#š`š?Ä1J¢’gÞ?œèჟ×?IcAÚ;ë?¢{µeçÕ?fÛm•Bï?LŠ3Оáç?[¢ŠþKýï?ˆu¥¿/EÒ?8Ç>z »?8  ôÚRí?ЯDGW;Õ?Žù3~ÐAÜ?—¬÷/ã?ÿý©ìéöä?Ó¡;G¬ï?,_Áîî?DM‘Ù×Î?q ùµ}.ì?zrä2FÝ?NÛ&äïé?@)¬Wc8é?@’u¥X ˜?à¤ÄÝ÷öÐ?ÑÉ.Gè?G"\çƒá?L.Jî¥NÖ?\À[9º`Ù? .}ûPêî?ô“™âÈ?_@=XÚ?°‘ri™í?ÚàT£êõÔ?Ö^,bŠæ?®2³"Uá?°V‰ãÎ?‚ò LÓ?¸edÑ!òã?ÂWsªpÿë?z·´¼í?šn°Í¾â?/ ç( é?¸ºË=§*Ú?jë?îćì?WF"eãë?ÿ»éįá?ã˜Á¨ã?e1• r=ê?rã×Â2få?ôÙè¾ûÏ?€ÿæ„ø%w?Ž Ý¹›Ö?(^$½Sã?@V„”T§?ÄA.Î<ç?V’.–ðéì?££C˳ïæ?ErÝØê?ö,åæhá?ŒY18cÅ?0!m-V=­?<2é0ê?4 "²,Ê?c$2ïä?üóEÍáå?0+Þ²»vµ?g´#@ñâ?í¶±,["ç?^~•)Žâ?FÅqvçï?«öF+Ç?âó(VbÖ?FT°Ó?kà? /ÚüÒî?¦fõ ˆFë?¦?OšÖì?ur¾ƒvmï?lÒu¶žãÂ?‚“zu+hê?HŽšP…é?@a2·,”?DÉêuågæ?b`Ç8 ã?˜ ˜…-±?ÍÝÈJ±ë?s é?f¸*ã?‘RGmÃ?õƒUã¨Sê?ðQ›ø¦?hã Û!°?4#As™yã?#‡œ'á?ê«ÅèÊâ?H«ˆéµ?ú ÕgÞ?,DR­ÈAÔ?¨ªw+¢÷Ó?*\B¬vÒ?x2[œ Ç?â®ù(Üæ? ¾/±9Øï?fÉBCg?ÐÃFÙøÑ?`û¼e±?)DWÜSë?ø5? Ô½?Œ O[ùÒ?ã;VÇuç?Z‡4··TÓ?`wŒ´jË?iŽ™&#På?]ÓFðÎÁê? c õMéŸ?"×i½Áã?èÛ¡ÛfÒ?‹Ú¹ÿé?¤Ý ÜÒ?B_¾ŸÀá?ˆ†0#4ß? $Â@«ŠÊ?vÑà <Ù?ýïÙyCå?š$íÂåµã?÷V8©ç?Q5æJ›à?gœúè?¼ËûøÑÞ?9çÌmJ=æ?dÈè˜ãÁ?Š}ß¼Z½ï?ÄOœù–#í?<Øe{ÄÓ?oºÀ†’â?Õ”i¾?RÆ0qžüæ?u÷r¬é?üY˜›ûUÄ?`’„æíšÕ?[àäÂÌ?=,­ÙøÌ?TBV—ë‹Å?̸¼ØÐ?Ï|HòâŠè?Tî…ìÀàÄ?fBs™å? |)jhÝÑ?¼%þÅLþÄ?3ãäÌì?è9R£"Ó²?0ÀöذãÁ?bTKÈÒË?¾4`Éó3Ñ?á#-úé?¶GÁØï?E-¬6ܘé?ÒÐ8írqÙ?“Šv¥.â?knRµ’|ì?¸Á%R×?Ü­Œ4a â?´°Û‰ÉÏ?Xߊµ?Üs¿§>È?õU¶[Ø?ÈMß!í@î? #Âf.8¡?¾TúÅÂÑé?b{ôJ è?p›žwõÁ?(Ó·]}ØÍ?®G²£Ó?€-±MEfÞ?Œ{xžëÖ?ÜVÇšwì?òÀ@ÅâGÝ?²r™Ž"à? ¼þÇÒËâ?@ý³\ÛŠ?„“V{?´ŠÓžäDÔ?pÑzÇ Ûä?D<…]¢²È?Laâ¤m¼â?bÜ„°à?ì@ÞÊ?£AòiÃTã?$Ò ¸¤<ã?R—lÂÒ?ÜÒzªÙîæ?½â¡*Tä?`Ž/¥¸?pjKÌt·?Îk1z,Ò?p ë…Ë?¬*úŠÔè?F›+çÚÆí?X¯/Þç?2 Ž9T?4)/9ŠÖ?7‚DÖCì?6<*‰™ä?¯_´ÞÃâ?º#\-¾Ã?˜‘gúA×?›Ì/®îí?ªÏÒËYDÜ?܉0ëöùÔ?ª" ðËÝ?\öíõÀ×?>‚ÒO¿Ú?K@{ â?ðÜ£+dÕ?LnŸ$Ä?}`ÛU}£?_4EÛ×?²õ´Ÿ¹Ú?€2cú™ï¥?8úªfwÚ?êj¤ÂÒ?µ‰Ùé¯^é?€oeAPÐ?jêÅ58¦Ñ?(ù–+øÙ?(+Ý4ˆ}Þ?˜t$íÀ?ÀŒ¼{z¨?·–Dj”þã?qó­üƒâ? ²HÕ<$æ?ìí…创Ì?œŸYІÂ?˜T µjë?ØÙ7·ÞuÈ?ŒñRñ\”Ë?D Š0æ?8²ääƒÔ?lØèžÛ˜Û?hTlë­°?ppß?ØêÆÑ?ð s¥«?@ïŠkà?ª¶(U°Ö?Ò Cp™ä?™ æ4â?ˆás.ä?23Ûjdá?*¾z)´ôØ?=Dê&s|á?èzyãÝ?îíÂ@dÞ?Œó/m™kå?ý—ë«6 à?±WÖˆè?/A;s'à?pAíI.Í?@l]=¨v‡?†?Üp¶GÔ?眳Ñê?b;›¦Rqß?éïo^"Öï?“Ù•.¢ê?ßHô‰µ¦í?XÀµ6¡nÉ?&¿‘aþÒ?²ŠCDPá?hÿ=ÕÔ)ä?.”lqžYÚ?©vÊJ@æ?ƒH‹Ï"í?ÌêÆóD²Û?XuQS,Òæ?øymà2vº?X™Šs¼KÙ?@ÿx¿¾)Ô?ŽŽN -à?«z)~'ã?GîLˆMë?NHØT3Ð?謼vP%³?á åóÂç?˜Ø$âܵ? §7¬èdä?Ü+¨–)ê?Iªe`³Ží?hC`˜æ?öìBÁhÄæ?{TØ+“ké?(–Ò›©ß?LFWöWÒÀ?ÄFªõHüÇ?€­k÷鈰?ÀÛ̳á?\öWp<ÿÇ?ý¼TÚ±?NG}-¦ï?.ɵ£î?#ŠŒUà?”™‹ñZ˜Ã?t*q­Êí?¶H5È­;î?Ë}Ý¡žfæ?”…Á‡–ÔÜ?®LêµnÑ?â8~i0y?ºys™šÛ?pJî%q»È?{ Út[ã?¼¥¥þ=À?€\aV‘¼›?¬(êÿ0IÖ?X"WÐd™Å?<ò‰!Á?¼QŠ'Ýâ?V–n^cÀ?‚‘Ÿ½ŸÝ?˜?½Ñ/õÏ?F–`ˆð&í?ŒÔ]÷«?Ý7Zô¡ß?@Ú¿í=ä?L4öl€å?x4 À¨Ù?×ÃáV£?PÏ©y"¹Ô?†{`º?"BP¸«?ìA½f^üÝ?ͧ¬¾¹¼à?à$ˆ'Ø?ø…ÎD:·?Ä®¶Ì¦>ê?ðÊ´ª¹Z³?ÝÈHlË$ê?½X˜´í?ñÇÏ&zÂã?T›ûöçà?o¨ŸŸÙ?SÂÄŒÄê?ÆùÖW²ºÚ?ë"r›Óå?|˜‹%´ä?«fb­ÛLâ?vFˆ„×ôâ?•¢¨f×?9Duˆ÷á?>aÊ!Hê?:=r3.–Ñ?x¶8ßYÅ?x‘&4Ç?w˜5—à!æ? Ü|€À?ÄízG†+Î?Òwì3Ý>Ð?€oÃâczé?V RÿŸß?Ä4×°?ÙÆ Àóä?Þ 0Ø´¶Ù?PÚ˜²dÀ?”ycÍåÓ?‚ægÎ6qÙ?à¤ÿ^Â?6Í“Áñdí?Z1Íâ:‡Ü?6¬RÞÜï?š¥ºª?-@¡Žâ€è?HÖØÚ?þ4pytzå?ã©È?$%`\Ð?NYHë§‹?ˆ¥ÁÀë?@þš›Â̵?L /LŸ‹Ô?àú¥€<±—?ÔÔ3ÈÞ?,ô,–Ûß?hƒ§Lí?Q5Øvq¬?&p¨(xÒ?Lª$‹ÞÑ?ðêXP…žÂ?:>ó”ì?U¦_s\Lç?Ë9þÀê?Á¿|¿Ôé?€W³ÈŒñÄ?êFùþø„Ô?Ù5z/—”ä?ÍPï“2â?HC¾à§µÄ?T®Sà$šØ?Ñ £ÄÌá?!mŸ«–†ï? 7Îï¶?”wI)ýcÄ?¦&0<½õã?[‚S;P¦è?}ÐK´q¡ï?|}tتì?‡þ €ê? ƒmß?x «·-É?¸ ¿|}ê?Ý æî?èÏÛ~dkÃ?ã×£„Lì?¸ ¼áÜÎ?09·[ä?ë [z©è?ßDÕ¯ Èì?Àж°¡/Ý?±öÎsùå?\¾û´°¦Ù?H¤I!€`ì?VèeW„è?˜nô–¶Ã?®Èµ£ß½ç?Û‰v–à?d³!Ñ™Õ?½ß´rõµ?9Î [£ê?ÀÃj4?Â?rmW–bdì?ˆ7.{½?ˆ¼¹.ØJâ?e>\ ‚hï?¶ŸykGõá?’äC´ÃžÛ? ÍHÀÒa»?°y¥í»ÆÉ?z9öI{Þ?¹èåÈZá?ž»Ä…(‚ä?;º½9%ç?ËåAÞªå?0«N–¾Qê?é"æQ*ÿä?éW©a(è?Õìú”˜rå?À0&g¹?+Ðí\g|ê?i“N¶á?Wdáʈøâ?'õ›:Î? X,Ⱦ’Ñ?ŠwMîï?ü=f„ÚÏ?°¼ûè~·?˜_/®î?„i-eê?å?ÐOðo6M¬?ñ.Mç‘yà?ªÃ¼Ψê?¥œƒÜä?B+-j0Ø?¢ô“ê:è?pÓ ßÚì®?û®;ÀÝûâ? ‘ê¤! Û?¤¯Dn°Ã?Ä\E5÷•ê?TC:ž2í?nÃwœaÙ?Àg)½ö'Ë?2¦¤T Ú?’¡æ`y6à? ,Ýî™+è? ¿ P²?[Äië9è?ÕÛù9`ß?T^ÚÇžÝÇ?0k³ªÍ†Ì?<ý9ðEç?ÆfaÜ.°×?¼øŸZ¦Æ?½àü‚MŒê?t¥­}[/à?¶/ºî©ç?ÀÛå]žÙ?š!ýõ~@ê?èofø@æ?;§×mF‡ã?†S*žî?ôúÿ9UÉÃ?vÿ›cNïÑ?ÖrȇzÅå?šÄ¹CR\Ð?<¾˜¢ÞÃ?¨hœã?ç„·½î×ã?è ÕoáÊ?+¹6Q»kî?X5Ofž<»?(Dɉ8>È?à‰MÆ»»?·Å—t.á?„òA£´=á?`:ìä3hÄ?·¯.\mä?e˳˜R˜à?p+Û‚!uà?µBBâ?&«¤Àèdì?”ÿDHÐ?¥&:º•à?æçѢȴé?:âw­ãï?×qÏ]—Êä?@;>ýã?]6ß‘Aœì?¼¢oÌÝ?Lñ•h½eÃ?AVo>ZFì? 8›ÖÇ?ð&r©Ì´?x3«w Î?pÁÖ½pØ?—–N™â?X(ÉgTEË?DBVu€Ç?¦Ü>5ªÙ?öc6Cu)ß?¸IÛé¡8Ó?ö3Ü#YÆß?W&o¶tBà?z6rÆ×?zöûá?uYF?´¡?øØ‘&1Ò?ó{«ü°ì?`½æä×”?àÉÎ䦶?å b¯{â?ÙUÅOè?¨‰t/Ÿ‹Ò?2ÒT‡ñ´?&&ý”å?o×ÊZà?¼Ò»½˜ä×? @ÄD @Ð?Èñøïß‚ã?Š…N&8Ü? æ×/È•ž?<)ÈíòqÄ?LžòMÚ?€ïË(žû>ÓëÒ»!¸ä?cÿ}¶¹³ï?Œö;ˆµÿÏ?r0íÎÆ?˜HXÖp½é?ÖÎÿmbñã?°Ó AÞÚ?# à-ä?—g†ëÙ?S\'…á?u‹Á½íï?ü=RÑ5Ï?oP4†Æ á?H]þÖ×è?zÛIÝ4åÔ?ùí•è]à? òþI.[›?õ¡Þ¢>è?úá#6"à?• l’,µì?ð~6Á ï?:…Bcùí?ÐvkÞ¿ä?@*#¬Nä?hŽ÷ân~æ?z¶ªzÚ×Õ?|¿T»Ñ8Å? Vì÷/ Æ?°Óc2ʉÒ? ¸lÇï×?GUÉ»Ó?d2N‡•á?L~Liº\è?zh­¦Óî?Ê¿0ý:­æ?swò`iì?¸v]q@â?4rçÓ„lì?’¿ûºŠsâ?‰Íö„Åä?°-dD‘§?()Íõu²?[½´~;úá?;wúãíÓã?ëñëÈúÿí?€US„n)w?ÈÔ;óåÅ?s¹Sè¨ì?–(YÅ­«ä?´±-<—#Á?¤"°`eê?“¨¡‘Èâ?>º«(Ñ?€ÊG¥ƒ$½? h×õE7î?EÁu M.ï?`[¸™læœ?™ Û÷§ï?ÆA{³LãØ?6ð÷Aò"ã?ëCP¸ß¾å?f~Qn Gà?X©”Ý7Ó?ŽŒËÁûÜ?1e&w @à?ð(OiàÀ?âxÇ^IA×?6š6 Úè?"Vò¯úã?øú·*\ä?€IŽ] IÜ?vßPßôÝ?T‘|ç»æ?<ä@Û®¿á?ð/¦°µ¾?À@ÏáuÔ ?VN&K;žè?ûy¸Týë?YýÆ7Efì?yG†[jpë?dLÈàÙ?âfÀe¡ç?@M“T4¥?+þ]iÜ? 7ž?è½g(ëÓ?¿lžlWæ?+GCmá?›ÞUR˜î?Т«¼™Õ?ÐÆ—9ìì?ËØŠËÈ?/íɦ&Uë?³ðÈåõmë?ÛtßÎPoå?½òx~Xaç?Æ b”Éê?Ò!7>'ðÔ?T¿‰0ß?hWà(Î?^Äh”(bÖ?*¬Òy5£Ò?®ïÕñ-é?¨¢ã©ÅgÈ?ʶԙÙ?öFLlF]ç?¹äƒìÍ?ÎKý fÖ?ž™ˆWûè?b’¥õ;Yè?ù9k} Õ?PáT6.…¨?¾èiP­Ëß?4My¯>Íß?¤#âØŸå?r9ãà?è EYÂÏ?¸ÖÑVÙ¿¼?ªí€<"Ó?˜…ÀgÍß?½Z01Ó¹ä?ÆGrØçï?Im€ïÌå?¬ö‡n%Í?¨Þpí³¿?ŸS¨‹é?õ³å?´Ïñ„RÈÄ?¤fëoÂÈ?:{úûùmî?p¤ØE´œª?€‹Ñ›Ê/„?N°@;ʼnè?àǯæ?Ôª>ÛÊ?h. ŠßÎ?᪤Øfï?\x²éþcß?`’?ǯý©?Ýø $’â?€’½\úž?(·<­¥#Ò?è§£lÒ?¨Ó°ì´0Â?ŠÙ.q9â?¬W^’o/ë?ƒov·zDê?A¤Õ¯B±ç?.üy#ºhê?Ä„f@,Ä?˜ž Rä?ÚPw³ûÓ?[y”·ýÂ?Læ¡Oaà?Dª|]‹Ê?v?nš”áÒ?;M ]«Õ?¸»ù™ê³Ä?Ä¢lzÎ'á?Ø.|ì%¢Ê?tçïWÐÂÕ?æ4t²ïæ?øB_vöÃ?S“µ½”Aã?àœÏ› +ž?jÕœa¢å?åß3ýÛë?àŨI¼?îÔýÓ„”è?TÊó÷Ùä?ð#xq´?|<çêD6Ì?YeÈ!›è?WB0z ï?,ÿÿ +èÁ?üÍ„ƒ·Ú?ªI=&‰æ?ÈZm\Ï“ß?ºu$¢äŽ?øõtZÂ?BíÐ\0Ä?s2H 7ë?dŸ¶ :Ï?¬ýzDüÜ?ÈnÙv¤M·?ôÿhhU÷Þ?ï¼¹FsÄæ?8=Çb²¾¶?ÿ¼G´íeé?9Oí2º¡ï?†…[±Ê`ï?‰O7>ô¡â? ]E€7¹?á–•Ó?âi‹·ÐÜ?lavò­ë?Ó—BpD,å?2H7£ÚÛ?@MÈ¿þí§?¤†Ì"šTê?x´Öæƒw¼?Tk#é3×?fçä áEà?ö =ÎmÛ?yýe;â?JexVþæ?X.¶ö®Zï?³Ìˆ®«àä?› ‘ÖÝ?T©±¦ž—Ñ?ó á¿j`?xÒB^í?_ÑÚ¯è?@Q#u¼?Ðý¬Xu™¼?Q€„ãbRâ?饪ïÇä?à¿ðco´©?• m—å?Háägß)±?ëOX1Aï?èÍ}¥2Ì? ÍžXŒ£?ï ¹fì?èŠHt×SÕ?˜ û±^ZÝ?ØÃ«Uø©ê?Ùk³¶Pã?î²³{Ü?ĘybBQ×?#5®Á”%ì?ÀRuÀËÆ?@1±Cs……?äãt †×?{ýȸG®æ?ÒÀ Ñ´è?£±Çävç?€žùFUØÔ?^ìÅ@Ÿ;Ñ?t ÍpÒ?BÔFÄç? >mäÀ Þ?àUúƒ"î?£œ;·™Fí?ÈÅ}^bgê?^.e6õŠÑ?Σº_±Ý?öòï0מÓ?ÃøZ¡Þrï?}õj–d\å?§Zî:ã?Ü_îz¾×â? Ö)¡‡æ?<ÀtC-}Ä?xiÀz‡²Ø?\ËÕ‡ÚÖ?,4õl¤Ö?®i–I©/Ý?¹|¡aRVé?c< ¬RTæ?w‹Úñqí?ôÈiËôÂ?-„ÉCNÑ?4–µ6«É?X|J†Ù¿?ãV†½°?ÀOÝF²»?0ŒÛVÔì?Ì¡ênÊÒ??ÁŠh–“â?XnÛÞh~Ü?ð3K;R¯°?¬ŠIš½ŠÃ?¤É´.Ú?3è³v%äé?V{p /¼?bºÝTå?øÿ³K.ä?ù»{N¡?¼ÕBÕÆ?A‹¾Ë|á? € ôƒ)à?Œ`×=LYØ?¤E³ …è?Üy… nÇç?è™Z–I·?æ«H£Ó?Ö×ÿ·ùÜÖ?6¡öÔüùÖ?”uÒ6&Ç?|æ&’Ð?ä2¾di‰Ö?/òò9Õ?ùOytËÎæ?¨vw"“ÜÁ? uWÞðÙ?üû©<'qÎ? ÄzœO!ç? ÁÒéV¶á?ÑÜIÄá?°—ík¹ª?)Ì00Ôà?ÿ’«»$éì?ºh¥/cæ?ïžl‚³Aî?@+0wË‹?À—Ô°ÔÓ?œ¤V,Ýpï?k;b1êå?O(÷Óä?°¬?"¬ÁÍ?èd]¥ÖÒ?>‘k}ÿÛ?«»üå?ÐÙÐÐ&¹?hðÀ jÏ·? E (hç? mÚƒæ?µÎ²˜®Eã?f£ – Çç?@* è4Èï?”4­M¤H×?àäH“Ê—³?Ö&Ÿ4ì?“}ôlƒ¶ä? G]»žÒ?ÞG|’å?˜ —ßÏî?¾O«LØ+ä?zu~¸@Ñ?bW·.Ñ?À1*óÊ8º?¶ˆ¤øœÝ?#/4äç?2·°†&Eï?(\+óBÒ?Þ% «wŽì?^ÌrPÕå?0iÒ@2òÌ?ÀÀ`´•Í?tÓE×r×?¬‡1ëeÌ? 5döDjØ?™3èÆ?ƃ”öáÞ?vÒ ªF‹Ð?€x¹ ¾î?¨—haÏ?UO©ýï?þ•=He á?8þ®-yÏ?…íè €åâ?€Mξ{¨?MØ6Ѳøï?÷öK½?;gÆÒ‚ç?þv¼Rð¹ã?§8–„Ñí?&`hyl¤ã?¾´Ûy5Mç?( ŠÝE±Í?{ÿkVÇã?—ˆ&6"î?Pb,¸Ç?bu3ÜE³Ù?j:>Q#•ê?02­ž«Ûî?¢X.bøÜÙ?03H‡´ì?¦£}þ{à?Øj"9í?3¦ÄIà?ÄYÜ!âè?·Õ¡± ï?‚Ïu¨¸RÙ?šÌl1Õ?Òò b á?L^-gÎ?&H^ŸdšÚ?€·d«øu¥?À\£‹Ú?¥E(tÊà?€ù 9›þ½? G‰89ÚÕ?äÄ+ñÿäÔ?íK.dØ?ü$‚V©{Â?à+­“4Ó?ú­ks–ï?l§ã ŽÑ?PM¨J¨é«?pŒ)`ÄÇ?Íy™ë?`âeûèÁ©?=v™\Væ?Ó…õ„Ø?ûbréSIá?øY3<úÒ?·×„«a‚ê?°ñNOÔ?”9uÕ?`´vÕº?$Ò4uô¡ê?(@w ¦»?q=ŸÂ?<ì\ ¥ÖÕ?\^¶x~”ê?&2Ô¨Óî?˜}ùüYJº?  y¸?ílÿ»‘¨ï?LtJºªÆæ?Îz]F=Uê?†šC‚Ÿêè?Šøœ‹¡ì?·)ªžþ`ä?X{Ù;§ZÁ?Z6àõoï?d‡—EËÌ?ZÌÊs]ê?ËJ$B˜â?˜JðláÔ?Ü|Š‘šØ?‚Qæ¢Q”Ö?Oq§Œ!æ?ú.uä›Yá?À©‘A‹“Ò?D¼ê TÙ?äʨé?¿~nx~ê?µø`Wã?|!³¸>ï?Æu¥ °Ü?»R”à¦è?t«x/ÑÂ?æÊLÚºã?³¡ìrgaà? =8ÃQ3Î?€æHè*å³?n ¦S·Íä?xŽo¿ˆlâ?c¾,°B¶ë?ºeôVZÓ?v–®â8Dæ?à ¯âJ”?hÉy¯ðÃ?ÇøˆSè¿å?‹=O v—î?¼>©ˆ[Ë?j«É®ì?©-çáŠðë?þ‚Êšl¿Õ?𢙰ҳ?-2k`Fqí?ãf É›Fì?š‘¹lIî?ò¶ôÓÊÞ? '¦ÒdíË?˜—Õý`¾?ÚP_®è?4QåÑ"Ã?Öû¸:\Ü?ƒ‰¸´‰¾î?—’{GÉ?àx+®ú©×?“ÿ©ê¾Lê?;Þjì§å?Q¨ŸÄQØê?š‡Üy;FÐ? ˜=ÀÔî?%ˆËhÁì?$`3¬{é?Ðd/Q¶Â?XÍï®w–½?,zøÞæ?¿–!Á‚3ì?~5õá?hÞï?oc·Öí?@‡lÈ4þì?fŽÉÞÇtá?rÖâ(вê?·ëÚ™Á£æ?Ÿëd@tá?§ém‡¶é?X$Ç®£À?VŸã¸Qí?Ü•¶ó±?™³©ªÈã?à©;æµ?"ŸôØ´¹Õ? 6Qá~Íî?€ÙIK£>£?þ5vµÄÑ?¸šÔ=“gå?­í4/™ç?пâGqÚ?º2+ªÕué?ÀÈNsÔ?´<í#M•×?øe:Yõá?Ê¿½ÓÜAÓ?ÃÞ‡é¡ç?øØ'/Ô?|"E»!è?q§¤í?<š­@më? §$™9î?ÊWb"Hcå?<©3¯_Ù?›>$šÖè?¤ì Q¾ä?v› #*ç?`Rº¼!ôê?æ“¢°ò}ê?4WufÛ?Ÿú­i¡ƒè?’KÊõ+Õ?¬ŸÜÒV$í?Gî R‡¨â?0[ÜÐÿ—»?2úÏžŒ¨ï?ñ9ú*øšâ?0Jõë­“á?FÉÜŠ¹Ó?ÝÎÄsÕ•ë?ÿ Od®?yýˆO®³?bŸf5Ó?¶ÌbÝ^ë?’WŽ á?Ò™á˜ÕMÕ?<Ã¥Ô{»è?ÖyË@@Ü?öR‹‹ßÿÕ?õûm¬ïÉç?&-ô”BuÐ?†i3?ŸÑ?ðãé½¶?£^;äCî?ê1Û›ÝjÝ?9¦0‚wÒí?1ôR©4ä?l³o 0¨Ñ?L$eµZÁ?`D—ikâ?ö߯·jÛ?JBâ¤#^×?<3,ü{lî?¢G±ÊÖ?1ãÑ: Ó?Ào’:°Œè?àu¨þÈŠÐ?ziÓ ñhÜ?ü¶XŸD<ß?ØJ)GÛ?hu’hS†Ú?ìjÄAwÇî?ç?­š¬_ç?æœrá?ã;?xÒÄâ?È3ŽÖÐ?y:cîá?Ú{ ¯Xé?Dsw/Ö?ÀŸaÇ/ßê?ù1Ž1á.æ?1|Tï«Ùê?ê ³úà?À¥ÑplÒÑ?¼^õq¾´Ï?jÃÜúÓß?TG/š3Šá?ðD]¸×­?VjN\mtê?¬ï7¶ã? ¾óü½Á? Œ„QÔÝš?\TÚ“Ã?eä–ÒŽ ë?LN…ŒlÐ?=êÕé?øêz¥þ»?ÁÇq­m¶?ä«—¡Ý?)‚Ôköòæ?ã)* —ë?æ lâ°è?Æ!„³è?§*˲Ãí?\dV\ÏÎ?B«INE!î?lÖc0€‹Ô?–«ÌŽ9 ã?p>é|Ö ?µ8}Gʦå?Ò±x,r®Ö?“°ÿèLÚ?Z¸»låMÓ?žšçÎBî?ÛZÀ½Oç?M~IqÄrì?̺Ó\©à?4 èŽ/Õ?Oî:ò ’à?Þ§¡í\|Ô? z7( <Ç?€<Öžîç?ñׯ¹Ê?LhwræOË?:³×i\ÉÓ?šlWlÛÑ?Ò¦º˜íÜ?†GZ²1Ü?æ‚9ªÜêê?Å…GWï?ø-0ÔŠï?0«ŸÍM˜´?b+qqʯâ?fõ§ëmë?¤+ÆÀ¨=Ú?jÚ™køé?€•ï³²>Õ?M"!ÏÖï?§#ŸààOä?{&Èýˆ¼é?®q--ñ‚Ð?›à.Râ? Ô޳?€“ï…€‚?’”g>› â?<tÅ%Ú?BPà†Û?”\ |ž3Ã?$TEì›à?+pE®#ï?€Â]`mœ{?––<•½è?fàþk§ß?B’ž¶à?Йð‹w®?YØ}œë?cCÍÃ?¦ÞžÙ6å?0¶o¸]®?¹UÅp©?Ä[B­Ñ?P ·é¢5°?\º{V]ã?xR±“É?ÁÁ}V€#ï?Úzî?ÀßCEú4–?€!skå?§Dad½à?¢QÓ?‰˜á†$úî?õ®(6+)ç?ÌŽ‚ÄP¢â?×dú/7á?Cé%™<ôä?¦|´;4ç?Æ>Õë¨Ö?gži®à?æGc¾„á?ðøì¥ï´?&ûaòÿýÐ?òT'ü›´ä?˜™Ð¬‰·?öd«3'Ó?„˜ 3¦ å?›+kØÏ¼î?Ýò™¸/]ä?†R«{âÐ?„ùhoK×?tp‡Œâã?8Ëœç øØ?bC?ôïå?‰±ÂŸ8ä?çÃê¥é?æ ÉÍÐÖ?MP…ÉFá?¬ãž½MgÝ? æFzëß? `þ¿zÞ?\IÿŠýîë?§û¥õdÚ?{fûû?¨ƒRŽ ~½?eM§‘ôá?¶ï·Š‚<ï?Ô¯â’ðå?ZKþâéÂ?¤ŽÖ†Òí?ïÂÎ âdì?xí×·TÙ?dØl*sQÆ?[†XË9á?ᥣ.–Åé?³è‘ûwØï?ØÞøº;ÑÃ?Q·ôì™èá?¸ŸùNh×Î?Ài¸þP?–²ÃÂë&ì? ?{Œ¤ŒÙ?x­¦oµ?S¶E|.ââ? 2¿öXì?iù¾Î–¬æ?°U_KÛ¬?9³gÿæê?àMi—³ê¡?€\«¾o̶?CÊ¡‚L©å?JÛt,§™Ü?V¿Ñýë?á½ §åÉ?èûïÏš×?-”þÑÓå?2¸uQÌÝ?}le€%ãã?Ú~©zjdí?ÜÏ²Æ …Ö?‹fô,‘Ñâ?§¬ˆÒ!â?Ô”Ð]_­Ò?ô7•ä=¢ç?ƒÜ‘!å?ÖMx\»Þï?ÇÕ^†–í?HÝŽúéMÆ?ÌJb³Q¬ã? ”Ø€´·?°QëÉ?yÛ?€K£nÃÛ? NŠC¸?™ú¿¥í?û´0ä?Hé&Fuî?ßtæ è?â%c`^í?Ó$3,´ã?¨x•Ö³?°°à»²»?ˆp.™iÔ?7ŒOÎÑ:ë?–HWš}Ð?†aG-|ß?ù4âîœûé?xiçkŠ"Ý?„™K³ÿ9Í?¯Ø>»Úæ?ë@wܽà?⊹ŸB²ì?ï»îó&í?æPøäÒÛ?Ë“Ì'cqé?ò4,È?ˆª\÷]¤Û?²¶ÀØ]ä?‡¥Ô¦Üñæ?TT1K8Ù?Ȧ«!üq·?Èi Ê?ú\äÌtÙ?ÄjÓs\Í?­œ#0W#ì?HN2Ž&_Ä?H8[VL@±?yüÝQ@ î?ûŽr6%¸í?Þç›IöQä?dEdûÌ5Ü?®p`Ô?8ÇJˆYÊ?ÞLõ¤0î?ÛŽ^r”Ôæ?hw°mQ¸³?JAº±Q%Ù?ÄYÛÝ ŠÇ?rMBýÆÀÑ?–‹{¥à?Ò¹fØ?ôíîÀqÐ?(d¬èª9Æ?„ÍÌêÒ?æÚ#ÓMê?U˜K $Cã?¼RšF¨Õ?Ìå iÝÙ?0K+’^®?°oo6ýÀÔ?ù…•‹,fè?a[g¤ê?X€»Š7ÄÖ?(¼K˜õPµ?X±ï‘ ±?‡d‚@µä?D¶4dôÊÉ?V,@ý½–á?f^]aê? õë°–ãÆ?<«=’Þß?²ßm¬Èì?¶Ê§=(Ž?“Q]Ùx£ê?ÓÝâƒÔçè?ÕûÑÇë? âÚ>ø§â?ƒÝKfãgï?¸]Õ ª„¿? „ÍÊØ?‰¬<¬xËå?枈Õ?Ìøæ?ÂûÊ?²ƒ±•™Ð? î0¦æ?Ñ¡¶1À—ê?öÖg°‰Ø?°é'<;#×?ºÔ}GÝÍÑ?}鯽â?¼(ië?¸”SÄ5Ï?ï²*‡¡pç?1ïó÷ë?ô ?ø„;Ð? u(ß–|Û?%/8Y4ï?€T;ƒ\‹?ñÑèH+ê?=VåçÌ?äÏ>\})Ã?°7`ß¿HÆ?< ]ç¯Ö?¦ë¾”ýƒá?³÷K%ÑÄ?‚ôËâ„Ùî?sO×ð¸<ê?€Ùª:ÓÐ?`½Øç“Ï? U8²å-‘?-¤“©Êä?ð¼uíG+¼?fµèÎGÛ?`d®0’?_ÐnõÍ0ã?¼¾–BN·Å?@ @ÄFªÁ?ÈÜOk¨ú¼?v€iOh–Ø?ˆòÝH‹kÊ?@Nõ´º·?›3ƒ'*ã?”%˜vÔ?·ö]!ä?ú²]¡è?À=„HÖÝ?nŸÂLŸÝ?ÖÕ¨ö„Û?0h¸¡¶žÝ?Ü@´<û”Á?àbžMúàÍ?Ðtñ e–Ô?ku©mé?Û×6ÄNå?Žoã?L¯ÄÝ{ç?n€,œ[.î?éö:·Òë?F¡[$Úïî?€·ÜZŒä? þç'D¶?öÏvÀîç?h4È‚æ?˜… ýì§ë?‚ÛÓJ{é?×?ðFz"í?8n+®‘ç?"!ø¥ìÓ?D’ËØ?ˆ¹¯üáÙ?Ø„¢è‘¸?貺J~°?ÜܵpúÔ?ˆ› ¥ðŒ±?z2€Œÿé?°uÿ&é‹§?\¿ò$‚Æ?”€šý…ùÇ? Ý 妣?ɶ¯ µì? °"c¸ÄÉ?øÂëŸz?!¬ë=,pí?®‚÷š’Ð?Uåãï<)ã?ƒ£÷?ê?ftœcsŒ?d3ý(Ñ4í?ÜØ=ˆ¤Ë?®~mb÷ï?çúímÚâ?ÞÍn7oã? k$âCÝ?£‘B×µè?z uÇ3Ó?ˆ6 £qj¸?ÓÎ3®ÊQé?Üȱ§8Aã?¨3å}wá?½ [©]uè?ô;ôÍ…Ý?˜œ„ô "Å?KŠ“0á?¨4LáA ë?‘Vý8î?‚ ôsÔ?;8fœç?X¾õµAË?ÍÚ?<ÐÒ?Hö4†ÀÆ?Œ>žð0ÆÛ?¬£šã±Ê?}_<ôafê?ÌKøOøâ?uwÉZ¬Ñí?‹çw{UQì?ŒdhÞ ï?h‹:¿’n¶?üx{>5ÎÂ?Ê^Äè.ã?®°@ÛÄ?V<ÁTð1Ú?P»G7á?DžF%öÜ?HÇ»rÏ Ü?æŽó6óþå?¼ïˆ¾‘Ã? ŒMá?J`ׯ7ÛÜ?þ•4hé2Ó?Íz4WÅ?èÄSP¯FÊ?q?#¼ƒ÷é?ø` Ä¿?ü+®vhé?’Èh±öï?l §þfkâ?¤"ŽG·æÇ?ô¢ÉkbØ?ž%lš2FØ?Aݼ{<æ?vÌÀÊè?ÛÃý8Úýî?À€md䔢?(IýÚr¸?>$ûêv.ã?É‚ž¡¯?xNgôQñ¸?°äGÁ°?È£Øß¬é?2LþïNÙ?=0jî5å?#¡Õлžá?rŸý xæ?‰ó‹h$Âè?·I«*òké?-žÄ¿ é?… <¯?ùä?>^8h¸î?àl-ÞÌ?þ³ì"Çì?uÛâ͵Ôä?”:ôOÞ?ºÿß·&Žê?³Y¾Úîžï?¡À z,ã?ûì:?Œá?“Ýñ§¼å?W]¼l\Þè?XOÀ¤´î?jÊøbÐ?ƒ6•åè?ÇÿBž2é?k/5Ùáyí?€Ë{oaÌv?Èä1ÓF´Ö?¨ðL¦GÁÀ?¨¸<æxüÄ?‰¬¶e¡ê?¾N€ò°ß? ŒƒÏ?8q¢&˾ç?Ü62¯1YÂ?sž­?Îë?J±Å©÷×?Ù\×/HÍ?Š£iµÞ?ÐhðjáÎ?P ‚‹ï?s_@ìdä?Þ¿Yɾaç?[Ùmä5ã?ÐúãW$]¶?˜‡§,»?p0ª¬¦?oeS2ØÆí?Ðß´z [¡?4ÍO>¿è?2Dë­ŠÂâ?šhHÙýÜ?ÎQïì=î?PÌÏœ¦ ?ÇUCîëé?ðG<ô Ûã?‚¸ ;ñì?PfÀF|Oã?ä„-÷Tà?h‚á´ºÄ?ÇÊ«ï?„¨$Ñ8ê?+›‹|žôí?:¤v‰zÍì?I% £C ç?Ð’dæ°8Ú?Ž£ÔÒ^ýë?¶!Å•î?J£`×sÿÛ?ÿRß{BZâ?ÌŸWÉÃÜ?4Â5;*æÔ?Èd°<52Ë?Ç,àIÅ?°{g¹šæ?%Õ‚`g:ï?À‡lw9Ò?{)ß¡wç?馸… ã?ŒæØ©¾!Ú?vCïØá?x‡þïdÃ?ÈåV³îñÃ?ÇU¯õ'½ê?Àäø=‡‘?8¢] ÒÜ?Àfq/G™ã?óV‡…²·í?€&rT1‡?"lHÿQæ?p9Z¬Î?\U«²¹È?¬ÍLìJÎÄ?FÜ9w2Ò?Øà{qãÚ? æç¬ˆPØ?¸T‚8 ×?Ð o'æÉµ?Üã(™»ÏÈ?ä²h®Ò?a)À—lä?výpÚ‚0Ù?. HFÛ?¾íÔŒƒGâ?(EX+ŒÕÎ?"QÕøÔ=ï?¶Xq†¹¦å?È.¤aŒ}Û?ã! ý €å?sÂøêBÛã?‰înnä?+ä‡ öï?¨û½‚sÂ?œëÓŒÏ7É?œÞF 2´í?8N)p#UÜ?V‘H2(Dè?§4 å?ù×—‚ç?DbÿðÕ?ÒyØSÞ?ØÎg“à?ÊáEüæ?1˜qiËã?@1L,5™Â?Ì?^®~Ë?Âýl+Û?`’°Týì¬?д7W¹´½?£Kúý‚â?W€¨Q)Ü?iHIbiAí?‚Cƒ/*á?ƒîÙPgê?hŸô3Â_¼?-¦÷Æ_á?È9=°˜¶?þ„8&ÇÙ?l¾ÃanÎ?t··Ô´3Í??­¤Ú?®l ]_Jî?%­º¤çè?_A§jå? §`1ßÄ?“®â0 æ?Mm°F9ê?xˆ¸1Ý?™yí9{šá?HÍ‹*ì?¸4S"^è?|×ÂebªÓ?òEV Ÿ¿Ð?p"º]r¥¾?îð˜–é?BWÜ?{Œ¹üáã?棟œ¾éî?‚l£Îð¢ï?°7¯…>²?p^&×Îç?#}îˆ Ý?´k…Žÿ,Ñ?ü~Òµ zÊ?Ô3îÉO¬ï?° UÌ^»?ÀXˆi›¸?ÐÍn B¸?V§A‹êöä?je~‰Îá?M.»ýçÍá?È HZÑÕ? ¼oGæ ê?€ÿPÔp;v?€Ä¸é*“?«cµ·= á?°a±óâÇÓ? ¥ÁùÆ?@‡;ÇDÒ?Ç “@é?&@Ý´`'å?°X}ÿä?ð¯ƒ?ØÖ¨Q–%æ? ií#wíÜ?IMqJià?Ž^ci\ä?:¾i¢!sß?Lþ^qæ?’š=[Ú8á?Ø:95ŒÒ³?ºƒlŸ×?Ø´!—¼ÜÒ?…烼¯Ùí?=%}¯Úðë?®r  ˜â?š®Aƒá?*Daÿxç?8}uî¥$¿?½ÂV4ú~ã?ˆ¡&>½^ì?ïx»¶±ßä?¼‹3=ZÇ?&¢®ágKà?¢»:˜äÍë?;!!N«cï?VÔÉô î?þ^ ,¶á?€c¿ØÔLÚ?S˵ÞÜ?ºìT$šß?°¶Ö bWÎ?p1‘Šb“í?,ë8X5À?Ì弞ŠÕ?cŸ(®.ã?<Òç¾/¸Ä?ŠW!9 æ?í [àñè?<ë+ Î?‰AþçÙ?FÔøëÅÓ?ˆ’Åc %Æ?ói”ëÄì?(›nÞ?gÛõ’ËÒ?Â͉3Ñ?ò–ÈÈáSÔ?©zìïUªç?¸_/¯šÏ±?¸òc&¹?þ!ß2‡9ê?<×hatÞ?ˆâ÷—IÕ?üóFÙtxÂ?+µSÏ·à?ì7gÂ?”­ëÐáÊæ?xš‚a×?;›u°-æ?ã+–ËÆ?c:+°z·â?à©¶À€ÙÐ?ì´à ŽLê?ì‹““{â?¶;ñv šá?ý¨á]è? ÖA0®?oO+UD¿î?~iÛæ¿à?6÷}î?``yÓ®¥?&'2”õè?Å ™ëÔÓé?N/%:Ñzã?hI͌ٻ?ÁHÂy Ãç?ÆÖnãÑ?´› ÈçÝ?Àw˜f÷²?[QÁoKëä?•~ó#[í?¸2θ©·?°A×»Ä?°Ž7Ä í?5pÎ¥ˆ^î? ݺ„ÝØÕ?$3ÒÌzíÓ?¬ åþØÙ?:XNæÒUï?~ì×Óä? ZÏD<׿?¤z*p–¦Í?27,S¼9Ô?1”­ç¿?¡y+;‚Cí?m3´t“ê?¶:får¶×?@óáøGÇ…?0‚“Ø} à?èH¼¬â¢Ø?7Êw÷Y•å? Bùåæ?5XyÏ‹ç?Œ\N±¯-Í?×­¸/ç1à?.R U(Û?@É®¨Ê§?÷¸}¼ýî?ˆº“ðd–ì?4<?Ïߨ?š3î Eëã? úàRš€ç?@ÞünëË? ão1ìç?¢íèiˆµÜ? RôÐQä?ù½ïW¥è? ÚÌ'á–?@ÛÌ“ýãÖ?¶xü 3æØ??õ@ÏIå? !|ÎÌ?á•þ¾þã?’‡fpÕ?—êº\­‚ë?Ð+íUz ¹?pš;!ãÝÞ?£ä‚[>å?@·ö?”b¶?¢ëºyÞà?ðZsè?¸~¨[š³Ê?D?eL¼$Á?D¨¤«T°Ì?X@Šã±?î:ÔnÊ?肨Ô?MòÙÛã?8kò«<Â?l> RùÑ?4§8C/©ê?|(ÇŽ­ ï?€^ÎEÊ? Þ¸žWÈç?P·L€·?h‡m°{Ü?~DÖu¥ä?´ 3©é?ä\¥N{OÛ?À½Õ1ÝÖ?8l‡if¶? çç±=ï?þqúòwÿà?âÿAd×’ì?Œ÷Ð^GÏ?p¸ÁÐ2*À?|+ålôË?Ŧ=7eƒä?ùº&uÜùå?êXg4ÅØ? Ÿ¢¹f¤Î?,ë šQÕ?¿‡PK‚}ï?øF°Ê¹Tí?™D6 ç•ê?Ï»ÏDüç?¥ç¼žÝé?Tà‰p1·ï?bf®ã›tå?¸.ÞWÀ?À¶ký4®Á?ó(Õ §ã?öI«Hî?äŸGh;Ø?@¡«(›ÏÑ?^ȇãïà?ï»^óÜ?!›„uæùç?µ3î< lç?ƒ‘ Ö–Êç?ÊXøo²î?”òZm6ðÜ?Kâ±g@É?êÃÌXFöí?ˆŸÒTÎ?£ðO›a°í?ì&*«®í?ìélåùâÖ?¶Î´ü-ßÖ?ÈZQÜ¥VÜ?D„„½™Ù? :î±iï?¶°A²×Ò?Æcl.f„à?OÑÿW(å?„Ì‹i¼Ï?ÍX‰ƒ'¥ï?ÑÎæÙÇ?¨Nˆí¹‚Ü?„|y}Pjé?aÉ„uçâ?‚>‘h ûè?~¬Ð5î? ¥Ø¼ÚËí?'kŠ¡fÇ?öúëê{î?Çä @îè?ú½7CóÑÔ?@ ø•R?ÔT«ì¢žÜ?üq#¡¯Ä?öÛ(c1ÐÖ?2ta±­è?‚l±gÁ°ã?pw nƒÔ¡?\6ÚO}Ë?äKí±þ*Ô?ü#…'{ÊË?B–ú ÅØ?v¼àþ‡ÊØ?DL°#Ö?ƒæ{¹Ä ì?ºæ ãFXÞ?‡ëÁs£ à?¶Ïß-ç?5É·™î?ä/<ÎKØ?´°çdO„á?¼¸É@Åmã?×:Sù–ßì?`G7ì¶¼?íºÖø.Ëã?Hd®L½?wvyð_ã?ZG}£¯é? "¼œ†”?àIlqæ?dâÏð§í?òžcyä?²}µ©¾@á?¦ÓgTäÄì?A5‘ö¬bæ?¶c'9Dé?º$~óûÀÞ?øëGÌŠå»?Ä—¿púäß?¶·Ïö…ã?ˆÙuc¿Å?¤jgééÍÔ?º@3 !l×?ÚÙáùSá?TŠò¡Ê? $ÿă“?àWJX—ß?àª:43ë?°u+pÊSÓ?¸a•Ä?ØæúYBjµ?`WÍM‡U˜?øO´zÖ%º?¥ ¬B:å?ÑSÔÃÁ?¸©TÖFÄ?Á‹Èñ5Ü?÷\ö½/°â?ô]"Âî ?.<˜Z¯Ò?§ÉÚFÔá?ÐóáêÜÒ?k9¯¾¶Né?bF§û€ªÕ?QFx»˜Þæ?ôÕMÉië?¤ÙŠSÐ?‡E`Éá?=OŒ†…ë?\B@à+QÁ?¤ñ*A\ ß?”§ãæ?¬FgÑgÆ?òilç–YÐ?`V‡JHyË?°,èVÞ?ÊšzÔØ?²òÁLŽÒ? ÅÐó¶Lã?(b½³ ­Ã?|XêBþÛ?.cšÊÐZâ?€ÁiO]Þ?ÀÀ踜¯è?=žnƒî?2AUe]Ù?‚ ÅôPï?ðÝ(¡jeè?Œ—d€`Î?`n-oÛ(¾?òÁQv%Ñ? ÀÁÆáÈè?¼f2I©Ç?˜¼>Lt×? Š‹W‰? ç}Ê@°®?.€[+†Ý?T2§nzèÈ?ˆ!/#Æ?ä£ày JÉ?\n;âÎ?yöˆ(aÎ?>^\+óØ?å–•98â?(,K5tsÙ?¼ÎQ¶PÚ?ômœ/½½â? `ÅAtðÛ?ãÈ@_ë?-ÏJSã?•hÌß?4ˆÀþ]sß?ލ~´V0ç?•Ö[—Äç? 9XE×?B”­àbí?d}QŠíæ?Õ K•ï?pH¶±§XÆ?j1¯ißÞ?̰’ǺÕ?¢LO-NmÕ?’‰%o¡gï?Ã8Ó6—å?£„zuª™è?*^ºòP=à?ï!Úy8™ç?BãÉý³¶?ˆ­;0¾tØ?:³JnÏsê?xŠ_Ä®‡±?OÖòÛví?þPãØ¢ã?[½÷~ë¤ê?b•Ùmnà?À™û„Þã­?8%X ´é? šKòbs?\ªo´ßÏ?æ%ŸNÁûë?a¾šø¹óê?¸E”‡oµÖ?„‚êf%Ü?ᯉ"_üî?Öt”ö†¿â?É®©…P»ë?žMÙ˜?ÛÚ?€½Î6xGÓ?Zg”ºÂ ë?^õ/Huzã?¾\4ùºâ?Îß ‚€¡é?ÿUïÝê¯ç?Ä™}íÕÊ?}ߎ…í?ÊÙ-æÚ? eÛPg­µ?†¢G'ê?‘„¸Í?´b1ä ‘Á?#Ó¸.q‘?ÏËdç?møÂWKà?LËã§ó ê?€¢loÇ?™Õ ì°ã?”àŽÐMá?]í[ ëbè?Lÿt!„Ì?‡kºÃá?:±£îSã?ä:!zÿeÔ?E„yœÔî?i{~œê?ŽG»µ?4Õ?€´Y¤˜?*ÁW¿Î{à?—º:º$Äâ?–bÈøDÛ?˜V¯2"é?8›·¨|Â?YíAìì?Dâå%q\Ø?ºò€ÙÌèÒ?ÖUÂêülç?„?о¥_ì?–ÆË» oÑ?ò$ÔÑ·oè?±¢9]Öï? ²º…\ϧ?X¬ 3¾?ìšiáY*ï?N' â_î?™Ùä? Yª?0su[­Ì?öŽ®`å? [dJ»?NZµk£|Õ?F"—¶¤á?€>G{@­?V–oqy)Ù?¾XÝœ\Cè?€ü»Â?¶‡é§ç?Ä’€ýë?ÄÒ–—å­Ö?À ™Íû|Ð?Qø ÊtÖä?K¦Çáéå?½ÒÄtœí?õýï|¬èì?·âµþ} æ?XÖ4oaáÛ?ÐFk]dæ?ÉX—FÇä?4ácÆÖÒ? X뎊ï?Wu.jzDã?º-½9Ó?4@eók[Ý?–„‡ÑŸSÚ?Ó ТÞà?¨j ,À?‰šª©ìà?h-/­Ê¸?ËV¤Ô'!í?)jÍbä?8üǶҟ?#‘NlÈèá?Zö§Ö§fè?,/zäëÉ?úZ¾á´ç?XÇm\DÔ?‡ðRâb2ï?…Óžî?ï?V¼Þ2SÒ?UÀ9Aº[ë? ;¤”«lÉ?×LŸu®\é?Œç‡¤é?åÔt•ÞAï?C4 ó]Té?£zàŸç?`8”q;ê?hÌ`º97í?ͼÙôDí?Lÿ}òjÐ?¬NiÛ™†Û?ø5ÀÒçä?X+Í!Ì?*“UHÑSé?T9ó—ÄÊÏ?¼Ã£P Ç×?s‡ë@à?Þn÷O¨ã?KDŽPMié? Ï>Õî?Ë&îÌr$æ?^”¯ntâ?XkæÛê?þ~NAê?¸Y°Ø½?Þq~ªÔæ?À²5e¡?€œñØÆ„?ÊÄïxý|ê?ÀþV‘¦?üµˆ*_ŠÄ?5ü¯Î dá?ãߘRÑê?Îí¡»tüè? J—Ö? '’…Fá?àžâ±]!â?há×Þ?DÑЯҶÌ?* Ô¬ä? 3¼¹üÎ?öF5Ûè?§Ì!î8ç?ØÚè÷¢ç?(ÆÜ«Ó?B<’ºæ?¨0Æ2.zÐ?ë¼~$ná?ìÎRÖË?ÈVá¦È?b@âé×’Ñ?ê:<£¾ê?ôýt…[ÀÚ?ÔM2Ÿý3Á?ž‚2¯öªÔ?iÍ«,_í?ïJ-u6½?ì[´Ø·_Ï?¡|_þí?iÖ$³ëÁä?ˆ4K)÷üç?Hþ"äË3Ü? >!¼EÍ?ªpb¥ÃÕ?½(‰%¥é?ˆ+ÿ.Hï?­8CU§è?t!r`A—Í?øbqË2tÈ?“hÔè?˜„Xø@»Å? f Í„rÅ?|Tû÷è?+é% í?Ào=öMŠ?°”ûôÍç?ª®+g‚Ò?TøÓTë?hR»Ò$©¶?©TÍ5Ÿê?B‚k·n©Ó?Îä³Zh6è?0üè5©#¬?á£Ö»±á?ô¬il Ó?L©ÿ§áï?Lé¼’ôÆ?šº¶ç‹ë?‹1ýƒ¯î?ü€Œ©ûŽä?‹èówã?åà(¸?ê?`ÄÊÖ?ÎÃ"ÌT®î?<œ»ë?"Ño yÞ?Cz´ç?þf!â$ë?ÀÄr˜ßâ?˜~äIÉ{Ó?o\Ý”Äè?øï,—á?Ðþè§í?–ýa·Ü?à› ±fgÜ?k¥¬Ÿ&Ò?´$=ÚmÚ?·>™X\)ç?@“\\”Ã?þŠï×nè?à*ùU„Ø?íïVÒê?V¢µŽ‰è?ìé4ÉÍ¡Ö? þØáÓ?ˆ‰¬ŽÏ?Œ¼hÍÝ?¨¤Ãlä?³Ào‚[ê?’^…x؇â?7âWÊ)é?@…Àós¼?Ô?—N Xä?=¸Cqeå?5Ÿ3bAŠç?l¶guÉ?šµ…JÀà?¥Í¢Â•sæ?ïàç‡úïî? p‘ †èì?Ö“[‚¼Fè?^ûËêñòß?ER<_˜í?‰9kÙ?@1zçÄçº?5V3K­oî?íSÓOŸDï?`Ä$¬¨†Ì?"Ü4â›1Ö?Ñ70"è?@œ½h•?Ä¥  Ø?di‚÷8à?uh(¹ªá?äjÊuBÙ?rÈxÊ»›Ý?¾ýž™Ø?ZVBç?³°è?u· Ìì?ŒÇ ­€Ô?NNǧdxÞ?üÂeýÏØ?\õ UãDç?ò8¤jcê?8,uŸ?!Ö?ùƒ+޲ ï?ÁGiuy?Ú œÌ¹Ø?oõ°ñVöé?Ü€hæùÐ?¢Äí;S6Ó?~ûàSÃ?&‚tFì?¹}ˆHÐ?£™A\A(ë?àÙ÷DÕ?Rm×` ‚?$É„'È?®ÜÌ•ïÊá?(4è‘,úä?fõ÷Cmâ?€<1¯Œt?]£Rt?lÀ±ì­®ä?yÊw΄‹ë?”âóÊüˆÄ?+IÅàä?šž‘ô–Õ?웤±QÃ?ARk÷í?P°N=C£?,!Gç³3Ì?Øžzrž(å?Ò$Ûs¤â? {ôæ÷-Ø?AIƒ¼ä?€Caç?¤\Ÿ#Û Ê?r“ÂC–»í?c*ç‰Dï?Š-ÕThTÖ?¿ƒ³éä¡?4ÚkþÄÜ?ñeŠ)÷í?fO»cJ¹Ö?îIYâ?¨ 2?oÄÈ?`– —?¨ÿ;:qÞ?¸!ÉI«´Ð?ÑZŽWý=í?`¹Îhöµ”? ‚Ï­U²á?^ÿ”¾±1ß?â»òÛ×?@úŒ.=׊?*­[ø§ê?Ø®ÎâŽê?F ®iÖ?Bã$Sõï? #¾eVçÃ?à–ø3ý¬?¸r€+ë×?¸‰KE¡»?‰¿~Ã^Eá?VyY«}Ø?˜~ÔU?åê?<6¬»}ùå?e UËä?”Öy×-Î?Î>¶ð›å?í~Ó4®™í?]¸«ébâ?þÊm…Ò(Ò?Î9kWoíä?ª_ßÌmrÚ?äž €VÀ?zp€W#å?ŸílôßÇá?HtzE”ãÇ?ÝŽ“A,.ê?@+RB¨?Åv’t~Ìç?Ô%s;lä?pIxøTBÇ?€ ;û«öy?x|ç{Ìå?B“ÎI\ï?P#4 «$¶?ºû™,ÚŽã?Xåó“pÂ?ÉžKuö7ã?´Ûv¾$€Â?63Ì ßÐ?Ú'ó-èä?€+ó"k?®gœðÛè?¹¬!{ã?Ì5“ô-¦ç?cå´¯³â?p’s3rÜÝ?ŠÛÕWï´î?0åk!íÃ?x+:IÌ?àÔt€!·?©¤L’wê?pö|ö†³?˜®x$‡´Ë?Öc¶±3.Ñ?À¢*nâ–­?D,îYÙ]Á?üo}mnÎ?0ËÇà!Dê?¹tWíæ?€€0p©°Œ?¼’ž¸ôä?@ ¶VÛ½¾?h#á³¢[Ä?á?Uê|¬è?sf­~áìã?ø’&ªš1Ý?ð¸T¼ÂŽÈ?@XÞ2˜cè?Ìçä.?Ç? )ãšRÙ?€oÏA;#—?ˆ:_¼NÜ?4Ù¥»Õ?Р¤ýØÎ?Ì ÜvjÄ?Ь„£83ê?v,ПЉÛ?ÊKŽ_<«Ö?qyÎÜ?“êiRõã?àÃxÝx½?¬U…ÔaµÕ?ø¦ÍFˆãÈ?€iæí4º¢?„¹²ò!µÎ?Ímó•äGí?{Yã˜zòæ?e}û÷î?Ó0¬Øç^â?à3€ i¯³?ˆïí3›è?˜'3î#¶â?'È¿Òa'â?•%ŸR;ê?ÞÍŠb×`á?¨6<…}‹ß?À1†g²?Hz aö>Æ?°bç_´½·?ôv–1Бß?*êAkŸŒë? ¤,ä|í?f‚6ëjÜæ??Sã•Ï×?äP"[NØ?„ }øöÀ?,œc fþÅ?€S7¯ùò¥?4+Ô KÜ?b¨‚¼:ç?ÒN†bñ•ß?`ùduÎ+´?0Ít@Ïž¸?<ÐåËy¦Ð?€ËÐþ4V˜?ºÿøô¢5Ù?Èö¤X·?ÐZ‰Ÿ Ã?޾"sÒ?RÞÑ“Ñâ?\R%zØ?h¯®1/ºä? ólJç?¸Ýp‡¬RÉ?¤u7`IZÌ?šV:Ä Û?àxÄì°oè?ø,»ezoÛ?8‡Í ¶aÕ?Îò7>vì?h­LêØ»?.ZÊÆï?!š÷Z°åì?Ø ÙÄe³?ˆéüðWíÇ?€.:JÁŽ?PŸq˜è©°?Œ¨… Éÿã?±âí©ï?èFO~§Ã?©¤–éè?d‡®µžÏ?jû â?ähîz¾ÛÕ?vô%«áÕ?oB éfØ?G÷éVÜ?PC÷ ¬Ò?¾:sÈýmæ?¨ ˆ;Ÿ×?QÉ„2æ?ð0Í03Ã?­ÕëÛóº?Äà\Ü?Û?¸7ÍlU®?¨ŽíigØà?NÝj×?’¼otå?ãøl¾á?Ýv$Ö†à?P«Ó9GÌ?Cö•zUâ?À¸_d!Èë?.Èmêß?¸àè-€×Ã?^V`å"!Ù?§¢f¯Òì?(÷ƒ%Þ?ª¹ÚbZÛ?PÖ¬í?bêÐU„aï?¼-Sõ}BÈ?H5Ëyb¢Í?À)Í—iʾ?:•â— cÜ?X¶š8É?œ£–ç?ÑýFAmà?€òÔò"uÔ?h“D—Ò?øôÞËBç?U)Îù¦Õâ?Þì–›ãíÕ?ö>áÅÐ? —Q©@í?ØWçiXê?¼hM.x:ì?U+jÒ?ÜeÀ(½ì?…ÚHƪ ã?à\PLFó—?(çÂ@Å‚µ?i@ƒ^á¾?èÁä¯Ufê?>,ÜýlÒÓ?š JÈñÔ?¾•)áÒ?¹à†.î?¡«~P§2ï?0œ†U—µ?Ôû‡8LÙ?8¿ÃàÊ{?ù™1²-ë?ß;0a;ê?Xq|ç,å?È›ÖÛŒà?H×7ÉÀÇ?²q4…'‹í?¬öçÑÎ?¼ «â7|Ó?x¥£×é)¼?¶˜|C¬ Ò?D‚G—eÇ?h^û+ Ë?øïÓ8HË?{1ÊÚ?D2N}í? ,K—­©?©76gè]æ?P·°¶BÅÜ?(Úkl£æ?(< ¾bä?²iýÏEÔ?ºÁ„ñ·Ô?Ž€®üá?ˆø’ŒsqÐ?ö(ÁL©Þ?»÷ã0Üí?@kyÄ­{º?6aycÒ?¨‡çJÉ0Ï?0œ¼AO¸?R© Ñ”?/PiTžÁ?pÆ‘iâÃÊ?¹xmßΪï?œëñõ;Ú?csLYý‘ã?À ò…’?<¥JÜè3Æ?H#n ×? ÍDÐÑ•‘?ðñ,,R¿í?ào#àò¤?”ùMGßà?²ÿLèÓ?¸ÜxëØÎ?¨}¹û‡â?ú—PCÎ6Ò?:Olc×?$ü/6Öì?…ù2{câá?p È×Aµ?é¦L×Wã?ˆ.>*ï.á?œ”ÄÒë8É?v€Ècß?¬y’¡4—â?0€PËP€Â?,/DÕ?N_MÔ$Ú?ÒdÄ÷þ÷Ó?^é·ÿï Ü?‡/+ A¸â?ÀzxË?®ÂÅ×ß?¬0d½Zá?æÅæ&¸EÕ?F&ì?Z1çW^þé?"5Ûà-ï?.ƒ#¬tç?yPã?§>â"ê?4t®'âÞ×?³ñÇusò£?ðqŠ“ª?¼mOþ¥Õ? {áQ£‹§?(¦§RÑ?ðŸt®=¬ä?H&2¸£ôÝ?êmŽõ[Ñ?˜lÖbƒŽÁ?ˆpš'ÆÁ?h?a\¬ê?æií®ØÜç?¹‹®`aî?þ µsHÝ?¦ÕÓ8ì?;h#×£å?6@í]CÏä?P Á0üÃ?h˜¡Ú·ìÈ? :Ñ”I?¸o8‘Þ?(ŸÉ­IÈØ?qN_|é6è?ª ˆÔòè?JÔÒKßßÕ?îX í@Ðä?“j-p½äì? .,(ûlæ?TrçÚgvä?Ð;”ަâ¦?Êh½Zdæ?V¤UÛÊê?ò§u²ÑÑ?"PTÔ¬Ï?F \±CÕ?¢xrƒÕ?¬:ÑnM<Ü?t˜5`Çá?ÊWƒ4í?³Xu‘´Èê?_ÝË üá?bæÉŸ3(æ?Üøg-—ŒÎ?´û{TÔ?'+Þ݃è?¨ëj¹ç¼?€[(çõ³?†’KõêÓ?ìšJ#üÐ?#ñú[e?aä9=¾?…0ÚóJÅê?œU‹“\Á?xáÆÇ?ˆ¹ŒãZà?dÁ3»ör?`…ë¸Ô?ÞC8fòØà?Àä^nò„? •Àõ/n«?I÷ÙUB[ï?Ìþ-ë-üÛ?æ–£ß?—–MÛ*Ùì?”¹4âŽà?×bÞU81ë?ç¾—Výã?`63m«FÈ?(§ÐÄ»Ì?25ÃIƒß?“\Ðòã¤í?¨áÈß:¤Ë?¨ìu'¥Å?×,[Ú†ë? pß—ïê?»¶O¹Zê?õuQ|KUê?„‚Çìéà?ÖHb°R\Ô?$ž1½÷ç?,:„8÷!Æ?€1—[c)u?¬®k ÝÓ?x —OE¸Ó? %úM~"è?X„ˆ2¬Ì?xƒóö¤«Å?@ò­u­-‘?Mw3âµ?â?ñŒBÏÔØä?Œ§¦Æ/Ü?Í#9¤Åûè? †^t‡]á?*í¬À¸Ü?w‰Ö}­é?(âq2ÐRÜ?Íxí°Î‰ä?GìKü¨1é?gÕ—°—×?ä¤hyRÐ?ŽA6ŸÔ?XÞŠ—ªÒ?€ !”@™? )†ƒî?ÙJ'YûÃí?ÂqaäØ?r.dê`?›Óç6®‡í? 3°ð6ä?X<{é¾?Ø‹D2`Ð?NSWNÌï?Ž#°.*¶ì?œ’Ñ"}*À?_˜ýûÛÍ?7 l‡óê?hÊîå/té?M/à? âavâ?@_Jþ°å¸?^by,óÙî?Èœ‚b9åÊ?~˜ „]Þ?ã@ñ[Ø~ã?BªÑ=YÈÛ?p§íwà©?"{xÆ4Õ?EQøÈNâ?þiZÈžàÝ?ÈÝßX*Ð?ÂtGÊå?øNNj8,Ü?<ÆÛqQÜÜ?ËÚ&YÉä?`óö”»?vZ-÷hê?`Ñ' ß?2·®êtÁ×?€µ$+É?¼Ø¶ºš;Ò?XXt6ånÓ?HõñM´í?òØd˜á?Oq]Œoÿä?ˆ$ÇãûùÅ? ÎªÉLM»?¼1îS.{î?ë óßUË?AÅxÕAâ?ÈY®7IÄ?*úF{Ú»ç?<ü‘*­ËÃ?”§íѾsÏ?¦â N$Þ?ê–Ý£EÔ?¬ÂËyCÉ?oÊŽÝ™ã?TJeÓÉæ?`r™$\¡?VÑËšRÛ?u[¼?ãa3:ð*ê?Ðÿ–÷pÓ?€THl|QË?¨ù»$óê?Ï4Ë'«€â?`¥á2Ë«?Kd¤á]¹ç?vŸÜí`ç?`/XŠ¢Øç?˜OÀ¸Æ?/ØTooŒê?Ça)Ÿgî?Ô-T‚•êÇ?î¼R:ÁÜ?lU+µ‘Å?.O,“í?xÜO„œ‹æ?­Ž¤ä]Ç?ˆ6y?KDß?¤:hâÅ?˦Oe¢Då?Sò‡Á ï?xÄöqhè?òÑñê(›Ð?Úš~ºª¾ï?]OOSÿê?ÅgçQà?e¿®« ™á?ö^1=8Ýì?v!²ª¶?„^(Júî?’·FxÈã?²ú% “èì?¤‚G⬙á?Àä\-]Ê?záÐ:…Ò?r@sÿâß?ÜËnRßâ?œ)ßÝJïÈ?ß æ{hï?¾CÿÛÌúî?è˜ÑhÀyØ?žyÇ({pÝ?lâ^­Þ&æ?7i(÷ Yì?¸~ë/ytµ?œÄ0¦åvÈ?héç]ט³?ôú€# .Ä?ù«þL â?.“©ýÜ? &ˆà?àßGÊ8¯?ÓÊJÅÁà?»× Q,ç?^eœ|A’æ?hŽ·Àãå?|ô-ó:KÃ?hJ‡×ù×Ã?ÌšêaaÛ? xØaÇ ´?4-_ÂÍ?Øæûži;Ý?ÞÖc ö$Ô?*Ê|T¯Ó?ø_¢•(½?샭ù®tÀ?)ºW ,î?B©mVì˜ß?¨Ö9 IIÁ?è8ªÚ?Âù0Dûâ?p?ÙG˜Æº?÷H/û˜eï?¤¢t]¶¾Ý?kn¬ò›à?Â^O‡ó/ï?ØŠ>à êÕ?·ŽTz$!à?¯±T×ä9ä?ªÉü’§kè? .-]µš? adF‚î? ©'·Qä?ð}þälH³?¨E‘&â´?®ƒÁuÑ?o`ŠGˆÆã?xªRÒϱ?胜֙’Ñ?8ê;BoÝ?d ½£z7Ñ?hœ/z-³?É®ˆAå?Z?”èÒ?Ÿž«šé? •0n“”?©÷„Xj5ê?2àóÔoÞá?€`ƒôV¥?^-­;“:Ú?7ûšÖâ?€G×’Ðev?/Åõ{­â? …óü¦Õ?ØGYMû|Ö?@@)GÃ?ذ>N^'Â?ió~îní?aI¦ëâã?6XnL²Ô?x;뿤Éß?l0óß?‘®¾¤`í?ó½°ô÷×?¢#Ý$µÓ?ÕuïÚî?´BŸûúÒ?aCš£½å?ÿh÷/9~à? 9?Znå?Z ¤¯ŠÃ?PqJqšá?8…ø‚ö~À?´N á3ÌÌ? €×!ªé?aä¨Eoç?-ºj rç ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/block1.asdf0000644000175100001770000023505314653725311017220 0ustar00runnerdocker#ASDF 1.0.0 #ASDF_STANDARD 1.1.0 %YAML 1.1 %TAG ! tag:stsci.edu:asdf/ --- !core/asdf-1.0.0 asdf_library: !core/software-1.0.0 {author: Space Telescope Science Institute, homepage: 'http://github.com/spacetelescope/asdf', name: asdf, version: 1.2.2.dev870} foobar: !core/ndarray-1.0.0 bizbaz: red source: 0 datatype: float64 byteorder: little shape: [10000] ... ÓBLK08€8€8€\¨¿7Z‡N%­ò><üІ«Éñ̯?¥MÎmÖØè?¨ãŠJDbÑ?ÒBã³+jÖ?F€>:cáÜ?Žgü¾‚Ù?°§v ÿ~¨?ôûé_òCé?`íæŠÉÜî?aœ,­På?'˜„·Øí?À›S­ŽPß?Õ“¦v2é?dq‚˜ië?ðçn¿‰FÎ?@MèqñZŒ?5ÿ^Ö¢Óï? ¸Ô$ðÇÀ?%±J‚·í?Q†©0Iä?\ÌÓÝàÝNÛ?zæ§Î=µÒ?øÅš­`Òí?P“Ys!í?9›&Ø? Ó˜§ø/ë?ì ø Õ¤Â?åÝÇT-Ý?l, ­Õ?*)YRß?=m2±xè?`œ™c@ž?ʳå¦Õ?&Dï¶Þê?D¬¥A›·? “ÿhY?À?:‰çl:Ú?²B.:ùÙ? ò|‡Ò˜â?±fÒ@À-ä? ÷îG%Mä?º’iFçæ?µ|Ϙ˜Ù?Ë|8Rª„ë?žÙÏ^B¶ï?w¶²Îî?÷)Fix é?ÇÏ6Aoä?Ä¡¢Þï?¼c8鱯?·ǘøÏî?à™ÌõDþâ?tô¼ê#€Ê?«WÎ-l`â?ÂIyûç?:VtúE×Ô? åogØ?0üÖ»Â?ît&hVjê?h…’lðøÙ?ÕJ6°?bô\Ø?÷‰Gü±?bÔƒCú-ß?¿€½Ddæã?ù#…_ˆì?æÓ¢pŸÚÙ?²ÃôýOrç?ÆE·ŠˆÙ?hé£ ß?œéë]@yß?ŽæhŸC?í?ÁúM¿Åæ?æÃmsä?‹@,…¾lï?( ‘­±*Æ?@«iÜð ¶?FH+J»ê?~94öÀ ë?ˆl'dõÆ?@? y2ë?gá7æŒÖ?!ý|a„‹à?Øçiƒí?°Œ3 »?ãt BCê?¹PMì…è?ìÁ¡pº4Ç?abÖ‡ä?"¸ 2CïÐ?ø|ù¢‚à?`¤®q µî?°Øò (É?²®›dlÕÒ?fîô…:LÞ?>øÝ‹’èâ?¨§¿Ä`¶?ɵ­5/ä?2” Q‹Ö?*Ô’žy&Û?è;¨yw¾?ˆ/åïD=º? '"NHé?—”N*î?ô¥ ]2°?ä7ó¸¹?Vã¦J(µé?%êW¦Çæ?¸Ôd“"È?j0éUú–î?Ê UP—cÖ?s%Ná?öÄ»Lë?hä–hÞ‡Æ?[¹¾Îè?! Œ!øç?µ@r®¨Uä?]X'Åáæ?–¶Jóô¯Ü?É9tè?¡{xoLvå?PPEpT Í? øGàWÊ?ÉÀ)¸î?m ®,ÃÇã?®uèâ?dN6ü¸¾â?ºÙÎæòè?@ö\r¬5Œ?›‘â…Èî?áંê?i¬øb­¬æ?v! RDÛ?8å“ã<ƒ¶?/Ñ8Vï?³áùþ±ç?ö¢±O›á?†‡Ðø¼¬?€ùn¶6À? ¯U8á?àƒ9 %Ü?Á\¢x#À?š£Ô2ûàÙ?9ðfø)ßî?¾Ÿ­C\öÝ?8„½½ù…â?ŽBeé9Ü?3%Ñ0µ{ã?B?¿®TÚ?è3þ Áà?„nþ'ºÔÔ?€ŠšÈß¿Ÿ?¤÷É¢ÞÔî?8˜<® ±?Ê)NõÏ?®X&ÃöðÛ?ZBŠy8Ñî?3ÆÏØH«ê?JЍý%>Ü?(M_gwÈ?zÁFâ¦hÕ?®Éxç Ü?–Tåƒ`ÆÚ?xƒ Õ³4Ä? ±9àôÆŸ?ŸÚèKе? =à“%J½?ÒÅ¥iæ¥Ñ?°€³‹¥.È?DZ'r‚ªÌ?–ËÂ4Â?ÀÁwi(0Ú?b%±#A2Ü? nÞ²Û?P¼_émSÏ?Ê«³‚Nç?häZ$„ïÞ?2Ýpë ×?4«B²Áé?lH(Á˜?±øV±ãë?-ZÌÏÛ‘î?A˜O!|(à?ÄYRéÔ?0æ•¶°?Tñõ–ˆÈ? ½ »¶Ø?X0¸áÀ? p|*á4Î?NäLÆ-êê?\ãyÏa·?>Éø,ã?8 â8×Ü?&Ú݈cÁÚ?ho§ XÜ?(þ=ý!ïå?-Cç1èç?¥€¶Šè?+]6MDÃì?c#ÉT¥°î?5¹VOÉé? ³jÇY×?5Ï<“¯Gí?ÈÏ­4Ê?cpŽ”¤^î?`eÍ”_Î?œÁ¶ïÎèË?^dæ=î?0áýõ^Ï?Ô ´DÑè?"Øã: 6æ?7ª¤›¥É?•ž2Ì4à?©Lí? Stehî?¤éÚÁ–È?(y$þ&Æ?bl a-õÓ?£Â,uê?XíXÅ‘î?þÀZ'êç?nÎqž¤?Ô [´7@ä?Ëái_ æ?êÙ¹à¯å?ùb€î~ùì?ÂŒ* àlÝ?8zF:q¿?ùÔ/rmžå??š ­•Ãê?øS¡¿·@Ì?¹.2!ã?ÚçÇ1½Û?è<.Ê•}´?l|…¯e;ì?¤ž•øòÒ?•^`ôuÖê?ª|õÆ×Õì? BPàÌÛ?ì’gX%pè? &¢G!¹?vcïZo¸ì?^ï0gEë??i îcï?(¥5»Éµ?2^»õß?Üň<µØ?"ÉÖÑ'¸Ü?$U¢À Â?ø…½2;Ý?1i h%Ô?Â9ÌãlÔ? Wkp2•?> `³\Ä?`¡ÐÎ<Â?˜Çj‚ ?ye3acå?»ÃŸbû¬ê?pí³ÁSÙ? íøÊ¦¢î?¤Ý):Þá?’afvÄå?€!¶ëñŒ?æ»÷qó‚é?Þv˜5rÛ?Bù‡dûß?HšÞž³üÊ?D%I#L ê?Ú —?Ô?bÇ­CÐOÞ?®•Ç&hé?¯7ºyíõé?<fcÐÃ?&p³‘-ì?ytõ(Qà?Å·¶@«ä?T¸,“3Y×?ÐÕ‚Ñz²?¤eÛ>Á?o-~t¹è?&ÍáV&Ó?å:+~rƒí?” ~Ýúè?€ô¼›?`Q8ÿWå”?Kð“‚ø»è?Õê­V&¥ä?¨N1øÏË?|¬Î!Ô?±54ÿç?çÉ(% ­ê? Û3ïÛXÑ?¸"úG…Ø?ošg ö¶â?èñ æH׸?³+ŠÜæ?Š?‰ ¼ë?†ž1º¢Ò×?ŠÇu¿ø:ê?ÉGæ4åã?¸tÕê½?ÁÑž]á?xså/,Û?Àµ •³Oã?m;=€üë?U¥ 9ªÞ?NÆNÿEôæ?0ˆƒoÕë?#âý—ûaá?Àæ{h§©ç?Ða,îÚ}è?s?ÚŠfäì?FÊIˆÆué?‰ƒÓ(ä?Â{¹Ùà`Õ?únÑeÏÛ?Úul‚x(î?`ïÎèwç?úˆµžÚÂí?©vjî?Žhå¾€˜è?C×Ò͇:ï?À—[€°?Rõá+Yí?àkÄ…²?N6i,´?þ ýóã?x¹À²î?›¸ŽŠÂÉ?×O–&˜é?n|Írì?Œž¿ñHÜ?)š°b²Èæ?ÆüRÌOß? Bó—ô3£?èÖJ\ˆå?ó/ô)†Æå?lŠ7=êFà?H¤ªï ÚÛ?ðYîÀ–ß?ɪòÿDŸê? ^•¼àê?˜ nÛ\¬Ø?„P¼:çyÝ?ÑÓ¾È?²ê?ˆ ?°Ó Á?á3¶P=é?DÉað÷Ï?@Èô©Âø¯?ˆ{Í\Û?vµ>­ÂS×?ïü?ß?ôuú¼?dÎjEç?÷¶†8‡¨è?z!uòã+ê?HE ›¼É?8ݺµ×ì¹?šë°,Yå?S]A-æ?ºÖQ?Ý?ðÈ_i}È?VO ¡¥ Þ?ÆŠ§s–ÁÜ?ጆï?D}Þ™’_Á?Ê}ˆ8ÖÛ?b‡Û`ã†Û?øRù‹AÐ?䌈 ºQä?L!kße¬Ú?\ö½ÿòé?eÈs¹Ñç?€“Ößì? øx‡?^­r{ß?‚Ž!Âì?ü o1ªòÉ? Ç¿ ©FÝ?ƒŸj×ãæ?ÜèÄi¡JÚ?r/Àó¤Ñ?èšÒ?ÇØ4)ï?ˆ{Sü¹ªã?lÆ)F(Ð?„‡—Ë?@å D¶ ?vÃâíw³è?-ŽkN¨hè?U» å×ì?ØÊ·ÉõÑ?ŠvY¹*ì?f1ïŠa^Ø?ÀÄ XD²?ˆÂÀWÈêî?¨0“YlÀ?0”÷”6 Ñ?ŠÞaFiÜ?P¿{Kôo³? ÍNyz‘Û?” >ù?×Pc2ë?ÎN»ÿÜÀ?‡Ø½°ˆFå? Â?èæ˜ü2»Ç? ÕÒÒ?(zeï ¨ß?[Bi‘jÕ?<‹ŽÎm9ë?+i ¬§¨æ?|ˆ5ÂCµê?FüÀ€Îâ?ê`6dä?Ø{dz4µ?JYpk‰ã?t˜ó?{é?<>çUÞ?…]íÆFç?ÔÞð-<à?6£x—æ?ú^à´4”Ð?RÄ/qgá?„‚9¿ÈÝç?Øg`wÆW×?\´·"}í?¦Ù°ÕëŸ?`^¸¯æ?â)ùù¤æ?p†ô0Î?r–xãg®ã?>“EEÆ;Û?—Bìàzí?wçéç»ì?©.ÇÐ9À?Mó­ä=ï?3àï/§î?8nÏFâ?0¦Ý¡/Ö?yª³¾å?ÈMQß‘¿?ä¨ y/Ú?Œ•ù9<æ? þùRµ¬?ºu-mxæ?Ïxr‹ê?'d­ÆÊï?:ŸÃ:#ß?Ã"”É´Àì?í+xÛ?? »äùËå?O7ZZ<â?|(¨),ÑÏ?EúG{î?Ðõ ’7­?¨^pÚλ?Ôšëm&ñî?\a-©¤Ë?]Æ ªÿä?¶ó@µáFî?¤9G!ÇÜ?h¶![­ß?< µQO¸É?"l[S…¼á?.˜<æ~ÖÒ?FŸªž²Åß?ÀOëÒKª?htA¼’ Æ? gÌ ŸÛ?\Êv½7SÜ?›íf¤ã?@¤ÄÒ´š†?¬Ö>#Ë?šôr(‡dà?€Y!ƒ—j‘?š5Øç>Ý?0I¥!{Ü? ¼oMCÌ?‹Ó¦öë?è¯R Ù?ïXæÏ" é?jŸöKAdè?[è¶|ì?v‰zIæä?À4Ã!€Þ?¼çYÞü;Ó?xÆü1Å͸?ý9àkÕ?ìIUå6%Å?蜋% x¶?Ô³8ôÏ;á?˜Rì¯NÜÊ?ùŒS¾}ë?èpà9Bí?Áx·î?0)JªÀã?úâÆÐnã?àÏK pàœ?> ÷Þ»áì?!<”ªà_ì?VÜ/Ã&Ô?=ŲEFÉâ?+ÎÐ5ðî?ôß±F;Ë?¤Ý¯ÐÈÀ?èd£}-è?ÔAˆ ¨ŠÇ?îˆ|@äé?¿¡Œ¼å?ª'ü|Üíç?¥ßÞ“[¾á?A ¯v§æ? «‡y¢›?§ï±–KQà?v4­U:œÙ?Bq›¸sÚ?a½a~“í?K¦s"ê? Å‚zvî?ذyG°NÅ?tº<7NVÍ?‘²‚.Rà?dy_õ_øÁ?“‰'z|šë?̾¶ >Õ?YQã%ˆê?xŸ¶v4"±?T$ÉØÀ¤×?\ƒ”GíÌ?ÀEL¸Îu¬?õˆ½£8é?䪚Þß*Ô?°âðäÞÌ?ðîˆ'µæ?à©cH´è¯?*nN_ÖÍÜ?þf^Y4Õ?š0JTðÖ? É_½1‡ê?x––YEÇ?²-Áê#/Ñ?Û/ò¹p:á?¨GÐ×±?xÜåy-;É?Ék£¡vë?†ÈcñmãÛ?æ×5Ï@í?-éÕtÓ?VYãJæÞ?yÅ®g'à?‚A¸í?®÷gBÀÖï?RDËIâ?®øÐA]vä?<º;¯BÞ?åOÖÐy×î?<‚–!Æ,í?¾½\êÄ?¯Ö¯£ì?f¸{±&ã?°ˆBËì?¿®³(1å? dWе?¨9 ,‚‘Ñ?œN/…½Ëï?@Ñ:zØ€?Lìø¬_"Ò?G 5Ö€Æè?@\õŠOË?¨ŒæÈ æß?BÎŒT¡:ã?aÑDšûé?` s¢?2¥D­é×Ü??/i'MÔê?I5ºÔÏ£é?l _ЭuË?Ø~¯BîÒ´?%ËÇŒªGæ?ç\9¹ÛYå?œÿØÚÐ×?žð¥™F_ï?âs1¦?†ìâeÔ?ü|ø¹YÉ?L "‚rHë?F»G† í?”'Ͳì?°M¯b žÃ?YiMÜÑÀ?žÖk‘ÖÕ?ঠiÌ?È[]FpŽ»?t*´©&ç?¢“iyäGà?Ÿ|ÜÎýì?Jj¥?¨ÕÔ? FÖ¤é?hx?O®Ò?hÍ<%1Â?tŽFêßâ?uÏ%ë?0Ä·R²ª? ÜÔ›Ÿ¼?¢ÂÐ/:ä?·ÉØiZä?ÛAD,ùì?|>aDZ]?~Î0ÙƒÞã?Ù¡V‡íâ?[Y{\âì?&LÓáöß?R 9j¹Ü?°ýôà¼?Žéúñ»–Þ?’Y[kXïÙ?þµ«r\ä?}¼6Ïdá?<ӦެÅ?˲Xj°?†2U#;£í?¨2iGJ‹Í?Xç}–ÂÉç?pÕF„l¥?hŠr)€ôá?¸bòWæié?ÔAOqÖdè?Ó»3Lì?‡·¥Ídí?í2Ì#Ÿ’è?1xJSÁ?Œg¤'²âä?*B½‘ÛêÞ?#Ÿø92é?Ù©1B#æì?|±Ö”ÞÑ?µ4–s7â?è%¡¾Rè?Y33Í[­í?ÌA›fVä?€Ïž‘eÝí?ð0´ˆ7¤­?š"çcb¸ê?ddRî2äÐ?éò1~è?f^z´QÖ?™þøM¶5å?XyG39:ë?¹Ð(TÂè?–Ç-˜Ù×?$ $&=ë?ŸÕâÁõ†ì?sˆÈT@ë?˜ØÖü!¿?°Fü¼‚êÎ?Ô¬dÒ®$Õ?ª ~ÔÀ•ã?œ¢~R‡Û?„ï½¥ Ý?Öʲ=ýÑ?è»cE½˜Ï?Nðç“Ò? %ƒìäŒå?JpàÔìÒ?xÔ)ÍYî?"/ȪiÖ?ôg’ Õ?E÷:é?Ò9Šç Ýë?„ºÀÕ´ŽÁ?0/,f—­?@T#ìç?v«XQeÏë?Pj®Nûžã?H¿ÿI”ëç?à Ÿ¤vú¯?Ö)‰{€ì?ÄH"jÍsÄ?\–°ˆ^©Ð?P’Ô³ŠUÌ?°wÅéö2ä?0oÎÕ®ˆ?¡è‡Ðï?ÚΔn;Gá?â9I5Öì?TL~}|Ç?ÚsI Ûç?\ya7}kÆ?ÒNU¨Fœß?\¨"Ä«ôÀ?ÄÆø’Ãâ?Õ`§€ï?~’çà¼pÑ?|Ê.Ö<é?8º€;:æÞ?Ú¶÷u+uÐ?ߓƖmiè?$ýPí`îê?Ô-µ Ð?ıɀŽZë?)â9Öàâ?KZ#$bàí?ÿîÂ^´â?Ô4„¬‡Ä?U†m&\ùå?%Ë‚ºxã?8‰g á?;feíØÙ?$´õX dÅ?ÎÂuÒØ?þCõµ Þ?¨µ@ÜY±ë?þoÊTèÙ?»˜ûÈÌIç?¨™B°Ñp³?§ßÿº?H„‘Ù˜'Ë?Õf*É?€oßÐ9V¸?D§fBÂ?pßø™¦’¸?Ý_ùLã?´‘[%P×?ΑÜÀ‡? Úhy¶Ç?´}GVSJÊ?QÄ#=c»è?Û‹öÇä?p=« âÌ?칿º?ÀUTÈ-ˆ?lõƃóöÜ?„‡E´ Ð?SØ0nËÏê?`±ˆv8[Ü?2ïýkîÚ?–3¬Üñ½ë?±ý°õ¦Sá?<'ÈâE ß?Šûj•×Õ?!GÆN…å?,ÀÈôÂê?€õ‘Z§Ô?nóö/Æë?“ŒÙáì?¥;Æû¡Åè?ˆI@ÏcÇ?€*$ì‘Ø?ÀBÄ1M¼?Þœ‹°Yæ?h¢rèÞÔ?x˜:>s‚Ð?C Å·ê?ÆÐ¾…ÈÂ?.ߟ/Cä?Ø÷ç iß?úç€7t"Ý?“;Š’1¨è?w]@Öá¼í?Œ‚œ,Ž‹É?tïUotÉÐ?1´¶š‘ì?¢,cùæ?`¹Ž¿×Õ?ÚdG#Øâ?†¨ÕK÷Ö?¼‘ðÎ?¤^>_@ï?bMõJmKå?Ø.pš*ç?èõóèɳì?:¦yf à?¬‚š“ºXË?ð«t×"à?X8èBå?ÜÑ÷8[Äè?¾“Ò!$íí?–A½Ê÷æ?J'¯=Å{Ó?p…]Á‡îÎ?éèßQ4°á?äü³ÏpÏ?D]âïgšã?À­:E•.í?ÖwÅŽòÖ?yîúE™Òë?sôJ7È?['Q”ÈÝà?Hu¼º›É? ×Kï!å?ãÜ4²Gùà?œý æ?Ñhɳé?,Ò‘ØÝÜ?ZjÂÁJšÝ?zØåSÜ?礛þÒ-ã?¼x„›%jË?L‰:Û?º®š^†]Þ?LGBΦ×?d‹oM—»Å?mYæÌ–»?ÜÉ~*Óíã?&^û‡‡Ð?XY¨=:Ë? ÒëÒ”?ÖróÊé?øa ã~¾?Àpw‘yUç?ø¤Îäœí?h¼ UgÔ?µ`R°Í×?ޝëÔë?ø1Ì®¤í?‘¢5µ^Nè?0›,ã)Ô?d·¯ÝÖÁ?D„Í_“jÍ?,_º›t?6äe&Þ?ð*³ï½†¹?`‡¯*Õ¡ª?݆U›×"ç?Ì7ÌF90Æ?džäbé?0\UÒ&Ö?H}2Ä .Ï?Ð=ðÉ »Ü?$z´XZì?n]‹Ê?öAïíâ?/ðd¡ñJî? ^mÙª@¯?€Ã)û_Q­?~ÁÖ@èúÙ?v¶úõSÜ?Jº–渣Ó?³\B—söë?ÍR¤GÙ ï?f®@yZ/â?¥Û‚ñ±¢à?!{4€ƒóà?Œ®èC»è?zÅ[ìvë?® Æëªì?c°÷Ö'mà?'Hú«¡é? M${PÅ?ÃÑ`¿#}æ?¬?NÆ?tJnUžÄ?,ÖÑÖ?:`7ÆÛ?d}QÆ›?ØM‰Ó›½?A;¦MÆá?ÀƒV H!?xY½e/Ì?4wGWØè?`8þp#JÖ?ÓÌ䵪zä?L»ulI>Ù?!l;»)•ï?`ü{~;L–?8#—2ƒÒ?¨ Æaù¿ç?}=—Àæ?íw+7|¥ë?0ÃPBè!Õ?eÌ÷Š‹{è?q€ßÁ0Uã?d×Ôˆ„ê? ª¾·óÄÇ?|uè" $è?Tk"ñÈGÏ?xÎFÍÉ?U¬«•?tTS aá?T] ”…ˆå?VGŠëî?¬SRÏÔÝ?^¢ÓJpÿå?væÂÈmí?|eõ›iÅ?›óþÄÞï?ðçªì%9Ï?¥=cPU»? CgMlÒ?¹t/jÐå?D­Ü;¼Õ?¤Ïa±Í{Ø?†å^´Okå?Êè^xIà?aʳÛ?Ü¡„|“Ì?×l¸díÀî?f6‘ð3Ò?-X@ì™ê?€.U"¢? =E# šï?¼¬†ÿÕ?¹( = ã?ñjÑŸî?÷ê• Çuè?K+¸Ü»ç?œÞÜ>Ï?lô ˜ûâ?’{–’ÅÓ?˜Ÿ‘–ÍÿÓ?ò±VrP¥á?ô±*¦Ô™Ü?D“®ðí?â?è>7æ? Ôî'J@Ä?tÜ)·ÿÇ?µ_åÃ?D>s‚%â?êþ™ï¸sÞ?xQÿ ê?°ÛUOAÞ?OÎQ¾ì?tÚ³áÖ?ˆ” غç?uo0Ìv|ç?ÒM]xUœ¼?ã9¥}ië?°òtl&L¤?2?ºýzØ?N`ß5ë?øÉæGÉ?à'ƒË…?óI¥ié?³ÍMpoì?z;†fhç?ˆ)´‚è©ã?¦„‡+Ö?dcðP:3î?¾ÉÀ`nÝ?œÖݯ¤×?h‘*òµ¼?t¾dC·8å?€B‚­ìa?Pei¾îÖ?ä<ÏbÆ?¬Yæ¸äí?³3KšÒ?Cî<—? ÃÓëK§?ÛØ¼‰&Ê?b$•ÐÓ?Zœ-I,2ç?Çàs‚–ã?/ëÓÁ–"é?Xþætк?Pïž<Î’·?JÏÏ æ×?Lá]¨ZË?$Áö¾?µ»™úDë?`gtÈ¥ï?;³G½ ç?šºùß?.ß--tÈ?71´{7å?æîX/ ×?–É·¢Àí?ñæ1Ôè?Îd/¥Âöà?r‹­ Ü÷ë?àù…úÜà?ÄZXŽÎÓì?œèþöNÝ?V¬#/MíÓ?ð>|·>i´?·… `Hå?¨0˜K àÎ?IˆÖC³uê?`ø˜¤Z›©?¨Ñbî^Ð?žà†ySÞ?‚Í|Ioà? ,W»¦UÃ?-+%—¿é?ß70ÿk_ê?èDÖ ß}Ï?Ò \4kë?RßžÏ:…Ñ?|‘º{Éï?®ˆ>üÍ?WýUé?Z>zÞâ?0<ûŒ¾çí?À n}èû¯?¹T»ªøØâ? «¹’Ë?\¸r«qË?=“§2µã?zH0ÜÜ?q¸›®*eç?ˆ"¯ÓØÎ?»“±AÖ?†ký;Eí?òd¦Éì?þF6ô4ÈÚ?¡DÞ;÷å?Ì9r‚\Ù?Ð f=@?ç?ÎA(0vÞ?ë± yªšà?åäktNÒ?€šS”ßþ¸?Û΃©EÍé?½ ³ºždï?à¦TøûØá?˜ÂtN×Ë?Ь»Ž–Õì?ÂÙf# UÚ?‰£¾È•à?X‘zó0»?‘sq0ñà?ì£ì*Ý¥è?Ôvj¢ßÒÄ?` =ô·Ø?¨…Å7èÌ? ¯8Ó–Ù?ºÉ ( å?hùanÄÑ?0¡ëI<½à?Û6ž™TÆâ?”3:ÜJ Ã?`¸s²_Ê?­` PBeà?@UÅch^?'ø¯ ¦cã?|¢Vˆ¼Ü? ç ô†D?*˜É¨ÖÐ? >ÑX,Ú?` º/ž<ß?4Àø@[üÎ?k¬ƒÿ­îæ?·ñ”oØ?ö_PVEÞ?)~y±ìîî?<¨Îm… ï?.nݦÍï?ç]Px&¡å?Di±  î?¢Á@HŸ½ã?ñZóQÓ(é?Šÿ{d¡úè?ê·.óë?áÄ¥>Hï?ôåh¯îä?é?vÙ˜YU•Ü?>ÐB´{]í?û¸k-¡Ö?W7Áæ¿?T/‡Ò?tݤ¶ºç?ì¡p˜ÖºÈ?8xþà?fÜ.b|9Õ?͉^ÐOãá?NÌ|Ä{Þ?XTr*Ïì?$C]sð.å?@Å#/Yï?˜bbIAâ?•DáG9¸?Âc hÖ×?tŒ´Å?+Ê8æ?Hû‡û‰–æ?bO1VæÞÒ?P…r;Y¡?,úE¢B?é?ìB#FiÖÍ?µßà>¿ƒä?ïcì³âè?\ñãçÒ?ƒ·êÏâ?SO£aÉå?DƒAÍSÍî?Ñ™r?ÉØ?HÕð(Ïw½?šäu\ üã?B§Nm“bÒ?æGT{g‹Ø?¶±‰få?œ 2+-ŒÜ?hÈv6îªß?¦óºßê?)¥f,­è?ìt.N°Æ?+ù†’Qå? ín—¼]Ã?èÿWØTã»?‹˜¹™=î?(£]’‰ÅÒ?ª)îÃ¥å? M•×Eš?r/a¦Ã?P©qy¼s¹?.¶œF>Ó?s7îJê?9õ‡»Ê…ë?žÍM­æ?9FäÌŠ6á?@ â”2›?ΧŽêrñÖ?_ã{eê?㙽Ý`@ì? ÐLR)á?nÃØ5O¡Ñ?¹œx´ á?f‡-¹”?¸/⨳Ù? BDsý‚ß?’]@0õÓ?`í?¬æâ?ŠˆÚ_aXÛ?ähÒ3éÖ?Ì©]‚úã?¬8rÞÖì?ÒbBkéeï?QPÚ?^¹•À¬Öá?ÆgU +Ð?À -k!Æ?‰Ž;á—@è?„“{b¹Ñ?Àž«÷@…?8D§T@¢Ã?]øtm²?¼•ýa–ÊÀ?’~ëßòë?ø ¬:– À?M”xªçê?жMšï ¿?ÐY¾dvÃ?óô+*Tèä?Lºå#öOÉ?ëH¥·é?üíAw~è?»}’ƒ½å?þ5Âè¯vé?üÌs³ ¡å?ܹõ&ƒä?d§—má?Ô' ÔÙÙ?§µbõ_à?¬ÒÜ”ç?yêéÙÈ/æ?@4çE]Γ? f£Gרå?ÕØ2Ù©ì?DÄ‹kïè?¿7¾>ļé?%ãvžždê?°7bÿ$W¢?‚fGÚ×ß?` útOÛ?’_0nî?'’ÙÛÉ%ä?qIjÊté? ôNhî:Ñ?÷ÙCnÌï?«k‰J>{ä?8b~?\òÓ?wJ˜¤í?' juáâ?ž žÖ?ªUÞ Õì?Úé3+­sÑ?-‰èùä?®ã$FÈí?0‰sŽyº?®CG‚lä?/A¯ ê?”güº¡yÜ?|8…¡Ëèë?dþ¯bZÚ?˜³;êÄÜ?"S–3è?”Ëj`Ò? ¢kãºBë?Á_@ÚLŸí?~Δ,”á?Æâß×âï?@}wŒÈÎ?Hn‡T‹ÀÛ?„´ì‚öË?!Á ”æ?8ºC¶‹JÎ?àÖùÐÕœ?õá­€B9è?+ø ¢Ìî?Î<: ‚î?ÚÙh?«ÿß?¬Ç‡±¶Í?øúqùR†é?P¿‘¿ç?c\~*Ùæ?ŽÞ°‹ˆMÕ?)ÆW_z8â?.T]ª2ã?µé¥c}ðï?€hNR°Ù?€#}H×?8J^"sÎê?„ ÁîÎ?í=7Ô0)ç?æ}4 kQä?ÿ“ÈM‘è?Ùò ƒ¸Îç?!à¦Ç¾å?Ѐ¥C€ôÒ?,U]Ž£ê? =TŒ—ß?À'Üîço…?Û©¥1Q¢ë?•Vx¨íä?V?ጠTæ?‹ìÈê?W?Ÿvê?q|è ç?ÉÉÀ9›ë??ñ[oè?E¬-Çã×?í-^Ó¨æï?œt×àáÚ?ýì„e&å?/oˆ+òî?жbëÃJÌ?œvšÑáÅ?Ì[£öÅ?<àÛnŒ3Ñ?$/(í?5Ø´ë–Lé?ÀƼ³ʼn?`Ê5øÛ/?ŽÊpžë?nœÔnÐÝ?€2xåšÅ?Wœ‘£Äãî?Pó…ßÒ?dAŒÉèß?éTmƒzÓá?ØÛݸXâÔ?¸J„UÓ?M\಺ë?L¾%C×DË?‚«Ø´ÒÕ?¬55¾ÆÇ?¼&Ξºzß?G*ñŒcÑ?Cõ„&•å?K,õ?ÀCì?€w5 Yß?–9®¨–Ö?äaLCð\Ç?Íapiÿî?D†zb‰ãã?¹0m£kDâ? {Ñïº?,åL’*Å? ¿b7³?¬û¸ÊÈÊ?hWâ¾Ñeæ? ²(æÍ?øŒG÷+³?ÑéãÞbŽì?æV'ëÔÔ?xÊ·dFã?#â-yí?CHI—“Êã?b’G†¿â?\¹iëAÓë?€R}ÐÙŸÛ?œ>à‚»“È?ÆîÔå?K¹ÄÛÎ?Rná¯0÷Ú?@fEsЬÌ?ºú—Aêã?#]ÝP:æ?©"ͶÄê?Þ?ÔkL.î?<’õí?’(¤6Íç?°Êð˜Cµ?^“e,¶ä?»YÃô×ä?Hòuõ—³?÷êªCòíë?Ö2â¯ú!ç?P’vç}¹æ?`=0POÒ?ˆEÝbÝ?F£\ƒÖ?9ú ¢}â?Òjbò4Ô?·ó½åí?³f!ž‡ã?$jË~»ÖÕ?Ò¥f}T×?øÄLe0Ó?„¹ññ‘é?ë²$ç?x {&j¹?—W•œí?nÏ%EhÓ? ïúÝ î?û•Ãßè?j2MÕ¹yä?Ä]ŽQßÎ?4éd¾ ÀÖ?ùÍ8ȯí?é)h„æî?xT\µ×?ÞÅÇ×ÎÔ?Û(+rØë? "6d5ã?¿”°ÜËå?»L•©óî?èÀN ¯ê?p–·DŽÝ?ë‡kÍê?•"³o} ì?ònu«SÓ?ô!Žô\Ìá?…Õµä?ñÆQñä?j“ÏÕù‹à?=_“'wâ?ˆñRë?| wªÑ¦Ô?L¢¿ÚCÉ?È^?ó–ë?Î’ðo|¾Ò?‰^ˆ‘ ê?›­›e ã?`8G:s˜ ?×P²´"Òç?°·°Š·?¼ŽõWHÈ?1ÓÈk¢àà?Äü¸Ñ?”×·™¶é?ªEžfÚî? K¥ìµ×?¶ >ŸÖkÝ?èÒô4P7í?\ä'sèÂ?MàÙ°ZPæ?-Zx<ã?0$Á-çÑ?;ZÞ?ìÍã?%‘»º1ë?ÐOßš¤?ˆÉÕ?øÜÝ5SÁ? ý7âäœ?l…ÏÃcåÅ?øðüCÕõì?k÷òVÇã?ìx•¹HÃ?m d§ãÊâ?NÚÙ³f!Ú?˜/6¾< Ä?ÅwˆÁ'Ü?f÷žÍÄÑ?P.Áì¤?ê¨ÅeÜ?ðú’9>×è?‚® ‡ÎÚå?°ï7bö#é?eϼkÑ?¨ÌãÙžÅ?,Âo¥‹êØ?±à¶§[|ã?7õï5¾â?»öj€,òâ?lI4ÌäÕ?5Z¶'½ï?û³Ñ gç?ÀžùKàÚ«?¸ãGÅüÒ?Êòl€Ø?w¨¨½Î¬ã?ÀoÞ­?–‰]Nðê?fn(`£Ÿç?–¥Žä:%Ñ?H©@€LÏ?Ÿ¡šÀ3î?´ÝV³Â½Ú?6#-ï=ì?hÃXд é?€hAO K?Þz€#hrê?‚Í›K é?[‘l™wËë?,þƒ„,é?@g)ƒ?ŽØ?X~¾Õ}Ó?a‚råê?`˜ ïÃÆÓ?GÊè?žJÐÉ<—Õ?~,·ÓØ?×Ç©5qâ?àéñ»½†•?Ð? ?8Õ¡?èvÓ®T¼?øgÂ71Ó?¶ˆ¼ˆPå?t–]¥¾Ï?¾­“áë?´×¬ÜŸ?P ¬V´ ?Ì»z=¾¦í?ËÃ`±ìÒ?ïNN¿Rï?ŒêRUkÙ?S÷×vVÛã? ß*ÐíÄì?8qž½RxÞ?ëU'–í?hõu‚;N²?˜@-‘ªØÐ?ΫÞÚ?Ž˜W³šá?žªš]/×Ö?¦µdƸÑ?DFÌH@)Ã?V(®ýDÚ?ˆõÎ „ï?l.õ°qå? ÀlÊ6òÔ?$9Im „Ç?ßà,‡›Éä?2„˜¶å?ðS ä³?¬è¥×žÇ?pÜ óÿá?×?ÊÐï?¥àKxÉaã?`Yš—°?âžwÃô î?h&‚®hè?(÷ÍãžÂ?×èGnCì?ˆ8™Q„?Õ?æ™ÍíH×?£ã,EýZé?éu ëÆ à?çºÎé-Jâ?lÁür‰·Å?ÐÍ*ŠôQÈ?x`‰˜3¼?„2ˆ„$í?5ËóLì?î|=µÑ|Õ?ö>ü²<Äá?å<ïXyï?Jÿ½¦Nã? Ð©í¨aæ?êÒRd<“ë?Š&¥ yþà?ØÁÞÀ³}Ý?Ø(˜“kë?Ud¬[wŠï?À!ýb?­Oémà?€ &I£?¶pq>†MÖ?œQãZÉï?œtL¦žÞ?!û\énÎá?.Õ¬+«ì?h.‡:ã?^Èlï7:Ñ?ŠŒþ龿? GÃ{Ù’Ñ?¶óYô'•Ð? Ð—Ë?|GQxvÑ?{¯.u‘î?ೂSËê˜?Ç£³ï¿ï?ŒÛK¥Úøì?@„YÇ]ü˜?[ó×£›/î?ž:{-mÛß?ß…6ú;ç?{<»p“±ã?™G´dw?C¡Î1ƒ:ï?xw忏o°?ä²uPÏ? fUf2É?) Ê eå?XñÛ®){Ð?ù’ÓKÐã?X<*ª™ß?êÚÙ†Ý?È órãeØ?{UöÚwðâ?Xûé’ŸÏ?PÂÕÈä=â?¶®ò—ë?\ªä1‡.Õ?ÌPaž¯Ñ?ÄYkfGÜÖ?*Ç (¹Lã?:_—‰DÃë?4€KOÙ|Û?„U„¶tªé?p e¾&½Ä?(ãœ*u„Ý?µœÓAâÐ?²Šüê?cÇsŸr.â?øYäÇc*Ý? ¼IÈ?ßk¶à¾«î?,M¹kÍ2æ?lÚf5‚Á?ྦྷV}Å?³ã´¸ƒwã?&BU7aØÚ?™¸¶à–ã?wÞ ×þç? œ¹¿â?€€ ®å<»?€®5¡ôoË?°Ô€£èÈ?* ±¨Ó?`?iH+7¿?UÚ 2Jºà?pk2—Sõµ?¨üTîŸOÒ?Ïu Ýcoì?­@ÁÞºë?·¥Ä î?Ü*>Ê?˜¦¢Çï?ÜßwÙaé?ÐoŒP îÝ? f•¡˜7ï?:|ÏS‚Øè?íÁžÆÄá?j½6 â?Ù·ÐÍØ–ì?Þ¬œÄ?üÃy†<Ç?k{¼¦måã?HN2ìò?á­|a»å?pá(ç£ýÞ?ëÇB¥5Ò?ðªÏ¨?Ü¡–ú}‹ß?Œ)û k¶Ó?‚îW~îMë?ØÈàèåß?$ L ?wì?èÞË`¡…È?¸U'Èê³ê?M‚ßçóí?™òÞºiå?€ûØ4—ò”?¦,î¥@&ë?X6¼û¦ê?êKÛà§Ñ?¾û£ *QÔ?{?—`˜á?UÒ¾Ô£è?;Âíóâ?‘æã–ê?v¿ÌúCsÐ?Ú>—,æ?ktpWCzí?`ØÜ=´’?7p%ÂZâ?»Î vó±ê?†ûl;ÁÊì?l~1¦³?>•þn?̧¡Ô>Šà?úÒé´©Ð?ü…+Šk8ï?h5…ÇŸÞæ?À™'2¼áÛ?1ˆQ$îê?òšv*•Ö?ñ š‡¥ê?h7í—…Ä?Ö’“M‘%×?–Mç=\Üà?»©Ø ì?’[\íœ8Ô?S3øj´ç?0¹~(}À?ð¥»"âÐ?åž÷Ÿ]ê?Ì ùnšã?4Ö¾&bFÜ?€ ovÕL ?P¸2©ß?õF–Ùæ?d’ò™~óç?ÔO^â©Ô?ž¢/Ú?I±¨ ñÔ?eSÃùµ0â?¼<éÍRwÊ?>ÜC]GÒá?-X¨5ð^ï?†G² ƒaÛ?½:ÛHìá?¤}Ÿß`Ö?PeîÓ îÈ?ÂæS™ÞÕ?Â(û“ûå?jTÐ…‰Ù?øô’øæ¾?Z‘ÇW4á?ˆ˜IÄÃÛº?mBa—á"ê?®sXbDç?Hê>à :?žP>oIå?\áÊÅå?P°ZCâµ?¼§^H*â?Û´ÿõ±&è?M–É_Uâ?D]@2Ÿ¶Ã?¨ßäµx1Ú?,/ïxÞ?÷j)ï?Ëð)=ë?BÊ@ŸÓ¥ï?ܤS,Æ”é?$¬7V«Í?ÈS®>Ó»Û?P¿å÷6Ã?)ps£†{á?ˆi©{jÂ?óܸ®Ëä?ÀèÖ ¥ŠÝ?0®GòhW°?õ2 Ù?p¬»!Tµ?ºÙ1hÚÔ?çÞ¡áT›á?Èù"ïåG×? ñ$%èç?¯§Øulâ?Efè Ú?ö¤S:qMá?i‚‚oï?Èa僾±?bSv5™ã?覗:¹©±?¼Ip¡fß?àÆ(ë¿ Ü?à%_`m¡£?‘Ê÷YÆ›ã?Nõ´àï Ý?0E oä?ãTçîî?ô-I""°Î?“ý8§g â?ä?%»VÑ?äÃoÔ¿àå?ï?P´Y½æ?VÉó.QÄ?8av…˜pá?6´ÛU7ËÒ?Òª*Ë‹hÝ?Yy×÷ïë?ãïv°tíá?ÀÌǧ•»À?!¸Æê?E 2Ñó€î?.0pàÂ?”<ËL Ò?hÌï&Ì?Pù!sØéï?ñ¼µÅÅì?ć<,oˆç?¢]PM±è?dT¨1GåÇ?c#œ”ï?maëÛ?˜§…Tüâ?(¬0Mf|Ç?pxã#‡0ì?ºÌ–,é×?ÃŒØæè?ŠÃa0w9â?àᵉ°dÝ?STŠ„Rä?›–¹-˜‹á?¬¸cï?Eê}6¦å?îìô®múÖ?Túôq\°Ç?ÔÇWð¢Å?³øƒPöÒî?’ º²aî?²Ïëq?0æ-¡öÐ? ¦9M£È?0Š‚‚³,º?(…pÅ ¾?XóȤw<Ë?Ë—Â)”Çà?í?øeðæ?àçiæë?På™QÒ4ì?óaýD¿>ï?n*ïSí?2ùX$ΤÙ?V<ÇÛÖKâ?fC.ûDØ?1¹úÈÆç?l'Kf”Ò?pýœ‘` Ø?Á+]óá?¶'CÿrÒ?f&ä½!BÞ?˜ÎöY¦±?ªEŠ…jØ?ðmp þÏÌ?ÄŠPÖBðÂ? …ómFë?„‹ÙMAYÙ?âh¹U“Ð?*P[ÕHŸè?ÌjË.®¿Û?÷3{ÿpÞ?bèG‡º¬Ñ?0âÃå)«?àq£Gî?ÔD˜i<¸Í?`h¢²ÄiÀ?›ÙµÅæ?V8,šÈ?ÞÊÃVB×?e ïMFRí?1|µ–s*à?BœÓ)\›ì?¸>h6Îjµ?ú¢)çÌÙ?òª~œ@2ß?†fö¥ðêß?D¯7[5Õ?,ÚË´Ó?½Âr—Wã?ž€QâÛ?˜³«ò€Ò?òNæ¥@ŸÔ?_q”Š.ï?Æ<ĵ(œà?àøù©3¦?Ɉµ5å?&uÌ© ç?V3áTƒ×?o— 9è?ȃƒ]ñè?÷ÎDÐéë?V¤Y48ä?Ü•*¹#Ú?öA ügá?°Y𠉝? ÎJÄÆ°?ÑÞM{ãeä?œ¥Ž·E~Î?zæÒ­ÅÝ?Ê$ýã?´1‡¸$Ê?GÈr‰Õï?ðóǨ¼GÇ?& Xç×Þ?„#ú±µ ì?ÎÙÏèãHæ?l—ßôpË?<Òï§„›Ú?6 Mi§‘â?DÔÌ´ºÄ?`ß]ãfl¥?B.H†gì?þôèÈ”Õ?óèiFÒÃå?¹ÀÀf|ã?iLK¿ŸØê? MÛj*C–? Øhy¤?ËOHíç?ö‹Ã|šêÒ?ÀÇK»OL¶? ʲOÓá?‰Ð³’ñá?Þw—»|Eà?aéÔ‚°uç?U'Œ ›¾?Ro©ª¶Ö?ã•ÎÚÕ{è?Àôw¸´í?^HåV×?è'Y ÇY¿?°ïÃ?à¸õO§?£¹4sº<é?JƒàÛ0ã?葆qá?,~íÞ.Á?¾ÆTŠK#ß?t–¡ ë?$þµQÜÑ?À ÊËàœ?õ¾~q›Cï?w½Ó::Û?„Ö•î+jß?à¾iZòêÛ?4ÖŽ1{ê?;|B“\î?ƺ§ì1bê?8ÿ覞 ß?J,ФxDß?Êþþkí?PBÌh¬ŠÙ?¼×Î…Ã?™°(åzâå?Ê+üRŸ:ã?õ¤Ýó•9ë?úƒ[«¹æ?TÅ{|Ä?=}R°ä?ôˆsZ""é?_· á?Åæ“}qà?äŸ&ßóþÃ?¨¤^çÙ$È?þ·°ä¯Ù? ’9Õ/<ì?òú+ÑÔÞ?é™5(p†ç?èn}ŠêÜ?†µÜÚ’ÍÖ?$Òý`]Á?jÊüleYã?T@ºUlä?•\CÄÐ? -þIì?dn!Jä?j_¢õ»è?,TZVûÐ?°¼¾Ó¨ï?¬Á‘#€£à?øqPÍÿ[Å?`õX;#Ô?žEXO>€Ô?˜ÂCÉ¿Uà?c†å6“î?è€\f)Ã?í¼ü¨påí?8îø“±à?IÈFúí?Í¢´æì?`Ãwòàã?úø¿¿Óæ?*Â…ž¼JÛ?"$¯’zä?JÛpÈøØ?>PsA«”â?ÀT ;k¾¡?⯛¦.Ü? AÓa:>ç?àžm´ ›?Ý`P …$é?`í£q¼PÌ?P½xX:’Ì?œ¥¤UÎâÂ?oO>ÁEï?œ3Ëdu¨î?L±å…¶á?>J™>Ú?=ƒC–[â?ª¾ú1¨“å?N'x¦Ö?À|dCã?NÆ ©UEà?P%dz{%«?¦ì1ÄÒ?*ž›F¤Ô?ЮˆÖߌ¨?b‹£ëä?~A'• Ð?`Y!~ €—?T $Ôb?XÂŽ©€ÍÊ?´G¢˜½È?Qd¾ß?Êá?jgú(2\ê?;¬žÎ?\rP30×?³Æ³¹Ç±à?l1:ü˜ß? ·jà?ß=I°UÞ?#ŽÖ!Wá?xn8º[x³?w%. ˜ê?°ÅaË?ÅÝ?G¦V½ì}ã?^–NìÙ?ªF'ÆÏŠ?óaPå?À_/$¹?,[.¯Âä?Ƚ§SGâ?¦Ë€/¨Ô?¸h_Æí?ætYº2ÁÚ?Ér¹ÿHè?ý·½nÐ?D·‚êx…Ï?ÒKÝ?°`d³LÌ?G}Z3öæ?O|WZÇÛç?Øœ?ñ{Øä?t{AÉ«Ê?À  ‹ï?bŠÁö\ë?%»Ð?av±Wã?¼ Îícå? 7©Ly8¼?º(›häì? Ÿs¯ƒ’? ¸ =Ï×ë?ÛT°Óã?p`üæùư?Ècšq¾?Bo±bËå?0’ºG×Ã?øÝî?@C¥ÂµXÈ?³ ’T¡ì?nrš/ÿê?a,6åvâ?Xó‚±Sqé?‡ôuGº5æ? äæDA½?x—ÄœøOÕ?Xø¶èA±?ÇÄ;÷Õ?ÆN(7æ?¦¨žúš\ê?^÷eõ4Äî?§b dá?Àˆ TC(ª?ivÇ$ž7á?Àv|MÈZµ?° ¼K¬Uæ?(CŒ9×C?DÛˆàë*Õ?€¶••»Ïz?5¥Í—S÷ã?PÝýøÒè¥?êäÖò ì?øU.xòâ?peg²jæ?kåË¿ýî?ö“ü—ßÖ?²°\¥Ò?`X¼o~ä?@êvÔÕÈ?¤è+1á?RüË +¨?Ú¦æJH`ë?Àæ¨kׂ?­|æ³vç?z´\è?XÅ6ì¹4»?ÝÑ„¶Øè?¶ýEÿ¯Ü?œ9„Ië“Ù?§‡pDñòç?0¿ÜÆòý£?š¯¿‡¨í?É_:_è?0úŠÎ”¤?L™]×+NÓ?ÌšAõLKÆ?Nš=ÂYÐ? €óFyع?`¿ü ów½?÷`+Óxî?©Û[Ê¥í?Þ"÷·`Ü?¨¸”nÎ?ÀÉØÇÈšã?"cuèäçÒ?ìªÈçIœÄ?Çñ2æ–Ë?|&Ìxß?§lY›Úâ?D9¸pdë?ÞŽåUóòç?hè·˜”¶Ð?vW_B¢ä?°Ž`ªHï?ëì-™õ9ã?.Éœs=kÖ?G™—Á¬ï?äõr׸ß??Úïè\úî?€ë&äÌ?ÀÞ€~«ì?ó@p-Î?°šòc‘ª? TTS~ª?!²z;1{ï?Nb½o~?b4B?ؼÜ?\w5ì\IÔ?æÄü)ºé?qf€T3æ?œy¦ Á?ýº.vÚ?¾ìü;‘fÝ?LJ”Á½À? ðÏN-Ó? B , «±?¼sAZµÛ?ÀðëÃËH„?vòwh.Ô?üQù¾#çå?¼à˜ÅÒòÂ?jª¸L4žè?#ÁÉ·ÔÜç?$ƒÆ—E{î?¦KÇŒÀ?¶5˜:4³Ú?ã†R¼jë?L¯Ô¿÷à?Ïõh°Œ‡è? «¥«Aè?øÕfã¢ÅÒ?àµ÷ˆë…š?lJ£G?àž´k[1¹?K-,@2¼è?Æ #±±¼é?4¾_ÐÐÛï?àï|Oê?à4çC¦Á¼?®ýed@—Ü?lÓDœì?SŒ,`Egå?VSæ¯ÄÒ?Èâ6ŸÏ?gB̧á?{à'ú òì?à}Ë>¹Ö?Ä*«9Õ?ùkénY—å?p9Y?’#?x4tû-Câ?XçŠeGÛ?(¨'»3á?J¿µÒ}ÛÒ?j’b—ÁÕ?LÏ龘ê?湸ÀÕá?‹®ÌÉéë?PTN+꽨?ܘ”­ŠAÆ?VÂaˆI¸à?Ê BKä?d¾å(‹Ú?îðm}n'î?R“Ù&qÚ?Ƀ78ò“ä?¬zÆÆº×?Æ4…õå Ú?ª{õäÑ?á÷ýqÎí?gŽmlЂå?d2cí¹Ó?ŒÚ“šÍá?{¬T¢’ûå?¤=!×:å?ICl°È?XRdbj²¶?lQúíeXË?«›Ç4já?x•ú:æ?&qЗnÛ?Ý3 ÖÁ¶î? âDòÈ?à¤và@Iá?\;0é?ÐËöεÞ?@Ü#°Ö»?oIðuÉë? é´5sÝ?µ¨q“ç?8 5‰ŸÄ?&û\û¦Ù?T¤ ”vÏ?›½ÄŽDå?É<åÁa¨ç?žw€ºöÐ?¼¼ZèÃ?åKóË-ê?­ÍØÔÍ?'À·ÒÝï?û†àÜwî?ËÀ;Aã?åBêjæµí?´¯K’*åã?1ùösà?ìþq] Ã?x\ÉmQÅ?ˆ¬19Úž¹?ø¼B0Û?¨*2Í—ß?}rÓðà‡á?“ƾjbã?ÚÞšgÜ?š?ŸÝ«ÙÑ?/SÎÛyûâ?@%¢y¯œ×?èz–iÌ?á(¹—¶à?¼«]ÞÊÄ?¹…$Ô?7×lcë? L¿<2Ä?¼¾Ài1ãÀ?ž}ˆ§NFÖ?PNé눪Õ?¤›Ç™-Û?Œ×øioÌ?€–9ebÏÚ?>‹ÍbœTÚ?#ܺ…Õé?3_‰¡Ž[æ?…¸ÏÝ Ñ?´Ÿ&ÔÄ?à½a\‚d¾?¨¦¯é@Ûº?öÜ\–FÂæ?ÐRÙq;dÙ?ò &é?-3•—MÅ? «&ÅÑ?i0_RZ8æ?°ª+z-}Æ?téæàaÕ?Ø”Êí9þÅ?Ð_ÔFxAÏ?:öÔ¹á?ÀÚÕT¸÷Ú?N!ñÇ,ÔØ?´¡"èÝÕÝ? rõ¿³Uä?†Ô0°XV×? DÐA’=—?y\Љ†Ðã?` ´å´ »?¬F¢VÞ?Î)ʰÞ?ÊÙ»õq0ä?׸_îWé?Ø|ÝÐ0Tæ?@©YÄf¹?¼<&8iÍ?@òPdn§©?pz§Ý‚½?ÈÑÙÝÀ?dwv”_ã?À}$À¾ÄÃ?"îó ÉjÛ?,Þy$× à?×KòŽé?8ü¶C!YÂ?„ €€å?YÒ¿§|Ýé?JüØ ‡ã?äÇõö®Ëã?hÿØ$Á?„ÆÃÈïòÀ? Â ªß©à?œÅ—qyóã?¨¸@ §Åë?p+êYJxÞ?ЖðÜóý¾?¨ÿ¶vnYË?^ÒS]ãí?#ÁÝqŸí?¸âZMÁåë?ê­ pZ¶Ù?=ÎÌï?ÔO†d¿YÜ?ìÿèádä?àBTÂN¼Í?ù`›ÝK¡ç?ùÀ?ôÐ${åÍ?w°†Bïê?~§„‹@©ß?‚z&' @Ñ?¼þœ>YœÖ?@_X£W3â?@ä˜ò§¯?Ö$²x¾î?$ÆŒ8OÐ?ÞÙ6¤oƒè? °â dÏÍ?ŸêhùäÍ?ÓfiœÝ5ä?ñé€n? ÎŒÃTZë?¥ëºÛu?áöñÈï¢ä?ËíŒî?°ûµÚvvà?ÔlE3Þ?€W_—j”Ë?è¡#cõ±?ìŸs8@$Þ?@½3R‰?z]{{4ï?EÊ¥S¶g?Ö­ŽÔç¦à?{Mæe“áà?z d¼Ïyà?`y–Yˆ‚Ÿ?t o^Pá?ø&<ò8?P‘›ë×­?zíi+:vÚ?5÷÷èî?€íÝþ¢Ê•?T—TÙa=Â?àçÚJvÒ?¤\gGEaÈ?…ºŒ-Þã?uÓÕFXä?ŠT£ ¶Ù?L âüU÷É?» +¨(}ç?­³gà3ë?þ3Æk'áë?(äþ‡6À?2”3ô‰VÞ?f~¬ ã?NaÇ NÑÑ?8˜^bŽm½?¡‹Ÿ¦¯ðà?`÷0°J„“?¤a]ª ê?Lå!3Ä?Z( œ]Bí? O/@&Ð?Èk(G6Ø¿?T ¼-9”Ý?ºÅÊyRùî?gâKâçà?;„¼‹è?øRÝ£ÊÙ?µŸñÈbè?$ªwuÚ?Œ·¦sà?*¶B&~Ø?­ÿ*©Oví?BÛ ß„Ö?îÆÆÓŠÕ?`ß`^ÍòÇ?ƒÚHóб?¢n¨òèáÓ?¢ Ôýº?÷”Ö‰lŒã?üe¤Û´¾É?>›ÃOEæ?zÑÃ]Qß?óc\ß<Éê?€mqj¢/˜?{ùgB.¥ê?â¶Œ^¾2Ô?.ÖÍiEì?¤$’S<Ü?êx”Tר?LÙ¦¤ ªÔ?$ÓoÑ;5À?€X©!'¢œ?NÏ–Ëô`æ?ƒ'E÷*å?®Î£ØÚí?ØN‰p:ï?HWFÞÒì?´&ÙföÇ?VþgªÏëá? #œR%°¨?¸3Ój1!Þ?×ã""á?EìâTÉï?.û²Ë;KÝ?lš8ýnÖ?0ÙðCUØë?FÄ\•’ªí?¶ÇNœÛ¹Ò?Ë.ì)Ÿœë?$‘ÑGÃï?–W5ØyÄ?aQ?ôî?9h`Îä?¨°#SÎо?ð £ÏÊá?s©Ôè¦ë?è.¶úç?i©¯èà4ê?psA%˜¢Ü?jK>iChÞ?X? ,YzÒ? E±B„Bà?Îhr÷íÚÐ?|Ó-=‚ׯ?R”ndmÛ?bm›@á?äûŸ˜ùÊá?jSàŠÙé?dû¤‚bRÏ?I¤ bbë?ˆÇåä¤ä?C¥“Ãá?4:a·r? y•ï?¸Yú]»Ë?NØÕl:ô×?¸‚ˆ[·!×?0 :@´?ñÐ= ®Ãï?¨1¨Ukî?Ò'°‹å?Üé‚¿Ý?`¥ŽÌné?ŸbüëîÛ?€š-œø¢?gbÒŒ=Ùå?@Ë•WÛ…²?,ÅÑbO°ë?°òã=%«¿?Œ¯”nÑSÓ?aC¹Ûl9â?pžD•µ?øYá×ÉÔ?-H¼ @$ä?°zøZÆÝ?BßkÜjï?¿ÿV×¥?tévÖùõÁ?€Õ0›zÛ?p·ÜÿÈÎ?òAY*ï?ñ^­é8í?Qš ¡ é? B~œªÒ?ég1A¼¸å?NÛ”\Ö{Ó?¢†Ê˜è"ì?\˜*ñÒ?Lÿ¢@ú•à?„@âí`Ä?[„êN@Î?hГ—ÉAÎ?ÁFŸ?…¤à?©1“·:é?­ÛÔyï?âÆÄÔ”=å?¼j™–fÛ?ÔOø@PkÔ?xÁÏF¢º?PúeqÝ?­<¶Kâé?¬ioÏÙ©ã?Îí¬“Áä?íû/p¨ê?|7`Erä?‚Á‡gˆüî?½-A€¬?$áHF¦Î?]²h<Üå?À–(¹ìà?x¬ÐÙ¶Ì?ÚqÒ€¥­Õ?&úy¦ÿé?O«x¡æ?´P§œŽ$ï?¤Þecj÷é?˜c½ßFå?~Èí§Ö?¬NíW7gæ?j`¢Ö?Ë¡–5ê?”ÄXNÓ?@ààÂÒ—ß?ðѹ |á?ŒCFõåfÈ?àk~Š~¢?Ea-üæ?rr+v¤Õ?vÐDEˆ è?ðÉ|.iüÍ?8ñä9”bÀ?Í\Ï™Û?àÙ‘$õ›Ç?JÌèðXß?Ô!‚ !Ä?jÖ–šýMç?Ø íHØå·?耕;í?䙣(’Â?’üFý-Û?Ñ³Š™ê3æ?(ÏhNÊI½?þ&%Sá?`gQb aÂ?žFV¸Rè?Ô»³\úvå?þŒ·eÚé?Öˆ˜›ü–à?¬s^ÏÄ?BÆmî–Ò?˜^U€í? \y÷ëé?Ÿø3`î?ï(/oÓï?ˆAt“ܽÈ?‰Ò8îté?ºì’•Ëžë?¸tõNeÛ?qoXÜäà?Šv ­ñãÖ?iþFO« ã?Œ¤Æ¶3œÕ?8q,ܾ¹?‘× àYï?ý~}~<„ã?„Ð&,#òÃ?úe£Ë€?Ð?*¢¼Õ¹?*ÕqÒò¨ï?r‰ÖJÓë?à9$¶¥?™“Üíœîè?ÔùrCÄ»á?m6ÒÈ®ë?¬æÒ˜â?«Öç×?øºCε@Î?ÔdÎ|3ã?õ Öí9Qâ?½ä.RÏÊà?ZÂ¥¥!4ï?€$H§é?]ßÐ^²Àã?¤Æ5ÃUSÑ?þG:rå?b÷ÉÈ?ñIÈÖÅë? ]Þ8”X™?™Hù‚Ûèë?fl ÈŠ‹â?ns%j½´Ø? ‹ZÐç?ÆÎ¹\` Ü?äžžœîžÉ?¸Å+=Þ¾º?’ÓW’Bøî?v±uIÞÓ?ÑNnÀã?D‘ÇG…Õï?+’u-˜á?žfµQšë?‘Ä.6ç?øt­¯áż?ºá½›¸Õ?…еå¢@ë?oWÃõ²Ðã?®@## Þ?T¸ÚNùä?ò6F£žÙ?¨Ÿ*ï»å·?Ÿ[Í·¯Ô?:âw¯¬Õ?k‘—úæ?`öW1ºñº?€K¶/Eâ? 7ôúËäè?UѶHTì?h‹¿!œ³? HÅ?`~qGfë?ÂÔªelÐ?¬h¯úéÅ?`¢r}Ù?ý˜“Ä@øå?ºl /bÚ?è;ÑR¶\·??*+# ?ù¼6iÐå?׎úï$ï?ņÌåÌŸë?Ùв)ä?ð8{@5ˆ¶?Ö‹+WŸ…Ó?H¤%¢ÐÉ?¢»ù‘¶ë?Д®S:pÅ?ØØ4…å?ÿ·~åGùá?tÿUV/aï? ÷²E—Ò?¦1ˆ”ßà?öÀ è-©Ô?j7‰uâ?9]Ò$è?) k¦í?>— È©ŸÙ?¹v' ®æ?ó"¸î%ä?¸lœîðÕÐ?L”õt Â? ãXsëêå?¢=¤cò¦ì?Aùˆ§aå?ŸHàö_ê?Ș˜<•ÍÊ?¨ÙРŸ}Í?tàq6šÐ?ªLw &KÛ?-ê0`Xï?šßï°&Úï?nÞÿå+àê?nGälÁ?˜ï ©ÑÖ?Ð3œ[@ÙÎ?Å@Ï3JIì?Þg-×ÊÒ?<\Uñä?Òšëþ·Õ?[ïG¶Úê?ëÜ'¢I î?ºÆ©ÎÖ?û7XEè?èw´#e<Ô?'ãÎæŠÚ?ð6÷0@+Ï?‚W7(®ê?Pðr¢µ{ã?ãmÏ¢å?†æe¾ÚyÐ?¨„¥Ù¸?à¼n©œÌç?þKý¼ºkÙ?ݹèÏÁé?1(~¸Àã?HÛÌC\·?DâÙV²É?ÐÓ·ÕuÚ?K5×Bßûá?ÀÝoœ“˜?0 „0ícî?œ’º>÷Á?a'✇Ù?2÷Ü×?™“êRwÄã?†‰2¸Ø×?'` Ü4òï?¨°315èí?à¥j¾ÀËÔ?0i‹Ú?ȹ$æeº?hHÁ»ˆL¾?N G;:¹ß?ÒF>†Á–Ö?ÆYÓÈ7¾é?æ­FTòùí?@\¦ËÇ»?ñ8Ýkßé?<XŠa”È?¼¥ñ¤æ?;Ô ö‘Ú?h,pBÐ?À#·Þ °?ü].M­ë?XßËŽÝ´?v)&EòÓ? ¤Ÿ—ÿw×?7ˆƒ6nÞâ?ñBZ½zè?øÉ[¼²?AN¯t¦ë?Š%‘‘„ß?H­Áf9¸Ø?‹iÜéÜ?€Q0&œÀ?Òª´°Š×?€÷0¤à?¬Ýýo,é?2ý·boø×?P«% û¥?^Ü’¡'Òé?ðˆI&"ìä?ú'š.gÖ?Èã²¾?èÂþ¤EÂ?ðuÕóyÃî?šË@>oá?@þÎ'нç?èÜÄR Ä?¥`(sì?3Dë´â?wUÊÃÿê?0 B¿ò©? ›øÕ8ï?5F‚©›£á?f“3MèÜ?LH2Áã?.7vzå?ªüÙ Ñå?l¥~UË?4€à óAÀ?„ÛN¶éé?b±_âLƒî?“ %£µ=ç?ÀÓ¶´¢É?^0·­ðå?Úf —‰BÚ?Ú*bç?`²‘/ØÊ?uàn TEê?U>Ëå?ñÃü¢§ì?Ç×xiOœì?ôFÁË~WÄ?«ŒÃp<éá?VЩœÍì?LI@ ÙbË?úÔ,|4×?ˆ«û‰/á¼?\nåJâ?Pw ¨í›¡?n„ U8âí?ï[+Ãmžä?Ðh£ªABÀ?¸rApS*¶?Ú,iÏÔ?lMŸâ?H§›"o0¼?Ž®ò«ÚÊë?àKaÈU²?w]抿ï?C¿¯ÇÍ?ÎóÇ«ÊûÚ?ðR]¬û Ø?¸¡“àǰ?º$Lúé£Ó? •TõI,Ú?LR¿k/â?0V×ÖT»î?€ŸÓ3’?r°ºiï?ÆËÛÔÔ?Q FžÃÐé?t†Æëñ€Ë?\ãB€²ÈÂ? s²¹Šcç?TÝý£êaà?î@O6cÓ?îæ9y™Ò?ôêt^°ÊÕ?ðƨÑ' ß?îcÓ ¡?>¿ßÉfMÖ?DdÊ-Eí?·ÖÌËá?û~Ð?@…ܹE?¬x&ñÊìÉ?ʇP<ÌûÛ?lž»~C#Ò??Gñø,Áæ?؇(É ÚÝ?\ãñKú{ë?ý†F¦œî?ƒ±¶ûKÑ?DÌ*8ÂÞ?0Y ñçÍá?lz‘žÞ@î?qÀ^q¸ã?•ÖQ°Bä?Bî3Ö‰¯Ñ?âÇ ü•Ú?Ê¡$Žæ]Ñ? jóÿ˜,¨?À1  øþÙ?L&ì$UBî?Od6ªaa?'!zÎU&ì?…ûë}‰òê?ºÄ´ƒ¸YÔ? 9çâZ‰Æ?…2Aô'ä?Â6 dr«?æ—™ç0ë?|wÿBüë?@}˜¿÷Þ?t4èŹßÜ?°_Å eÁ?FßÌØ;nî?ðlÙཊ?Pçdžåí?ˆÉÐúŽeÙ? ¾„—.å?à¸ãȬè?X˜­0§ƒâ?Þà Ì¢è?“ÆÔ»GÒ?x߬ìî–Ï?Ò½û0Ù?ð^Ñ.Î?zÇ[ M`ê?¶ü+¾¾Ò?é MYOë?··â–>î?œ —LøÄ?|‰xMj¨á?ÐÌÒy;²?’¨¢ä1Zé?ddŒYèÇ?¶ÈØÚ$Ô?ž¼Ç¾õë?¶¯û.BAæ?â–œùŠî?lVI½ Ê?޾?ncé?wôØPÀ‘ã?üúß×!qé?{çl ±ã? |ϾÊÚ–?6j4‰ËÚ?…!7~@Ãê?ˆUaµ”'í?»æIž½Ší?l‘ãO–ß?ø_€€×ç?"èÔ°}ùÜ? Ú±—¿ Û?,§K¨wâ?”°¯.<Ø?9yå·ç?[êÐíI á?Ö ~‘9SÓ?Û‡¦˜ùã? Æ·øª?Ü‚ž½ÔÚ?r¯OoèHæ?>ÒÙ#Œ;ã? ®éi‰kê??y­rY‡ç?ãàݤÃã?H« q È?BØ8_-Ø?Üò÷T#4é?{=¿I‚¡æ?¸A'CÄ.Ê?J]­[6Né?iÑ;åêè?T`‡à›%ë?|ˆ`ÜÞ Û?ïÜpšiæ?@ß,‡©Õ?û(N^òöî?²™ô|^ùØ? Ž?Ï*ü?¸ßôv›Cì?|a÷i{Á?,^gìØÐ?àY©f–÷å?X{9ÚIë?8uùXè?êŽ%ì?H_Ç2xÇ?â³½o¼}Ó?®âìò—(Ü?Fª= sÓë?òC‘Ðï?VrU$Xë?5#[CLî?Žžòp$$Ò?d\&.ââ?à‡L¬_ì?‡&—|ää?™ƒÃD>ë?PA=ª(ªÐ?¢#`ï uÒ?‰ì2ºGè?ȯñœF†à?è¿ÉÚ¤×?Á äIý¶?×]Å£?ã?0Ÿ³:æ?[‰Ÿôñê?íµ.^á?<ÈtgÛÉ?ÒÛÒø‹'ï?Ô™Mˆ©^×?Aó®½?ï?ÔqØ[÷øÀ?xºóE¹? }p!Ÿæ? ß•5Êß?Èdöÿ5ÖÊ?ìåóà?µñ6Æÿtá?š ,ü–?„M Ä?ö‡âØÕ?ÿ ‹µá?Éú®ƒ…Àá?’ÌËðõæ?«e÷ûh¾é?ìí"BÓá?’­ÖWšÕ?Øo¥n)(ê?ÞqcqïÕ?ÂWbTWáÚ?Ìa< =Ò?¬šH÷î?‘1ÐûÃÅè?N/ÃüÓ?Dz+*Œé?ûM4¡Î@ê?¾@K¬ŸÕ?Dûbb=PÎ?¨”K†·?^Õjñì¡Ý?XÅ7³‘µ?šË«0p|Ü?E%u¨µè?ËÈy•Ââ?tý 7J„å?1Ê »9nä?ÃÌg©¡ï?P¿ ÃêÁ?+á}]zzâ?ÔáýJæ¶Ã?¦TÅÓšã?à}Ëú.¼¨?Ò—YNÿÿà?†Ö“\¤Ô? Ÿ¶¯%¤?ͲúÅ?¤Nõ!ÐÐ?ÑÜ#—´eá? zûò–úë?*v»…àÚ?hð'µà?Ÿ½ó³Îâ?ö«ÝZï? ¹XÓàß?À0¼šö–«?Wê5oýýê?”¤‰oÑ.Æ?+ª²º¥Nè?R¾0í? YÞx8Î?³£]¨í?N ë*†œÒ?ì³¶ïË?ÔJ-å/Ð?ØñàN8Ô?=›†"–ê?V0ê0$ÓÓ?÷f(Y×ç?H9›f¼ìá?°û$®B9Æ?âäÑ™Tå?˘£!,'ì?‘“oOzà?ƒ¤÷?ýé?jÔˆÞËœå?Öý_Ð>î?b•^^é?0>B™¢?ŒxHüã?ÌÛØ]ÿ>æ?t|ÎÄpcÙ?ï>îÓê?ÌVØ3×?òì&}XˆÑ?ÏÐo«éï?Då”™ÕÎ?P…LX¶¯? è=MÍvÂ?+¾¡n—üè?,þ¢å?ô‡ýÉ?ðjÑìUÞ?èh¢óŸÚ?X܈ø‡yÚ?å/6Tç?TØG[/ƒÏ?v“cÛ[¯×?)âû<ËLí?§lcÙî?™™xÝEá?²“)„ÞÞ?½´ßyÕ?ëù±L†î?LÕ¢©cÈ?õæd¦|¸?3¡ú·ªë?úLÌW]eÞ?þ{ªÖ¥`ï?ŸMá("˜ï?~!“…šâ?„½:ÎÄ? O Ç!ä?!®·œ ä?ÔÇ<ÍÏ?Œ¥ïïÖ¹Á?$›hÍëyæ?ºë5Ô»å?§DÑOä?àÀ;`Æ?‚ÄW~Cê? ¹ü&ª¸?45*ߺÅ?žös©×?ZN‰J1§?`§–Cìq°?ã‰å?jÄâ!­ÆÙ?Ï ré?©Ç®Øìß?9¾_A±ë?L±TÑç?dCvóÝ?—ðM§V]à?p]8ør ²?§Äoܼ±?(Îûa’Ò?³¼ÓØ?ˆ×6¸Öê?‚5Íê“´í?܃ñ%%ê?à$Àp ¥Ñ?§}I Çì?RcQpÿÝ?XJOïw½?àùófáÏ?£°»Ñè?þež¿£ëà?÷½¸f¡Ìâ?2.rEÃí?ì`ÂÈSè?³Dƒ§±Ÿå?¡8®iPLâ?ØŸ„‡ë?ö>oŽRlÑ?}G±žšé?’_D¤Õ¨Û?ŠG¶ï?ŒÄ޶Â?¤¶lµ¾HÙ?ÀÂÏ•û §?1]Κ¥ýæ?Ü7Ïþ×Rß?+?s{QBá?•ìÔSï?ûP-wü"í?ãú£Õêé?´b1šý£è?ü6—\¥tÜ?ZbŠLÔÛ?ì›.œÆ? vª‹ ÌÛ?p‚?0÷òÈ?äú»8ÁÀ?bxшß-é?1§0¾yî?XSyÇ]Ó?Û°‚zî?p¹=y›¤?,—Éÿx Á?Ìg'yÒmì?»æ¢$Ní?ˆ€÷kÐ×?²tc÷ LÕ?ZΔ´E Ù?D34:LÛ?WÙUÏ"ã?V HÜÈß?b¯Ôû¹Nç?)óÄQh…í?z;@UûæÐ?ÞJËEŠí?ÀE²+ ?¾y³ò©Ò?Äi‘û©Ó?)É,÷^â?@–˰:½?·v[Ìôâ?ô9§ÍžtÉ?*SY+&>à?amQë]àä?„⡦ìÔ?NmÊ‘\Ãæ?D#QÇCâ?¬Ð,TtÁÒ?ºÔû:á?#X0¢ä?f7Ô™Éè?¼Î¥à?ì!Úâe'Â?䲋˜ÂÃ?(¬TÈ}Ã?‰‹è Ó?P-Å@q¯?å4ÐÌè?¯ƒð8åé?Ü=s“ù›á?ö‡üùŽæ?LêéüxÉË?Õ¹ïåÑè?ñ&àRòë?¤"ȃå?òT‡@‹ Þ?Âæ3sã¨Ý?s†îÓ?YéUö‘„â?ÔÆË«5Ø?NŠO2cé?Cô Ÿ6 ë?°pqQÛ®?¶Ž_¦Tæ?È[˜X<ì?^ÞÓý×?Pö•´?à§W’£ž?ðÛŽx” ?ð j‹‘–½?ÁŽù—É•è?tÎè”^Ô?Æ[EÒ¾6Õ?$Ïtt ä?ò´‚U²ÖØ?Ȭë]Î?¢g7 Ð?²÷˜¨Ûm×?£þÌUÛ?@DïÏüª?ýòÄÒ€êà?¡©$8›ì?0˜êÃk“¾?p¿­žÇ¿½?/ÔR~÷¶ä?3ç²  ç?Z ©%¥Õ? âÖ-œÚÈ?°fL¾¦^ê? – Å6“?ðÜ“‡~ç? d€ÿ Ï?0ÌUéÇ?à˜Ý0è«?“æ`Œ¿ì?Ò(eJôjå?!§ôÁb^ì?˜›E”ü\ã?®8)Jl›ï?— |õJí?(¢úBØ? Hþ Œ©?À5 !”Œƒ?41ädTäß?(š:©ãÈã?ÄÝ»?é?ÒužTÌÑ?sö?­¬î?ÀÉ4¥ËÂÁ?íó0îì?€Fàè·?ò3O¬g|í?°vÁ]£?ªõì°CÞ? ‡ÖjŠnÅ?sC¤ŒÞ?Žø7dÏÙ?*7Q…‡Ü?­Îâ kï?‰9×U…úï?TÍ_MfŒ×?™ÉµeÃÛ?£¶QQLðå?MBo*]»?ü0×ýÞfÎ?ZBë?8 p›sAË?sÊ”¶à?P §ñW@ê?"Ék®'wé? —$Ïá?@ý’M­Ý?ôMňì?®{àÝ?Æ0ÓÞ?@¸kÚ{hã?ºÔ £Úï?ép)“BÍ?T%6Ìøé?˜†…PzJ¼?˜bž¨Qé³?wÚö<£Ÿà?ª²ÏK··Ü?–å2uÙ?àÉ¢a«²°?Ö<Ø:îëÚ?n vÊ5qì?æÇ6ô…sç?€ÛHx !Ÿ?Œd§•é?Ž}ê?+›S±óâ?ý0×Ké?Èi"MŠK¼?\ïW’©È?XóJôÁ$Ð?˜Ä$üE,Å?¸Ô„”úÚ?ÖRi4Êê?èçÁ-ã?¸?àbDŠÐ·Û?Vû¾B+èÞ?XE…bÓ?þýߤÈæ?rãEZà¼è?Ë——Þ×ä?À<3å>ø£?Gá‚ ê??R¼}×î?¼€(T©Ì?h¦Ç$qùº?&õ#ÍÒß?-içÑ!Ä?fϵƒ ¸Ò?-³)éã? 0¾¤týÛ?pÙL`ý´?vX$ý"èÒ?X‹œr¾?€<Ι¼Ì|?½ò 7 }á?žvµ…NÐ?Úé±"vFÔ?Nô…rqâ?ÉËûªíá?Ê”f2€?ÔÄS%Ä?foÝdÚ?YfŒí?œ…J¿•è?dŸˆ€xUá?pÞï _£Â?‡"&»ãÏå?zAù¾ì?ä4¯Ø,Ê?„ b+é?)*a7Të?tmü×;Ù?ÀÇ„àEP±?º0γ4á?ø?K]ï„Ò?±{Y‹$Øí?žç/Y:ƒÐ?ŒêG#صÄ?yÂŽìÞüç?@~@ ÿ‘Ê?º›ý=^àâ?`õ$IAÕ?zç9SP‰ë?  òÀç?ó¹ ŒÁå?útÞÚ?çáüA!í?µëY_¦í?ìäaUí?“+}þcè?\pYÕÕç?.ËüÂâ?G¡«´ë?˜”Þe Ó?m‰`Üpß?çšE˜±ç?§dó5ê?oi5V‡}à??›.-æ/ì?*>­ruâá?X¦|ŸÏóå?7èéDÊÅå?ªž5Pê?EvTuMúí?8D°ØuaÀ?xý€9ë?òPøòDÑ?¤í¦õÀðÕ? ªÞßÙjç? ³íÑ{‚ž?ˆ )¾87Ø?4WãBÀ?˜o|{:Ö?½0¸ŸÊë?8&¥wmí?Ü€X_ŸÙ?˜]Ô´–É?îos|ø§ì?ЭÖPÔ·?J’¯ß?¶ÞÝû]Ð? Áþ…uÍ?|L–ßÅ?G¦—agá? Ÿ×Ȭß?ú­†)£ß?°Õ…×=¼±?ƒ®hkí?I\áy gí?àÚè6Ø?æÛ|ˆ#ß?„<3ÔïÎÙ?åί:â?Ñ `‰ð¿ï?´òþ^ü Ø?:³w¹xÖ?ø#!¶Ä?íkùÊxé?ü¹$2ŠÉ?„b¸`»Ö?'à ¦ì?“)¸¥‘rí?øMvR–µ?†x(O×þØ?!‡¦QËèá?pÙ° ™ÜÀ?a.×rüï? Ë|x®–?N:oW•?Èà"¥Zë?ˆxìïºÜ?€?=p‚s?}Níÿ¹æ?©p¥è?À;&QÈû×?fØøV¯*Ð?´}ú‡"˜Û?êÆ>ùp'Ü?RÅë…æ?6Ÿ'¨“:î?µ§ê‚©á?Áê sá?–(´{;™Ð?ºeºÑ?È/+Ͱ[Õ?†lð¸ç?‚‚e¼1_Ø?CiQHKÑ?}·W çâ?§êqã?hžæMØÑÆ?H¦Û©ç?¨Uüèu!³?xz„X£)ä?U‰ ±Žà?$4§³g“Ê?°çAkĤ?„e¯F œÛ?BšHÔpÒï?àSÑšBêÌ?O®ä4Ý?¥»FýÕ¾ë?cïÖ°oVç?!©"˜,éê? Ë&Õ?w5‡Y]¸è?ц÷2@é?Óäd§ýõå?ÆýÁݯåÜ?ÆcE1[òØ?áRàß?X¦´ñÔϹ?h¾e8ÐÏ?þLC¬{à?x×ÔëI à?ØXׯJR³?ê ÚŒ›Óæ? è/¢Œ©Ã? ÷ó7c»?–‚ã³yì?*Èõ*ŸþÛ?ºmÍXú»?ŒçýVÕ?$Û!6ç?6óîE,Ø?£E Þ¤î?`¨¢Íú¸‘?¬É"RIÆ?fì$®ƒªÓ?îï·PÛ?ptGì72»?ŒµSÏ{ä?–XO p?yĉ-Tê?ÈíUÍÆÒà?‚öÚøÈ?œ\7c¢·Ç?ø”WKè£?¨yÄØE…É?ÀÑZh½¯¨?3ñVÅÉÁà?¤º„Jæã?W}°°à?0… ¬º°?1sV¯äé?MÄÿJƒè?`…NF{ñÓ?ktz^éê?ÚÎl|íÍÙ?@ dç^¢Œ?—œYEWÄë?¾S±’ïßë?ajRZ7Å?W­÷³Š…à?Èzý@&æá?P‹÷Šç¥?\ »Þ?2É%ð|Îè?±@ÃG¸?0Wê@¢Áá?T×^3[Ó?$tÜѦì?°¼(›ÎôÇ?+j»jüã?ÀäCTÃK¢?åB¥Öòå?ÁBÀå$æ?IF¿é%é?Bs½m<Âè?PƒXd |í?ðê¼DœpÐ?à2>¸eË?Ô 7d÷Þ?ˆ’ï?‹Ò?¨“l·KRÝ?`œÒZEc­?]“ÃÌy›í?'•?Õhë?Ø o¼¥åÐ?âT˜I±ß?`&xwŠJ¸?@Ðö®Ó?ßÓÌaI»ë?@RóƒøÕ?LJ¶~aÓ?8sŸí?É1Q¸iàä?ëé¸Bç?èÕ(-¤å?pIâ›ô™å?Þ <¬ôyÒ?X½²ÞyâÑ?; ¼¾ç?#` jà?}m¹<1Žè?ˆ•.µæzà?žbKžþqã?Ò9„èØ™Ý?µ/]·É"î?èšîö,¡?½ýI‹£Kí?¼F7 Ô?þûx†kþÓ?ªNEÉ#VÝ?!Ù–jï?{† ví?è,® %›è?–¿xâ6Ñ?E8ÌBfã?@”R~S¶?óA¬RÔí?à\ ½Éc’?hSçÞúÖ?hL„_Scæ?PbçYÐoÉ?ކõÿÃì? ç*Œ<â?Ö4ìÙñ…ä?D—™eŒIË?ÚÞpjæ?Pýã ?«?¬Ñ_5ÔØ?Ž’¡µB>á?Hƒ;m¢Ü?ü—Þ†’Ï?¶×qžbä?,á Ô›-Ó?4ìØÈøåÚ?9´ŸUxî?ÌÄu%_×À?ØGÊ‘nÌ?°Óäpñ×?>¡6±`öÓ?Œ¼Ä Ô?h౎À­Î?„!Ö¹Õ?H:ààÏç?ØêçTïä?äæDhbEÂ?,‰ß›tèà?6Ùþð}nè?£í:/+é?€šöÐ-½?”ÐwùËÜ?ø˜~=óÔ?xpúéâÒ?´xŒ}»×?\±ø^ÅáË?®ê;¥=àØ?@㼆KÝ?ÕèWòDÐ? IßT‡à?ÀÙ‚sJ„? D¬w ä?9°q:ôæ?o&зúÚà?~.Õ_±Ìã?4tæô†Àæ?ØíªŽl$Æ?þŠÛ‚>ÅÜ? ¨IM~Ð?ö‚¾̹â?€x Ò9É?È «×­Ñê?îtyÎ÷ŠÜ?h÷êfšò»?¬—9è?Š€ë-ï?ÂŽ`nÕmØ?‘çÊ=wä?,/“áÅ?¢­ã‹ií? ›PÊî?”ÃØiÓ?ç ­”Oà?Ñ8í8ÕÔ?ÿü$Ñ?X²bsLË?>LŽXðî?ºÇ·‹qá?=P“ ƒoí?®öY½HÒ?Dâpæêä?Ò¸ûÌ»[æ?¶•}M+ à?bYÛ¡¥}å?ߘßUÛ?  ±Ú:«?$&߈¹dÛ?ÈÕ²°LOÓ?-² -L5ì?ÀXqmèò½?&KŸÓ?{|Á*ï?0jÅ .U§?*Ð…:žØ?I<´²\î?Z̯¨Ã—×?‡4Wv•ê?J­Ã*Ó? |`"Qä?Û5›Uº…â?BÄ?Uy?1È!ãè?ÀþžEuã?Ò²b”ß–î?KYe÷}íâ?0ZÝ—/ç?ú㈲`úë?¨ jNÙË?rJ“„ã?ÔiVÎCTä?tÂ×bŒè?ua öU9ä?Ê÷ºòþp?4íF•Ð?¬‚áéÍä?Zù3Cà?Ð;D‰Yª?àíWÜ*¥ê?˜BXlá?Ú¸8ðšÖ?EBf¿æ? ç«AYï?ä%‰EƒmÝ?}ãÛ«”ì? 8Ûm÷ïÂ?´¾ó³6ªÔ?ø¤ðÈœ´?lŦ”Ð?$»5 Ä?ø_| òè?œ¾ŽÄ aÍ?ŠâŸ!¸‡Ø?¦ü†¤Eâ?Gf#í?0EQÖÞÞã?ù^àå@å?åŽ}gÒî?´€ç©%×?¨ò/“½IÂ?:Kq”qè?úßÜÂLÐ? ®Ùâ&¤?¤bïlLÜà?"¢‰2ÂØ?JgNtÐ?€«ŒR:ýÑ?õ˜´­ÏÂî?ÈÏì°â?7¸™m²î?Úl²íß?ˆ#Ç ?µ³î… é?ŠK9¼yÁç?˜9ž£ÓÜ? µO;F¯?éq}vQbã?55\:)‰ì?$¹IØ?J´©Pê?dM 8<Á?Æïujkõâ?݉UxÃé?¸§ë,ÒPê?S¶"Þéé?DvHÜHÜ?L>kõxxë?$vG?Ô­È?D Á]4Oå?@_Ô°:Ê?ô'ÓÛÒ?¸µP+ÑÍ?¹Ó‹Gë?Ðë(c¢œÑ?¯0¢-V+ë?`ßa žÕ´?ôÕø7Uç?Ñg±WÚä?†i¿¼çóÙ?¬aµ|ãæã?ˆþõJçÜ?Ð,ÌÐ!º?\L_Ü@Û?Oqú§]Ã?OX¹·D|ì?&8•Më?ºò\¹;}Ú?x9­Ã£Í?»{MÌ×ä?´tK…¥È?äÃFT~±í?nOl`>Õ?†ÿ_]ŸŒç?-¦«ž¹yî?l4ëÚƒôê?hi8UȰÎ?/ÛyÉ“è?*ê×=@ Û?Ú*s1è?«¯ð½Tê?ÞË|Ä¡=Ø?x‡°Ø™Ä?Êu™Z!ŠÝ?<„f¤jÎ?жñÔ4î?€`eãÑåË?àî@ã#Á?ˆÂÃÑÜÄ?Ìw~É€¢â?Èxú‹8¯ç?‚ÃÐhî¦å?ŽÐæòˆŽ×?XNzâ*Ò?8Ñ{Aؽ?l·Ùß?À2VÍ]òÃ? ³±ØœÇë?î ]…¤ËÜ?D¨®»}²ã?¨¨ôAîÈì?àZCïb÷¾?Ìø%™€Ç?ÔÌn`â?0' —ª?Jev˺á?ùéy¯÷ç?0Ø>œûÒ?ÈV©æækß?0UÅU zÅ?eI¼;êåï?H³»½®Ó?¤"’ô ë?žu~¢_Ù?óºì ä?ÙrÝ?L3 £nÈ?ÎQ€¶ÄNë?µoQ%5˜æ?¦>µ6ÍÔ?q€yÒh6ê?€Ë„q-Íã?@q@Ÿ¦ëª?¶ÆFÚê?¢E0!]æ?uðIìåíé?èÒéz’ è?¬-ªŠ&?å?NÓøHŸå?“ŽÓ°NGè?Ò†» -â?Œ y•Ó?=ýw*‘é?`é‡=O°Ô?”ïY–|˜Æ?B0 dHà?ð|ãJ)°?ùy³8Ýäè?½èÕ¬3mé?t.¥Š7œÐ?xÓ øWÜ?agÏ&Ù7ç?`‚d9…2·?€zÐÃ,Ž? …;ˆâ?'Ü8uN×ä?˜‹¼o8Û?£7:ÊŠ4á?2ßd,hß?ÐCÍ´¯É?ú¸ãVÂÞ?:Éå?X 9¾t9µ?5ŸlCî?ë4t«ªæ?À"H‡†Œ?»?Ü#à?c«ªëôÁî?0_ቓvÕ?>ÛkKì?pR¨7‹6Þ?a³Y>,‡ã?‚“U®{Ö?a~» pÇå?®HâqJòÒ?_¤qUà?qìJ¤uâ?žÄø™Ó?hª%@ë?H•è¶óFÃ?R2™·tê?2›²ÝŒÑ?~Añ­Ú¨Ð?@Å=[ç²? bøÅî®? â›Õ‹Û?ÄjÑväRË?PD~ŠBî?Þ3I߸Ú?Ø6¸ã±í?àRó~Tª?1È2'å}ë?Øý5O7æä?Ç6Æ#ïPâ?8V ¶â¥»?¸ÏŸ_Ô? ‹à9´ÔÁ?{r¬™ã?è3«–Sî¶?‘žB¤=ï?@J—87˜?ø°°’À×?ˆ}€Õ‰ï?ÃÆÇºï?ä4¹é?@è?p`Wý/©?ÒT„aÔÔ?¸]íBs†Í?Ûq9‰]é?DrS{KÕÖ?0 ìä‘é?ÎÔ¹´#é?°ø]jfÞ?ø´ªÚ?x ÑܶÅ?ŽKA6x ×?€eý™F)ä?j {O[Yï?91‡‚õÆà?p #’BØ?ɹ²9öî?Äø‰pç?rK м9Ò?ŽÅré?ã;ö0C`â?’tŽAÖá?@|Š&æ?ÈnBµ`Á?NÁ?kP™Õ?8«N4°?ü]¿) é?:Ûày¬xÒ?»ÒÚN .á?p›Û‰FJ¸?˜m€”s Þ?k¨Kk}Yì?ñênóz­ã?/fãè€Lí?`ê1z¼¤®?,l@Ñd á?`ò¢Cæ è?Hw›TÆ?1†?Ù?P-2Sr¡?Ò¼Äý2ä?À÷ÄÄbTî?ÂÓ}шÃÛ?^oâ¨.ÀÜ?¨Hz…»ƒÊ?` hÛ ÓÇ?³¡Oø‚ï?VëøÅræ?ܲfð~Ø?’y‚ ¶â?b¨Þ¥Ö6×?7T{™ñýá? R¨RÚùÅ?\V³¼fì×?®Le:Q×?­n¾•Íïî?díï*è>Ø?WœÆ‘åí?«hþQiâ?Ìð4Ld"Ú?;M·–4ç?›ðì{Ýä?Ç#@EÂüæ?´ð‘½…÷è? v¤¸tfÞ?T•PϪ#ß?ȪÌúúV·?‰d»w ï?ãv¦v‹îè?PÇ¿¬…ý×?o2;]­æ?ì¼:Œªï?ĵP"éá?ßÃÄ?’ >5Œß?`vj2¦¬?7X¸*3¹á?2I¡á×té?|’¯¨ç’À?ôÚ¢…=9Õ?š}Ïáæ?„ƒvlç?YW£Xdäé?%+ËŒ'Ó?¤a¾³Þê?ƒÂ¼¾?™?¤«ÿÆä?w¹ËËÃì?àJ?}Ö¥?až¦\í’è?ÏL“ü¹í?v|?ä Uâ?‚ÿÖ ì½ê?üŠÂ¦¼±×?¨„BÅ0Î?ØëÀ÷¿ì?_àŽÔ¥ æ?Ć`;m¬Õ?t^Í óÞ?~|r÷ë?îeÖÇÒÕ?ÎÞu+µ§Ó??2N5–ï? zâ.ôé?`7á Z±Ä?@ÿ<Ýnî? Ávœ?_A7Mƒgá?Vì$U #Û?¹tÁê“yê?Íuáv/å?œ¹eƒ„ù×?œËö|É?@´B§¬ñÄ?ª4Uè~×?JÙÈ =pØ?¸l()eÒ?°d4´"¼?VÏliIæ?PC˜q<Ü¡?ê[TDÔ?îûM…¥Õ?pÄÖoD¿?V_§Æ\à?õÔ(X¹Áå?)xû=×?&þÓ”é?hló0pé?\Ùȯy†ã?`‚ШLœ?Â1ÏÛsÑ?y€Yòæ?°÷/r;Þè?þìCú»úâ?F0ìäßí?X¤¯Z—ê?ØVc¬ÿê?[ ¶*;Ý?0ª ñɾ«?â$ÝôbôÒ?â§ßµ£ê?À%Dþ2?ÑÚPæû¥î?Äú‹^eè?màk£²¤ì?x]ʹ?RŠ…<ê?P×1iP¨?¤ô\ì'ç?D›G© ×?¤£Üÿ YÑ?…;ÓuJ³æ?°1^ó'ô¥?Ë;„¶U¤à?@8¦9[¡?`iûlD©?$<`Þ?[8¸œÀ?ÞSÄð9¶ì? •¡å’?p[b=ã²?Ò$|àø×?Àhl†ÞÍ?x0¿°³?ë$í?É\¶ûVá?0ý2­|?ä?ÔºùÔTë?häS Q»?X Œ˜Ë Û?¤ˆ}ñ™4î?ÙZOVáZä?jô•IøÉÕ?àe šÌ«?­\Ä&©uå?/ù3s)]î?j3ßöMQÓ?Ž4¦MµXì?¤ü‘ðNÖ?'û¬J¨ ê?*áT´fæ?á6£ã?ØÎnï©Ê?Ý·9*pé? k–¨µ*Å?à‹meö^ç?W®s9ëÅ?¨¡–‡¸ï?ÌÉÊ? €zÅtn™?â[|çé?È?bx c²?„UC0J×?ÐØë„h©?‰·þf›Ìê?ÎzS™%æ?©¼ïbŒsè?6’Œ¡æ4Û?¨,H¦ï?ˆeµ‰§²í?°—%‡%ÆÂ?J4¯îQá?xß'gí²Æ?4ëOøxæ?–x‘DõÝ?„ªÔ7n(Û?÷Rýþ&\ë?eyâòì? Ï üÕòã?0‡(&Zß?o¸Ž`Ië?6èß[{ËÜ?è„Ä,»æ?üœ’„e~ê?hL2ìvÇ?û9Ø;là?‰*o+æ?“ä&oçà?(ð^¾õ½?X*–ïÓé?°ïLñ²’ç?Gf¶Ó¹Êä?:SdØ–÷æ?Ì^Ï*÷[Ú?gƒOªžFå?&s=zoר?-EØð³Ú?DuäT—ÄÚ?˜W nÕ?ÐevÕ’¥? šuJzaë?J‹è!-_Ú?@x#~g·À? 1§-óÖÞ?˜â{Æ?rÓ?Èh¾Ò0Êá?Ü00™Õ?¡ôŽíé?‹fSvè¬ì?€_lŒñæ¢?HÝ>Îl\°?øbºvCî?kt¹¸?`S¬Quu¬?ÈuIžC¼?Ó„m¦Ñê?ļuTˆx?sKþ¶ å?4¤SúõCï?TŸÃ Ø?L²¬Ä`;Ì?¯×Þ¹9èá?|Øw†Ä/ê?Ú:Ryá?ŸHÇNR¥ê?aZ°$æ?P´IF­[·?nÃñ¼•YÒ?˜¦ý†wa´?~ÞðF]Ïê?4O?ÝE¦á?`­¦p±?¸òùñ‰RÃ?ÀÎË,¸Ö‹?WÂ@ȳ?“²—„æ?, ÷/Pî?øpþ&]I»?€Å»ée¸?CÝzÙÄ«?@ånÐÛݯ?Ó$bbü’è?4\¯B9Ú?s9ñpL3î?.òÝÁžê?ö*~ÁèÝ?þÙ›üóX×?ê PˆÊ›ë?žï—]žÓ?ʉT0ÏÛ?ˆ6R!v×?žú¬nÙ?°å·Î$æÐ? o„Ô»?¾–Õ$—é?@¼*ó]†”?Ó‘œÐËç?·®©Ï ë?ÃÌäŠæ?©u(–.Þà?%dS°î?zÏEøä<ì?ƒÌÈE¹Ø?@Ç«B18¹?‰^ %uÝ?1>½TxÞ?pÍ;N ¸?žÂ FAï?вÐZ…µ?rVz&ÛÙ?K+¹Ñ/Ká?ì÷¾÷»Çå?,Ô1ÈNß?ÎmJe%–æ?Á ¸êÉÌ?àC…V]’Ê?K([#ïîä?hû7 Ï»?¶YK–ÈØ?.ÉÆ¶“ä?Ô»æ€hÛ?/ì2±J™å?XlSgù¶? º×³š}Ñ?Qv1%Ó?¢,Ë:-ðì?ÔOú½ß Ì?ùA—­:øâ?ê–ˆÑô}Û?ž=߯Åé?¯ÿÜ›¤?>iÙï|ñì? &,.É¿?úÙNTÆ¿?m-}–Zä?€ì bZ›?¢€›9pÐÐ?E»Uþ«§Þ?ÌÓ×Ð? ³Ñ!èá?cÌ#˜ã?^á 5ËÙ? eæ­I¬?¨'­óbÉ?™èÀg~è?ûöR¸BHæ?^ØKñºÝ?R*ÙÞ>Qê?JV¤)¥®â?üøº4 hØ?«ü‹í1à?ðCü¯§?÷K¾ëtæ? ωl®Ø?z˜S4åâ?€ Dª,Z|?ÐÔàîÐZ¯?‘ŸÚ¼„µ?f|ÐXò^?Ù*GâNÐ?À*)¹PÎŽ?'©|u¿à?Ú$‚â[¯Ó?>è•Õ0êä?xü‚H·AÙ?çõ<ºU¬ç?4ÛÄL‡Ò?˜³yø“Á?`¼p{§KÚ?cÖ=ófíä?Xz±Yâ­Ñ?öÅÒºù‘è?Š!³’ŠÖ?.Ì–‰¬êÜ?ì7:pÃ?Ä)ãY"Ó?RŽª¤ðã?6F¯+ä"ß?;á1•‘Jè?<¯[–%ËÄ?‹W¥Ê«á? ë¹CÜiÔ?¶¹dç 1Ø?¾Ï²…Ê Ó?È “ ï©Ç?’<£ÏÔ?*ü'ðÙ?an$’ê?8×ßâ8øæ?æ•Ô%Æë?ph$ ^”Ë?ÇÊ£Cã?âjÖs'³Û?À8 qý2·?k¶ç?–ÎÛ+¡ê?€,OËŸv?@YGJƒQž?€¤#|>úŠ?¬o¨¢Ð?RÊŒmÛ?s‘•™ å?`&8Ž´”?)Î<-å?†f˜ø¥ÛÐ?…gߦ;è?`Ååqª3¢?¤¶14Ô?*~©xé?pê¶“æ Ø?YñÍÆ; ã?òâ<º@Ý×?~…Ì/+Æç?®¼¯n)æ?(»¤êœ¾¿?”øöW Â?"˱–ð–Ù?üaO`á?lçy6kÐ?ÜŽ¥-huÀ?p}Aù€òä?šê‹æØ?ñ(EršÐ?i‹>kͰê?ŽXïÇ÷å?ÖµÿaÖØ?P áúx}Ä?¨ç ,©í?;¼ÌZ¤iï?p`†IÈ5Ò?C-p¸ \à?•"ñeŽá?¼š{/›ì?P(ø@œAÍ?`±Ûк?TÂr,%³Ä?€h¾pî)ž?ÌÌ^²K¼?:˜n°Šâ?”k 4Gëë?Šžô©ï? yYáŠI¯?üU÷Їã?T”±àñÄæ?ÂŽ«Žà?“ªÕ»0¹æ?°S3ÐeÁ?ì^lú»å?ÀïkãËâ?1ËEö•Ðí?ÀȹôÁ3™?"Š(¬øÛ?í¬T—-ä?œÂ”!ÜË?ø¿Ò› n±?Hò|nvA×?XÜ´N É?($}•þÊ?å‘^þ"Gé?ÈÌØÆSÉ?ª‰CBéë?ÕÍ(Ä­oê?ò7—¯B;à?Ì•\-½®Á?ýÜÏA=ã?Äë+é?Oî§:zë?Ò} Lè?ü†à*ÙÀ? ÝÙ3å?0ùr*ä!Ñ?lК9îØ?®–|NUÞ?¨Gõ«Ç/â?*ï1ý¸Nå?Û,{¾úÅ?͵·ºµê?ÁG!Tbªá?ªZéð¬—Ö?édOª¬½?ŒÐÂäïÇ?ò*ÌÊùóÞ?\f¬üñÓ?pmÑÊ%û«?Fe°ñìl?™y~Û¶å?gÖŒ=Bä?mÍqlìç?8)×ßoì?&_wÑ| ?Ü6´µž Ç?´KÖö]Ý?¢MÉM<â?‚‡¡ Ñ? ö¹œÉÛÌ?›ß›†ë?T)œ»?lˆo‹U«ß?žÓ²êº¾â?àm,Ѱ5Ç?”‹ S2Ø?4:/©6ë?¶a¨\"Öá?0Ý´ô”º?9M,näã?zÿ=¾›ÿÛ?îEkÈÖ?8!Ÿ2ljº?õRŒÁÉOç?C\¢Åì¶æ?î„v2„’ë?~#ýÕcÑ? [ð/u—?’ ³,gEÚ?áÔðŠXàã?ëâ2øÉ÷å?à]gw5&â?0JhÙéŠÛ?=¬uíiï?ÃykZ)î? &Ï‚îXÚ?ézPNõì?ð0¶‡è?¹¬½¹†²?Þáê?ìí4¿RÆ?hsxÄ>¹?æË°á?@…Ë›¡½Œ?Z›_m’à?M½Þzóôï?ÛvN’ìã?tˆG fÙ?€`Á㈀? ”^…€ é?ÚváæCÙ?mÑpc9ë?<Ðö>äÖ?L7ç/ãæ?~*u²»ã?ÖñA­ "Û?ˆæQð;³?ž"jÙ#EÙ?zèêÄÃà?°Kd©õ­?<‰ A…zå?ðk[Ý?"³<(uÔ?³ÙÄ,Éiï?æöØ/3_á?XÙ¡ßǬÝ?`Y[÷™?3{s>¶?ñŠòMñ!æ?$ZS:Tà?@/dz„Þ?hWòX8Ô?<$yTåFß?©ƒ Zä?q©GÀ»è?O̘r½£í?×(¥;Ñ è?;ý]³À6è?¤_ÐñoÜÚ?!¢_^õâ?x”ÏŠSÀ?0¢™lýÄ?XÌ =ßã? k‚ftFÁ?Ü[?ØÊEá?´’±1YÕ?Ìí¼DÁ?„ò:85ß?ÝEÕôÖã?:¡Ã×? ÐâÐà?®xû%«ê?(¿ja³Î?çnþa”né?` “ ?,„'Ôãï?‡ÌØ­æ?˜æö„È?òê_í?¡|n£"×á?ˆíßÀà?PÜ×GbÉ?¦wXwæ?Ì€]ÊXxé?jDW¡Ü?¬Ý¡‚>ÞÁ?ª¬±- ?ç?ØK}¦?|!ýÛÂÁ?¯º áØ?B¾9´Ø2á?q•5 ì?ýay&O÷æ?œãWë?Õ?3ìqã?.ÕFw»í?A‡«ô'ì?Z-6[Ý?bͬ˜ì?_Ü_Laäæ?êW6µ3Ïã?@aR¸ …?Äš#Äð€ì?y·u,í?yíJªS#í? ¾–>”ôá?ðºÉG—[á?˜pÞÜè?¼­Ž©p¨Ñ?–R•ò’BÒ?»¿}ñ:±?-Ö8$â?` JÙ!…µ?HȱÜeå?ƒA ÍÝ?лŠž§?#ìœ1rNë?\IíÚEfÓ?@%Ò›q}Ø?H ôà¶³?øN~ |µ?Àx^Ôˆ?ÀJÉ!:Ï?Ö9_Aº? Æs£·ñï?4#:¹¬¿Æ?…× &ã?µ–>²7í?¨ïš¢±é?ë|ôF¾?ã4rk©î?pL5z6®?ëø2ºØ?nEž°‚¬à?ô¹QP¸LÚ?šÅÆ*ø½Ö?úÀ×¶é?h590ù½?Ü]9q²Á?º¨ô)2 Ò?ü|Qâ. ß?“l‹rì?”4šçœÙë?œŒ«—Aí?Rdcï?¼ÇSÚëì?f=IAÚÑã? ²A+¿µ?“±´#8ï?êêt ‚¿Ð?'×ã?Z•“ŠíÝÒ?`äɪõ—?0C%Œë=´?¥ã²GŽí?ÏOú”Úé?À)®^@^Ù? 1í'„®Þ?ûNÛvLÍå?Ì¥¦è‰ê?xv¤MF×Û?TÏ—”ÁÎ?€¹fô-z¨?8/£Ý©Ù?x\Å÷ëØ½?…ë:á–ë?¼|é—ÏšÞ?&¬õ¦ê?êlÕÆùÑ?ŒwéÖs¬Ò?…%ªŽbâ?æCÔ§{^å?àoÑo‚°?@ULÞpÙ?eˆI?š·æ?ÁF’mì?}$uH“ƒâ?Ý¥\Ë%±æ?´– ;/Ô?£9 (dÛã?h+ôŪbÅ?ÀrÄ8$ïÁ?¶Áßùà? éŒ§Ò Ó?„ˆ…ÊquÌ? ɯ$ÑÊë?ÿaÎ GÅí?!-Mîølê?½fe^^î?òXõ‘9TÑ?Ûºšï™þã?OM0(Î?rfÛî Ô?â I··œÒ?¤›Á»æôÒ?”Å™»'ÇÃ?¦¾(µì Ö?ꮾúÃÕ?G£[¿ÿÛ?\ ;ø—EÓ?2y;÷{ã?À´TKlrÈ?5Hrá`à?L2ŨYáç?wùÅĤ?Á½'ß{Rì?»u\é³Ü?'† â€Bé?¨ˆýÛè(í?j‘Úd¨fÖ?²”k;O•ê?Ìä5¿uÑÏ?ÏJ.â4ôæ? 9UÊÎæ¦?оªŸÔ¸¯?MÊ·´ì?ä kZèÑ?ŒÞ5Íg˜ë?( å¾Sí?¶N¹Þ]ê?/¢¾÷Ðì?óm±Ð?Ã.õšå?jsu?í?4É’ÑÐßÚ?M -|Èï?ÄÏÉï¨é? ´´'„Ï?Êœ€WÊã?Ìñ–äVà?§k9p¥åå?¡¹´ °ã?ÌG³d>bÂ?/âÞà?~±®2½ì?ŒÓàrÝ?ðÒº#>Å?.ïÚš\×?Àû§žýå?œèÔûNrï?Cª)Œéã?Væ)ëË_Þ?&bþÅòÚ?ìk3ò}ê?È H´Û?NF/så?Ÿ&`ÝSéá?Ò·õ]á?¤}õ£.ñÝ?jÛLô ?x’ "Ë? FBHµŽÐ?¶8_¹Ü?Ø>F¡ïÐ?(™ˆR“¿É? UGm­h×?îl?èxä?~PÖ*„Ü?&…åßÔÐÛ?º…*„0Û?ò²k+É?Ô(‚7.,î?¬'7{Ò?1H·¦!Eä?6l…;“šÒ?ˆ³+²Î¼?òÁ†øf¹ï?¿“dù]Eè? Ë³f¢ ?xÊ®á+Ïî?À耠…׊?0°=?ptÅ?øyƒR¶?’4hê1¡ê?ϨÄùvî?kš +œî?‡¢;߇Þã?(+î 7ÝÐ?Ì0—Õ?2Y z_mí?ŠršˆAýí?Œb|ëÍÀê?ÜûÚZ‹kÔ? [Ã&– µ?œ'~êèâ?˜w>‘×±?GU¹xë?êë ¬í?ðœà—]i¶?­ÈϯG‰ç?ÓDÚ Ê!á?оù@9̼?ê^$Tm1Û?»ãŽ%ßã?åEØÛç?-ûMô8®é?pÿ/3—Ø?ÎS¶K­Ö?ž– Rjçâ?ëûÄÉSåå? rì…ì³?¾dª7Ù|Ø?pø”~nÄ?š¤]â¼Ý?¢—t–u¯Ò?`Œ€æìæ?þÑ[o ¯Û?®]&é?Ü' OÌGç?ÀãÝÄ-yì?%j$œiã?Î¥#ƒâ?ÚÃ<Èä?$m’Ndå?‘±èÐáÓæ?T7$8SØà?Íg3E#è?D>Àž4cÇ?8ò5EÓ ì?…Þ£òýæ?trI}yÊ?Zÿ_Å yã?lк]"Hß?Jv0Óžì?€žwí¥MÊ?È)æ›Qº?!ÉQÆ®í?tïȪûÎÙ?ÀÓ97µÝ?3À5ÛÜÏé?ãû˜ Œ:ã?¡û¹1aé?o/„p|7ë?j´‰¾<Ð?˜ß¬Üáà?Õ[Rïþ¶ä?¦¦hüPÕ?~ ÄzÙ?K>‚+:ê?Ä ö׃ÝÖ?°¶™|——À?’´B#²Ðá?:IM­åÒ?¢É"nn¶×?Y´y…‡[à? öÚ {m?b{³[Õ?¬êw¨|ï?¡Ý¹_* á? ¡¿xï‘?érÁ«5)î?PÈî:¡Ã?THRVáÀ?¿ï]²"-à?¨¸áàÇÎ?yî ¡£?÷A^å é?ƒEþ0nê?îrq&ß?xv“VÊ_Ø?0_†»Wæ?ŠFaBåìÙ?˜;¿XáÖ? ÿÐ’wéç?‡"Ì?¼w”ñ“Æ?rךßhÞ?EL€rá?á÷g?]å?cÆþ¶ åã?€_P€v?D⻬tÁ?@ U®ð•?V7W3ù&ê?&¢üCQÓ?äCå˜ì?`fÍì?ˆÎµ¸¯²»? #£ÆÃ ©?ïèÍ&xà?>˜$åFä?9üV®ç?22† NÒ?°@AMã?,Öžˆ–ýÔ?€=´?Í3 ?¸ñÇ'5)½?ÞißÞ¨Šè?Õ,ÓÚ½á?€®œ $$Š?oÀ’òoâ?–F¼dÞ´Ð?…»o°•bê? ,K«¥?÷üLM¹ç?``©ê…–ì?Øž)*¤å?:¤  ‰ÿÑ?N€s¯|-Ò?–‘)»æ?¯~´¸€?àT›©HÀ?2ûa<ðÀØ?«w¶è?Ö€`‘×? ü&€eÁå?Xbúž¶Þ?§?c&ï}å?…8‚UÌã?Û…Õmëë?ËZâ¼äå?þÝ'eÌß?Ð5—>Í?$÷´©\¥Í?ô:T¨†½î?üM¥obHÑ?8Æ~È(5Û?译%Ñ~É?Dcâö8ƒÄ?5»Æ=Ö?æª:×(ê?•ò€oÈå?ï5©£ìVä?dñÅI'Îå?ºsã7½?HP^—„Í?‘D»'ä?< S¢já?ÀÞ VCƒ¸?œr°!Ô?âÞ3”5ÍÒ?¿œjŽKä?Χ_ŠMóß?7¦vL»±à?¥blµñ1ä?îä’, ÈÝ?¦¥/lìÛ?´´Oã'úÒ?h?g÷ ”â?b;eo¨Rë?RÎïY•Û?¸ß¡Ë>³?T"‘ÿuì?ÎùéX½Qá?ÂP©èV;Ö?û³ 8Æí?ݽËrrì?†‹FÂD™Ø?*Ͻ 3é?l•õK;]é?åÙÄæËä?Ô°'UÚ-×?êý[ïÝ?§Hf•Cá?Šþcáüè?êB¢·ÞMÝ?À–,jÚ? ]7z;Ý?º hï?&RYK$ªÔ?ôçpFûÜ?`¦*’ªKÂ?@^¦**té?Lv'äÏšÅ?ƒÁì$æœï?€Ÿ#?♆?q=qŸÃ0ä?Õy^`ìæ?ûL°¹§Áî?(t¶Üñç?BãÍ>uå?tÍêë?ätYa_î?XeQ\£fÕ?·¿[Laê?Ãõš3Wªë?n e¥YEÖ?>ŸqÝœÑ? ª¦FZöå?ª9æÒŠcì? ¨ÅåFÞ?2þ©&åÙ?@noñ¹Ëì? ¬ú9—éä?Ú:P˜ýí?ò硦à?dÜOï,î?üÞ6?à«É?€ÞÙ¦Ú®?pÉ3§Àâ?0vXòö{ã?wTª’î?À(m"žå×?âóõ¬Ó?¡nËãöLã?¦\uSÔ>ä?ËÇ?Ùè´® á?oW³÷é?PÚ¹Üßìî?R1+BXé?¢³®C°ìì?Ä<ýéôâ?* z WíÓ?OØ´Úóå?5Ù. £è?ÖF+Ò„Cå?8K„S/Â?àÓr-¢ªœ?칿a°?DÉ ‘æ?„žáº<˜Û?‹Ö­ Ýã?aºUE;Xà?ëu¥AÛ?%RÈ;Uî?<­í†ë¹Á?CDmÌ™ë?N¿2C7+Þ?üfé\õÜ?¼3‡xSè?ÝýtQ‚à?)EÕfÁbã?Û¹‘»Ô?6 ,HÆà?|Áb§Ú/ê?Nâð2¡˜á?˜æ^7Ï·?ñ¾•â}î?Q±/i*Áì?ТÜÐ?¬2iÕ$Ý?]'Ö~#æ?ào{ ,JÖ?Xï~±ë\Ú?ðpï•ç<¼?e…Tê ç? 잢ŒÇ?˜â<³«ÙÓ?зÁâá?zs¸Dòé?P}¨íÿÁ?Üâ!«™À?ù«ì•òâ?|÷-Ú?hr®mê?A²ƒ&Y”ê?í£½`>×?Ô*v¸hË?×Tu—Oç?|É]Owß?˜]a©y߯?$ˆ¢–æšÇ?3ßlRî?Ì KP§Aç?¢SG¸i¶Õ?ÐeÝ{\í?sY`[ò8ê?ÀpÅBÀ?ÉÇb+ë?ìÄ%Ukã?Pš:6…xÁ?]®!Pì?• ç†Uç?ô¨,i¢ŽÔ?ˆ» U#ÄÇ?-1]±Âãè?°î›n¬Ðæ?m;ôÁSé? ~¨%¨¼?°äâH Î?ºÑiiW¢ê? wtѹ¯è? gW>ÞÙ?p0Í¢ò,Å?Lõ_‘µê?85Ƈ&‚Ü?&?|L›Ø?€êtÓ?°Œ|ßÉè?o EÛÍë?+·£ç?cM×SŸœé?¦Ô Ù<Èå?k—Nä_ì?ù¼»”³ç?ðåôÛù Ë?ž‘AznIì?f›P—B)í?¬¾lSªïà?gÜYÔfœã?²pGimÑ?¦5b-ã?tÖY‘mÈá? A>‚·%°?5c»·×gê?à•¥¯Bï?‚ÍÄ’¬GÑ?N¤z3õí?,LpFÑ?ó%™XÁ1ï?”‰¥ÇÝÓ?¤s„’†¡?‚XH ë? ¶¸Ó:&—?ìf¸òèJÇ?ë[ù$ì?Þ\Üãåß?q”ñþå?t= ¦9\é?· Hè?Ú·¥\ øÑ?l^{ã¤sØ??Øç]ÝÚ?8Vh‹kÂ?•d= ‰?F[,ù?ß?× 9ä%‰ë?ü$ ”ŽsÄ? F ù4Ô?C¢[A=êë?4:bÝO?ü׳íQÒÌ?€·?äCÞ?­ƒó}]ä?Zãì½9(é?kzq5;Bâ?WY¥Ò{sê?Øû˜!RÁ?‚ Ø ØJß?®T83iÖ?qãY?V$í? §üP-À?+9Žšï?`?Ou/®?xù~À¦…Ö?9‡ÚùÆ?Êô«ýÓ?7P·.pÑ? jWv¤—œ?×C•0Gï?3 ƒŸ?Øí>juí?p4øß×?|„6E›ŸÑ?ˆœŠ Šì?}tQì?dc~'ÐÝÁ?ù{˜ãÖ?Zs‘ÓÑfÝ?㊗Ó5zê?²‚èRÒ?4 ÍV|ê?mNyø×ä?µÓJ5Væ?Ïg’ü²‘î?¬ùyé^ÎÄ? ¾~Ø(zí?DK ‹KÚ? :ûËrÖ¹?¬îa6‰à?z™«òñØ?>ßp¨Sê?lœì!/ÒÀ?¶Ž=gýÿæ?»”ðSà?"Àü…Ó?XYñ¿Õ?œ*~&ö ä?ð‹3æHÚ?G¬¨Ê¬ç?Ð. )H"ï?&È‚ßèè?„¤9¢©?M¼ù”¢±ï? )/ÝØ?øÿ¦ÑbÔÞ?pF¤’eÌÑ?ð«viÃ?*ÇQbÓ?$†»Ýô­è?ŒˆböÚ?èן±M¼?éF¾ ÿpî?ú;8¾9Ú?H–º† ò±?¸¸rØ?T‰ìñVÕ?Êð¼`<æ?æP`€üÞ?hTWý³¿?€_p”Hv?%„I‡#•ê?Ý]°ˆè?Q>»?D¦všƒŠè?è¸N)tÒ?WÞ“ÌBDá?ÞàÂÛ΃ß?L€ç¼4Ñ?î赤 ×ê?4ÂÛ[õµÜ?iðù‰Eå?Z!Žä×EÓ?äá§Áì?±ìå?JÌžh½?˜ö;´­ÝÆ?žä¦ä»Èç?°2“¾Ð¦Ê?~q¥²bmØ?ðü[ÅvV·?üS#÷ÊùÚ?Oɶ;VSç?'Ì”áœè?5qîd´ç?øËÐ7G"»?°³Oáf“Ä?x?­Ë?0,z,°?%´ÔÒî?¤Di½DÃ?pïªÜS£?)¨ вËã?äâuCêôÅ?ÂÖlŒ¬¨Ý?½£•žæã?‡° ã?(åL©Î?2Ú‡3Bºä?ÀåtP`”–?•-ò¢Žì?¶#© ¬‘Ü?lŠØÍdÄ?Ú°3®7ç?†‚YØ,Nê?Fª¹ÓúßÕ?à 5Äp7 ?Œ°¸¤Á¶ï?´wZ±Š=È?Ø’Zôí?¨“ã÷ˆ?ðÉ‹ú•!Ô?éÆ!c¬é?&”“0ç?ÖAš ««Ñ?ÜØeìß?1.*ãí?zàGE»?,ðm/jÞ?$¤Bd©"í?˜"¶H§Â?¯m[e3ê?¯—Kšôê?øk—ÔÆ¿?KG;ˆ„á?åÃÄ£_ì? Úš Ž…Ë?£4&Ù?*—‡ˆÈ.Ð?Ǹ¥²Hê?ÄG¶Ò]ê?øKoFÃ?ˆŸ¯=>ÉÜ?oðÐë0…ä? çùŠ©?°RêÁPÉ?°íuÝ|¤?{ †þá?ÄMBCÝ)å?Hpa^­Ý?œm‚cÿß?a7Ê×Í? Mµas³Á?(ȤÂlÍ×?DðŦ'è?$š°ôÔ¶?ý)ŸÑ?h É)î?pqönmÏ?Øg3A‡†Æ? {aÛ?]¸^Õ¿!é?–ÒJ¦=#à?:S@N¾<ã?éÆK]³Eî?…ÿBßë”à?LX1yVÊÍ?¨oJF¹?–RºÚÒ¸Ú?E ¯Òµ&ì?¨œnñÒß?Y.’ÚÀì?Ðæ°€¸?`J7t¸<¤?|ê<{iÆ?z qfæ?óQsŸ†sæ?>ûý¾Äæî?qÙO¯ê? ÝÛáåÉè?ºµ ì?R" \ôèâ?'OŃ aì?bž&ºÕä?°"ñ¹ÎÇ?îÞy'øê?d&>Í"»ë?6Þºu‡žÛ?@ÿ_ºÚ—˜?>Ÿ]Ýeß?î’¾ÄãÃÕ?á­P]eïî?d`¦SÄHÄ?„˜àÙˆæ?=W×ßñNâ?N95"²§Ð?àþDÀè_Û?'ù`@¾Õë?Û*éÚÔÌë?|Øìý’Ë? ªýPxÉÜ?Œk{Rì?ß%Ý}Ã?heaLEïÒ?FÉ?ÄzYî?‰ð²Š=ç?82¾ŒVnã?hñ–+Síä?J ‚œ[ÓÞ?x å`$ÁË?Žóÿ—Ó?ö®£Õñ«Ú?±y󨧥?}F®]á?ÅÌ}ì?n°–ÔRÜ?¨tM«W4·?á•ïdÒ? u\èa'Ð?&ZP_WtÐ?4ÌWÿR«Â?PH€oÈ?ÐMØ ‚˜¬?S06-Ûsè?®¶×xá~å?` €åȨ?hÊú+Î*é?ƒPÄ¥.Ôì?«4îôï?N޼⮻é?I­ñcÃî?Ði°” ,¦?‚EÜ>.ê? –|8Î?~þGBuÝ?l{ùÑ ·Ä?ÿRâw²Ø?ü×Öë?ðEW¥aÓà?, ½7<ÂÂ?ÊûkóØ?Ü®¬MÄh×?–Ý”_ ÄÑ?=-†µíà?îÓš»û1Ô?nËEd¤Ù?xßmµ,Ã?,iáòX6Ä?NØ3û»?ò¼?Âqaâ?ªÍÿzV$Ú?.ÔåH6…×?y•Tß-oâ?„ÐŒ0@Æ?i¯±:{/í?p" )YÚ?škÅõNËÐ?PÀË™ Ú¥?EÜ ¹Žé?Ãõœý;ä?,„¦RÉã?ÀòÕ9öÓ?PvÇs®?Àc–MÝ’?brÅNÐê?ò‹Öb0Óì?ä^c3$‘Ê?Éí¸?Tú!gsaî?£¦cÀ™ê?©â­?aüã?àêã8ªHÀ?Ÿ”à¸_xä?˜Aή?´?'gØRï? —‘ Œ­®?>œîë?bP‚{+ë?xköŒöuÄ?lJnÇ3É?lU–y¿µß?x<ôµ Ü?úÿ]lÝØ?¼ônIRÜí?\…uIÎÌ?„§Ás˜Ë?ˆ–@ ì? øqI|˜å?¾À(JØ?¥c´Àáë?øDAOHNá?zœÕ˜À*á?Æço{…ß?TFª´ˆÔ? Ô]«ò—? š¦r Ì?`Ÿ$b"Î?@^{ Š?ý| /å?ŠŠùw|à×? qÏ€'g×?À—>iL—?éêdœðˆì?§ýgâ?žT 0Pï?Ñ\¦£…Uå?…™Â'3îè?öÿ„¤‡öÑ?Ï~?¿ä?T™uMKÊ?¶i1uÅéæ?aÀZìt¬?\Œ½ž‹xë?`8Õxóí?Ç6¾>²ë?PIÚÕ‰Û?AÞˆåå?y¯ÁP6Yá?_kÜ}Åã?e!¨{ç?ÔÍT÷íî?€/÷+®?6ò]k¹Ü?ô®=Žyè? µ†Äl<ç?° H^0½â?€‹›Ú¸Ó?„tᢈÍÝ?ä‘úîÈÊä?8 —úVÛÚ?cÞOú»ç?ÀP‘\ØÑ?ðë rÔº«?Œ%ö¸ê?´<ÛØj´Ä?*¦0Ä@ré?_(gÕpÃ?°8öÌKx³?dÆWCº6ä?f3£Tèµ?2ŽXåä?ç¯Cø>ã?ÒÍÃZÚ?LÖFúƒþÍ?é,ŠnOâ?àiuƒô ”?®Ÿ­Šñ©ß?Dº$'4 è?²l2ÞÄÖ?l œYË?$òÜSYÏ?Eì@i³ì?Ìï³w?.yû܃Þ? ÎÍ-þÅ?šoj|á‘á?Èä}NPÔ?üБÙNNç?¢Õ8jœŒÑ?€d˜ÿØ?bKTìÞ?¦ñ~Öêì? ê¿•öÔ?tæãâ??¢ ÂÀ?^»ñ€˜Ò?°Œ¼ûé­?Ò:Ï¿"Õ?mèÚä0á?è딉c°?êÌP!}Ã?T&»`Ç?ʸüc¼ß?oZo Uï?pÿAx‹™è?Î6Y™°¦Ö?iãÜŽºè? IÀKSh¢?# ’ÜË%ä?@/õ‰Uƒ?ý€*±ÁÓ?’Õê[jÒ?Ðr°6·éÃ?ø Ø{Ö?ÄÏ™×¾žÔ?ÒT,ùÌÝ?(_=-UÓ? iß¿Ø?¤Êt‰¦¤à?Àócž]Òë?ÒòqPß?`°Ò²9?f Õ1±ï?üÒ¡Ûýî?­VT\æ?+»H¨'–å?B§­fMå?ˆ¸T¡½jÃ?Ö>ذ‰˜í?–úªüRç?©¤%Ç*â?dŽ¡ Æ?ÈcÀ©yÂ?ï‰Îfà?ðÑk‚ƒ^Ò?p0fÇm#Ð?†âžðØ?Ð4™”™å¹?ø}Ù[ZÒº?ÇxY8¼>å?„Zí?—â?0þ\²7Ñï?üÉ¤Þ qÑ?²@­ î½ï?æÿÿS¶ì?VÕâLœë?Ô÷Â#v„Ù?7×ò;zÈá?|Îÿ*ëÐ?ô¬!Õß?òeŸü'Ó?uÉÜ\½á?ÈvÈöH²?MxTàÞï?ЮéÔ™Ûä?–é ö°-Þ?L¸uocâ?¢igíßÙ?…‰.àO]í?ƒ¹eä?àð8Å®µ?(hõòÅ6é?À<=ž)»?È®ìèàøÓ?÷D£JDì?èÄ;ÈÒõ·?¬t`ÿVUÀ?AÜ‹UTì?¾*¢ªEñà?¤ä†•?ÊZ(r¸²ã?JÓc¦?å«Ïƒë?ÜSŸÐò$Ì?üúŽÍªBÞ?ÎÔÜñ¨Ù?„ÁDöIÐ?¸4N …Î?KÛÚo÷ç?¤+ 4Þ?@<ýUmã?¶ž“!æ?°ÅÉùLª? üÙÊ›å? ÄÒH½´æ?Öt–cê?n9—­Næå?ŒeE3[½Ñ?–2ú\qSß?^Äûÿ ß?¡Š¤¥âä?§ç–í?TÄŽhW×?¥ý1 -ë?$†±Ñ]Þ?•o³ˆ¿à?,¸ ]ìHÌ?zás%¬×? „Ňrqë?v¦?d?lå?Ax!‡Ðí?H ›ç¸á?#påóhè?Jâ3Þâ?˜? ×?ƒç‘Sàã?Ú^Ÿ«Ø?0&iDÎ?õc—HÂç?ÿj–ômßå??M2¯ÐÏ? Û`Ü?¤7E]Í?ÙÛ_Xé?mÏýÈà?¢OŸ÷~Þ?Ìãgê?X€¼¸–öÜ?ÉÅÝzã?Å3í©¥à?ÀJ„lî?ÜÝ.’ß‚å?1#2àõôá?ÕçÉ- ²æ?¼‡A—Ø¢Ø?¸H¹<;ß?ÇÁA¸·å?øZgC»æ?¸Ø'¦Å?¬S¿®Ò?¾åužôIà?jWf ‹á?AI9§ƒæ? mÁP½Ã?¼¾aÅ×ç?d†M±­Ò?H\Æëx0Ä?€Ùôwhr?¨-fåF£ã?œ ‰©åÖî?Rž)ÞÖqÞ?°|'Ä?pBjû®þØ?…¸Þ†á?HF×ßu¯ë?2Ýk5ï?N¤#Á}¤è?`‹Iìn¶?VðÏñ.ÇÔ?YÇÛGc¿ï?[}æB®^â? áuŸ~ÆÈ?°Sj;§?PϹô_ÈÊ?´'±#VÜ?€ê 6A*?`‚<¯ °â?2õ¢A*ÎÐ?’ʾ’ã?®ÎøNw¦?ʬy±ï?] C£Ãä?(«/IÇžÅ? fµ÷­Ê?òy›9=¬Ò?~Ë@fuà?6¦Y¡6 ä?”½o7î?ËKÔ&àÏ?Vý `ù¹?,‚±3,“Â?¸VÈ‚€Ü?–×o¼'ÔÑ?`r³FEä?º¯tkàá?Ðã=yä??Gzÿ<ºï?8H„3"ñî? Ǥ Wï?Û8ÁŠÕ?޼¬PÓâÛ?Bq3ãØ?Þ}qw:‘é?¤ýÆßèºÉ?î6nËéå?’í^žã?!tTrWÞ?eüÜ—ç?:)oîúáà?ÞR±G'Ó?°+9Ô?|÷¥¡ï?\¾‡Ïµ?\¹ì* Õ?H¿¿ŸÓØ?`$L-ïQÞ?ÂYÆ¡hî?`ôm$‰ÐÇ?,–è?PÌ >´/í?¦[¹ºÃØ?8:Ì@Ë?©8Ý´ò©ç?ð(bW4Á?¼Ý|¸úQã?]B¤ñÙá?m¯(?ç?…î;ÜÞ?5Içã¼ è?5Êè?V„8¡ùè?8äëL1²?~(i2=æ?œøN¹¿Ï?sP`çå?˜ÿ‚ÕOlÅ?p¨wäR¸?päc¼Q³?ºóJÍ+|ä?Ë仟Cèá?Ö¨.¤ó„Ò?ôqGØ·á? JL</¶?bÞOK¢<â?!TFä?ØÐ‡ø£õÆ?vréä?|–EÛšEÖ?@ýñŒyê?³³F-ƒYì?:ÆedÚ?@Nýs¸Ô?=§Ø‡Úæ? c•lB>È?€£0$ŸÏÊ?o$3à¡Ô?#UµŒÄæ?rNMio?ú‚ ¶!ß?=^oÒî?kîAP€Uâ?Ÿm¡žsì?ñC"*»Té?AÉ÷y{ç?NŸù°Û«Ø?ú‹¼b@[á?~á‰6ÒÖ?îñHüÛ?)êNVªÊ?Ö»Û¥›Þ?gÖ³XC.ë?Ù%*Õí?¤  rË?–7ç}vUâ?§ )ï?ÄPîkN-è?v݆.Qå?Q{ÞÀqà?´>.g‹Ú?@Wi½¹ Þ?®4S9õÖ?.m¼üŸôÚ?1 _¥Âã?ÿ¨uÒÒÃà?©t¼àïé?þþ^çø]à?™›ÜµRî?Døn)Íá?¶T‰ñ7´Õ?0øF` ¹?[¢¹Þ1î?{Œ—¬ôìä?ñÏלí?¤ÐO…NÛ?R§«Ò?t×Kªà?hv™0!î?ð[]¤eºÎ?`½5ñ”?¿Ì!ž9µá?¸Í`<ôµ?æeÊe>›Ü?¸„èñy²?ÅMB¿U[ï?н¬¡»q¾?Ø~3¥„KÀ?XæáìÌçÕ?Z´Lûí?’ÀB8k³á?˜–Ž ÔÅ?c”ý–GSá?·.ëîGï?EŒ‚bV8å?+%—móï?JÿNÜÑé?íÇ]ЊAí?/|-Ùâï?XýÔè£Ð?ÜN|þÚí?f§¬¼hÝ?^{ŒÇγÙ? agòþã?¾„ÔQlì?6FW‘5kÒ?=ÚŽšê?9K²î'>î? mláçû?ÈoÔ (Ò?Ü»áÎVÑÆ?«qIÀâ?ðN¡=PpÚ?Ü1ÅÃÞÁ?F£|ë*¼à?*ÈÅ8@`á?žý›¥ê´â?áÌ4Ý?è¦ä}©•Ê?D•ä«oÓ?`¶"‣?8yØš Å?èæ—Y9SÃ?¨óÙUd¸?ETq³(!ï?ü÷Jz—Ñ?¤fµôö¹Ú?®>%nØ?Í“y¼J$æ?ø¼®Ë¼â×?Í\jp è?8ÍÊP_çÑ?Öo£õÛ?¨õâ-'æ?(jXÒÜ)¸?FÕÝz²Ð?®d¤ƒ¿—â?|ýÖƒ[Ã?Š{Ê…àÚ?`¸26ÍÃ?3Ù1òè?š«@ ûÞ?éøc äè?°€ürÏÆ?h]¯UÐ?«^Íè]ùä?¸µx DEé?Þ£¢ßÑ?fn&³ÃBÙ?ð @\[ެ?òNW£ªFÓ?íç‡Ïá?-*Ûüüæá?o½Î÷Ú?XäÉMõ1Ý?€|Ü‹›Á??ŽÊ!·?<Û=êž´Ú?2FØhêí?d&*bt9Ð?Œ5„^šËî?³ƒû~‰vï?ÂNi`,'Û?s¨5öûûæ?ÁÒÓAÑå?œ·ß^Cã?ÖÜ$_®.î?„Î{ÜtëÙ? ­A†‰g?HäÚ_²pÞ?l•© X½ç?zùK·qèë?<æ=¬ÐÓ?¥,=ù"Eì?œ¤ö™!å?ÌèòÚñWË?ëI?]ý^ë?¼Ô—¢ß?úßÊÈ5?ì?0ë‘ûË?hE„7f¼?v96tã?n„ÚWÞ?í?¨fæ?\¹ìTƸÔ?_Ù½Ë]í?óÉ©"í?3•‡áÊÓå?pœ<”ì?° ™ÕÿhÎ?¥=Ð6á?Íw4s_—ä?˜Täü¼°¹?V¤'Qëì?À½íÅž°?ô–°2ö"ß?`÷íÅR½Ï?à/ðÌ‚Ê?èhþgºúè?$‡vEtÂ?.DXDÁì?ÈdA“ž²?ZQs{32å?XÂøËKXà?€/A€Š?÷)ÊtXïã?¤ïÍ?¡u—ómî?è¸ÿ¶ô×?®I¿3å?Wš(mÔ¸?Re9ü‰Ð? óÙ)`“?Cµ¦‹šã?U«5 É?¤•Pa˜¬Ç?H ÄŸ±·?UnS“ná?t¹ÎOšÜ?(—þí¿È?fÛÌeüÈÚ?9é1Ëáî? K‰D«Äè?J…LJú$æ?Vøyo »ì?>5<¢IÙ?øï!xž’Ù?_tAÈìá?óu^2„{â?À‚ƒ`Å ?µveÓ5î?¶ÐØ^må?6ßÁ wÜ?7CÒ:õ’å?Dâë&²¬À?U¯æjï?³Ðήöå?P½9Ì;Æá?Àt²‚ûÄ?xÖ¸pÈââ?máûõÓê?_^ @œøã?”Bø¥ãæ?Êâno ç? Õú*¶Ÿî?3^­þì?€ºÄñeÆž?.à™ozÏí?*«Y[GÕÙ?fÓÛƒù´?ü̦èˆÚã?õ‹ mÔÓá?>{˜ó©Ö? .)|›ž?†X[ê‡Ù?LuúÅxÉÓ?æ³S6ŒPÜ?UWqóŽë?ìzÓ#Á É?ÒÞ5ãÍà?¿ÉíèÕì?®?'ï?U~ÐUvÅï?€r9€¯?¨2ÿÝé?8,\Õ,¹?5ñxÊtÒ?â´9wªÙ?ün™]Ý×? °ý8îä?NdtÈÌÐ?<ÇòúìÙ?êAc„<é?c&ÄP=Ûî?@Ìõ’Œà?cƒAH«®è?´ŽaË_ÑË?˜"tÒ?ƒ!¢Ï”vî?xDÐ szÔ?ÎŽP(Oï?b.¹r Ð?3'™½üê?özü‚Ǹç?2‰mÔÁÚ?Cá>yÒÓç?Þ¦UÐÖ?h Öòæ?º ùG1ôä?pKžÒ?ÿèÈjÒ?> )¥ƒì?Hr[AÁªß?¨” º´è? ¸ñë?È0œE¼ÛÎ?UÃfž å?#ñœ,ââ?¸3 (jué?àÄxY4¡?x×N×á?H¼Ý» wæ?jxÜâ?œá´\Eç?wƒU“Jí?¨Pà„»?fi4SŒå?óÀÒ2˜½ì?º­’TØ?"MI»)Ý?À Œ³lÒ?Œb[—a®î?=8Þkäüã?„Ž™¡¹?‡î³›ì?ª1æ.›?`쯑ÐCà?T4~®‹ÌÏ?@’éÖ…?Ää%2cûã?`™ÀjW™š?3dPÄóYâ?lÄîgSÎ?ø*â?R"Ø?bËÌ›YŒÚ?$ K4íSß?oZ‡í”í?ž¹ra¬Á?Ä:$ÄÉnØ?ŠŒOhö:Ø?Qq‚úHä?DZúHâ? E¼z Þ?€o~.H!¯?*ÚŠhaÞ?ìVªmœÄ?:,ÙÉÓ?ðµƒ;;Þ?ç?D[cµs“å?G6<®{†?x?Ö`ÉêÏ?q‘„Œ>˜ç?ók6@~ì?Ù2J—âÂ?èö­Ã5Ø? ;Ð)UÓ?ü´þ‹EÌ?‘cÛ$G‹å?ˆ3`ì9¦²?E‰oÂAFà?R§Ÿãš¼Õ?ž„3Û?׉4Ú?]IJ)0Šå?žTŸMǺÑ?1¨Nøà?Èáá ¤ì?7Ü2·Uâ?Œmß[¥fà?Nðrb£Û?1Èy~»4â?šwéã?K±K’¥ê?þ¨ç3hæ?ÒÝ­Ú3ç?Y`›xôê?èP–i,ÛÃ?cY¨8Ýã? aM¾å?@Ò`iá•?Š¿b‰&Þ?™¤G<æ?¾ãHuBXÕ?É04tâ?º^w½6î?ô$U’6Ë?ÐǶEË,à?¢/æ=çÜî? s€Ä³?ø‡$`@ïá?¹ß3”XÑ?××éÌ9×å?&Q·DÝ?ùoq?*’öK‚3Õ?ïÊOÅî?çŠõÇ?øê?F¢iÛ†Uå?ŒfÝÄ[Ë?ôT°dž±é?’œ-´æ£Þ?p·€м?¾¿Ïðd5Ú?,zýZ6Në?ûØ9âLè?¦#`·è×? ®SdÍ?8õnÔŸ¶? '”gÉç?2hh^pß?8+?ï‰öÕ?ŒK¨ç?¢ ûJèÓ?àõÀ:d§?´¶á_é%ë?¾úµLê?¨@@däÛ?ýå-—ká?ö3CI3<æ?7ñE,Ÿâ?ê¼V²ê?ü2 ÈÛ7å?to>lkgê?X}: z?"ÉÞû…í?3œåƱå?À•°uF·?ÔòBP6ºÃ?ØÈI4 tÑ?‘õÊKèê? êH§Tå?°Å¸îdÒ©?ð*µÛШ?X$N‹ýÌ?õ¥Wdåè?Òñ–Þèá?œžÚ?ºxè6Óß? ‡ÕªÛî?àÚ|NÃ?F0R…Ø?Œ÷¬M¾‚Ó?'7çv˜é?üHC²Ö?ì7Š´Ò? ; „l”Ü?(&Õ‡-¼?%Øb<ùTç?ÃÁ¡Ã?(ÿû+Bbí?±GùœOËë?ú˜u’à?;Ozt;ìã?~bÒBé?óNjËä?èuËZ‘¸½?pil¥Õ¾?âp7X¿ï?€û{¢ŠÄ?ÌxŠÅZã?¦ws‘3?á?¦(ðÄ—/ß?¡ÁSo§é?œœŸ/¼Ã?$ð]ð<Û?LŸ‘·Ý4Ø?A‰†•ùç?B!oªïÖ?d"ã_˜Ù?ZkCÖ±ÒÓ?˜?Žq‹É?Öü‚éÚ?HA±":Ñ?PÌ$ÇÃ?*‘:”¹±Ó?$ÆœýŽÁß?º_ÅðŸlÒ?Àb‚A#¶?|õÀÔ’ŸÂ?[»­Wd(ï?"E3”·¢ß?r¢K,ÀWî? Íå7Ëôá?æY 0šWá?À–x™íÀ?€û¦ï9q?cóÁ_»¤ê?æpVâSí?)ÂÓYéÜ?0·'ND^¿?Šé׃/¨á?Üð¡ š¡è?üâQ[ê?hÏLOt±?€ýfhhØ?›Gpî±Òá?¶”eÉ1Þ?ˆBŸ¹kaí?Ô³‰oÔ?2%@ Yë?Då !î? ào”6á?à㉇[ÒÀ?ØLÊò=¹?à,°ºÚ?Á?!$´ã?uÝŒ]Íã?<Ú—s±tØ?F0a¦‡?Px×[¼‰¿?€zeÇGs?<½,εùÆ?Ù[ÕD\î?¦Ã3_P¡é?%¿J‹®Äî?HÔ4Xâ?`iü³Ï?¢ÀrfX¼â?€Ç¨Û]¤ì?ö6Bï5ÇÜ?ðY¡ÆÅº?½r39è?²êÁ4Ví?äD+ÄBØï?¬†—â?DÑ'Ýá?H_§_Bä? eêÅ[å?0Hé?@uKnd–Å?ï C+|ä?Êâ6è«Þã?0ÉâI¶«é?Ð,¯ÓE6Ù?(û¥:0Ù?6†tAÛ?3"‘ÀMç?7Ÿm©á?®öoÏ4ç?dÇåþ.ˆ?j'[Ô?€ Oqrª?är‚oàõÙ?Ô㟧øWç? &Ö6oÈ?àÙgŠÚ?óõu)Þè?dþû’žBÅ?HaNüÀMÅ? Óì’© ?˜h 톓ß?TuŒI®à?k@þ`T-ì?Mt®kÐóæ?ŒHX¯? («ä?¬-žÜä?$%*Ê:ç?p¸Lrd»î?0æ×ìé4Ç?í¶ 5Û?x6pìÝ?x´ñ2ÆíÊ?¾8ìô™ä?ûÂôÅ9ªè?Ô-P²¸Ü×?úͽM"0Ý?T“à !é?#Y‡#ÔDí?À-˜î¦‹î?˜¹Ü÷«ì¶?ù~ r¾ï?Ä’ÖЬBÁ?…ì2áËä?FÎ=éÑØ?\ôÛmOÌ? tNV;²? Æ —Ó? ‰JJš?!o#Xöªà?0ïÿ_!Î?üÄl6LÇ?â¤`2A?¤‰ÛŽ ©é?·sØÙ2Äí?Ä/³ÿùÛÖ?üASÓ?·ÊŒüNià?ÍÌàø,?L­™—ˆíÍ?¸îþF—8Ù?Eù‚u7Êæ? $KÉF“­?¨PìrÁ1Õ?Ȥ¹MĽ?4´;f0iÀ?ü>›vê?àÒ`Ù¯?çAZ¸ñRì?y†ë³ÒÚë?‡S‚Pè?òÉÈj÷ŠÜ?„ˆ”ñûšÓ?ïÕVš4Õ?#6ìŠ@¤?PÃN·ÀÓ?‚;‡î¦Ó?8Qëy†¶?­ÞT&Wíå? ¹Š]Kœ?ˆ]ð‡‰·?¬ÂÏhë?À$J҆ͧ?OWJÞ?|Ï|ÈmÄ? *v—HâÀ?®>„4®ï?¸ÀáeƒÒá?(l™‹è?‰N`à?ÉýШ²¥í?pJæ&üÈ?aç?Í­íŸøë?O_$Aí?¨-é¯;•Å?ˆœN?jÞ?¾ )”^Ýì?xõžÑQcÕ?]ÚøOõxâ? Õ™ m§?@ŸLù‰€? Rùr?À?ñýìóë?Ž÷{þ¨¬î?@2>Ù½”?rü¢*;{ì?˜´‡Am¤¶?PØíÙmþ´?ä£BúÖ?g=àFúûê?¤ÞÝ·Èé?çò°‘WÈ?è|"÷^2µ?@¢Å´f²?l“‰€,Ú?ŵ†[Qàä?[æ»oÕ?2–ÁÖ?êÁ‘š 6Þ?TQÊ ³êÉ?`£NßQø¤?Ü_÷äÁ÷Í?À_Vám^?æ‹2:á?Š岉Ø?lIÌøÚ1î?H/'íuké?¢âtê?€É}£¬¦?*±P ÿñî?õš@^ ?²$ù[æ?.7M‰íÓ?†HkbQÝ? Ö÷Qÿ°Ö?ø¤i@ŒMå?üOgëtÏÔ?Ü\¡Ù¸Â?n¾ovÐ?KÿˆÇµÔè?øT_Pbë?CF•Ý(Wî?”––¬vâÑ?ã&»8»ê?J"¬2¨ã?*åé?^÷üE\^î?‹ Iìà?`ÌœÛ"—¬?lj6RWFî?z\¿ëÜ7Ñ?°ÿ/Åé?2‘a_mÞ?©U²ï¯Ð?6ˆ‡Ù·Ó?$’ÄËX-Ý?4KþaÓ?`JÈE©ÈÙ? ìf¡Ýî?©U˼Öaç?ˆ4¨´?h‘nKOoÝ? 5P;vÞ?èì^fܼ?Ô¶QŸÇFÙ?ÊžOê?ÀûH£“?JŒ¼¡˜ä?ׇ2¢q á?°ŸóR`­?ÃPÕ¬Ò?XNQ] Zá?fýü8å?ŠÛ­ççáî?uJ+ZÛ‰é?è"2½X×Ñ?Tÿ®W•Ûè?XßF ©ßê?pW‡”©?mì´‡çï?Ìÿ ø(3Õ?¤÷'^”pÒ?¿º‘ Ðûë?h;Ç7á?`&8H¾È?¨æûþZLè?1$ú¢Þõã?2d@Š&ï?ÞÀ2SïðÖ?pÎ;ó»©?C3èe‚„é?xÞ>|¬ë?;ãý^W‚æ?öyá,”ç?Ø_Ãxkæ?<(VÂÄûÇ?èAZÙ°êÓ?’ºMLÒê?Y­ø1nËá?m7[þ…ì?3ß(⥃å? 9ÃT +Æ?@Bº‚³?À|Ý{PÄ?·q ûÐ?¦²:+7íê?€ÿVyjºÊ? È2‘,4Ø?þÚ«¾Ì?«ãn/œ&ï?(û +æÈ?@$uuêä‘?®Ò~âá?¸P,æËuµ?`¦Êš¾Õ?äžAúðÞÙ?qÐd‡Ý?î+úGªUß?àòÂý/Ä?TË.0˜ Ã?W1ÑUhfä?‚À–Š™rÝ?nFŠƒ*ï?ŽC\/(æ?]` lûî?¦ð„<Ä?¢X°È«$ë?$%Ù!جÄ?24âT&Ð?/vC“ÔKâ?1í\ƒ3Âä?ކ/4Þ?ÁÝM›–ê?\‘É ÷ Ý?¨ }‡éNÈ? T6Ñæ?”.cŒs¢Õ?DÍ0 À?¨¬%&¹€Ã?ÛË5?ì?ÇôÙê å?’ }$G4ß?ÆôC—Ù?`®ùø¤?¾2²íܲÐ?Ô<‘SLö×?”Õû¸P‹Ó?8Êl2Ó Ç?÷EôÑ5é?šÍâ±”ì?ßSxlBç?¶§÷DÖ?p+¶ÚÚÙ?''$€&áä?6è¢%ÛÒÓ?¨t7å¬êâ?Äÿêx„oÞ??`ô¼¸dà?¸}—©›¾?ÜS¥Yëbâ?ä%ϻߔç?—>Øï©Øæ?Ñ׋4á?2M8ó0Ö?8 d|¤ÇÇ?cëŸá?_“Ú²M¶?STRÃê?d}ÖÔ$Ö?¯=‹üÊâ?àÚ¨ƒ!ÿÖ?»PuÚTì?Ç͹㭲æ?hóû<ÂâÑ?LK³î}Ê?--¬6Æè?Äãn6ð#ß?1÷aÒ•›è?Ð&Ó×I±©?Z/&‰Ø?Ö?|yÎ3*Ë?t‰Ì ïÒ? i.ïÐ?ƒtè1U%à?|¶¾ÌJÏ?ðÜ&±\Å?B§°¼€ÑÛ?R‹ÔdÆÓ?²Ê;žBè?Ö¨ÁÃöEî?øæßÓÀ?VŸpGϼï?WH“w Iå?îªÁç7OÓ?ûí$žå?Pi'sÑ«î?Ù9¾2=î?zÈrJG™?ø¥4QU’Û?ÆGw«ñ­Ý?Àž}¼TÇ?©•Ò’Úíç?Œ¹³z£3ë?º8Þp½aÓ?ˆ°]æÁ?ZÎ;_oé? úzÈ[Úà?pÚØ,`l¤?¬43Ã¥î?˜‘­ZÇ?ãõž ©„ç?ð´fÒ‰åå?úN8øTyá?(µÅB«ì?jñY¡â?À„8äçÅ‘?¸Ü 6…ŒÛ?bÕœÒÁPÔ?ü¹I Óí?䔋`¯„Õ?¦È´õÕ?ÂþFn$tÐ?N Q4@ß?X~µ”å`å?šÜ=£\Ñ?hjO­|©Ú?ïÈ 2eÑ?vÆ PÙ1ß?þêæÛIÛ?P°®SÍxÁ?P~Åë««?2Êêá? ÓÈJ´?.«º…þ™ê?ÙC‰ò í?×Õ±~ÞÁ?ˆF§¶?n–æîë?Ðú‡ùÔØ?ÔfzÛ€Ô?ïsS,‘ùä?)c‡óÏå?«z,ú¢?Ök"ûÅÑ?A±ÄÈÏ à?K†æÛ9ûá?Ì©ÜèÁ? ùÙåùã?­§E Âå?ãì é¹ì?À‚UÚ?Î?(Ÿžñ—XÖ?þ¯p*é? û‡Ù]Gã?`%,Öjè?‚£Jw}ì?œEÇÉ«Ý?.r5HgVí?|ž(Ut<Ô?R|B2çÜ?Ö¤‘®“uÚ?“™øÈæ>å?wùÏ#{©ç?ØuéáÔ?%y½kÈúè?мñ,à?Š/IÁÝç?níâ ¾Ü?~NA’ãŠÞ?¥x3Á!è?„Rkç?©±h÷«Žè?(<××áY³?¼ÕtòÒµï?5*Æ…Wœá?l­Þ׉OÛ?¯¯Â¶Í®â?x‹þôØâ?¬H*åüÝ?8Éã?è)Êß¼Ä?æ$éokç?yOWsì?°&‡û «?à(]ÃÐì?H=ÇôŸî?o+žÊ?М^ì£uË?‡_ð'îYç?H(ö“1Ã?¢žšGá#ç? ú+ɽwÇ?sÒ<æ?3"«ˆà?¼¯b¨Î9à?ÊM|—ÿtä?KÄIs5Ä?¤§tã?ôr{½Â?y«Û²½í?܈žØ?ÄÝ?b¥\l= Ó?І›dÆÚ?~ïÇÏØêÐ?ªÌçu„Ëî?à§F¼Çtš?Men>CÐã?”Ï~î&è?ðKÑÆ?™ý½9èì?€a°ÂÅÅ?Ø—Q2Œ÷Ô?Ø µÁ¡lÆ?txûXÃÑ?H $Uî?¨%ÇW=]Û? U¹uß?ÇÙ"éYä?ÚPü8$ä?Ì jÃ*Ñ?ßÀ¶dá?À9Ãÿï8ï?¯˜ZùØEã?Ns¢Â³`ì?.ŽN|ùÑ?ˆ±ÛÔÃÕÒ?è /Ôø»?XëšU_Á? Ä·ž'u”?½ÊC*4Jî?;xë¡Èzå?/û«øw7â?Û}?¨ÏÈ?:bçtï?á±ö‡–hã?KwJ×<ì?Høi~Ö¦è?QÏñšé?”×qFô–?óÊfgß?ÐúßgO±?³p«êÃ?kîz[ô¥í?€ƒ¤Uº?Å· O€œä?ý¶ù^ì?„c·7ÓÜæ?1‰£Q•Då?Úo®·›ÃÑ?`¨æ"‰Ë—?ܼ-LKÕ?Öª… ÎqÞ?çÉzD(!é?xÒUÌî¾Õ?fÒ3.Ú?HÊ܃áh½?¼O'6þ™Ä?â‚–·(.Ù?5Cs¤Žé?¼?‘ë—ä?N%‘MÛç?Ø„‡ó4Ì?6=Š]ïÙë?€-§f.¿?RöþkIÒÙ?vYx±óaÕ?9ÐÌPåî?Ð&E­SÕ?c¯6öŠì?ÈÓÇØ´?ã¹Ý8ë?H¹V…ó¢Ë?k­¢½Xã?DtåÎ<è?ä‹ðïkàâ?Éðg“\eâ?óŒg| Õé?Ú¾wÅ”ðØ?œµ *µiÍ?t™9àÔÞá?$ª…ä¾<Æ? ýC±{à?lx|™[?Ïù œ=à?¸¹†±„§á?3×Ä·óå?; ×9é?- 5ì?ðj‹­ëŽÚ?¬Ã\UÔÌ?ÀHJ;ÕÕ©?à¢%P™å?¼ðoéÇä?Œ$”R<ï? úì½»í?P±n€”J¶?Ъõ³-i¶?Ôã‡;nsè?ˆŸýȽÂÞ?bÞ€¯kÕ?€4Bã"š¦?lf¥—e0æ?²*]ÚùAÒ?ìEíBßË?$·†¯3]ã?qÃùÊä?ªu.<á?ؘI®–nÃ?èôÐJCûÆ?ˆÕL‚ŒHê?qƒ *Éä?Á¤=ô óï?î}„"í?P ;*¨¢?$ŸgŠ£Å??·CÛBì?@Ýáë&Þæ?aW™wå?>8™Åµ?ø`ÒˆSÖ?F}åø˜ï?óp9’¿Væ?@åëFl“?H#yÇ‚Å?zt˜×¬%Ó?N¢vt@Ô?܃hjËÛ?̧7ÿê²à?0Â+3¹?l–VÓïÝ?ðÎw7Ä?ìpã}ªµÎ?À;_¬†?á<œ¬ÀŒå?ðà (NWË?èO-Šræ?9¦Úêí?p#gÕZNÚ?²yÍ— É?¤aæÔnì?» Ó7Já?Í¿ðzÇ?ä®BáTBÍ?2Ü%ÙÏØâ?­G¾äóÿè?e£‡áèç?®jú—¼Û?9.´Sî?ؼM@ÌÜ?¼IújÐ?@ªŠpÒ1¡?86K CÚ?ô&fÁ?®qp€O¯ä?iî´ôtí?n^={Ý? Äglþþî?Ná{@~ê?8tìÞ[¼?98‰nÅí?ªrãr\?¸˜ôëž_º?´IäÝ-|Û?òhkîë¡Ú? [̦"kâ?gl#ã?|¯àŸíê?8Ð¥AÛ³¾? ÃáWIªÞ?‚ª dZï?äv{å#Õ?¦‘isAâ?À'¿ã‰Ì?–Q˃é?ØŒodÄÉâ?UÞ(?ëä?ðµà÷Ö±?Œ'AéÉ?}Ñà˜çjä?|«7Òã? O ›¶™?mM†“üë?@Ûz8s‰¹?.ËC]ëIÚ?x1ËåKå?¨æ=G»×?¸p ?Ú?Ç÷ÈÁ>å?ò°yþaˆÔ?d5.dõÜÂ?:£Žû AÙ?pPÜr;¿Û?‰<–YqDï?>¼¸D„UÓ?lUcô-í?z5_‚Ñ?˜B¤Iú¶é?¾zÎõ""ç?0†ñÍO2Ï?´ÊKÅ&§Ã?d»Ó EXî?Am<¤šã?8¨¢€'-Ð?‚jp(Õ?ºÉÔ|YÙ?0ö,0 ¨?ÖGS_ë?ûèÖ9Ðê?Ð(ͪå]á?èå…*Bî?ë›!ÿãÝê?Ë[ØbpË?n\wWÀÐ?°dfüȸ?¯{ש»?´éŒdï?Ž‚é‘âä?^¨Û8¢æ?Ü˳jÉ?T0yzù½Ê?2zhsPá?`ÞõD|à?´rÊÀÃ?›UL+fní?Ìç7ør>æ?Qœ´Öµ?ùEƒ+Èöâ?xó ¡M¡½?Pp’CGçÌ?¹fDu¯úë?@*„­ÔŒÑ?µ„taVÿä?€vÎjD ?Àò]Ÿ¼\²?ZŒ»Þ›#Ó?IÈiÛë?ò+ìG¾Õ?ˆÅ»Âè?¼Š¥×?SéÀag)â?qíöy é?@ -d†È?°@ŸÃÖŸ?Ï|_xÝ?`éPM7•? •¦f?ˆ†USo²?ðÝ·FõÀº?4q$éjã?œ*õúÔ?€€ºIr¤Ø?β}¡–Xß?]û•z¥î?ÈÜ·òMÏ?Æ«ÆÍžì?@P˜û.è—?‘hØ>ã?èâyéuþÅ?…ótqê?’;ˆ½šÖ?übbž¥Ò?šr[ýçÐ?§¢v£E»á?Ÿ%Æ ‹æ?:ö¤˜Sá?ŒÞåraÍ?žu³Úà‚î?°º#Æ=Ű?l•Å)_Ø?²1žœà?Ç€ 3¸•á?ÓX6,=Ëï?°¹„«¨W¯?‰Ãüi×Ü?â˜`C•Û?Ðze—'È?hÈ6Ç·?T¥ýb}!É?T{°˜ÍÈ?Р­ÐÓ?´:tA¬á?MöôÇ+Éà?´&„šß?G#.Ë6’á?€&üHÛç?vx¸OtíÓ?~]&®‘5ê? Ü{ì%Ë?n†øÕ?¨ô+òà?¯ô‚µcê?€ÕØÚ?ÂE¯!ÈyÙ?sùî'òÛ?ð 8\„Ë?{Ó“MˆŽê?YH¦ ½,è?2ÑÿZ|Õ?Ÿv¾öå4î?Ðò7¥U Æ?Ð@ïå?Xƒ6&ø(»?˜0¶ á?Mäa7è?´™á÷ÿ¬Ò?pìeø!¾?ÎÆWß·î?@ÊkËO¢Ï?R;{ –ê?†NŸ•{é? ñ‹g=zÔ?&QLï?Ä¡°ËÊÀ?€=àSÀ^à?oyiíéí?„ÄôÍ2í?¾ÔªÆíë?ØéϺ¤?`û³>Ylß?ÄVGäâ?ÎÄä2gÒ? nSÞ§ ?þ1a'¿Â?Ÿ *sS[í?@ìËoÇm”?“[Ÿˆ#sã?ÄÒ“qñå?4øî²Ø?(ÏÛøëÎ?>t ãnÙ?\¨Î_r¼Ö?`cE=¼Ä? !ÆöÀ à?…s¸òSâ?PQ•µ±¾¡?¦«5ßcÜ?bFÆË(^ì?ð·äfrª?àŠ›á~Ê?&ÿ»¶NÇí?Éé.†qç?%ŸQŠRFé?¼¸<¢ªä?€ åTn3Æ?v]~ oä?$à ‹—ãã?{.¿™û±á?ü´e* ÅÇ?Z%øË¹aÞ?ý•zBÕôå?•e\ lì?…|Aʵ?(Ç߯2ÙÁ?1Ðè>+Èí?\I•€‰$×?¸cvÏÖ?hš5@»óì?>v Xãâ?ðÝWMQì?\\Áã±$Ç?‰"2Ù8œá?ÂIàP©Aî?úT-Ž ç?)´ ¦ýøè?¬dÈÄ”×?·_Ù³E ä?ån%P†Há?Lç%~FxÉ?þ Ô,Z§ä?+%_ß?’o£@Òä?×ñÛ¹§Ï?b$¥¥ Û?¬™ Pä?.+p<&vÐ?ÀWŒN‚¬?dö«vSì?Ol&»ì?lÑšW˜‚é? H”L7sì?n÷Ò³wVÜ?Ñ:ÈN›ë?ëZG&®Vë?rJEê?‚=µö!â?•GÇîñî? 8)sÏè?(ƒ‹âµ?Ð-ÝnÌ]½?°O.ªB ×?¯= j1ã?’uNíÔ?ZºZˆå?ð|R-q±?â”.µÌë?À5ÓÑ?ÑA,îônï?í,·æ?gØÏ ðyé? PC»˜˜?¡ ýyä?ÂjO›>Ñì?`9O#¡î?¨ìCÄ)î?¢ÍÏËTã?À' n³?8?éùÙ?€ º[w/?EÌÓ”ƒâ?Àc8Ú…Ç?ׄíŽ]ˆå?PbˆFÚ?@¢ÜÇ~ÂÙ?¤Ì4´lbÌ?ÀÉ_o•sÞ?òû5]¦Ú?˜‘â¬ÑŒå?61¯Q-Ñ?4-X^‹Ù? ê]ƒ …‘?à™jYïѶ?, jS?RÚ•gÖ?`iA ª¦?~SêóÔç?,}©¬ùÄ?Z¡ á?ûÆE­çƒä?1Ö •—í?[=³€r—ì?,.ç¿ð×?xöÐâÐç?<[¡Øøã?; i³–ç?Œ~†vûà?Ç"FAöuä?Dí¡(:¹î?ß“d(/æ?3¸8J™æ?·˜3ÓEˆï?öž·!Íì?"XhüU,ë?ø¢ùJÔ°?Â~›ÎÜ?A+’ òé?Œ;Ójë_Û?ëoIÒâ?L q°¦ê?W u:Å?8°GßȘ?À,g®!¢?’”ú÷‚³î?´Ày¨üÇ?äÆŽ+JÂ?6Bùàíì?°±öãô¸?zp‘¬Óß?³û­ÅAï?„AÿGûì?Øü³õ#Ñ?NAÂ4)Ãâ?§Lø”íï?H´£(Ê?ˆÉ¸ËÏäÄ?|^Óù‹pÁ?ð¡wäEl®?eC¨µ¼Zí?÷ð›ûç?cq‡Ÿn›è?l…aÛ+¢Ú?h˜íýLê?ðÍW\J²²?b å+ÿí?°Ð$O3ת?á4_+¦ï?dÌôäêÓ?™‡idÓœé?°Ã92ÍÍ?@ò/@£z?JðŸå?¾®ÿ!›Ôá?˜¤ø˜2WÏ?hG·šÖ?0k™aõã?h!Gdá?D ßÅâ?ºâß´óè?ë³Ï¹ðî?ø£2éÄ?r˜mµ1iÞ?2DëGSÑ?QZêÆ=æê?æ9u6Ù?Fè}O„xè?bµÉ%EÞ?ìtÇõoÐ?0>8ŒB\Ê?àÕÞAaˆ´?z}âY˜Û?øáµ™mß?Úò8Z§üé?2m™!D‰á?̈'V»Ì?ó˜sG™eé?yÅ^#­ç?Øpº ÃÏ?æ^ý0êá?2°7>øøÙ?Ù2óÍ?é?}øzã?6îõË šé?^~‰—ßËë?q,¢Ø9ê?Ô¨}æ•aÁ?rsʹ?4 Vì!å?0mymeå?~°r<( ×?`‹ÿ˜£˜¨?ðÌ{>­è?>”—ž í?·Ó®têÔ?`‚ü¿Éàä?`C³"£˜É?Y€< 5é?88ØÆÓ?ÉvBbóÀà?1“³¼ê?š…¯N€Þ?”«¢²)Ùß?Jnýïç?{Œ§q‚à?-K>—:±ç?ÄÇ Má!Ù?”ÞÔµŸ}Ð?Ë?ã‰ûç?wJÞü–Ûè?hªð•Ëçä?(Q~—såç?–äé÷Ô?[|H¡„ëê?Aa¼CðZë?T'Ô=HcÃ?£ˆAHNØì?|Šœá×È? ‘è¶Ø?_ÝôQŸæ?†°q¿-Ô?0%ë™yì?0MëSúÎ?ù0 Îã·é?e©[x.¤ã?bÀü˜2åÒ?Ÿñ‘æ[ì?YK½‘Uç?ËxL+ÞŠæ?#]ç&(á?¾>ê‚o;æ?Ò#½MÖ?SW Ñ£å?r/£6p}í?\ãôbÔ?U[åjòå?Êéån¢WÛ?0þf$4¯?üÌÂàuÅ?h¦˜8?-Ù?áÉö¿ªï?(‰÷zT°Ó?ïÏ®kPê?û ®±Å³í?À Ùûð½?XÝTÓIëÝ?œÜ³O]È?+üfNÔžì?~õ£ ‡ ì?̱·%KÖ?”ƒßÝé?hÕ*©bç?*÷cJEÉä?Q~…â<ì?_É&Ú&Ìá?jönI~é? Y?ùdÒã? ŽŒì¤?ä?ŸÐƒ«°÷á?ºiw§ËŠÜ?„175äÒÊ?ÝnüOxá?n€ç$ÞÝÖ?QB†%_ ç?øZÑs`ëç?Ö!4`˜ë?´å¶—RÍÁ?5Vçc4Åà?JMhD[=Ø?Ëzhû=;ã?8«/Ø€iÏ? ¾²1·¾æ?PÞXž1õÝ?º#ïµÙ?ÎjTÎß?vqf>[Ó?æÄø£NöÜ?sÌš ã?h˜Fšâ_Ò?Ìï x­è?„"«žt3Ð?LF°h=¡ã?°º±¶\ÃÌ?Ð/ÂeMÁí?/C½Sxòá? ʱùÀï?ñ²ÿNë?pæïl ðµ?~Ž~úñóï?͈õ>ØÉï?¨‘‚€²?WkŒ:¶Õé? "“Õ”ê?•vU­ÕÎé?ˆ•éeÖ?𘿠iÓª?öáÀ¾Õ?Ü7׉2‹æ?×MŒvkî?”’ÎÀâ?ÇFŸÇU0à? {ùbÇïà?”Tðg€Ö?fO÷P¸ï?ÅÛèýîzá?²] ™Y‰Ô?º, òÝ?ŠPUî?nàÝVñí?a/‘€6ë?êå¤å?íg…£ehâ?\“Ù”€ˆÞ?ZÜúºå?ŠlYî?äR!Á?L©R™ãÄ?`q‡eÞÉ?ŸoRÄá?0õßhÕá?“9rC«Uã? <¿/¢? Ak÷¥$Í?Ưb9Þ?êÓ¥ºØ? …2r ã?À Ü@ÔŽ?ˆ¼?èrm`Í?ŒyØcSÐÆ?€%œ7…Õ?x•«ÛÕ/Ó?•L ÎÕè?¸Ç(mÚ?dâžµ¥ä?ûÏw›rè?âdõ/HŽÕ?T}Û*•ÖÞ?œ.ËÞ?@;¬Âhµ?ø±ÙžÓ#Ñ? Óv†#˜³?Ò3WÇÿ í?$®ñt~Ìç?܉)8®?aŠÎPtá?P›p‹í"¦?:÷KYiè?ԨɋÄòÏ?æ•·Û‘á?l:0 ʦÐ?;³žKë?8©UìÂà³?à*¼2¨Ðª?‰âUÏ’ë?{Ñu rí?4¾ "’î?ÔžS\ÇÓ?núÿLÕ?ç 'gæ?´t|”Ì®Æ?‹ŽÕôhè?üeší/Ëå?T¢•³ñžÝ?šØxàf,Ú?@¯á´<€¢?hŠÛ„øÏ? Ñh,-¢?ñ‡f>è?ê4Ý,Œä?N¥g½Ô?‘D™*±æ?Æñiì.¹ë?Üst…Ø?ø*‡þ½Í?ÎdB}îÚ?Ū‡çdÀï?e…¨û.Â?_4x“Zfë?Ô‰«»Ö?amâz4é?vf XgÚ×?è¥þŒ8ˆÜ?¤›B-Šï?6Õ2^cè?®AJ4ƒé?̸eëiÇ?!ñ™¡¹.î?º»›œàä?@–¼Ù 0í?D'ââÉ?dOÅNyŠÍ?ÄÖØ¡°ÇÈ?8ôA·Ýî?äTžchÍ?€ÙhÎk†?FŸ³GÆ”í?˜ËíÛ³Ú?Ô-q* Õ?ƒÆ};¥&â?wA´;6qç?@×øZð?ïð,-wâ?àL„^c(Ã?Æü€™6±Ò?¨-ÃTø·?Þ•Ö€ Ší?g¿>×úþë?Um,ÂÃé?R=±1øûï?€nÏçÓÙ?PØŠÏ2lÇ?@ÒýïE‘›?ÆGo/gþî?²XjÛïï? ¡yà»?´IÕ¾Ç?oùÿèr(ì?ÞŒ¹¥ãqã?üVrájÓ?[;¨0Ñâ?’LHhÓ×?ëA‚>ê?äx>¬@Ò?PŸô£e*Ô?“Ml¾¦ç?Pö2—Ø?%ÈþêÛå?î$8 Û?̸…¡îíÁ?þ}»»Ð?T"l5Ó?h›qâ«Ê?寘è?¬šùöê?+‡9w’3ã?=#{€ì?àÎ¥Ä%JÒ?0MåJ ¼?U[tÕßâ?H$±K5?ul- ¶î?{#UæÇ?Ibk®Ãâ?„ºá§QÇ?´-M2•ÉÑ? ƒ‚ȆÌ?̸Hø|Â?F¿äŽÚä?—¨ØqW'è?d9· 5hà?V`16aë?|ίÂù±Ü?¦Ú÷©Cmî?pªt÷þÊ?ÎJ½Ÿfï?@ÍÅ–™?ðžTè?Þ?xügJX¸?3?X=è?0ƒœé?0º”¤ ?”IïðÊ?Ž+oÅËNä?šbðoa ï?è²,‘ž4Ê?ò°5ÎP!Ò?͉½©}ç?Aÿ'Qyæ?ûœký9¡ä?ɉ0^çå?!þ¼.è?ب} öûµ? js=(ãã?@­Þj»¼?Ä_ص0Ýä?‡YJOºä? 'ýì€ã?ÕEwI\|æ?@-Ñ‡× ?槃ld‘ì?–¥Hï|AÒ?ð¼•k^ ¨?Æ'i‰ÜØ?;ŠÄítã? ÛüI°¢·?Tæ¡­~Ê?ÍFî@§ à?¤»ûf2Þ?À’"·±ñœ?b<](ç?êYÙ9rê?<]˜à˦Í?VFŸ!Õ?Ô¬ç}õî×?ðc¾vÞÚ?ûí+ T·?Š8p ƒÞ?\ü—µ]Á?Æ£Up)×?–¼VE£?Þ?pÉþ <™­?B?h @^á?i¹†çj¦ï?x}#cY#è?ab¹9°óè?PÕ¿òëÖ?°WçÀYßÛ?È55 Uo¶?¾¢5JÓ?à£SÐÉî?ô[1DHì??LVˆ‡é?ð'IéÊÆÕ?xqJË4aÓ??nÜÑ?лa㑨Â?@C›“uý”?2Ÿ»¨ 4í?±Ù²­ëßã?ÞuúiÖé?tÝ"™•öà?J§ª~77á?´ú™seÎÓ?ÖxµÒ…Ü?¶¿mÒ6,×?2ä‰nòá?QTçèé?}ºAˆôË?Ì[æµÝ Ð?<)?U¹\ë?4©/úíåÄ?ÆøRDÂâì?@¸M!b„?ùí˜n¿ä?Úˆb¥\Û?ü%Ž¢qà?Œ&ÚÓCÌ?tÌb(D í?O¾õXâ?YŽ“îñ¸ä?Ì’蔚Õ?0¨›Ü? W¼Ì¢ì?KÌáaôç?HÍÜÐ^ªÚ?ð˜.cÑ©?øÔ ‚—½?¥=éýï?(~DÇ&~Ï?Ïû®ÑÉí? øÙ¥fuà?p‰—sã¿ì?й²Ð=æ?ÃÂÐQÖ?ÈÞªCÝ?——•MÈé?|ÜÙ7³oä?Hôm>ÇÄä?eÚ2 Ïnç?d›š*„wÇ?ªcõí„ðß?÷óˆóåã?rò_9íÏ?W-b„¾Âá? Ú½MMQ¡?6’¥`ÓÐê?ÂxÓ1 ×?þ(ÏbðfÜ?@\#è~ç?sR çDå?ˆ7ýkH;ç?Êk¿¿­Ú? a¡˜Xê?P:븴Ü?Ý‹#Ôè?Qd0 ʃê?ŒN½¹ÑÄ?æŒaoƒí?¹Í2¶ŽÕ?9\fªT è? yý¶#¨“?PÀ9ë<‡¼?(Í1èƒÓ?„0É]È?B·»¥†Õ?ƒ}O£_æ?`^îöÊ?ñDDi ¾ì?êJÄØiuÖ?^Q½XâÑ?øƒ:ü[¼Ë?F¢Q±\”ì?å„ õà?·µÿõwë?…°syyï? =w…óà¹?XDFœÙÍ?nŠIµuæ?~Ză¡¶ç?J`mÑbà?tøÍËêï?BŸö (Ö? Ô+Â{Æ?‡a¼Ìæ?j33«ÚÖÛ? ryžYÒ”?¥K›IÉ?·%Á¥Šì?(Ñ~ )ê?*N‡v¾Û?´1oòà?„ æ‡Å?-ícˆ)Õî?ðàu:jº?àí4:¸×?vúïaíÞß? †ª1Ø«?N&ÇÜ? æ/ˆ1ê?‚ÃÓÝ?¦ˆ!°Úz|ÓÖ?Ð??f§?⬹¬ä?¡Õi>±"é?Ú¢-F»ë?€’±¡Å?XÃÙRûÖÀ?ò ú™Ù?ÑxŸýËá?Lk8²ÀÀ?½÷áI Âá?:°[ŽP»Ô?,s!´ &î?Wûeº‹Óì?º c©"è? ­`óé4™?`ò€é~«‘?”÷üP„èÇ? )|í~.æ?F®kOÍÕ?86ªÊÔ™è?øãLW±¸?Îå1.è?k@ŠI§?û¢Ž£›Ð?è©?Þ{Û?tZ·«æ?¸X°Km‚Ç?à©!al¦?øF~#€Ù?’n“7ñâ?Ð8NùÇ«?pôçnèW¯?Á Ó×Ýæ?ž]ËóÖ?ú³ä êgè?ƒÀÓ Vwì?Ø&€RH Í?@˜çjñÃé?]…æv/5ë?ÈB¸^Ñ?7¯o->ûá?0%:+Iú»?š€ n€¹Ý? 3´DqÄ? r}:Æ?0P„:¼Ë?‹ MùœÕà?îÐBpÕ?Ö¿Üb(kí?Pç„gÃJÃ?eÑi°Á:ä?Àø€Ûd?]ÓÓ§ææ?-ü3Ó`©è?4Øyï±Ø?üL`é?`ƒtÉÎVë?J«囊î?úÐΫi/Ò?,WýjhEê?~fzYî?Ÿx&wqà?©‰Uð¯é?¼'°‘½RÌ?Æ@dËúgâ?øŽòf‚uÅ?ÐZܘwe­?ŽUÎןÕ?`²ôΡ?É[§®¼Ý?OÝ]“ê?  9£¬gÕ?îáà?6mÎ)â©Ð? ê+:Ãê?0‹« FûÁ?É¥—ãCßä?صU(lË? ¯`ï? >ƒ–‘?ö_,ŽH‹Ý?v(—ïà?³¤ã?zò.˜üeÓ?r¬8aví?À6J´¬›?..8úäÞ?Q–Í¿«ç?ŽŽœÎVÙ?d×D’§yã?àU·Ä?nT§÷ zÔ?-¼]Aë?XM8±.º?xÍrFÈ?äLUZÙ?ÖO°a.æ?DÚ»3È?²«‰uò„â?ÐÿÄf¤Ú?ª·µ©%Ý?€äb·³±ã?(r#îw³?ÌÕSO[0Û?YÕ€à?¾¦yUv3ï?4# $y¨?ð‰]ËÑÕ?-ky´úë?¸{^ݤÃ?Ffþ×ø’Ü?×yª Ï?Ê¢2ègê?×m`nÎ?¶ÕÄAùß?()ÊpDîÌ?ÞDSŽÑ?`‹KÃ? ¡3Ûé?`VÇ­MÜê?¬2«iò§Ô?3Ô¶¡í?f„êúpÚ?z¦CþÓþÜ?ß/lBï?Lù¾ÂVë?ƒ\6ݦæ?|Ýýp±ë?¼þsŠ5=ì?`qÍ´ý®?“Š,Ì^è?âZþ5U ë?@‘X¼Ã?ÀǦ‘žž¼?lˆ­=6wÙ?Pö³Ç£º?vYÈ$üÞÝ?6ôÃô å?*—¨kÑî?iÁz;Ý?ú×ßkdÝ?*Ø$g‡ Ô?6Ců°ï?-Ì‹|w‡é?lBú6VÐÉ?¿ìÁ0`è?€Þú?r?rSü}é?«b‡j¶?À˜þóïîÆ?ÔÁ·´½>Â?9kå Í è?º\ÐWÒ?´)døWä?bLFxÚ?¬ƒ“—Åç×?`Õ6’Ö Ê?ÀçÞ0\ë?Išl.î?ýáhej æ?˜ïGqdí?n‡„ròrï?¢$¦üs\Ù?è=Hƒ˜³?¨ßú\ìê?bò;R7é?£éh‘†9à?ÂGÇËï?bƒT.Ô?Hj; ¿õç?€‹RT~Öï?s0kcçÌà?’xb2CÛ?¾]  °·Ó?‚úåN {Ó?¢9aá"–å? ßÌä?à{¶ Ów®?TA@¯¹oÞ?†•ïhœ–ã?(½?fm?p6¶BBݶ?ÏNxã?xíT ¹¿ê?pq>ü­×?€áÕ8\§?ê,Ñê*ˆÙ?tÜG<–à?*ÚNùÞÔ?ªÚ㣋ï?4 Y^Ù?øy^ã)È?8>ŒªÈÇÎ?²¤“× ›å?sÇáäÂæ?¸ ¢ËÞ ä?f+EMfJï?YSàºî?ƒ`‡(Çã?“ps»ùç?€ž£ã'œ?ëÍàqœä?4‰`u—Í?€åÑRü·?ÚZ;(“Ð?(ÌsÏh?öÆí›HÛ?)ù¤º#©è?6Â/·æÕ?ËÆE9ˆá?{òùqÁšé?äl톎ðÒ?üÔl éË?±h­þuÞ?ž$ „eá?`¾îBLÃ?LOáÙE²Ú?ƒ §Ê£á?H–Iº4’?% 9 °ì?°¿àï†ï?ðqH ÇÙ?ÃB¤lÄç?˜>,Êää?¬xÁ×Èà?@êʦ[6“?@³ÞRXÅ©?HøÄæV?Àn¡3H¾?ðÕˆ¬iG·?¢ïÛ¹ßmÜ?0he‹eá?bóöfë?$ãa@ Î?ŒÁâAQEå?°€Y;¬Éº?8©4æ?€Ð½úFôÈ?£d̓ç?䓇‹HÔ?ˆÄ©·ôî?(êœI˜ž±?UœžÔÿží?ž*åÇ[æ?Ž ÇIÁ?‚«`ìçPÞ?mù­ÿxé?ßÒ>ƒFå?•tEi8Uá? æR'Gë?ÑðÃeöÑ?pãžô¡?Òyb]àõØ?I>aæ?Ò¨GÛî?× ‚ é?OjmxYôé?ÁPc£8›ì?®«dÿà?Òp%€Ü?–ƒk"%å?¼n"wò×?„ý™YÙ>é?ø¯aÁmkÊ?¬_™mlÃ?dxLÓÛÒ?ÀØíHdà¡?X‘¯«ºˆÅ?1³ŠÑ³é?ýªB÷wâ?쀉›Bí?^>ÓPâ?\ìÒ‚` ä?ÂŒ1™î?Ði)wÀá?TkÙ¡ûá?+¨âYä?-ÿOØgçî?#ìäI­ã?Þó1þ{uã?èBÒ~´sé?á[÷,º?0К¬;uÌ?$S@Æ#æÕ?@Èž²½IÑ?$ÅÉËíöê?Ô &÷ië?Òåw"í?’ÊYûá:ã?(¶W@²?äÕºÛ=Ââ?’ëØGÍrì?@»:U§?£I§È±å?£n¥—ì?*xìÖHä?NÞ¡FÖ?PÛüêŽpÀ?œF+r‡Ó?t(¶ã£Ñ?‰¿èÀéÏ?à›tjÚ·?È6´>_Ö?¸˜P&Câ?¨ïŠ.þÁ?Þ< <äï?Ê\=èIÚì?Ú2ÓD•îä?è’ j§å?Ù¬ë:¢ëé?ØPJ–ý(²?Æ71¢‹Ù?4å]"Æ?¤†éÉ-0Ï?@!ZqÜ?n rÌÔ?ˆ½öxQäê?$Ø ÛÃOé?:³¿þFµÚ?N$¸¢áî?&–V$sFã?ýòÄ'Æ¥? §à/Çê?s4¶àOZê? eôôÁé?l½¾Ä&õÞ?sÒ¸õš˜à?°ÎF°Ä?¿<\x´?°qHÿ¢§¯?$+´üQãØ?¸d¡ƒ!È? t”°2?ïÁW0§Âã?¤†àõ-òä?ÔܘõycÕ?÷?¢ùí?gæ¶«êié?eñîÏè?ž×ÅGß?ZâÈ¢í?ŠïºÆiÓ? &¹¡Äµ?€õlaà?€ o=W˜?,×ʵæ?x:Ä ÕÇá?œEèXµë?ÚjNÛ‘ç?¨hUïc»Ä?g× Xëâ?ê¿D3/æ?Ø|ßœÕ Ó?â覘íÕ?Dƒ$ƒàÌ?Ƶ }ãMâ?R<ìgÁÛ?É×ö NÅê?Vèù’g—Ú?þq”z†ß?Ü=«Àséå?X*‹{7>Â?8kÐ÷£ŠÃ?àL|…°Ö?ÌE.ºUÓ?ýµHôR×î?ÈsKAÃ?Há™j[Ú?F é(vã?lãô‹XÆ?âéI­iÚ?vg‰côŸÔ? ™)„#¯? š·XwLâ?/ôù‚ŒÝì?dÿÉ*râ?ÎU-àŽ´Ý?ÒÑu÷î?¶¥4yÙ?2kÄ´,üí?(ôªVpUÔ?b(ÛÈç?géÀïÃèâ?äð"n×kÄ?˜Ê˜„?À?æ¿I.&˜Û?EýT?\! 8Åæ?@†—ÿ¥©?]v×öCæ?ÀSô¬‘à?øÀ–¬Á?£vŠ~5nä?‚À/0…?¨“Ëûò¸Ù?ʱBÆüï?ž0ÂR°ËÓ?èncë>o³?€ç½gÙ%ì?Ø›‹»þË?Ð ×~ ?Ò5Œubß?üuÝêÔÖ?•ÁV)d¬ç?Ð#ýÍÙ¯?T”5xIÙ?ðÄ7ÎýíÌ?–³+†Æ¡ß?Š0Vm²rÜ? | ²uÙ? È–ú§Â?àgê¸?ð…{Œýä¸?ÕÆu>iªä?´BÊÃ?ÅØgϼ‚ì?Àhlt5mÞ?0#‡ã_ë?ÀíîÌÕnÌ?òÿæhÝ?„`uï˜Û?h\ïä?¤9™qâ?@Ég¶?-ZF ï?JNüFÛ²î?Wgx!‡ïë?Ø‚}&écÕ? LæÅƒ]é?®ùhœÏë?màâÎËâ?Kßq5®¸?q¡•í?†Ñà¸v8Ô?™@¥T‰á?Tñ…° Õ?€'IÛ{s½?ÜHkUјÊ?2äçÍþtï?`\ðC…·?>/Ÿô,4æ?ØßDëq¯À?¬/!¬mRÙ?òó# ¤ñã?´l.Oæ?Â57ŠËÇÕ?T€Æ®Ã?\€A”ëÒÎ?ýõ«³ë?1ÙºGàlá?|ä6å=Ñ?…nÖ—ÉQæ?|¥év@VÚ?ñŒRï?íÆ)Œv\ä?íQ°©]Kâ?P~uTAÕ?ÉãÕ£±Šê?„²#˜Þ?¸.-°sÇ??<ùDÚ?îP¨,ã?Œ7(ô·?Dïzòî?‹+Þê?S‹ÒbGå?š ÙÖÈÜ?wEä[è?À`FË)‘?i»§ö¿½?Ó-h¯)òâ?ŠŠpñî?¶ŽrÔ@}á?Ù/ïï?ðœY±?–Àëã¡Ð?¬`%uuÊ?Ü ø¸NJé?0 ZO–á?PRP︪?üÕò„¤Ç?x%9}·?PMK‡•¨Ò?$´0œ»é?ÓFh{î?ÝT9$ Tí?•«ÆÃ¿râ?ªvè*]lØ?ÔÜ÷ |Ù?%=;>ÂNì?šG›P/€ë?T?ÿ7nÙ?`¥˜Žéçá?NÙUÃ{BÕ?Šy®Ìtºß?àêרQÞ?[‡Ãçã?/}“Âì?LÐ)ù¡Ã?ä!Î…9Á?(_¹yôhØ?yi¢~@Üê?Оb¨è?Œ*‚É¿ ë?=`‚d±lä?'»ª·î?lš´7\ðÆ?|)ʺ©kÈ?Ìö[w ©í?ôŽ L’À?—¨ÈÎ ê?rT*[üvÐ?u{ØöÿÍ?¶8Qsé?ðX}›5Ó¢?˜ÆT(0³?«DÍ9¢¥ï?œ[2 ,Å?²-¹°ZÔ?Zû÷aè?ØÈiÝÿÆ?`òÉW ¡?¨ÙÊû¹@Ô?`¢*¨î³?äwed<Ú? TÂ(²ã?¤X€K°æ?•‰ô6âZî?R;Ìâºæà?8õp)è?ªF÷ûí?$‘¢Ë®Ý?$Í‚íÅì?8à §zÎ?0‰EL'Ì?Õ%!Âé?_j]gë?þxOnç?•-á%É—ä?¬Á”¸¦ãÍ?;ᮈÛ?£%°ºé?ëÿbzï?húšÉšFâ?Ý s§ÿï?¢ö•ÓxÆ?|p¾º"Ñ?جäTßUÊ?É”C·gÁé?CU°Mæ?j‡IIyË?V¿]ûÛHÑ?xÓFŒÏ±?R€|æ¥<Ó? £ªÀMã? .h!ÿ ì?ãâ:Äd“å?¬á‰é€¹Ü?6:nÓÉç?¶¶Æñ½Ôß?ü;§ø€Ö?ï¯&õX=à?ôò0wèŒâ?xœK °w¶?Èu¶‡¤³?^6küÖ?¹Í…üœá?­S~î[³ä? ±ý•lî?Å8²Nôä?T0ùDï?S†%¢ç¢ç?àþ½V®?Fµ“$~›Õ?Ò{YÙÓ? ;ôõmc—?Cl] ±ë?©u>ù$–ä?gH°X±›ê?V“ÀÓ°æß?[ã£;K€ç?‚œOõVØ?èJ`óùã?0›açî}í?ô·k9qé?ÞØ²a˜aã?pŠ!˜Ïà±?äαéÇ?HŒ«þï?øâZ´,íÍ?(/Ñ7·«ß?¼ÆZˆ§íÕ?ŒÒ¿ ŠÕ?Ê YYø-Ú?üI©qñÅÅ?˜…íÝÿæ?8:”Ê?Ö¹×€À¿æ?̤å¶Ã?¯T²Lé? >lH{å?ö_CÍÉí?Î~&°ÖÝ?ÔPIŠgè?zíÔ“èKë?ô%h·:Ý?pœL¸lQé?†2Zš1¬ï? wà˜x¼?:â¬Ñ“å×?u#*6î@ï? ¶#ÎÕ?×…DØ„”î? N›øß?fÊÙ?€U(Œ ²ç?P¡3ï?¿U÷ú0£è?øOVÔë®Ê?çàYZ’â?BÂDš½zê?ª–\Õà?g%bÉOKà?–+&Tû~Ø?é‡ä«Ý?PžxöVã?pŠ'^Þƒ ?(Z¦»À¤´?c^t_Ù?ÜÁÞÄ?Ù‘Û½¸é?) —dŒâ?ÏRH Ä}?ÌÉÃÔbÂÌ?”_ë2X¶Ê?ßêv9Dnà?ÂÜw3då?È´šZe°?D '_"Eà?³Ó?Z3yá?Љ÷Þâ¸è?Зà§´à?#­ AF‚ê?ZªÈ 4å?l¸Áqè?<ÝHÕ?v)‡6Õ"ï?@àñŸ`o‘?§pGkýºë??<m?m?±—¹åMâ?ïcJû½Êé?¤zæ¡…é?D—ÇŽßß?ÀéÁÆÒ?O\2¾bä?¡±¯à…þé?Íú )ãmå?ó„±ÿì?óã¨QSá?€ÕU‚ƒ/Ö?Ü5hºÐ?}J¡DzŸì?íù®Úì?Ó»€‹MFä?`ªÐæ ¯?€Ĩ‡ ”?@Ý<ÉSøŽ?˜{ "C‚¹?°ÞË^ ’Õ?˜KbcQë?øÞKE•ë?¤Ã€?¬¾Ú?Ah=v˜á?CO="»ê?½võ}ƒâ?nö=RaÛ?ˆPL4×?Áêÿ»æ?]bà)â?,¡[>Рí?¤ÑüÜ(Û?‚ra"A°?`À·b¢¥?º"{þ][á?Ð?¾ÑÎ?¨–!“)»?}ë–·Ãæ?*÷ònrfç?hÌ—ßîë?–¨æ­xÓ?x£E?•Îë?q?£ gã?çÉŠ15²î?Kêã›+Íï? >F[×?>ß âMÝ?p»'rê¡ì?ØÈ9TÜ?¿“£7rýï?:ó‘ÚpÒë?¡ðÐ"Í?‚äo ÊÚ?àÛ~Ï‚µ?"Œ¬›•Ý?ç’ëÍ2ä?ì«?Ûþ´?E}E0MÝæ?ݸ? ÇÄã?%â&«„ßî?˜4”-_D¾?°ØÐXÜ?ȹÔw‚²?Ô”ÉRƒé?Nqª‹À„Ö?4µJyÙIÆ?‚ŸqGMÞ?¦vë…;&ë?+K^ÃMã?’™Adšà?œÿžg,Ý?ù½¿ƒS¥?|­¶|qÉ?ŒË§ÓÝ?ú­I]©sç? ÐWÛMÔ?n™t«6Ø? ‘2Ç>Ë? ¾ÁP‡üÀ?‚\¬äDÔ?@OšÊf6?¹»›}.\â? ­Õä?Š%œ-àºá?l—* _Æ?ÈvÐŒ"¶?+ð@„Ìã?ˆhX1šÛ? Ÿ(Ä?¬‡åIuÏà? Ø«¾ò»Ñ?ÉúãÇÐÑë?"§b¢ÖôÙ?‚H+yðã?…¿¦Ý¡§?ené;žRá?šî•sÔ?ð”¤]ć¬?§$ê—ší?ඃ†Ô?PèÌ·dÔ?%c´¿Râ?^ˆfˆsí?|w™Ÿ×Ô?BÏæo(©Ö?ôð3½PÞ?K]2žÐïè?b9y7¡ÆÒ?~´ˆ*`0å?‹´­Ù?lØ7ü#Ó?€79”%‰¥?$ö5ì#Ç?/Íà;ë?Gÿ òqá?rPwµ¶À?àOαèŸ?€‘Æaë/r?ª$,ǸZâ?|ïí†Þ#Ô? ¶³óÕóæ?¨ƒq„F©ï?¬ CÝÕÀà?P@IU’’´?°\Aõ*¡?m %¢j¦æ?Ä4ÍMržÛ?‚²ž©è©î?u›i!a˜á?ȯL‚"â? vÏ}Ð?Â8+@ûá?pû¬Ë§²·?ÓÇK¦ŸŸà?xE&ëb×?¨äƒ#®Í´?Ja2Bæ?Hù§²žØ?à@ÛhÕ™?ŽäÄuÑ?yëg…Óê?jÜ5‰R½ê?_Xvp*é?Z¥ß?zlØ”4?Ô?ø_Yϰ4??Ùœ”ßã?~ñ ŒDÕ?DçX×Õ?€C°×™p? ãp·oÒá?àñ]Aá$ž?`Ú¦ŠÜË?îÄ.àlHê?˜ˆâKçì?pઠ± å?:òš¼äï?ü·ÐÔ?ø*`>ø¹?;]&¹¤Øæ?` dèç”?ðÀÁl¦?PÅü/´ç?4DËF9ï?,QÁ“oì?P¬`îŽü¾?£$µæŸÝä?h.‘V¾@·?Φš¸Cƒë?ðaËZÊ„²?nõ%j"îß? 9‹ÇN¶?´£ÔÉOã?èÛÆîEì?à={ªØ?&ÙcŒà?úð*æûæ?¡û5¨Šë?!D´ƒµ"ì? Ám³ÍÞ©?ð×›žØ¥?ˆlØwÓ?€Gù õ¯¿?ˆšœ”´?ÿ†a~¤?#V%(ã?€Gü+3ûÀ?ÀÔdœå§Â?`tk:¢Ï?$¢ÖUÈ?Bn¸;Ê›í?Ý5YŒ8˜í?š=r¯‘Õ?€ÁSÒ„ß~?{Tü~Vï?âùOçî?P²-XŸ×?;=N¬Ð?ô¼0”¾Å?ù0ÇvÚ¿í?ÀðX¥\ƒ?ÚYŠÄNÕ?ôü¤Ù÷Ò?8ÚðÉÚá?‘`”“ˆí?Àê>Ϧ¥?ÐXè‹ú¤?vR"•Ö?_W­}à?ÖðSBÒ?ÈuDŠê?€sd¡‡ß?ü\¥mà¦ê?¸õP2 .Ø?ÊK¥º½^ß?q-Tã?pZ5‡PžÉ?üHsÕjäÜ?~ba€Ê?Iõ×Ü4™ê?Î$7¿¥‹ä?Öùßf_‘Ú?½†FÑûÆ?8gãºÂbÕ?b5/ÁXë?œÁ®Ú°Ý?.·XŸŠCÞ?2 rÞ'ê?Ì"¶QÕÑ?A:Ôlèeæ?îP]DÅ|ä?nØbÅl3í?©5Jfu|à?2ˆMú [Ù?®!¿Š@é?Xåø2:ÿ¶?é[—ïÇßï?á}`lG ?ȶòÖ|Ö?RòcÊ„Û?Tú€ þxÜ?Eê¤Lïç?Œ¿5O¥ æ?¦XÉÝÂåå?q¼ Àðí?ØÈÿá1+Á?¢º´SÏÛ?.’.Jë?×½2į?ÀTåD£?KÁ¦}í?µHŸÁ4ì?ƒ_ûnjâ?,“± #ýÕ?* [ÔW8Ý?åPµ|gì?¶•ÏÇa/ë? TÒÜêÂÃ?\î_]‰HØ?i9ˆ÷‘Xì?Ä]úU+é?ßH3K/´ï?†‡Òf²ä?¯Ÿ 5ê?ÎÃñ.€ÖØ? Pˆ§»Îá?MŠgi3‚è?(®à[\Ä?æé PúÇç?Æ|\áè’Ý?àa|3ÆdÒ?êPaÑ?Z®w ·ã?Èzh¶°ŠÍ?UŒ;õwûä?*È™v´gÑ?øí 5U»Ð?Öî•G ´æ?0í°y³­¯?ÀÒ-ä@?ƒü÷9ïÛ?ø¨äß±?¦TƾXÌá? ›`÷Ä·í? Sá®SÚ”?lQ L­¸Ù?€Hñ®¡¾?j¹×³jsè?óÓÞpâ?š0VFß?À”1½³?ý/©ü.ì?–u_÷§?Ù?˜kj Á?$?¨rä¤Ó?J%Qs“8â?,ÍKb6cì?Yõ²CgTì?¨1LyÇ?¦ùÑ4Þ?€Ÿ†&äáÙ?h{¦%…£Á?Ì„&óñé?LaGí*Í?”n/MJÓ?°‡+p”Ã? @ÛÓÑRÛ?ÿ` oÔî?r¿šRRî?zî|¯? ÍrQÀ?Åý5&Ú?ÓPkÃTå?! Ô|f|á?ºÏ>U7ì?ÿÞg™ç?2sÈï?Ö¯—eá?³³90&7æ?þOŠí*Ð?«iÛ YÑæ?îS¤ˆb[î?X[ZhÞïï?X@›QÀ?¨„Ç•ÓgÆ?¥‘uzIé?•HPˆHî?JÌ/RAWÞ?–4Lª++á?tÎ|§®|å?€­r%ÇÇÀ?I短FÚ?’Íð¦,Ì?uçlEÜ?·XѸgç?ÏÖDãà?@Cq“é?”u€Í§Ü?‹]M "aì?Œ“ïWÜê?FÉcß×?À—x+’A³?&À¶8AØ?ûʆ피å?üD4à×Ç?$ã`E½Ù?"êÕD6`à?H7JkÀ–Ø?¯Ý95~â?ðÓ,nMàã?œ¾Tþ@^ä?¼¦éUì?žøR³—í?¨]¬:ë?%w£¼ í?ÒUEö?ç?+·D³-ë?Æû®maç? R›n3åÌ?düãñ»?ìí OÛ‘Í?Õ%öuÖk?¬VÛ‡×?“±Wq´ì?1Ã:C#ç?'ìÂ_ë?Œ’í'›žÕ?4»]qVà?pVUï?OFU"Xoè?7cK`5Ìì?LƼ”!Ñ?d¨Z5M^å?d€@€X-â?XL·çüâ?,Dxï¢Aá?dXªùïÑ?f¼U‹°Ìå?ªR¦rfÚ?Veõ8æÐÙ?œj<âA@À?.2sð+â?Ün—-€¬ß?õ˜‘«?µë?x$t»(Ø?pㆩ ÑË?@–Ä5°–?”iV+¦ÏÇ?ùËÕ¼ÄÑ?¼ò:šNûÆ?ˆíî~eæ?|øÍ¼ÏkÌ?†˜ÊÔ6ÉØ?’jØë¢²?aŠÕŸ»lî?mçL kï?bÍ5Õ¨@ä?ø‘[‰Qñ½?¬´»É?b¦æ- Ô?¼K°Ká?*ÚL>Ô?>²T3cSÞ?äÑ ¡!¿Þ?xàI Œæ?ô¼NK›!ë?){F_²Ä?ÓHc8;ì?DAS!aµÞ?`l€¼8GË?x%†èbd²?XSG4å'à?RvÛŸñà?}åÃɶ?jXŠô9Ð?œ%g'4ÅÂ?H)9‡­±?¼ ºŽMtÃ?žXäçà?¦„²ÓÞ?sO92Oè?ȃ9V·êî?`-tÊ)˜?¸2b}‘ Û?¥¦ŠÊAí? –z³Sà?ptûÁˆÃ?0³—i–Õ?@]Õ;j-Š?"ìFÕß(Ú?ø ïë‰UÝ?8Ȧ·Ü?8mþÞâ?œnÇ]‰bÇ? ’žØÁ?]b:Û„ë?ÍÙYs î?\ú_ìÝ?Ò?~WâÅÉÕ?[´\h÷ æ?Ø\ãëMç?ù?*8(¨î?t‚uV¿Õ?Ðü|[Z¶?]P^rCéä?Ðð·ç? ïíÿH(À?äFv:•Â?ÐOŒ¿q¦?Ã÷êªL è? è´›;ªá?7Cí®Òá?ZŠrXšè?`Á9úqùÇ?,X~ëU¿Þ?8)ìõ„Â?8$$h~н?X˜•½ROï?ÞyK¦ï?ß Ïê?°âÁ7íÄ×?xb;Zj;Ú?ªítn:šà?jT±5÷já?ôs'¢)åß?ÊÒ ñ‡«Ü?Öœ;‘Ëß?PÅ;^·?eîæÑ©ê? $ü@ÀŒÌ?Fè°\óî?0Ž—í©À?–²×3zÎÕ?e šÔÝn?À;ÂjÓ?Å®%7³á?êKN!Ìí?|–†Çu%Ì?®_.*à?Ë%¢Â­eç?ûÕ4Sì?Ê4ÊxQQé?âa=ªJ€é?®‰¦Uûæ?(iïn×é? ËhƒXzš?P·{æÏ7Õ?Dp»ŸcÕ?lTÄ]×Å?²ÁÐ\’Ý?Jés÷ù±å?AM¨¤D3ï?áZ1Ì}µç?ðe¨”ÍÔ?T¶# EÓ?4¥LÔbÆ?²hö‰ôúÝ?Ò þ«e­å?P_žN4†Ã?"d¨üÐ?4 ÀÂ.Û?fHøÈÔ?g¿=Íàã?±Éªç?Œ%!ϪÐÂ?0 —æ-£? ó\{÷å?P7}5üÑ?ˆcÇ€þË?M(jìc.à?Lᜎá?x™aó®Uï?À敱É?çB Ÿ½æ?R>WêÍÐ?èÞœ!Ì ì?‚º¨N‘Ü?°×òZWÓ?¸XÐôq–¸?d$žo3á?¼ÕYW:kà?;fÕ;×?솥w¤Ü?cûÀš¶_è?Pé2Ñ ñß?…† ïýËá?Z¼#‡Cyé?Ö°GöH-â?x~Ÿ É×?º le&è?ÐÑ [¿Ê?´"zÃÄ?=™jLúê?Ý.(…í?–i+vÖ?°h.uõ·?ö4Ûk× Û?°•ÔÙ6iÌ?øj-HG Á?­ãb»øÓ?±˜âÿãå?Ñ1Šqgãá??§£ŒNì?nMÑ8wßÝ?ÜŸµ1ï?8ù9 ³Þ?ð‚f}ƒµ¨?ø]Ç*ä?xMUä[Í?Z_¿‘wÕ?Z€X+ZÚ?ïOø¦¦éã?„¦¨ü#ÕË?Î$,aß?Ø;ÇDaáå?â*“ÙlÝ?H'ë$שÔ?€:hoøÊ­?/8áÍ"=ì?üw…þ±ã?Åî Úã?2|‚©ü™Ý?éÊ^LEê?íëq¿¤ æ?DªÇ:W|ë?l¥JOdÊ?´î}ÃÂÙ? ÝQó¥¶?ž¤·É`?è?\(ÈíNÜ?0¦ÑQ¯¦é?”ÃÚò…Ú?¸™wŸÙ?”¢%väØ?xåà1(Ö?@ÙòìÞæ?çÙ@¹/¤å?x÷¢KÛ?þ‹¡>Œì?1d‘sNÍí?,²Å¼¬ Ï ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/blocks.diff0000644000175100001770000000052114653725311017303 0ustar00runnerdockertree: foobar: bizbaz: > green < red datatype: > uint64 < float64 shape: - > 9000 < 10000 > ndarrays differ by shape, datatype and contents < ndarrays differ by shape, datatype and contents ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/complex-42.0.0.yaml0000644000175100001770000000021314653725311020244 0ustar00runnerdocker%YAML 1.1 --- $schema: "http://stsci.edu/schemas/yaml-schema/draft-01" id: "http://stsci.edu/schemas/asdf/core/custom-42.0.0" type: string ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/custom-1.0.0.yaml0000644000175100001770000000022614653725311020026 0ustar00runnerdocker%YAML 1.1 --- $schema: "http://stsci.edu/schemas/yaml-schema/draft-01" id: "http://nowhere.org/schemas/custom/custom-1.0.0" type: integer default: 42 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/custom_schema.yaml0000644000175100001770000000104114653725311020710 0ustar00runnerdocker%YAML 1.1 --- $schema: "http://stsci.edu/schemas/yaml-schema/draft-01" title: | Top-level custom schema used for testing. description: | This schema is used to test the custom schema validation mechanism in ASDF. type: object properties: foo: description: | Your generic kind of foo. type: object properties: x: type: number y: type: number bar: type: object properties: a: type: string b: type: string required: [foo, bar] additionalProperties: true ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/custom_schema_definitions.yaml0000644000175100001770000000046214653725311023311 0ustar00runnerdocker%YAML 1.1 --- $schema: "http://stsci.edu/schemas/yaml-schema/draft-01" type: object properties: thing: $ref: "#/definitions/bizbaz" required: [thing] additionalProperties: true definitions: bizbaz: type: object properties: biz: type: string baz: type: string ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/custom_schema_external_ref.yaml0000644000175100001770000000061314653725311023452 0ustar00runnerdocker%YAML 1.1 --- $schema: "http://stsci.edu/schemas/yaml-schema/draft-01" title: | Custom schema with an external reference, used for testing. description: | This schema is used to test custom schema validation with an external reference. type: object properties: foo: anyOf: - $ref: "http://stsci.edu/schemas/asdf/core/software-1.0.0" required: [foo] additionalProperties: true ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/example_schema.json0000755000175100001770000000423314653725311021051 0ustar00runnerdocker{ "date" : { "title" : "[yyyy-mm-ddThh:mm:ss.ssssss] UTC date file created", "type" : "string", "sql_dtype" : "datetime2", "fits_keyword" : "DATE", "description" : "The UTC date and time when the HDU was created, in the form YYYY-MM-DDThh:mm:ss.ssssss, where YYYY shall be the four-digit calendar year number, MM the two-digit month number with January given by 01 and December by 12, and DD the two-digit day of the month. The literal T shall separate the date and time, hh shall be the two-digit hour in the day, mm the two-digit number of minutes after the hour, and ss.ssssss the number of seconds (two digits followed by a fraction accurate to microseconds) after the minute. Default values must not be given to any portion of the date/time string, and leading zeros must not be omitted.", "calculation" : "Operating system time in the format of YYYY-MM-DDThh:mm:ss.ssssss", "default_value" : "", "example" : "2015-01-01T00:00:00.000001", "units" : "", "sw_source" : "calculation", "source" : "Science Data Processing (SDP)", "destination" : ["ScienceCommon.date","GuideStar.date"], "level" : "1a", "si" : "Multiple", "section" : "Basic", "mode" : "All", "fits_hdu" : "PRIMARY", "misc" : "" }, "origin" : { "title" : "institution responsible for creating FITS file", "type" : "string", "sql_dtype" : "nvarchar(20)", "fits_keyword" : "ORIGIN", "description" : "Identifies the organization or institution responsible for creating the FITS file.", "calculation" : "", "default_value" : "STSCI", "example" : "STSCI", "units" : "", "sw_source" : "", "source" : "Science Data Processing (SDP)", "destination" : ["ScienceCommon.origin","GuideStar.origin"], "level" : "1a", "si" : "Multiple", "section" : "Basic", "mode" : "All", "fits_hdu" : "PRIMARY", "misc" : "" } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/fraction-1.0.0.yaml0000644000175100001770000000110514653725311020316 0ustar00runnerdocker%YAML 1.1 --- $schema: "http://stsci.edu/schemas/yaml-schema/draft-01" id: "http://nowhere.org/schemas/custom/fraction-1.0.0" title: An example custom type for handling fractions tag: "tag:nowhere.org:custom/fraction-1.0.0" # Using anyOf here is a cheap hack to allow us to support both formats in an # example that is used in the documentation (see docs/asdf/extensions.rst). anyOf: - type: array items: type: integer minItems: 2 maxItems: 2 - type: object properties: numerator: type: integer denominator: type: integer ... ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/fraction_with_inverse-1.0.0.yaml0000644000175100001770000000067214653725311023114 0ustar00runnerdocker%YAML 1.1 --- $schema: "http://stsci.edu/schemas/yaml-schema/draft-01" id: "http://nowhere.org/schemas/custom/fraction_with_inverse-1.0.0" title: An example custom type for handling fractions with inverses tag: "tag:nowhere.org:custom/fraction_with_inverse-1.0.0" type: object properties: numerator: type: integer denominator: type: integer inverse: $ref: fraction_with_inverse-1.0.0 required: [numerator, denominator] ... ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/fractional_2d_coord-1.0.0.yaml0000644000175100001770000000054314653725311022413 0ustar00runnerdocker%YAML 1.1 --- $schema: "http://stsci.edu/schemas/yaml-schema/draft-01" id: "http://nowhere.org/schemas/custom/fractional_2d_coord-1.0.0" title: An example custom type for handling components tag: "tag:nowhere.org:custom/fractional_2d_coord-1.0.0" type: object properties: x: $ref: fraction-1.0.0 y: $ref: fraction-1.0.0 required: [x, y] ... ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/frames.diff0000644000175100001770000000233614653725311017311 0ustar00runnerdockertree: asdf_library: version: > 1.2.2.dev858 < 1.2.2.dev846 > frames: > - reference_frame: > galcen_coord: > dec: > unit: > deg > value: > -28.936175 > ra: > unit: > deg > value: > 266.4051 > wrap_angle: > unit: > deg > value: > 360.0 > galcen_v_sun: > - unit: > km s-1 > value: > 11.1 > - unit: > km s-1 > value: > 232.24 > - unit: > km s-1 > value: > 7.25 < galcen_dec: < unit: < rad < value: < 1.0 < galcen_ra: < unit: < deg < value: < 45.0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/frames0.asdf0000644000175100001770000001013714653725311017374 0ustar00runnerdocker#ASDF 1.0.0 #ASDF_STANDARD 1.1.0 %YAML 1.1 %TAG ! tag:stsci.edu:asdf/ --- !core/asdf-1.0.0 asdf_library: !core/software-1.0.0 {author: Space Telescope Science Institute, homepage: 'http://github.com/spacetelescope/asdf', name: asdf, version: 1.2.2.dev858} frames: - !wcs/celestial_frame-1.1.0 axes_names: [lon, lat] name: CelestialFrame reference_frame: {type: ICRS} unit: [!unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg] - !wcs/celestial_frame-1.1.0 axes_names: [lon, lat] name: CelestialFrame reference_frame: {equinox: !time/time-1.1.0 '2010-01-01 00:00:00.000', type: FK5} unit: [!unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg] - !wcs/celestial_frame-1.1.0 axes_names: [lon, lat] name: CelestialFrame reference_frame: {equinox: !time/time-1.1.0 '2010-01-01 00:00:00.000', obstime: !time/time-1.1.0 '2015-01-01 00:00:00.000', type: FK4} unit: [!unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg] - !wcs/celestial_frame-1.1.0 axes_names: [lon, lat] name: CelestialFrame reference_frame: {equinox: !time/time-1.1.0 '2010-01-01 00:00:00.000', obstime: !time/time-1.1.0 '2015-01-01 00:00:00.000', type: FK4_noeterms} unit: [!unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg] - !wcs/celestial_frame-1.1.0 axes_names: [lon, lat] name: CelestialFrame reference_frame: {type: galactic} unit: [!unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg] - !wcs/celestial_frame-1.1.0 axes_names: [x, y, z] axes_order: [0, 1, 2] name: CelestialFrame reference_frame: galcen_coord: !wcs/icrs_coord-1.1.0 dec: {value: -28.936175} ra: value: 266.4051 wrap_angle: !unit/quantity-1.1.0 {unit: !unit/unit-1.0.0 deg, value: 360.0} galcen_distance: !unit/quantity-1.1.0 {unit: !unit/unit-1.0.0 m, value: 5.0} galcen_v_sun: - !unit/quantity-1.1.0 {unit: !unit/unit-1.0.0 km s-1, value: 11.1} - !unit/quantity-1.1.0 {unit: !unit/unit-1.0.0 km s-1, value: 232.24} - !unit/quantity-1.1.0 {unit: !unit/unit-1.0.0 km s-1, value: 7.25} roll: !unit/quantity-1.1.0 {unit: !unit/unit-1.0.0 deg, value: 3.0} type: galactocentric z_sun: !unit/quantity-1.1.0 {unit: !unit/unit-1.0.0 pc, value: 3.0} unit: [!unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg] - !wcs/celestial_frame-1.1.0 axes_names: [lon, lat] name: CelestialFrame reference_frame: obsgeoloc: - !unit/quantity-1.1.0 {unit: !unit/unit-1.0.0 m, value: 3.0856775814671916e+16} - !unit/quantity-1.1.0 {unit: !unit/unit-1.0.0 m, value: 9.257032744401574e+16} - !unit/quantity-1.1.0 {unit: !unit/unit-1.0.0 m, value: 6.1713551629343834e+19} obsgeovel: - !unit/quantity-1.1.0 {unit: !unit/unit-1.0.0 m s-1, value: 2.0} - !unit/quantity-1.1.0 {unit: !unit/unit-1.0.0 m s-1, value: 1.0} - !unit/quantity-1.1.0 {unit: !unit/unit-1.0.0 m s-1, value: 8.0} obstime: !time/time-1.1.0 2010-01-01 00:00:00.000 type: GCRS unit: [!unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg] - !wcs/celestial_frame-1.1.0 axes_names: [lon, lat] name: CelestialFrame reference_frame: {obstime: !time/time-1.1.0 '2010-01-01 00:00:00.000', type: CIRS} unit: [!unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg] - !wcs/celestial_frame-1.1.0 axes_names: [x, y, z] axes_order: [0, 1, 2] name: CelestialFrame reference_frame: {obstime: !time/time-1.1.0 '2022-01-03 00:00:00.000', type: ITRS} unit: [!unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg] - !wcs/celestial_frame-1.1.0 axes_names: [lon, lat] name: CelestialFrame reference_frame: equinox: !time/time-1.1.0 J2000.000 obsgeoloc: - !unit/quantity-1.1.0 {unit: !unit/unit-1.0.0 m, value: 3.0856775814671916e+16} - !unit/quantity-1.1.0 {unit: !unit/unit-1.0.0 m, value: 9.257032744401574e+16} - !unit/quantity-1.1.0 {unit: !unit/unit-1.0.0 m, value: 6.1713551629343834e+19} obsgeovel: - !unit/quantity-1.1.0 {unit: !unit/unit-1.0.0 m s-1, value: 2.0} - !unit/quantity-1.1.0 {unit: !unit/unit-1.0.0 m s-1, value: 1.0} - !unit/quantity-1.1.0 {unit: !unit/unit-1.0.0 m s-1, value: 8.0} obstime: !time/time-1.1.0 2010-01-01 00:00:00.000 type: precessed_geocentric unit: [!unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg] ... ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/frames1.asdf0000644000175100001770000000732114653725311017376 0ustar00runnerdocker#ASDF 1.0.0 #ASDF_STANDARD 1.1.0 %YAML 1.1 %TAG ! tag:stsci.edu:asdf/ --- !core/asdf-1.0.0 asdf_library: !core/software-1.0.0 {author: Space Telescope Science Institute, homepage: 'http://github.com/spacetelescope/asdf', name: asdf, version: 1.2.2.dev846} frames: - !wcs/celestial_frame-1.1.0 axes_names: [lon, lat, blurg] name: CelestialFrame reference_frame: {type: ICRS} unit: [!unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg] - !wcs/celestial_frame-1.1.0 axes_names: [lon, lat] name: CelestialFrame reference_frame: {equinox: !time/time-1.1.0 '2010-01-01 00:00:00.000', type: FK5} unit: [!unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg] - !wcs/celestial_frame-1.1.0 axes_names: [lon, lat] name: CelestialFrame reference_frame: {equinox: !time/time-1.1.0 '2010-01-01 00:00:00.000', obstime: !time/time-1.1.0 '2015-01-01 00:00:00.000', type: FK4} unit: [!unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg] - !wcs/celestial_frame-1.1.0 axes_names: [lon, lat] name: CelestialFrame reference_frame: {equinox: !time/time-1.1.0 '2010-01-01 00:00:00.000', obstime: !time/time-1.1.0 '2015-01-01 00:00:00.000', type: FK4_noeterms} unit: [!unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg] - !wcs/celestial_frame-1.1.0 axes_names: [lon, lat] name: CelestialFrame reference_frame: {type: galactic} unit: [!unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg] - !wcs/celestial_frame-1.1.0 axes_names: [x, y, z] axes_order: [0, 1, 2] name: CelestialFrame reference_frame: galcen_dec: !unit/quantity-1.1.0 unit: rad value: 1.0 galcen_distance: !unit/quantity-1.1.0 unit: m value: 5.0 galcen_ra: !unit/quantity-1.1.0 unit: deg value: 45.0 roll: !unit/quantity-1.1.0 unit: deg value: 3.0 type: galactocentric z_sun: !unit/quantity-1.1.0 unit: pc value: 3.0 unit: [!unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg] - !wcs/celestial_frame-1.1.0 axes_names: [lon, lat] name: CelestialFrame reference_frame: obsgeoloc: - !unit/quantity-1.1.0 unit: m value: 3.0856775814671916e+16 - !unit/quantity-1.1.0 unit: m value: 9.257032744401574e+16 - !unit/quantity-1.1.0 unit: m value: 6.1713551629343834e+19 obsgeovel: - !unit/quantity-1.1.0 unit: m s-1 value: 2.0 - !unit/quantity-1.1.0 unit: m s-1 value: 1.0 - !unit/quantity-1.1.0 unit: m s-1 value: 8.0 obstime: !time/time-1.1.0 2010-01-01 00:00:00.000 type: GCRS unit: [!unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg] - !wcs/celestial_frame-1.1.0 axes_names: [lon, lat] name: CelestialFrame reference_frame: {obstime: !time/time-1.1.0 '2010-01-01 00:00:00.000', type: CIRS} unit: [!unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg] - !wcs/celestial_frame-1.1.0 axes_names: [x, y, z] axes_order: [0, 1, 2] name: CelestialFrame reference_frame: {obstime: !time/time-1.1.0 '2022-01-03 00:00:00.000', type: ITRS} unit: [!unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg] - !wcs/celestial_frame-1.1.0 axes_names: [lon, lat] name: CelestialFrame reference_frame: equinox: !time/time-1.1.0 J2000.000 obsgeoloc: - !unit/quantity-1.1.0 unit: m value: 3.0856775814671916e+16 - !unit/quantity-1.1.0 unit: m value: 9.257032744401574e+16 - !unit/quantity-1.1.0 unit: m value: 6.1713551629343834e+19 obsgeovel: - !unit/quantity-1.1.0 unit: m s-1 value: 2.0 - !unit/quantity-1.1.0 unit: m s-1 value: 1.0 - !unit/quantity-1.1.0 unit: m s-1 value: 8.0 obstime: !time/time-1.1.0 2010-01-01 00:00:00.000 type: precessed_geocentric unit: [!unit/unit-1.0.0 deg, !unit/unit-1.0.0 deg] ... ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/frames_ignore_asdf_library.diff0000644000175100001770000000221014653725311023364 0ustar00runnerdocker> tree: > frames: > - reference_frame: > galcen_coord: > dec: > unit: > deg > value: > -28.936175 > ra: > unit: > deg > value: > 266.4051 > wrap_angle: > unit: > deg > value: > 360.0 > galcen_v_sun: > - unit: > km s-1 > value: > 11.1 > - unit: > km s-1 > value: > 232.24 > - unit: > km s-1 > value: > 7.25 < galcen_dec: < unit: < rad < value: < 1.0 < galcen_ra: < unit: < deg < value: < 45.0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/frames_ignore_both.diff0000644000175100001770000000000014653725311021652 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/frames_ignore_reference_frame.diff0000644000175100001770000000014714653725311024042 0ustar00runnerdockertree: asdf_library: version: > 1.2.2.dev858 < 1.2.2.dev846 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/frames_minimal.diff0000644000175100001770000000041514653725311021013 0ustar00runnerdockertree: asdf_library: version: > 1.2.2.dev858 < 1.2.2.dev846 frames: - reference_frame: > galcen_coord > galcen_v_sun < galcen_dec < galcen_ra ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/missing-1.1.0.yaml0000644000175100001770000000021214653725311020161 0ustar00runnerdocker%YAML 1.1 --- $schema: "http://stsci.edu/schemas/yaml-schema/draft-01" id: "http://nowhere.org/schemas/custom/missing-1.1.0" type: object ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/ndarray0.asdf0000644000175100001770000000135114653725311017555 0ustar00runnerdocker#ASDF 1.0.0 #ASDF_STANDARD 1.5.0 %YAML 1.1 %TAG ! tag:stsci.edu:asdf/ --- !core/asdf-1.1.0 asdf_library: !core/software-1.0.0 {author: The ASDF Developers, homepage: 'http://github.com/asdf-format/asdf', name: asdf, version: 3.0.0.dev613+g96800153.d20230926} history: extensions: - !core/extension_metadata-1.0.0 extension_class: asdf.extension._manifest.ManifestExtension extension_uri: asdf://asdf-format.org/core/extensions/core-1.5.0 software: !core/software-1.0.0 {name: asdf, version: 3.0.0.dev613+g96800153.d20230926} a: !core/ndarray-1.0.0 source: 0 datatype: int64 byteorder: little shape: [2] ... ÓBLK0nZ]Ý¢öÃŽþ’œT¡«€½ #ASDF BLOCK INDEX %YAML 1.1 --- - 633 ... ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/ndarray1.asdf0000644000175100001770000000135114653725311017556 0ustar00runnerdocker#ASDF 1.0.0 #ASDF_STANDARD 1.5.0 %YAML 1.1 %TAG ! tag:stsci.edu:asdf/ --- !core/asdf-1.1.0 asdf_library: !core/software-1.0.0 {author: The ASDF Developers, homepage: 'http://github.com/asdf-format/asdf', name: asdf, version: 3.0.0.dev613+g96800153.d20230926} history: extensions: - !core/extension_metadata-1.0.0 extension_class: asdf.extension._manifest.ManifestExtension extension_uri: asdf://asdf-format.org/core/extensions/core-1.5.0 software: !core/software-1.0.0 {name: asdf, version: 3.0.0.dev613+g96800153.d20230926} a: !core/ndarray-1.0.0 source: 0 datatype: int64 byteorder: little shape: [2] ... ÓBLK0hfˆ¼Q•”ŽlïÑ¢Ù˜ˆ #ASDF BLOCK INDEX %YAML 1.1 --- - 633 ... ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/ndarray_in_list.diff0000644000175100001770000000035714653725311021216 0ustar00runnerdocker< tree: < list: < - a: < offset: < 16 < strides: < - -8 > ndarrays differ by contents < ndarrays differ by contents ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/ndarray_in_list0.asdf0000644000175100001770000000135114653725311021276 0ustar00runnerdocker#ASDF 1.0.0 #ASDF_STANDARD 1.5.0 %YAML 1.1 %TAG ! tag:stsci.edu:asdf/ --- !core/asdf-1.1.0 asdf_library: !core/software-1.0.0 {author: The ASDF Developers, homepage: 'http://github.com/asdf-format/asdf', name: asdf, version: 3.0.1.dev6+gaca944af} history: extensions: - !core/extension_metadata-1.0.0 extension_class: asdf.extension._manifest.ManifestExtension extension_uri: asdf://asdf-format.org/core/extensions/core-1.5.0 software: !core/software-1.0.0 {name: asdf, version: 3.0.1.dev6+gaca944af} list: - a: !core/ndarray-1.0.0 source: 0 datatype: int64 byteorder: little shape: [3] ... ÓBLK0ª•?ý@|Ñ|FÆæ¯/=#ASDF BLOCK INDEX %YAML 1.1 --- - 625 ... ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/ndarray_in_list1.asdf0000644000175100001770000000141214653725311021275 0ustar00runnerdocker#ASDF 1.0.0 #ASDF_STANDARD 1.5.0 %YAML 1.1 %TAG ! tag:stsci.edu:asdf/ --- !core/asdf-1.1.0 asdf_library: !core/software-1.0.0 {author: The ASDF Developers, homepage: 'http://github.com/asdf-format/asdf', name: asdf, version: 3.0.1.dev6+gaca944af} history: extensions: - !core/extension_metadata-1.0.0 extension_class: asdf.extension._manifest.ManifestExtension extension_uri: asdf://asdf-format.org/core/extensions/core-1.5.0 software: !core/software-1.0.0 {name: asdf, version: 3.0.1.dev6+gaca944af} list: - a: !core/ndarray-1.0.0 source: 0 datatype: int64 byteorder: little shape: [3] offset: 16 strides: [-8] ... ÓBLK0ª•?ý@|Ñ|FÆæ¯/=#ASDF BLOCK INDEX %YAML 1.1 --- - 658 ... ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/ndarrays.diff0000644000175100001770000000014514653725311017653 0ustar00runnerdockertree: a: > ndarrays differ by contents < ndarrays differ by contents ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/self_referencing-1.0.0.yaml0000644000175100001770000000027014653725311022013 0ustar00runnerdocker%YAML 1.1 --- $schema: "http://stsci.edu/schemas/yaml-schema/draft-01" id: "http://nowhere.org/schemas/custom/self_referencing-1.0.0" anyOf: - type: object - $ref: "#/anyOf/0" ... ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/simple_inline_array.diff0000644000175100001770000000015114653725311022052 0ustar00runnerdockertree: array: > ndarrays differ by contents < ndarrays differ by contents ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/simple_inline_array0.asdf0000644000175100001770000000075714653725311022153 0ustar00runnerdocker#ASDF 1.0.0 #ASDF_STANDARD 1.5.0 %YAML 1.1 %TAG ! tag:stsci.edu:asdf/ --- !core/asdf-1.1.0 asdf_library: !core/software-1.0.0 {author: Space Telescope Science Institute, homepage: 'http://github.com/spacetelescope/asdf', name: asdf, version: 2.6.1.dev2+gef67341} history: extensions: - !core/extension_metadata-1.0.0 extension_class: asdf.extension.BuiltinExtension software: !core/software-1.0.0 {name: asdf, version: 2.6.1.dev2+gef67341} array: !core/ndarray-1.0.0 [0, 1, 2] ... ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/data/simple_inline_array1.asdf0000644000175100001770000000075714653725311022154 0ustar00runnerdocker#ASDF 1.0.0 #ASDF_STANDARD 1.5.0 %YAML 1.1 %TAG ! tag:stsci.edu:asdf/ --- !core/asdf-1.1.0 asdf_library: !core/software-1.0.0 {author: Space Telescope Science Institute, homepage: 'http://github.com/spacetelescope/asdf', name: asdf, version: 2.6.1.dev2+gef67341} history: extensions: - !core/extension_metadata-1.0.0 extension_class: asdf.extension.BuiltinExtension software: !core/software-1.0.0 {name: asdf, version: 2.6.1.dev2+gef67341} array: !core/ndarray-1.0.0 [0, 1, 3] ... ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/httpserver.py0000644000175100001770000000346414653725311017054 0ustar00runnerdockerimport http.server import os import queue import shutil import socketserver import tempfile import threading __all__ = ["HTTPServer"] def run_server(tmp_path, handler_class, stop_event, queue): # pragma: no cover """ Runs an HTTP server serving files from given tmp_path in a separate process. When it's ready, it sends a URL to the server over a queue so the main process (the HTTP client) can start making requests of it. """ class HTTPRequestHandler(handler_class): def translate_path(self, path): path = handler_class.translate_path(self, path) return os.path.join(tmp_path, os.path.relpath(path, os.getcwd())) server = socketserver.TCPServer(("127.0.0.1", 0), HTTPRequestHandler) domain, port = server.server_address url = f"http://{domain}:{port}/" # Set a reasonable timeout so that invalid requests (which may occur during # testing) do not cause the entire test suite to hang indefinitely server.timeout = 0.1 queue.put(url) # Using server.serve_forever does not work here since it ignores the # timeout value set above. Having an explicit loop also allows us to kill # the server from the parent thread. while not stop_event.is_set(): server.handle_request() server.server_close() class HTTPServer: handler_class = http.server.SimpleHTTPRequestHandler def __init__(self): self.tmpdir = tempfile.mkdtemp() q = queue.Queue() self.stop_event = threading.Event() args = (self.tmpdir, self.handler_class, self.stop_event, q) self.thread = threading.Thread(target=run_server, args=args) self.thread.start() self.url = q.get() def finalize(self): self.stop_event.set() self.thread.join() shutil.rmtree(self.tmpdir) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1490982 asdf-3.4.0/asdf/_tests/tags/0000755000175100001770000000000014653725331015225 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/tags/__init__.py0000644000175100001770000000000014653725311017322 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1490982 asdf-3.4.0/asdf/_tests/tags/core/0000755000175100001770000000000014653725331016155 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/tags/core/__init__.py0000644000175100001770000000000014653725311020252 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1490982 asdf-3.4.0/asdf/_tests/tags/core/tests/0000755000175100001770000000000014653725331017317 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/tags/core/tests/__init__.py0000644000175100001770000000000014653725311021414 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/tags/core/tests/test_integer.py0000644000175100001770000000315114653725311022363 0ustar00runnerdockerimport random import pytest import asdf from asdf import IntegerType from asdf.testing.helpers import roundtrip_object # Make sure tests are deterministic random.seed(0) @pytest.mark.parametrize("sign", ["+", "-"]) @pytest.mark.parametrize( "value", [ random.getrandbits(64), random.getrandbits(65), random.getrandbits(100), random.getrandbits(128), random.getrandbits(129), random.getrandbits(200), ], ) def test_integer_value(value, sign): if sign == "-": value = -value integer = IntegerType(value) assert integer == roundtrip_object(integer) @pytest.mark.parametrize("inline", [False, True]) def test_integer_storage(tmp_path, inline): tmpfile = str(tmp_path / "integer.asdf") kwargs = {} if inline: kwargs["storage_type"] = "inline" random.seed(0) value = random.getrandbits(1000) tree = {"integer": IntegerType(value, **kwargs)} with asdf.AsdfFile(tree) as af: af.write_to(tmpfile) tree = asdf.util.load_yaml(tmpfile, tagged=True) if inline: assert "source" not in tree["integer"]["words"] assert "data" in tree["integer"]["words"] else: assert "source" in tree["integer"]["words"] assert "data" not in tree["integer"]["words"] assert "string" in tree["integer"] assert tree["integer"]["string"] == str(value) def test_integer_conversion(): random.seed(0) value = random.getrandbits(1000) integer = asdf.IntegerType(value) assert integer == value assert int(integer) == int(value) assert float(integer) == float(value) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/tags/core/tests/test_ndarray.py0000644000175100001770000007304214653725311022374 0ustar00runnerdockerimport contextlib import io import os import re import sys import numpy as np import pytest import yaml from numpy import ma from numpy.testing import assert_array_equal import asdf from asdf.exceptions import ValidationError from asdf.extension import Converter, Extension, TagDefinition from asdf.tags.core import ndarray from asdf.testing import helpers # These custom types and the custom extension are here purely for the purpose # of testing NDArray objects and making sure that they can be validated as part # of a nested hierarchy, and not just top-level objects. class CustomData: def __init__(self, value): self.value = value class CustomNDim: def __init__(self, value): self.value = value class CustomNDimConverter(Converter): tags = ["tag:nowhere.org:custom/ndim-1.0.0"] types = [CustomNDim] def to_yaml_tree(self, obj, tag, ctx): return obj.value def from_yaml_tree(self, node, tag, ctx): return CustomNDim(node) class CustomDataConverter(Converter): tags = ["tag:nowhere.org:custom/datatype-1.0.0"] types = [CustomData] def to_yaml_tree(self, obj, tag, ctx): return obj.value def from_yaml_tree(self, node, tag, ctx): return CustomData(node) class CustomExtension(Extension): tags = [ TagDefinition( tag_uri="tag:nowhere.org:custom/datatype-1.0.0", schema_uris=["http://nowhere.org/schemas/custom/datatype-1.0.0"], ), TagDefinition( tag_uri="tag:nowhere.org:custom/ndim-1.0.0", schema_uris=["http://nowhere.org/schemas/custom/ndim-1.0.0"], ), ] extension_uri = "asdf://nowhere.org/extensions/custom-1.0.0" converters = [CustomDataConverter(), CustomNDimConverter()] @contextlib.contextmanager def with_custom_extension(): with asdf.config_context() as cfg: cfg.add_extension(CustomExtension()) cfg.add_resource_mapping( { "http://nowhere.org/schemas/custom/datatype-1.0.0": """%YAML 1.1 --- $schema: "http://stsci.edu/schemas/asdf/asdf-schema-1.0.0" id: "http://nowhere.org/schemas/custom/datatype-1.0.0" type: object properties: a: datatype: float32 b: datatype: float32 exact_datatype: true c: datatype: - name: a datatype: int16 - name: b datatype: ['ascii', 16] d: datatype: - name: a datatype: int16 - name: b datatype: ['ascii', 16] exact_datatype: true""", "http://nowhere.org/schemas/custom/ndim-1.0.0": """%YAML 1.1 --- $schema: "http://stsci.edu/schemas/asdf/asdf-schema-1.0.0" id: "http://nowhere.org/schemas/custom/ndim-1.0.0" type: object properties: a: ndim: 2 b: max_ndim: 2""", } ) yield @contextlib.contextmanager def roundtrip(af, raw=False, standard_version=None): if not isinstance(af, asdf.AsdfFile): af = asdf.AsdfFile(af, version=standard_version) b = io.BytesIO() af.write_to(b) b.seek(0) if raw: bs = b.read() if asdf.constants.BLOCK_MAGIC in bs: bs, *_ = bs.split(asdf.constants.BLOCK_MAGIC) yield bs else: with asdf.open(b) as af: yield af def test_sharing(): x = np.arange(0, 10, dtype=float) tree = {"science_data": x, "subset": x[3:-3], "skipping": x[::2]} with roundtrip(tree) as af: tree = af.tree assert_array_equal(tree["science_data"], x) assert_array_equal(tree["subset"], x[3:-3]) assert_array_equal(tree["skipping"], x[::2]) assert tree["science_data"].ctypes.data == tree["skipping"].ctypes.data assert len(af._blocks.blocks) == 1 assert af._blocks.blocks[0].header["data_size"] == 80 tree["science_data"][0] = 42 assert tree["skipping"][0] == 42 def test_byteorder(tmp_path): tree = { "bigendian": np.arange(0, 10, dtype=">f8"), "little": np.arange(0, 10, dtype="" assert my_tree["little"].dtype.byteorder == "=" else: assert my_tree["bigendian"].dtype.byteorder == "=" assert my_tree["little"].dtype.byteorder == "<" @pytest.mark.parametrize("dtype", ndarray._datatype_names.values()) def test_all_dtypes(dtype): standard_version = "1.6.0" if dtype == "f2" else None tree = {} for byteorder in (">", "<"): arr = np.array([True, False]) if dtype == "b1" else np.arange(0, 10, dtype=str(byteorder + dtype)) tree[byteorder + dtype] = arr with roundtrip(tree, standard_version=standard_version) as af: for k in tree: pre = tree[k] post = af[k] assert_array_equal(pre, post) def test_dont_load_data(): x = np.arange(0, 10, dtype=float) tree = {"science_data": x, "subset": x[3:-3], "skipping": x[::2]} ff = asdf.AsdfFile(tree) buff = io.BytesIO() ff.write_to(buff) buff.seek(0) with asdf.open(buff) as ff: # repr and str shouldn't load data str(ff.tree["science_data"]) repr(ff.tree) for block in ff._blocks.blocks: assert callable(block._data) def test_table_inline(tmp_path): table = np.array( [(0, 1, (2, 3)), (4, 5, (6, 7))], dtype=[("MINE", np.int8), ("", np.float64), ("arr", ">i4", (2,))], ) tree = {"table_data": table} with asdf.config_context() as config: config.array_inline_threshold = 100 with roundtrip(tree) as af: assert table.dtype.names == af["table_data"].dtype.names for n in table.dtype.names: assert_array_equal(table[n], af["table_data"][n]) with roundtrip(tree, raw=True) as content: tree = yaml.safe_load(re.sub(rb"!core/\S+", b"", content)) assert tree["table_data"] == { "datatype": [ {"datatype": "int8", "name": "MINE"}, {"datatype": "float64", "name": "f1"}, {"datatype": "int32", "name": "arr", "shape": [2]}, ], "data": [[0, 1.0, [2, 3]], [4, 5.0, [6, 7]]], "shape": [2], } def test_array_inline_threshold_recursive(tmp_path): """ Test that setting the inline threshold works for objects that contain (and when serialized produce a ndarray) """ class NDArrayContainer: def __init__(self, array): self._array = array @property def array(self): return np.array(self._array) class NDArrayContainerConverter: tags = ["http://somewhere.org/tags/foo-1.0.0"] types = [NDArrayContainer] def to_yaml_tree(self, obj, tag, ctx): return {"array": obj.array} def from_yaml_tree(self, node, tag, ctx): return NDArrayContainer(node["array"]) class NDArrayContainerExtension: tags = NDArrayContainerConverter.tags converters = [NDArrayContainerConverter()] extension_uri = "http://somewhere.org/extensions/foo-1.0.0" container = NDArrayContainer([[1, 2], [3, 4]]) tree = {"test": container} with asdf.config_context() as config: config.add_extension(NDArrayContainerExtension()) config.array_inline_threshold = 100 # we can no longer use _helpers.assert_roundtrip_tree here because # the model no longer has a CustomType which results in equality testing # using == which will fail # this test appears to be designed to test the inline threshold so we can # just look at the number of blocks fn = str(tmp_path / "test.asdf") af = asdf.AsdfFile(tree) af.write_to(fn) with asdf.open(fn) as af: assert len(list(af._blocks.blocks)) == 0 def test_copy_inline(): yaml = """ x0: !core/ndarray-1.0.0 data: [-1.0, 1.0] """ buff = helpers.yaml_to_asdf(yaml) with asdf.open(buff) as infile, asdf.AsdfFile() as f: f.tree["a"] = infile.tree["x0"] f.tree["b"] = f.tree["a"] f.write_to(io.BytesIO()) def test_table(tmp_path): table = np.array([(0, 1, (2, 3)), (4, 5, (6, 7))], dtype=[("MINE", np.int8), ("", "i4", (2,))]) tree = {"table_data": table} with roundtrip(tree) as af: assert_array_equal(af["table_data"], table) with roundtrip(tree, raw=True) as content: tree = yaml.safe_load(re.sub(rb"!core/\S+", b"", content)) assert tree["table_data"] == { "datatype": [ {"byteorder": "big", "datatype": "int8", "name": "MINE"}, {"byteorder": "little", "datatype": "float64", "name": "f1"}, {"byteorder": "big", "datatype": "int32", "name": "arr", "shape": [2]}, ], "shape": [2], "source": 0, "byteorder": "big", } def test_table_nested_fields(tmp_path): table = np.array( [(0, (1, 2)), (4, (5, 6)), (7, (8, 9))], dtype=[("A", " a: !core/ndarray-1.0.0 data: [1, 2, 3] """ buff = helpers.yaml_to_asdf(content) with ( pytest.raises(ValidationError, match=r"Wrong number of dimensions:.*"), asdf.open( buff, ), ): pass content = """ obj: ! a: !core/ndarray-1.0.0 data: [[1, 2, 3]] """ buff = helpers.yaml_to_asdf(content) with asdf.open(buff): pass content = """ obj: ! a: !core/ndarray-1.0.0 shape: [1, 3] data: [[1, 2, 3]] """ buff = helpers.yaml_to_asdf(content) with asdf.open(buff): pass content = """ obj: ! b: !core/ndarray-1.0.0 data: [1, 2, 3] """ buff = helpers.yaml_to_asdf(content) with asdf.open(buff): pass content = """ obj: ! b: !core/ndarray-1.0.0 data: [[1, 2, 3]] """ buff = helpers.yaml_to_asdf(content) with asdf.open(buff): pass content = """ obj: ! b: !core/ndarray-1.0.0 data: [[[1, 2, 3]]] """ buff = helpers.yaml_to_asdf(content) with ( pytest.raises(ValidationError, match=r"Wrong number of dimensions:.*"), asdf.open( buff, ), ): pass @with_custom_extension() def test_datatype_validation(tmp_path): content = """ obj: ! a: !core/ndarray-1.0.0 data: [1, 2, 3] datatype: float32 """ buff = helpers.yaml_to_asdf(content) with asdf.open(buff): pass content = """ obj: ! a: !core/ndarray-1.0.0 data: [1, 2, 3] datatype: float64 """ buff = helpers.yaml_to_asdf(content) with ( pytest.raises(ValidationError, match=r"Can not safely cast from .* to .*"), asdf.open( buff, ), ): pass content = """ obj: ! a: !core/ndarray-1.0.0 data: [1, 2, 3] datatype: int16 """ buff = helpers.yaml_to_asdf(content) with asdf.open(buff): pass content = """ obj: ! b: !core/ndarray-1.0.0 data: [1, 2, 3] datatype: int16 """ buff = helpers.yaml_to_asdf(content) with ( pytest.raises(ValidationError, match=r"Expected datatype .*, got .*"), asdf.open( buff, ), ): pass content = """ obj: ! a: !core/ndarray-1.0.0 data: [[1, 'a'], [2, 'b'], [3, 'c']] datatype: - name: a datatype: int8 - name: b datatype: ['ascii', 8] """ buff = helpers.yaml_to_asdf(content) with ( pytest.raises(ValidationError, match=r"Expected scalar datatype .*, got .*"), asdf.open( buff, ), ): pass @with_custom_extension() def test_structured_datatype_validation(tmp_path): content = """ obj: ! c: !core/ndarray-1.0.0 data: [[1, 'a'], [2, 'b'], [3, 'c']] datatype: - name: a datatype: int8 - name: b datatype: ['ascii', 8] """ buff = helpers.yaml_to_asdf(content) with asdf.open(buff): pass content = """ obj: ! c: !core/ndarray-1.0.0 data: [[1, 'a'], [2, 'b'], [3, 'c']] datatype: - name: a datatype: int64 - name: b datatype: ['ascii', 8] """ buff = helpers.yaml_to_asdf(content) with ( pytest.raises(ValidationError, match=r"Can not safely cast to expected datatype.*"), asdf.open( buff, ), ): pass content = """ obj: ! c: !core/ndarray-1.0.0 data: [[1, 'a', 0], [2, 'b', 1], [3, 'c', 2]] datatype: - name: a datatype: int8 - name: b datatype: ['ascii', 8] - name: c datatype: float64 """ buff = helpers.yaml_to_asdf(content) with ( pytest.raises(ValidationError, match=r"Mismatch in number of columns:.*"), asdf.open( buff, ), ): pass content = """ obj: ! c: !core/ndarray-1.0.0 data: [1, 2, 3] """ buff = helpers.yaml_to_asdf(content) with ( pytest.raises(ValidationError, match=r"Expected structured datatype.*"), asdf.open( buff, ), ): pass content = """ obj: ! d: !core/ndarray-1.0.0 data: [[1, 'a'], [2, 'b'], [3, 'c']] datatype: - name: a datatype: int8 - name: b datatype: ['ascii', 8] """ buff = helpers.yaml_to_asdf(content) with ( pytest.raises(ValidationError, match=r"Expected datatype .*, got .*"), asdf.open( buff, ), ): pass content = """ obj: ! d: !core/ndarray-1.0.0 data: [[1, 'a'], [2, 'b'], [3, 'c']] datatype: - name: a datatype: int16 - name: b datatype: ['ascii', 16] """ buff = helpers.yaml_to_asdf(content) with asdf.open(buff): pass def test_string_inline(): x = np.array([b"a", b"b", b"c"]) line = ndarray.numpy_array_to_list(x) for entry in line: assert isinstance(entry, str) def test_inline_shape_mismatch(): content = """ arr: !core/ndarray-1.0.0 data: [1, 2, 3] shape: [2] """ buff = helpers.yaml_to_asdf(content) with pytest.raises(ValueError, match=r"inline data doesn't match the given shape"): with asdf.open(buff) as af: af["arr"] def test_broadcasted_array(tmp_path): attrs = np.broadcast_arrays(np.array([10, 20]), np.array(10), np.array(10)) tree = {"one": attrs[1]} # , 'two': attrs[1], 'three': attrs[2]} with roundtrip(tree) as af: assert_array_equal(tree["one"], af["one"]) def test_broadcasted_offset_array(tmp_path): base = np.arange(10) offset = base[5:] broadcasted = np.broadcast_to(offset, (4, 5)) tree = {"broadcasted": broadcasted} with roundtrip(tree) as af: assert_array_equal(tree["broadcasted"], af["broadcasted"]) def test_non_contiguous_base_array(tmp_path): base = np.arange(60).reshape(5, 4, 3).transpose(2, 0, 1) * 1 contiguous = base.transpose(1, 2, 0) tree = {"contiguous": contiguous} with roundtrip(tree) as af: assert_array_equal(tree["contiguous"], af["contiguous"]) def test_fortran_order(tmp_path): array = np.array([[11, 12, 13], [21, 22, 23]], order="F", dtype=np.int64) tree = {"data": array} with roundtrip(tree) as af: assert af["data"].flags.fortran assert np.all(np.isclose(array, af["data"])) with roundtrip(tree, raw=True) as content: tree = yaml.safe_load(re.sub(rb"!core/\S+", b"", content)) assert tree["data"]["strides"] == [8, 16] def test_memmap_write(tmp_path): tmpfile = str(tmp_path / "data.asdf") tree = {"data": np.zeros(100)} with asdf.AsdfFile(tree) as af: # Make sure we're actually writing to an internal array for this test af.write_to(tmpfile, all_array_storage="internal") with asdf.open(tmpfile, mode="rw", copy_arrays=False) as af: data = af["data"] assert data.flags.writeable is True data[0] = 42 assert data[0] == 42 with asdf.open(tmpfile, mode="rw", copy_arrays=False) as af: assert af["data"][0] == 42 with asdf.open(tmpfile, mode="r", copy_arrays=False) as af: assert af["data"][0] == 42 def test_readonly(tmp_path): tmpfile = str(tmp_path / "data.asdf") tree = {"data": np.ndarray(100)} with asdf.AsdfFile(tree) as af: # Make sure we're actually writing to an internal array for this test af.write_to(tmpfile, all_array_storage="internal") # Opening in read mode (the default) should mean array is readonly with asdf.open(tmpfile) as af: assert af["data"].flags.writeable is False with pytest.raises(ValueError, match=r"assignment destination is read-only"): af["data"][0] = 41 # Forcing memmap, the array should still be readonly with asdf.open(tmpfile, copy_arrays=False) as af: assert af["data"].flags.writeable is False with pytest.raises(ValueError, match=r"assignment destination is read-only"): af["data"][0] = 41 # This should be perfectly fine with asdf.open(tmpfile, mode="rw") as af: assert af["data"].flags.writeable is True af["data"][0] = 40 # Copying the arrays makes it safe to write to the underlying array with asdf.open(tmpfile, mode="r", copy_arrays=True) as af: assert af["data"].flags.writeable is True af["data"][0] = 42 def test_readonly_inline(tmp_path): tmpfile = str(tmp_path / "data.asdf") tree = {"data": np.ndarray(100)} with asdf.AsdfFile(tree) as af: af.write_to(tmpfile, all_array_storage="inline") # This should be safe since it's an inline array with asdf.open(tmpfile, mode="r") as af: assert af["data"].flags.writeable is True af["data"][0] = 42 # Confirm that NDArrayType's internal array is regenerated # following an update. @pytest.mark.parametrize("pad_blocks", [True, False]) def test_block_data_change(pad_blocks, tmp_path): tmpfile = str(tmp_path / "data.asdf") tree = {"data": np.zeros(10, dtype="uint8")} with asdf.AsdfFile(tree) as af: af.write_to(tmpfile, pad_blocks=pad_blocks) with asdf.open(tmpfile, mode="rw") as af: assert np.all(af.tree["data"] == 0) array_before = af.tree["data"].__array__() af.tree["data"][:5] = 1 af.update() array_after = af.tree["data"].__array__() assert array_before is not array_after assert np.all(af.tree["data"][:5] == 1) assert np.all(af.tree["data"][5:] == 0) def test_problematic_class_attributes(tmp_path): """ The presence of the "name" and "version" attributes in NDArrayType cause problems when our arrays are used with other libraries. See https://github.com/asdf-format/asdf/issues/1015 """ file_path = tmp_path / "test.asdf" with asdf.AsdfFile() as af: af["arr"] = np.arange(100) af.write_to(file_path) with asdf.open(file_path) as af: assert isinstance(af["arr"], ndarray.NDArrayType) with pytest.raises(AttributeError, match=r".* object has no attribute 'name'"): af["arr"].name with pytest.raises(AttributeError, match=r".* object has no attribute 'version'"): af["arr"].version def test_shape_does_not_load_array(tmp_path): file_path = tmp_path / "test.asdf" with asdf.AsdfFile() as af: af["arr"] = np.arange(100) af.write_to(file_path) with asdf.open(file_path, lazy_load=True) as af: assert af["arr"]._array is None assert af["arr"].shape == (100,) assert af["arr"]._array is None ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_api.py0000644000175100001770000004130514653725311016452 0ustar00runnerdockerimport copy import getpass import io import os import pathlib import sys import warnings import numpy as np import pytest from numpy.testing import assert_array_equal import asdf from asdf import config_context, get_config, treeutil, versioning from asdf.exceptions import AsdfDeprecationWarning, AsdfPackageVersionWarning, ValidationError from asdf.extension import ExtensionProxy from asdf.resource import ResourceMappingProxy from asdf.testing.helpers import roundtrip_object, yaml_to_asdf from ._helpers import assert_tree_match RNG = np.random.default_rng(97) def test_get_data_from_closed_file(tmp_path): path = str(tmp_path / "test.asdf") my_array = np.arange(0, 64).reshape((8, 8)) tree = {"my_array": my_array} ff = asdf.AsdfFile(tree) ff.write_to(path) with asdf.open(path) as ff: pass with pytest.raises(IOError, match=r"Cannot access data from closed ASDF file"): assert_array_equal(my_array, ff.tree["my_array"]) def test_no_warning_nan_array(tmp_path): """ Tests for a regression that was introduced by https://github.com/asdf-format/asdf/pull/557 where saving an array with a nan resulted in a warning """ roundtrip_object(np.array([1, 2, np.nan])) @pytest.mark.skipif( not sys.platform.startswith("win") and getpass.getuser() == "root", reason="Cannot make file read-only if user is root", ) def test_open_readonly(tmp_path): tmpfile = str(tmp_path / "readonly.asdf") tree = {"foo": 42, "bar": "hello", "baz": np.arange(20)} with asdf.AsdfFile(tree) as af: af.write_to(tmpfile, all_array_storage="internal") os.chmod(tmpfile, 0o440) assert os.access(tmpfile, os.W_OK) is False with asdf.open(tmpfile) as af: assert af["baz"].flags.writeable is False with pytest.raises(PermissionError, match=r".* Permission denied: .*"), asdf.open(tmpfile, mode="rw"): pass def test_open_validate_on_read(tmp_path): content = """ invalid_software: !core/software-1.0.0 name: Minesweeper version: 3 """ buff = yaml_to_asdf(content) get_config().validate_on_read = True with pytest.raises(ValidationError, match=r".* is not of type .*"), asdf.open(buff): pass buff.seek(0) get_config().validate_on_read = False with asdf.open(buff) as af: assert af["invalid_software"]["name"] == "Minesweeper" assert af["invalid_software"]["version"] == 3 def test_open_stream(tmp_path): file_path = tmp_path / "test.asdf" with asdf.AsdfFile() as af: af["foo"] = "bar" af.write_to(file_path) class StreamWrapper: def __init__(self, fd): self._fd = fd def read(self, size=-1): return self._fd.read(size) with file_path.open("rb") as fd, asdf.open(StreamWrapper(fd)) as af: assert af["foo"] == "bar" def test_atomic_write(tmp_path, small_tree): tmpfile = str(tmp_path / "test.asdf") ff = asdf.AsdfFile(small_tree) ff.write_to(tmpfile) with asdf.open(tmpfile, mode="r") as ff: ff.write_to(tmpfile) def test_default_version(): """ See https://github.com/asdf-format/asdf/issues/364 """ ff = asdf.AsdfFile() assert ff.file_format_version == versioning._FILE_FORMAT_VERSION # make sure these are different AsdfVersion instances assert ff.file_format_version is not versioning._FILE_FORMAT_VERSION def test_update_exceptions(tmp_path): path = str(tmp_path / "test.asdf") my_array = RNG.normal(size=(8, 8)) tree = {"my_array": my_array} ff = asdf.AsdfFile(tree) ff.write_to(path) with ( asdf.open(path, mode="r", copy_arrays=True) as ff, pytest.raises( IOError, match=r"Can not update, since associated file is read-only.*", ), ): ff.update() ff = asdf.AsdfFile(tree) buff = io.BytesIO() ff.write_to(buff) buff.seek(0) with asdf.open(buff, mode="rw") as ff: ff.update() with pytest.raises(ValueError, match=r"Can not update, since there is no associated file"): asdf.AsdfFile().update() def test_top_level_tree(small_tree): tree = {"tree": small_tree} ff = asdf.AsdfFile(tree) assert_tree_match(ff.tree["tree"], ff["tree"]) ff2 = asdf.AsdfFile() ff2["tree"] = small_tree assert_tree_match(ff2.tree["tree"], ff2["tree"]) def test_top_level_keys(small_tree): tree = {"tree": small_tree} ff = asdf.AsdfFile(tree) assert ff.tree.keys() == ff.keys() def test_top_level_contains(): tree = { "foo": 42, "bar": 43, } with asdf.AsdfFile(tree) as af: assert "foo" in af assert "bar" in af def test_walk_and_modify_remove_keys(): tree = {"foo": 42, "bar": 43} def func(x): if x == 42: return treeutil.RemoveNode return x tree2 = treeutil.walk_and_modify(tree, func) assert "foo" not in tree2 assert "bar" in tree2 def test_walk_and_modify_retain_none(): tree = {"foo": 42, "bar": None} def func(x): if x == 42: return None return x tree2 = treeutil.walk_and_modify(tree, func) assert tree2["foo"] is None assert tree2["bar"] is None def test_copy(tmp_path): my_array = RNG.normal(size=(8, 8)) tree = {"my_array": my_array, "foo": {"bar": "baz"}} ff = asdf.AsdfFile(tree) ff.write_to(str(tmp_path / "test.asdf")) with asdf.open(str(tmp_path / "test.asdf")) as ff: ff2 = ff.copy() ff2.tree["my_array"] *= 2 ff2.tree["foo"]["bar"] = "boo" assert np.all(ff2.tree["my_array"] == ff.tree["my_array"] * 2) assert ff.tree["foo"]["bar"] == "baz" assert_array_equal(ff2.tree["my_array"], ff2.tree["my_array"]) def test_access_tree_outside_handler(tmp_path): tempname = str(tmp_path / "test.asdf") tree = {"random": np.random.random(10)} ff = asdf.AsdfFile(tree) ff.write_to(str(tempname)) with asdf.open(tempname) as newf: pass # Accessing array data outside of handler should fail with pytest.raises(OSError, match=r"Cannot access data from closed ASDF file"): repr(newf.tree["random"]) # Using the top-level getattr should also fail with pytest.raises(OSError, match=r"Cannot access data from closed ASDF file"): repr(newf["random"]) def test_context_handler_resolve_and_inline(tmp_path): """ This reproduces the issue reported in https://github.com/asdf-format/asdf/issues/406 """ tempname = str(tmp_path / "test.asdf") tree = {"random": np.random.random(10)} ff = asdf.AsdfFile(tree) ff.write_to(str(tempname)) with asdf.open(tempname) as newf: with warnings.catch_warnings(): warnings.filterwarnings("ignore", "resolve_and_inline is deprecated", AsdfDeprecationWarning) newf.resolve_and_inline() with pytest.raises(OSError, match=r"Cannot access data from closed ASDF file"): newf.tree["random"][0] def test_open_pathlib_path(tmp_path): filename = str(tmp_path / "pathlib.asdf") path = pathlib.Path(filename) tree = {"data": np.ones(10)} with asdf.AsdfFile(tree) as af: af.write_to(path) with asdf.open(path) as af: assert (af["data"] == tree["data"]).all() @pytest.mark.parametrize( ("installed", "extension", "warns"), [ (None, "2.0.0", True), ("1.2.3", "2.0.0", True), ("1.2.3", "2.0.dev10842", True), ("2.0.0", "2.0.0", False), ("2.0.1", "2.0.0", False), ("2.0.1", "2.0.dev12345", False), ], ) def test_extension_version_check(installed, extension, warns): class FooExtension: extension_uri = "asdf://somewhere.org/extensions/foo-1.0.0" proxy = ExtensionProxy(FooExtension(), package_name="foo", package_version=installed) with config_context() as config: if installed is not None: config.add_extension(proxy) af = asdf.AsdfFile() af._fname = "test.asdf" tree = { "history": { "extensions": [ asdf.tags.core.ExtensionMetadata( extension_uri=FooExtension.extension_uri, software=asdf.tags.core.Software(name="foo", version=extension), ), ], }, } if warns: with pytest.warns(AsdfPackageVersionWarning, match=r"File 'test.asdf' was created with"): af._check_extensions(tree) with pytest.raises(RuntimeError, match=r"^File 'test.asdf' was created with"): af._check_extensions(tree, strict=True) else: af._check_extensions(tree) @pytest.mark.parametrize( ("installed", "extension", "warns"), [ (None, "2.0.0", True), ("1.2.3", "2.0.0", True), ("1.2.3", "2.0.dev10842", True), ("2.0.0", "2.0.0", False), ("2.0.1", "2.0.0", False), ("2.0.1", "2.0.dev12345", False), ], ) def test_check_extension_manifest_software(installed, extension, warns): class FooExtension: extension_uri = "asdf://somewhere.org/extensions/foo-1.0.0" proxy = ExtensionProxy(FooExtension(), package_name="foo", package_version="1.0.0") mapping = ResourceMappingProxy({}, package_name="bar", package_version=installed) with config_context() as config: config.add_extension(proxy) if installed is not None: config.add_resource_mapping(mapping) af = asdf.AsdfFile() af._fname = "test.asdf" tree = { "history": { "extensions": [ asdf.tags.core.ExtensionMetadata( extension_uri=FooExtension.extension_uri, software=asdf.tags.core.Software(name="foo", version="1.0.0"), manifest_software=asdf.tags.core.Software(name="bar", version=extension), ), ], }, } if warns: with pytest.warns(AsdfPackageVersionWarning, match=r"File 'test.asdf' was created with"): af._check_extensions(tree) with pytest.raises(RuntimeError, match=r"^File 'test.asdf' was created with"): af._check_extensions(tree, strict=True) else: af._check_extensions(tree) def test_extension_check_no_warning_on_builtin(): """ Prior to asdf 3.0 files were written using the asdf.extension.BuiltinExtension (which used the legacy extension api). This extension was removed in asdf 3.0. We don't want to warn that this extension is missing for every file that is opened so make sure _check_extensions doesn't warn that BuiltinExtension is missing. """ af = asdf.AsdfFile() tree = { "history": { "extensions": [ asdf.tags.core.ExtensionMetadata( extension_class="asdf.extension.BuiltinExtension", software=asdf.tags.core.Software(name="asdf", version="2.15.1"), ), ], }, } af._check_extensions(tree) @pytest.mark.parametrize( ("array_inline_threshold", "inline_blocks", "internal_blocks"), [ (None, 0, 2), (10, 1, 1), (7, 1, 1), (5, 0, 2), (0, 0, 2), (1, 0, 2), ], ) def test_array_inline_threshold(array_inline_threshold, inline_blocks, internal_blocks, tmp_path): file_path = tmp_path / "test.asdf" tree = {"small_array": np.arange(6), "large_array": np.arange(100)} with asdf.config_context() as config: config.array_inline_threshold = array_inline_threshold with asdf.AsdfFile(tree) as af: af.write_to(file_path) with asdf.open(file_path) as af: assert len(af._blocks.blocks) == internal_blocks @pytest.mark.parametrize( ("array_inline_threshold", "inline_blocks", "internal_blocks"), [ (None, 0, 2), (10, 2, 0), (5, 0, 2), ], ) def test_array_inline_threshold_masked_array(array_inline_threshold, inline_blocks, internal_blocks, tmp_path): file_path = tmp_path / "test.asdf" arr = np.arange(6) masked_arr = np.ma.masked_equal(arr, 3) tree = {"masked_arr": masked_arr} with asdf.config_context() as config: config.array_inline_threshold = array_inline_threshold with asdf.AsdfFile(tree) as af: af.write_to(file_path) with asdf.open(file_path) as af: assert len(af._blocks.blocks) == internal_blocks @pytest.mark.parametrize( ("array_inline_threshold", "inline_blocks", "internal_blocks"), [ (None, 0, 1), (10, 1, 0), (5, 0, 1), ], ) def test_array_inline_threshold_string_array(array_inline_threshold, inline_blocks, internal_blocks, tmp_path): file_path = tmp_path / "test.asdf" arr = np.array(["peach", "plum", "apricot", "nectarine", "cherry", "pluot"]) tree = {"array": arr} with asdf.config_context() as config: config.array_inline_threshold = array_inline_threshold with asdf.AsdfFile(tree) as af: af.write_to(file_path) with asdf.open(file_path) as af: assert len(af._blocks.blocks) == internal_blocks def test_history_entries(tmp_path): path = str(tmp_path / "test.asdf") message = "Twas brillig, and the slithy toves" af = asdf.AsdfFile() af.add_history_entry(message) af.write_to(path) with asdf.open(path) as af: assert af["history"]["entries"][0]["description"] == message af = asdf.AsdfFile() af.write_to(path) with asdf.open(path) as af: af.add_history_entry(message) assert af["history"]["entries"][0]["description"] == message def test_array_access_after_file_close(tmp_path): path = str(tmp_path / "test.asdf") data = np.arange(10) asdf.AsdfFile({"data": data}).write_to(path) # Normally it's not possible to read the array after # the file has been closed: with asdf.open(path) as af: tree = af.tree with pytest.raises(OSError, match=r"ASDF file has already been closed. Can not get the data."): tree["data"][0] # With memory mapping disabled and copying arrays enabled, # the array data should still persist in memory after close: with asdf.open(path, lazy_load=False, copy_arrays=True) as af: tree = af.tree assert_array_equal(tree["data"], data) def test_none_values(tmp_path): path = str(tmp_path / "test.asdf") af = asdf.AsdfFile({"foo": None}) af.write_to(path) with asdf.open(path) as af: assert "foo" in af assert af["foo"] is None def test_asdf_standard_version_tag_selection(): buff = io.BytesIO() af = asdf.AsdfFile() af.write_to(buff, version="1.0.0") buff.seek(0) content = buff.read() assert b"!core/asdf-1.0.0" in content assert b"!core/asdf-1.1.0" not in content buff.seek(0) af.write_to(buff, version="1.2.0") # asdf-standard 1.2 uses asdf-object 1.1 tag buff.seek(0) content = buff.read() assert b"!core/asdf-1.0.0" not in content assert b"!core/asdf-1.1.0" in content def test_update_asdf_standard_version_tag_selection(): buff = io.BytesIO() af = asdf.AsdfFile() af.write_to(buff, version="1.0.0") buff.seek(0) with asdf.open(buff, mode="rw") as af: af.update(version="1.2.0") # asdf-standard 1.2 uses asdf-object 1.1 tag buff.seek(0) content = buff.read() assert b"!core/asdf-1.1.0" in content assert b"!core/asdf-1.0.0" not in content @pytest.mark.parametrize("valid_filename", [True, False], ids=["valid_filename", "invalid_filename"]) def test_write_to_no_tree_modification(tmp_path, valid_filename): if valid_filename: fn = tmp_path / "test.asdf" else: fn = "invalid/missing.asdf" fn2 = tmp_path / "test2.asdf" tree = {"foo": None} af = asdf.AsdfFile(tree.copy()) try: af.write_to(fn) except Exception: if valid_filename: raise assert tree == af.tree if not valid_filename: return with asdf.open(fn) as af: af["history"]["extensions"][0]["software"]["version"] = "0.0.0.dev+abcdefg" af["asdf_library"]["author"] = "foo" tree = copy.deepcopy(af.tree) af.write_to(fn2) assert af.tree == tree @pytest.mark.parametrize("valid_filename", [True, False], ids=["valid_filename", "invalid_filename"]) def test_write_to_no_version_modification(tmp_path, valid_filename): if valid_filename: fn = tmp_path / "test.asdf" else: fn = "invalid/missing.asdf" tree = {"foo": None} af = asdf.AsdfFile(tree.copy(), version="1.0.0") try: af.write_to(fn, version="1.1.0") except Exception: if valid_filename: raise assert af.version_string == "1.0.0" if not valid_filename: return with asdf.open(fn) as af: assert af.version_string == "1.1.0" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_array_blocks.py0000644000175100001770000010151214653725311020351 0ustar00runnerdockerimport io import os import numpy as np import pytest import yaml from numpy.random import random from numpy.testing import assert_array_equal import asdf from asdf import constants, generic_io from asdf._block import io as bio from asdf.exceptions import AsdfBlockIndexWarning RNG = np.random.default_rng(6) def test_external_block(tmp_path): tmp_path = str(tmp_path) my_array = RNG.normal(size=(8, 8)) tree = {"my_array": my_array} ff = asdf.AsdfFile(tree) ff.set_array_storage(my_array, "external") assert ff.get_array_storage(my_array) == "external" ff.write_to(os.path.join(tmp_path, "test.asdf")) assert "test0000.asdf" in os.listdir(tmp_path) def test_external_block_url(): uri = "asdf://foo" my_array = RNG.normal(size=(8, 8)) tree = {"my_array": my_array} asdf.get_config().all_array_storage = "external" # this should not raise a ValueError since uri is provided asdf.AsdfFile(tree, uri=uri) def test_external_block_non_url(): my_array = RNG.normal(size=(8, 8)) tree = {"my_array": my_array} ff = asdf.AsdfFile(tree) ff.set_array_storage(my_array, "external") assert ff.get_array_storage(my_array) == "external" buff = io.BytesIO() with pytest.raises(ValueError, match=r"Can't write external blocks, since URI of main file is unknown."): ff.write_to(buff) def test_invalid_array_storage(): my_array = RNG.normal(size=(8, 8)) tree = {"my_array": my_array} ff = asdf.AsdfFile(tree) with pytest.raises(ValueError, match=r"array_storage must be one of.*"): ff.set_array_storage(my_array, "foo") def test_transfer_array_sources(tmp_path): tmp_path = str(tmp_path) my_array = RNG.normal(size=(8, 8)) tree = {"my_array": my_array} ff = asdf.AsdfFile(tree) ff.write_to(os.path.join(tmp_path, "test.asdf")) with asdf.open(os.path.join(tmp_path, "test.asdf")) as ff: assert_array_equal(my_array, ff.tree["my_array"]) ff.write_to(os.path.join(tmp_path, "test2.asdf")) # write_to should have no effect on getting the original data assert_array_equal(my_array, ff.tree["my_array"]) assert ff._fd is None def test_write_to_same(tmp_path): tmp_path = str(tmp_path) my_array = RNG.normal(size=(8, 8)) tree = {"my_array": my_array} ff = asdf.AsdfFile(tree) ff.write_to(os.path.join(tmp_path, "test.asdf")) with asdf.open(os.path.join(tmp_path, "test.asdf"), mode="rw") as ff: assert_array_equal(my_array, ff.tree["my_array"]) ff.tree["extra"] = [0] * 1000 ff.write_to(os.path.join(tmp_path, "test2.asdf")) with asdf.open(os.path.join(tmp_path, "test2.asdf"), mode="rw") as ff: assert_array_equal(my_array, ff.tree["my_array"]) def test_pad_blocks(tmp_path): tmp_path = str(tmp_path) # This is the case where the new tree can't fit in the available space my_array = np.ones((8, 8)) * 1 my_array2 = np.ones((42, 5)) * 2 tree = {"my_array": my_array, "my_array2": my_array2} ff = asdf.AsdfFile(tree) ff.write_to(os.path.join(tmp_path, "test.asdf"), pad_blocks=True) with asdf.open(os.path.join(tmp_path, "test.asdf")) as ff: assert_array_equal(ff.tree["my_array"], my_array) assert_array_equal(ff.tree["my_array2"], my_array2) @pytest.mark.parametrize("lazy_load", [True, False]) @pytest.mark.parametrize("copy_arrays", [True, False]) def test_update_expand_tree(tmp_path, lazy_load, copy_arrays): tmp_path = str(tmp_path) testpath = os.path.join(tmp_path, "test.asdf") # This is the case where the new tree can't fit in the available space my_array = np.arange(64) * 1 my_array2 = np.arange(64) * 2 tree = {"arrays": [my_array, my_array2, np.arange(3)]} ff = asdf.AsdfFile(tree) ff.set_array_storage(tree["arrays"][2], "inline") ff.write_to(testpath, pad_blocks=True) with asdf.open(testpath, lazy_load=lazy_load, copy_arrays=copy_arrays, mode="rw") as ff: assert len(list(ff._blocks.blocks)) == 2 assert_array_equal(ff.tree["arrays"][0], my_array) ff.tree["extra"] = [0] * 6000 ff.update() with asdf.open(testpath) as ff: assert ff.get_array_storage(ff.tree["arrays"][2]) == "inline" assert_array_equal(ff.tree["arrays"][0], my_array) assert_array_equal(ff.tree["arrays"][1], my_array2) # Now, we expand the header only by a little bit ff = asdf.AsdfFile(tree) ff.set_array_storage(tree["arrays"][2], "inline") ff.write_to(os.path.join(tmp_path, "test2.asdf"), pad_blocks=True) with asdf.open(os.path.join(tmp_path, "test2.asdf"), lazy_load=lazy_load, copy_arrays=copy_arrays, mode="rw") as ff: ff.tree["extra"] = [0] * 2 ff.update() with asdf.open(os.path.join(tmp_path, "test2.asdf")) as ff: assert ff.get_array_storage(ff.tree["arrays"][2]) == "inline" assert_array_equal(ff.tree["arrays"][0], my_array) assert_array_equal(ff.tree["arrays"][1], my_array2) @pytest.mark.parametrize("lazy_load", [True, False]) @pytest.mark.parametrize("copy_arrays", [True, False]) def test_update_all_external(tmp_path, lazy_load, copy_arrays): fn = tmp_path / "test.asdf" my_array = np.arange(64) * 1 my_array2 = np.arange(64) * 2 tree = {"arrays": [my_array, my_array2]} af = asdf.AsdfFile(tree) af.write_to(fn) with asdf.config.config_context() as cfg: cfg.array_inline_threshold = 10 cfg.all_array_storage = "external" with asdf.open(fn, lazy_load=lazy_load, copy_arrays=copy_arrays, mode="rw") as af: af.update() assert "test0000.asdf" in os.listdir(tmp_path) assert "test0001.asdf" in os.listdir(tmp_path) @pytest.mark.parametrize("lazy_load", [True, False]) @pytest.mark.parametrize("copy_arrays", [True, False]) def test_update_some_external(tmp_path, lazy_load, copy_arrays): fn = tmp_path / "test.asdf" my_array = np.arange(64) * 1 my_array2 = np.arange(64) * 2 tree = {"arrays": [my_array, my_array2]} af = asdf.AsdfFile(tree) af.write_to(fn) with asdf.open(fn, lazy_load=lazy_load, copy_arrays=copy_arrays, mode="rw") as af: af.set_array_storage(af["arrays"][0], "external") af.update() assert "test0000.asdf" in os.listdir(tmp_path) assert "test0001.asdf" not in os.listdir(tmp_path) def _get_update_tree(): return {"arrays": [np.arange(64) * 1, np.arange(64) * 2, np.arange(64) * 3]} @pytest.mark.parametrize("lazy_load", [True, False]) @pytest.mark.parametrize("copy_arrays", [True, False]) def test_update_delete_first_array(tmp_path, lazy_load, copy_arrays): tmp_path = str(tmp_path) path = os.path.join(tmp_path, "test.asdf") # This is the case where the new tree can't fit in the available space tree = _get_update_tree() ff = asdf.AsdfFile(tree) ff.write_to(path, pad_blocks=True) original_size = os.stat(path).st_size with asdf.open(os.path.join(tmp_path, "test.asdf"), lazy_load=lazy_load, copy_arrays=copy_arrays, mode="rw") as ff: del ff.tree["arrays"][0] ff.update() assert os.stat(path).st_size <= original_size with asdf.open(os.path.join(tmp_path, "test.asdf")) as ff: assert_array_equal(ff.tree["arrays"][0], tree["arrays"][1]) assert_array_equal(ff.tree["arrays"][1], tree["arrays"][2]) @pytest.mark.parametrize("lazy_load", [True, False]) @pytest.mark.parametrize("copy_arrays", [True, False]) def test_update_delete_last_array(tmp_path, lazy_load, copy_arrays): tmp_path = str(tmp_path) path = os.path.join(tmp_path, "test.asdf") # This is the case where the new tree can't fit in the available space tree = _get_update_tree() ff = asdf.AsdfFile(tree) ff.write_to(path, pad_blocks=True) original_size = os.stat(path).st_size with asdf.open(os.path.join(tmp_path, "test.asdf"), lazy_load=lazy_load, copy_arrays=copy_arrays, mode="rw") as ff: del ff.tree["arrays"][-1] ff.update() assert os.stat(path).st_size <= original_size with asdf.open(os.path.join(tmp_path, "test.asdf")) as ff: assert_array_equal(ff.tree["arrays"][0], tree["arrays"][0]) assert_array_equal(ff.tree["arrays"][1], tree["arrays"][1]) @pytest.mark.parametrize("lazy_load", [True, False]) @pytest.mark.parametrize("copy_arrays", [True, False]) def test_update_delete_middle_array(tmp_path, lazy_load, copy_arrays): tmp_path = str(tmp_path) path = os.path.join(tmp_path, "test.asdf") # This is the case where the new tree can't fit in the available space tree = _get_update_tree() ff = asdf.AsdfFile(tree) ff.write_to(path, pad_blocks=True) original_size = os.stat(path).st_size with asdf.open(os.path.join(tmp_path, "test.asdf"), lazy_load=lazy_load, copy_arrays=copy_arrays, mode="rw") as ff: del ff.tree["arrays"][1] ff.update() assert len(ff._blocks.blocks) == 2 assert os.stat(path).st_size <= original_size with asdf.open(os.path.join(tmp_path, "test.asdf")) as ff: assert len(ff.tree["arrays"]) == 2 assert_array_equal(ff.tree["arrays"][0], tree["arrays"][0]) assert_array_equal(ff.tree["arrays"][1], tree["arrays"][2]) @pytest.mark.parametrize("lazy_load", [True, False]) @pytest.mark.parametrize("copy_arrays", [True, False]) def test_update_replace_first_array(tmp_path, lazy_load, copy_arrays): tmp_path = str(tmp_path) path = os.path.join(tmp_path, "test.asdf") # This is the case where the new tree can't fit in the available space tree = _get_update_tree() ff = asdf.AsdfFile(tree) ff.write_to(path, pad_blocks=True) original_size = os.stat(path).st_size with asdf.open(os.path.join(tmp_path, "test.asdf"), lazy_load=lazy_load, copy_arrays=copy_arrays, mode="rw") as ff: ff.tree["arrays"][0] = np.arange(32) ff.update() assert os.stat(path).st_size <= original_size with asdf.open(os.path.join(tmp_path, "test.asdf")) as ff: assert_array_equal(ff.tree["arrays"][0], np.arange(32)) assert_array_equal(ff.tree["arrays"][1], tree["arrays"][1]) assert_array_equal(ff.tree["arrays"][2], tree["arrays"][2]) @pytest.mark.parametrize("lazy_load", [True, False]) @pytest.mark.parametrize("copy_arrays", [True, False]) def test_update_replace_last_array(tmp_path, lazy_load, copy_arrays): tmp_path = str(tmp_path) path = os.path.join(tmp_path, "test.asdf") # This is the case where the new tree can't fit in the available space tree = _get_update_tree() ff = asdf.AsdfFile(tree) ff.write_to(path, pad_blocks=True) original_size = os.stat(path).st_size with asdf.open(os.path.join(tmp_path, "test.asdf"), lazy_load=lazy_load, copy_arrays=copy_arrays, mode="rw") as ff: ff.tree["arrays"][2] = np.arange(32) ff.update() assert os.stat(path).st_size <= original_size with asdf.open(os.path.join(tmp_path, "test.asdf")) as ff: assert_array_equal(ff.tree["arrays"][0], tree["arrays"][0]) assert_array_equal(ff.tree["arrays"][1], tree["arrays"][1]) assert_array_equal(ff.tree["arrays"][2], np.arange(32)) @pytest.mark.parametrize("lazy_load", [True, False]) @pytest.mark.parametrize("copy_arrays", [True, False]) def test_update_replace_middle_array(tmp_path, lazy_load, copy_arrays): tmp_path = str(tmp_path) path = os.path.join(tmp_path, "test.asdf") # This is the case where the new tree can't fit in the available space tree = _get_update_tree() ff = asdf.AsdfFile(tree) ff.write_to(path, pad_blocks=True) original_size = os.stat(path).st_size with asdf.open(os.path.join(tmp_path, "test.asdf"), lazy_load=lazy_load, copy_arrays=copy_arrays, mode="rw") as ff: ff.tree["arrays"][1] = np.arange(32) ff.update() assert os.stat(path).st_size <= original_size with asdf.open(os.path.join(tmp_path, "test.asdf")) as ff: assert_array_equal(ff.tree["arrays"][0], tree["arrays"][0]) assert_array_equal(ff.tree["arrays"][1], np.arange(32)) assert_array_equal(ff.tree["arrays"][2], tree["arrays"][2]) @pytest.mark.parametrize("lazy_load", [True, False]) @pytest.mark.parametrize("copy_arrays", [True, False]) def test_update_add_array(tmp_path, lazy_load, copy_arrays): tmp_path = str(tmp_path) path = os.path.join(tmp_path, "test.asdf") # This is the case where the new tree can't fit in the available space tree = _get_update_tree() ff = asdf.AsdfFile(tree) ff.write_to(path, pad_blocks=True) with asdf.open(os.path.join(tmp_path, "test.asdf"), lazy_load=lazy_load, copy_arrays=copy_arrays, mode="rw") as ff: ff.tree["arrays"].append(np.arange(32)) ff.update() with asdf.open(os.path.join(tmp_path, "test.asdf")) as ff: assert_array_equal(ff.tree["arrays"][0], tree["arrays"][0]) assert_array_equal(ff.tree["arrays"][1], tree["arrays"][1]) assert_array_equal(ff.tree["arrays"][2], tree["arrays"][2]) assert_array_equal(ff.tree["arrays"][3], np.arange(32)) @pytest.mark.parametrize("lazy_load", [True, False]) @pytest.mark.parametrize("copy_arrays", [True, False]) def test_update_add_array_at_end(tmp_path, lazy_load, copy_arrays): tmp_path = str(tmp_path) path = os.path.join(tmp_path, "test.asdf") # This is the case where the new tree can't fit in the available space tree = _get_update_tree() ff = asdf.AsdfFile(tree) ff.write_to(path, pad_blocks=True) original_size = os.stat(path).st_size with asdf.open(os.path.join(tmp_path, "test.asdf"), lazy_load=lazy_load, copy_arrays=copy_arrays, mode="rw") as ff: ff.tree["arrays"].append(np.arange(65536, dtype="= original_size with asdf.open(os.path.join(tmp_path, "test.asdf")) as ff: assert_array_equal(ff.tree["arrays"][0], tree["arrays"][0]) assert_array_equal(ff.tree["arrays"][1], tree["arrays"][1]) assert_array_equal(ff.tree["arrays"][2], tree["arrays"][2]) assert_array_equal(ff.tree["arrays"][3], np.arange(65536, dtype="= len(core_mappings) new_mapping = {"http://somewhere.org/schemas/foo-1.0.0": b"foo"} config.add_resource_mapping(new_mapping) assert len(config.resource_mappings) == len(default_mappings) + 1 assert any(m for m in config.resource_mappings if m.delegate is new_mapping) # Adding a mapping should be idempotent: config.add_resource_mapping(new_mapping) # ... even if wrapped: config.add_resource_mapping(ResourceMappingProxy(new_mapping)) assert len(config.resource_mappings) == len(default_mappings) + 1 # Adding a mapping should place it at the front of the line: front_mapping = {"http://somewhere.org/schemas/baz-1.0.0": b"baz"} config.add_resource_mapping(front_mapping) assert len(config.resource_mappings) == len(default_mappings) + 2 assert config.resource_mappings[0].delegate is front_mapping # ... even if the mapping is already in the list: config.add_resource_mapping(new_mapping) assert len(config.resource_mappings) == len(default_mappings) + 2 assert config.resource_mappings[0].delegate is new_mapping # Reset should get rid of any additions: config.reset_resources() assert len(config.resource_mappings) == len(default_mappings) # Should be able to remove a mapping: config.add_resource_mapping(new_mapping) config.remove_resource_mapping(new_mapping) assert len(config.resource_mappings) == len(default_mappings) # ... even if wrapped: config.add_resource_mapping(new_mapping) config.remove_resource_mapping(ResourceMappingProxy(new_mapping)) assert len(config.resource_mappings) == len(default_mappings) # ... and also by the name of the package the mappings came from: config.add_resource_mapping(ResourceMappingProxy(new_mapping, package_name="foo")) config.add_resource_mapping( ResourceMappingProxy({"http://somewhere.org/schemas/bar-1.0.0": b"bar"}, package_name="foo"), ) config.remove_resource_mapping(package="foo") assert len(config.resource_mappings) == len(default_mappings) # Can combine the package and mapping filters when removing: config.add_resource_mapping(ResourceMappingProxy(new_mapping, package_name="foo")) config.remove_resource_mapping(new_mapping, package="foo") assert len(config.resource_mappings) == len(default_mappings) # But not omit both: with pytest.raises(ValueError, match=r"Must specify at least one of mapping or package"): config.remove_resource_mapping() # Removing a mapping should be idempotent: config.add_resource_mapping(new_mapping) config.remove_resource_mapping(new_mapping) config.remove_resource_mapping(new_mapping) assert len(config.resource_mappings) == len(default_mappings) def test_resource_manager(): with asdf.config_context() as config: # Initial resource manager should contain just the entry points resources: assert "http://stsci.edu/schemas/asdf/core/asdf-1.1.0" in config.resource_manager assert ( b"http://stsci.edu/schemas/asdf/core/asdf-1.1.0" in config.resource_manager["http://stsci.edu/schemas/asdf/core/asdf-1.1.0"] ) assert "http://somewhere.org/schemas/foo-1.0.0" not in config.resource_manager # Add a mapping and confirm that the manager now contains it: new_mapping = {"http://somewhere.org/schemas/foo-1.0.0": b"foo"} config.add_resource_mapping(new_mapping) assert "http://stsci.edu/schemas/asdf/core/asdf-1.1.0" in config.resource_manager assert ( b"http://stsci.edu/schemas/asdf/core/asdf-1.1.0" in config.resource_manager["http://stsci.edu/schemas/asdf/core/asdf-1.1.0"] ) assert "http://somewhere.org/schemas/foo-1.0.0" in config.resource_manager assert config.resource_manager["http://somewhere.org/schemas/foo-1.0.0"] == b"foo" # Remove a mapping and confirm that the manager no longer contains it: config.remove_resource_mapping(new_mapping) assert "http://stsci.edu/schemas/asdf/core/asdf-1.1.0" in config.resource_manager assert ( b"http://stsci.edu/schemas/asdf/core/asdf-1.1.0" in config.resource_manager["http://stsci.edu/schemas/asdf/core/asdf-1.1.0"] ) assert "http://somewhere.org/schemas/foo-1.0.0" not in config.resource_manager # Reset and confirm that the manager no longer contains the custom mapping: config.add_resource_mapping(new_mapping) config.reset_resources() assert "http://stsci.edu/schemas/asdf/core/asdf-1.1.0" in config.resource_manager assert ( b"http://stsci.edu/schemas/asdf/core/asdf-1.1.0" in config.resource_manager["http://stsci.edu/schemas/asdf/core/asdf-1.1.0"] ) assert "http://somewhere.org/schemas/foo-1.0.0" not in config.resource_manager def test_extensions(): with asdf.config_context() as config: original_extensions = config.extensions class BarExtension: extension_uri = "asdf://somewhere.org/extensions/bar-1.0" types = [] tag_mapping = [] url_mapping = [] uri_extension = BarExtension() # Add an extension: config.add_extension(uri_extension) assert len(config.extensions) == len(original_extensions) + 1 assert any(e for e in config.extensions if e.delegate is uri_extension) # Adding an extension should be idempotent: config.add_extension(uri_extension) assert len(config.extensions) == len(original_extensions) + 1 # Even when wrapped: config.add_extension(ExtensionProxy(uri_extension)) assert len(config.extensions) == len(original_extensions) + 1 # Remove an extension: config.remove_extension(uri_extension) assert len(config.extensions) == len(original_extensions) # Removing should work when wrapped: config.add_extension(uri_extension) config.remove_extension(ExtensionProxy(uri_extension)) assert len(config.extensions) == len(original_extensions) # And also by URI: config.add_extension(uri_extension) config.remove_extension(uri_extension.extension_uri) assert len(config.extensions) == len(original_extensions) # And also by URI pattern: config.add_extension(uri_extension) config.remove_extension("asdf://somewhere.org/extensions/*") assert len(config.extensions) == len(original_extensions) # Remove by the name of the extension's package: config.add_extension(ExtensionProxy(uri_extension, package_name="foo")) config.remove_extension(package="foo") assert len(config.extensions) == len(original_extensions) # Can combine remove filters: config.add_extension(ExtensionProxy(uri_extension, package_name="foo")) config.add_extension(ExtensionProxy(uri_extension, package_name="bar")) config.remove_extension(uri_extension.extension_uri, package="foo") assert len(config.extensions) == len(original_extensions) + 1 # ... but not omit both: with pytest.raises(ValueError, match=r"Must specify at least one of extension or package"): config.remove_extension() # Removing an extension should be idempotent: config.add_extension(uri_extension) config.remove_extension(uri_extension) config.remove_extension(uri_extension) assert len(config.extensions) == len(original_extensions) # Resetting should get rid of any additions: config.add_extension(uri_extension) config.reset_extensions() assert len(config.extensions) == len(original_extensions) def test_config_repr(): with asdf.config_context() as config: config.validate_on_read = True config.default_version = "1.5.0" config.io_block_size = 9999 config.legacy_fill_schema_defaults = False config.array_inline_threshold = 14 assert "validate_on_read: True" in repr(config) assert "default_version: 1.5.0" in repr(config) assert "io_block_size: 9999" in repr(config) assert "legacy_fill_schema_defaults: False" in repr(config) assert "array_inline_threshold: 14" in repr(config) @pytest.mark.parametrize("value", [True, False]) def test_get_set_default_array_save_base(value): with asdf.config_context() as config: config.default_array_save_base = value assert config.default_array_save_base == value @pytest.mark.parametrize("value", [1, None]) def test_invalid_set_default_array_save_base(value): with asdf.config_context() as config: with pytest.raises(ValueError, match="default_array_save_base must be a bool"): config.default_array_save_base = value ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_deprecated.py0000644000175100001770000001214114653725311017775 0ustar00runnerdockerimport sys import warnings import numpy as np import pytest import asdf import asdf.testing.helpers from asdf.exceptions import AsdfDeprecationWarning, ValidationError def test_asdf_stream_deprecation(): with pytest.warns(AsdfDeprecationWarning, match="asdf.stream is deprecated"): if "asdf.stream" in sys.modules: del sys.modules["asdf.stream"] import asdf.stream # noqa: F401 def test_asdf_asdf_SerializationContext_import_deprecation(): with warnings.catch_warnings(): warnings.filterwarnings( "ignore", category=AsdfDeprecationWarning, message="asdf.asdf is deprecated. Please use asdf.AsdfFile and asdf.open", ) warnings.filterwarnings( "ignore", category=AsdfDeprecationWarning, message="asdf.asdf is deprecated", ) with pytest.warns(AsdfDeprecationWarning, match="importing SerializationContext from asdf.asdf"): from asdf.asdf import SerializationContext # noqa: F401 def test_asdf_util_human_list_deprecation(): with pytest.warns(AsdfDeprecationWarning, match="asdf.util.human_list is deprecated"): asdf.util.human_list("a") def test_asdf_util_resolve_name_deprecation(): with pytest.warns(AsdfDeprecationWarning, match="asdf.util.resolve_name is deprecated"): asdf.util.resolve_name("asdf.AsdfFile") def test_asdf_util_minversion_deprecation(): with pytest.warns(AsdfDeprecationWarning, match="asdf.util.minversion is deprecated"): asdf.util.minversion("yaml", "3.1") def test_asdf_util_iter_subclasses_deprecation(): with pytest.warns(AsdfDeprecationWarning, match="asdf.util.iter_subclasses is deprecated"): list(asdf.util.iter_subclasses(asdf.AsdfFile)) def test_asdf_asdf_deprecation(): with pytest.warns(AsdfDeprecationWarning, match="asdf.asdf is deprecated"): if "asdf.asdf" in sys.modules: del sys.modules["asdf.asdf"] import asdf.asdf # noqa: F401 def test_resolve_and_inline_deprecation(): with pytest.warns(AsdfDeprecationWarning, match="resolve_and_inline is deprecated"): af = asdf.AsdfFile({"arr": np.arange(42)}) af.resolve_and_inline() def test_find_references_during_init_deprecation(): tree = {"a": 1, "b": {"$ref": "#"}} with pytest.warns(AsdfDeprecationWarning, match="find_references during AsdfFile.__init__"): asdf.AsdfFile(tree) def test_find_references_during_open_deprecation(tmp_path): fn = tmp_path / "test.asdf" af = asdf.AsdfFile() af["a"] = 1 af["b"] = {"$ref": "#"} af.write_to(fn) with pytest.warns(AsdfDeprecationWarning, match="find_references during open"): with asdf.open(fn) as af: pass def test_asdf_util_is_primitive_deprecation(): with pytest.warns(AsdfDeprecationWarning, match="asdf.util.is_primitive is deprecated"): asdf.util.is_primitive(1) def test_AsdfFile_tree_assignment_validation_deprecation(): af = asdf.AsdfFile() with ( pytest.warns(AsdfDeprecationWarning, match="Validation on tree assignment is deprecated"), pytest.raises(ValidationError), ): af.tree = {"history": 42} def test_AsdfFile_resolve_references_validation_deprecation(): af = asdf.AsdfFile() af._tree["history"] = 42 with ( pytest.warns(AsdfDeprecationWarning, match="Validation during resolve_references is deprecated"), pytest.raises(ValidationError), ): af.resolve_references() def test_AsdfFile_resolve_references_kwargs_deprecation(): af = asdf.AsdfFile() with pytest.warns(AsdfDeprecationWarning, match="Passing kwargs to resolve_references is deprecated"): af.resolve_references(foo=42) def test_AsdfFile_init_validation_deprecation(): with ( pytest.warns(AsdfDeprecationWarning, match="Validation during AsdfFile.__init__ is deprecated"), pytest.raises(ValidationError), ): asdf.AsdfFile({"history": 42}) def test_asdffile_version_map_deprecation(): af = asdf.AsdfFile() with pytest.warns(AsdfDeprecationWarning, match="AsdfFile.version_map is deprecated"): af.version_map def test_format_tag_deprecation(): with pytest.warns(AsdfDeprecationWarning, match="format_tag is deprecated"): asdf.testing.helpers.format_tag("stsci.edu", "asdf", "1.0.0", "fits/fits") def test_asdf_util_filepath_to_url_deprecation(tmp_path): with pytest.warns(AsdfDeprecationWarning, match="asdf.util.filepath_to_url is deprecated"): asdf.util.filepath_to_url(str(tmp_path)) @pytest.mark.parametrize("value", [True, False]) def test_AsdfFile_ignore_implicit_conversion_deprecation(value): with pytest.warns(AsdfDeprecationWarning, match="ignore_implicit_conversion is deprecated"): asdf.AsdfFile({"a": 1}, ignore_implicit_conversion=value) @pytest.mark.parametrize("value", [True, False]) def test_walk_and_modify_ignore_implicit_conversion_deprecation(value): with pytest.warns(AsdfDeprecationWarning, match="ignore_implicit_conversion is deprecated"): asdf.treeutil.walk_and_modify({}, lambda obj: obj, ignore_implicit_conversion=value) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_entry_points.py0000644000175100001770000001263114653725311020436 0ustar00runnerdockerimport sys import pytest from asdf import _entry_points from asdf._version import version as asdf_package_version from asdf.exceptions import AsdfWarning from asdf.extension import ExtensionProxy from asdf.resource import ResourceMappingProxy # The standard library importlib.metadata returns duplicate entrypoints # for all python versions up to and including 3.11 # https://github.com/python/importlib_metadata/issues/410#issuecomment-1304258228 # see PR https://github.com/asdf-format/asdf/pull/1260 # see issue https://github.com/asdf-format/asdf/issues/1254 if sys.version_info >= (3, 12): import importlib.metadata as metadata else: import importlib_metadata as metadata @pytest.fixture() def mock_entry_points(): return [] @pytest.fixture(autouse=True) def _monkeypatch_entry_points(monkeypatch, mock_entry_points): def patched_entry_points(*, group): for candidate_group, name, func_name in mock_entry_points: if candidate_group == group: point = metadata.EntryPoint(name=name, group=group, value=func_name) vars(point).update(dist=metadata.distribution("asdf")) yield point monkeypatch.setattr(_entry_points, "entry_points", patched_entry_points) def resource_mappings_entry_point_successful(): return [ {"http://somewhere.org/schemas/foo-1.0.0": b"foo"}, {"http://somewhere.org/schemas/bar-1.0.0": b"bar"}, ] def resource_mappings_entry_point_failing(): msg = "NOPE" raise Exception(msg) def resource_mappings_entry_point_bad_element(): return [ {"http://somewhere.org/schemas/baz-1.0.0": b"baz"}, object(), {"http://somewhere.org/schemas/foz-1.0.0": b"foz"}, ] def test_get_resource_mappings(mock_entry_points): mock_entry_points.append( ( "asdf.resource_mappings", "successful", "asdf._tests.test_entry_points:resource_mappings_entry_point_successful", ), ) mappings = _entry_points.get_resource_mappings() assert len(mappings) == 2 for m in mappings: assert isinstance(m, ResourceMappingProxy) assert m.package_name == "asdf" assert m.package_version == asdf_package_version mock_entry_points.clear() mock_entry_points.append( ("asdf.resource_mappings", "failing", "asdf._tests.test_entry_points:resource_mappings_entry_point_failing"), ) with pytest.warns(AsdfWarning, match=r"Exception: NOPE"): mappings = _entry_points.get_resource_mappings() assert len(mappings) == 0 mock_entry_points.clear() mock_entry_points.append( ( "asdf.resource_mappings", "bad_element", "asdf._tests.test_entry_points:resource_mappings_entry_point_bad_element", ), ) with pytest.warns(AsdfWarning, match=r"TypeError: Resource mapping must implement the Mapping interface"): mappings = _entry_points.get_resource_mappings() assert len(mappings) == 2 class MinimumExtension: def __init__(self, extension_uri): self._extension_uri = extension_uri @property def extension_uri(self): return self._extension_uri def extensions_entry_point_successful(): return [ MinimumExtension("http://somewhere.org/extensions/foo-1.0"), MinimumExtension("http://somewhere.org/extensions/bar-1.0"), ] def extensions_entry_point_failing(): msg = "NOPE" raise Exception(msg) def extensions_entry_point_bad_element(): return [ MinimumExtension("http://somewhere.org/extensions/baz-1.0"), object(), MinimumExtension("http://somewhere.org/extensions/foz-1.0"), ] class LegacyExtension: types = [] tag_mapping = [] url_mapping = [] class FauxLegacyExtension: pass def test_get_extensions(mock_entry_points): mock_entry_points.append( ("asdf.extensions", "successful", "asdf._tests.test_entry_points:extensions_entry_point_successful"), ) extensions = _entry_points.get_extensions() assert len(extensions) == 2 for e in extensions: assert isinstance(e, ExtensionProxy) assert e.package_name == "asdf" assert e.package_version == asdf_package_version mock_entry_points.clear() mock_entry_points.append( ("asdf.extensions", "failing", "asdf._tests.test_entry_points:extensions_entry_point_failing"), ) with pytest.warns(AsdfWarning, match=r"Exception: NOPE"): extensions = _entry_points.get_extensions() assert len(extensions) == 0 mock_entry_points.clear() mock_entry_points.append( ("asdf.extensions", "bad_element", "asdf._tests.test_entry_points:extensions_entry_point_bad_element"), ) with pytest.warns( AsdfWarning, match=r"TypeError: Extension must implement the Extension interface", ): extensions = _entry_points.get_extensions() assert len(extensions) == 2 mock_entry_points.clear() mock_entry_points.append(("asdf_extensions", "legacy", "asdf._tests.test_entry_points:LegacyExtension")) extensions = _entry_points.get_extensions() assert len(extensions) == 0 # asdf_extensions is no longer supported mock_entry_points.clear() mock_entry_points.append(("asdf.extensions", "failing", "asdf._tests.test_entry_points:FauxLegacyExtension")) with pytest.warns(AsdfWarning, match=r"TypeError"): extensions = _entry_points.get_extensions() assert len(extensions) == 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_extension.py0000644000175100001770000010552614653725311017723 0ustar00runnerdockerimport fractions import sys import pytest from packaging.specifiers import SpecifierSet import asdf from asdf import AsdfFile, config_context from asdf.exceptions import AsdfManifestURIMismatchWarning, AsdfSerializationError, AsdfWarning, ValidationError from asdf.extension import ( Compressor, Converter, ConverterProxy, Extension, ExtensionManager, ExtensionProxy, ManifestExtension, TagDefinition, Validator, get_cached_extension_manager, ) from asdf.extension._manager import _resolve_type from asdf.testing.helpers import roundtrip_object class MinimumExtension: extension_uri = "asdf://somewhere.org/extensions/minimum-1.0" class MinimumExtensionSubclassed(Extension): extension_uri = "asdf://somewhere.org/extensions/minimum-1.0" class FullExtension: extension_uri = "asdf://somewhere.org/extensions/full-1.0" def __init__( self, converters=None, compressors=None, validators=None, asdf_standard_requirement=None, tags=None, legacy_class_names=None, ): self._converters = [] if converters is None else converters self._compressors = [] if compressors is None else compressors self._validators = [] if validators is None else validators self._asdf_standard_requirement = asdf_standard_requirement self._tags = [] if tags is None else tags self._legacy_class_names = [] if legacy_class_names is None else legacy_class_names @property def converters(self): return self._converters @property def compressors(self): return self._compressors @property def validators(self): return self._validators @property def asdf_standard_requirement(self): return self._asdf_standard_requirement @property def tags(self): return self._tags @property def legacy_class_names(self): return self._legacy_class_names class MinimumConverter: def __init__(self, tags=None, types=None): if tags is None: self._tags = [] else: self._tags = tags if types is None: self._types = [] else: self._types = types @property def tags(self): return self._tags @property def types(self): return self._types def to_yaml_tree(self, obj, tag, ctx): return "to_yaml_tree result" def from_yaml_tree(self, obj, tag, ctx): return "from_yaml_tree result" class FullConverter(MinimumConverter): def select_tag(self, obj, tags, ctx): return "select_tag result" class MinimalCompressor(Compressor): @staticmethod def compress(data): return b"" @property def label(self): return b"mini" class MinimalValidator(Validator): schema_property = "fail" tags = ["**"] def validate(self, fail, node, schema): if fail: yield ValidationError("Node was doomed to fail") # Some dummy types for testing converters: class FooType: pass class SubFooType(FooType): pass class BarType: pass class BazType: pass def test_extension_proxy_maybe_wrap(): extension = MinimumExtension() proxy = ExtensionProxy.maybe_wrap(extension) assert proxy.delegate is extension assert ExtensionProxy.maybe_wrap(proxy) is proxy with pytest.raises(TypeError, match=r"Extension must implement the Extension interface"): ExtensionProxy.maybe_wrap(object()) def test_extension_proxy(): # Test with minimum properties: extension = MinimumExtension() proxy = ExtensionProxy(extension) assert isinstance(proxy, Extension) assert proxy.extension_uri == "asdf://somewhere.org/extensions/minimum-1.0" assert proxy.legacy_class_names == set() assert proxy.asdf_standard_requirement == SpecifierSet() assert proxy.converters == [] assert proxy.compressors == [] assert proxy.validators == [] assert proxy.tags == [] assert proxy.types == [] assert proxy.tag_mapping == [] assert proxy.url_mapping == [] assert proxy.delegate is extension assert proxy.legacy is False assert proxy.package_name is None assert proxy.package_version is None assert proxy.class_name == "asdf._tests.test_extension.MinimumExtension" # The subclassed version should have the same defaults: extension = MinimumExtensionSubclassed() subclassed_proxy = ExtensionProxy(extension) assert subclassed_proxy.extension_uri == proxy.extension_uri assert subclassed_proxy.legacy_class_names == proxy.legacy_class_names assert subclassed_proxy.asdf_standard_requirement == proxy.asdf_standard_requirement assert subclassed_proxy.converters == proxy.converters assert subclassed_proxy.compressors == proxy.compressors assert subclassed_proxy.validators == proxy.validators assert subclassed_proxy.tags == proxy.tags assert subclassed_proxy.types == proxy.types assert subclassed_proxy.tag_mapping == proxy.tag_mapping assert subclassed_proxy.url_mapping == proxy.url_mapping assert subclassed_proxy.delegate is extension assert subclassed_proxy.legacy == proxy.legacy assert subclassed_proxy.package_name == proxy.package_name assert subclassed_proxy.package_version == proxy.package_name assert subclassed_proxy.class_name == "asdf._tests.test_extension.MinimumExtensionSubclassed" # Test with all properties present: converters = [MinimumConverter(tags=["asdf://somewhere.org/extensions/full/tags/foo-*"], types=[])] compressors = [MinimalCompressor()] validators = [MinimalValidator()] extension = FullExtension( converters=converters, compressors=compressors, validators=validators, asdf_standard_requirement=">=1.4.0", tags=["asdf://somewhere.org/extensions/full/tags/foo-1.0"], legacy_class_names=["foo.extensions.SomeOldExtensionClass"], ) proxy = ExtensionProxy(extension, package_name="foo", package_version="1.2.3") assert proxy.extension_uri == "asdf://somewhere.org/extensions/full-1.0" assert proxy.legacy_class_names == {"foo.extensions.SomeOldExtensionClass"} assert proxy.asdf_standard_requirement == SpecifierSet(">=1.4.0") assert proxy.converters == [ConverterProxy(c, proxy) for c in converters] assert proxy.compressors == compressors assert proxy.validators == validators assert len(proxy.tags) == 1 assert proxy.tags[0].tag_uri == "asdf://somewhere.org/extensions/full/tags/foo-1.0" assert proxy.types == [] assert proxy.tag_mapping == [] assert proxy.url_mapping == [] assert proxy.delegate is extension assert proxy.legacy is False assert proxy.package_name == "foo" assert proxy.package_version == "1.2.3" assert proxy.class_name == "asdf._tests.test_extension.FullExtension" # Should fail when the input is not one of the two extension interfaces: with pytest.raises(TypeError, match=r"Extension must implement the Extension interface"): ExtensionProxy(object) # Should fail with a bad converter: with pytest.raises(TypeError, match=r"Converter must implement the .* interface"): ExtensionProxy(FullExtension(converters=[object()])) # Should fail with a bad compressor: with pytest.raises(TypeError, match=r"Extension property 'compressors' must contain instances of .*"): ExtensionProxy(FullExtension(compressors=[object()])) # Should fail with a bad validator with pytest.raises(TypeError, match=r"Extension property 'validators' must contain instances of .*"): ExtensionProxy(FullExtension(validators=[object()])) # Unparsable ASDF Standard requirement: with pytest.raises(ValueError, match=r"Invalid specifier:.*"): ExtensionProxy(FullExtension(asdf_standard_requirement="asdf-standard >= 1.4.0")) # Unrecognized ASDF Standard requirement type: with pytest.raises(TypeError, match=r"Extension property 'asdf_standard_requirement' must be str or None"): ExtensionProxy(FullExtension(asdf_standard_requirement=object())) # Bad tag: with pytest.raises(TypeError, match=r"Extension property 'tags' must contain str or .* values"): ExtensionProxy(FullExtension(tags=[object()])) # Bad legacy class names: with pytest.raises(TypeError, match=r"Extension property 'legacy_class_names' must contain str values"): ExtensionProxy(FullExtension(legacy_class_names=[object])) def test_extension_proxy_tags(): """ The tags behavior is a tad complex, so they get their own test. """ foo_tag_uri = "asdf://somewhere.org/extensions/full/tags/foo-1.0" foo_tag_def = TagDefinition( foo_tag_uri, schema_uris="asdf://somewhere.org/extensions/full/schemas/foo-1.0", title="Some tag title", description="Some tag description", ) bar_tag_uri = "asdf://somewhere.org/extensions/full/tags/bar-1.0" bar_tag_def = TagDefinition( bar_tag_uri, schema_uris="asdf://somewhere.org/extensions/full/schemas/bar-1.0", title="Some other tag title", description="Some other tag description", ) # The converter should return only the tags # supported by the extension. converter = FullConverter(tags=["**"]) extension = FullExtension(tags=[foo_tag_def], converters=[converter]) proxy = ExtensionProxy(extension) assert proxy.converters[0].tags == [foo_tag_uri] # The converter should not return tags that # its patterns do not match. converter = FullConverter(tags=["**/foo-1.0"]) extension = FullExtension(tags=[foo_tag_def, bar_tag_def], converters=[converter]) proxy = ExtensionProxy(extension) assert proxy.converters[0].tags == [foo_tag_uri] # The process should still work if the extension property # contains str instead of TagDescription. converter = FullConverter(tags=["**/foo-1.0"]) extension = FullExtension(tags=[foo_tag_uri, bar_tag_uri], converters=[converter]) proxy = ExtensionProxy(extension) assert proxy.converters[0].tags == [foo_tag_uri] def test_extension_proxy_hash_and_eq(): extension = MinimumExtension() proxy1 = ExtensionProxy(extension) proxy2 = ExtensionProxy(extension, package_name="foo", package_version="1.2.3") assert proxy1 == proxy2 assert hash(proxy1) == hash(proxy2) assert proxy1 != extension assert proxy2 != extension def test_extension_proxy_repr(): proxy = ExtensionProxy(MinimumExtension(), package_name="foo", package_version="1.2.3") assert "class: asdf._tests.test_extension.MinimumExtension" in repr(proxy) assert "package: foo==1.2.3" in repr(proxy) assert "legacy: False" in repr(proxy) proxy = ExtensionProxy(MinimumExtension()) assert "class: asdf._tests.test_extension.MinimumExtension" in repr(proxy) assert "package: (none)" in repr(proxy) assert "legacy: False" in repr(proxy) def test_extension_manager(): converter1 = FullConverter( tags=[ "asdf://somewhere.org/extensions/full/tags/foo-*", "asdf://somewhere.org/extensions/full/tags/bar-*", ], types=[ FooType, "asdf._tests.test_extension.BarType", ], ) converter2 = FullConverter( tags=[ "asdf://somewhere.org/extensions/full/tags/baz-*", ], types=[BazType], ) converter3 = FullConverter( tags=[ "asdf://somewhere.org/extensions/full/tags/foo-*", ], types=[ FooType, BarType, ], ) extension1 = FullExtension( converters=[converter1, converter2], tags=[ "asdf://somewhere.org/extensions/full/tags/foo-1.0", "asdf://somewhere.org/extensions/full/tags/baz-1.0", ], ) extension2 = FullExtension( converters=[converter3], tags=[ "asdf://somewhere.org/extensions/full/tags/foo-1.0", ], ) manager = ExtensionManager([extension1, extension2]) assert manager.extensions == [ExtensionProxy(extension1), ExtensionProxy(extension2)] assert manager.handles_tag("asdf://somewhere.org/extensions/full/tags/foo-1.0") is True assert manager.handles_tag("asdf://somewhere.org/extensions/full/tags/bar-1.0") is False assert manager.handles_tag("asdf://somewhere.org/extensions/full/tags/baz-1.0") is True assert manager.handles_type(FooType) is True assert manager.handles_type(SubFooType) is False # This should return True even though BarType was listed # as string class name: assert manager.handles_type(BarType) is True assert manager.handles_type(BazType) is True assert ( manager.get_tag_definition("asdf://somewhere.org/extensions/full/tags/foo-1.0").tag_uri == "asdf://somewhere.org/extensions/full/tags/foo-1.0" ) assert ( manager.get_tag_definition("asdf://somewhere.org/extensions/full/tags/baz-1.0").tag_uri == "asdf://somewhere.org/extensions/full/tags/baz-1.0" ) with pytest.raises(KeyError, match=r"No support available for YAML tag.*"): manager.get_tag_definition("asdf://somewhere.org/extensions/full/tags/bar-1.0") assert manager.get_converter_for_tag("asdf://somewhere.org/extensions/full/tags/foo-1.0").delegate is converter1 assert manager.get_converter_for_tag("asdf://somewhere.org/extensions/full/tags/baz-1.0").delegate is converter2 with pytest.raises(KeyError, match=r"No support available for YAML tag.*"): manager.get_converter_for_tag("asdf://somewhere.org/extensions/full/tags/bar-1.0") assert manager.get_converter_for_type(FooType).delegate is converter1 assert manager.get_converter_for_type(BarType).delegate is converter1 assert manager.get_converter_for_type(BazType).delegate is converter2 with pytest.raises(KeyError, match=r"\"No support available for Python type .*\""): manager.get_converter_for_type(object) with pytest.raises(KeyError, match=r"\"No support available for Python type .*\""): manager.get_converter_for_type(SubFooType) def test_get_cached_extension_manager(): extension = MinimumExtension() extension_manager = get_cached_extension_manager([extension]) assert get_cached_extension_manager([extension]) is extension_manager assert get_cached_extension_manager([MinimumExtension()]) is not extension_manager def test_tag_definition(): tag_def = TagDefinition( "asdf://somewhere.org/extensions/foo/tags/foo-1.0", schema_uris="asdf://somewhere.org/extensions/foo/schemas/foo-1.0", title="Some title", description="Some description", ) assert tag_def.tag_uri == "asdf://somewhere.org/extensions/foo/tags/foo-1.0" assert tag_def.schema_uris == ["asdf://somewhere.org/extensions/foo/schemas/foo-1.0"] assert tag_def.title == "Some title" assert tag_def.description == "Some description" assert "URI: asdf://somewhere.org/extensions/foo/tags/foo-1.0" in repr(tag_def) tag_def = TagDefinition( "asdf://somewhere.org/extensions/foo/tags/foo-1.0", schema_uris=[ "asdf://somewhere.org/extensions/foo/schemas/foo-1.0", "asdf://somewhere.org/extensions/foo/schemas/base-1.0", ], title="Some title", description="Some description", ) assert tag_def.schema_uris == [ "asdf://somewhere.org/extensions/foo/schemas/foo-1.0", "asdf://somewhere.org/extensions/foo/schemas/base-1.0", ] with pytest.raises(ValueError, match=r"URI patterns are not permitted in TagDefinition"): TagDefinition("asdf://somewhere.org/extensions/foo/tags/foo-*") def test_converter(): class ConverterNoSubclass: tags = [] types = [] def to_yaml_tree(self, *args): pass def from_yaml_tree(self, *args): pass assert issubclass(ConverterNoSubclass, Converter) def test_converter_proxy(): # Test the minimum set of converter methods: extension = ExtensionProxy(MinimumExtension()) converter = MinimumConverter() proxy = ConverterProxy(converter, extension) assert isinstance(proxy, Converter) assert proxy.tags == [] assert proxy.types == [] assert proxy.to_yaml_tree(None, None, None) == "to_yaml_tree result" assert proxy.from_yaml_tree(None, None, None) == "from_yaml_tree result" assert proxy.tags == [] assert proxy.delegate is converter assert proxy.extension == extension assert proxy.package_name is None assert proxy.package_version is None assert proxy.class_name == "asdf._tests.test_extension.MinimumConverter" # Check the __eq__ and __hash__ behavior: assert proxy == ConverterProxy(converter, extension) assert proxy != ConverterProxy(MinimumConverter(), extension) assert proxy != ConverterProxy(converter, MinimumExtension()) assert proxy in {ConverterProxy(converter, extension)} assert proxy not in {ConverterProxy(MinimumConverter(), extension), ConverterProxy(converter, MinimumExtension())} # Check the __repr__: assert "class: asdf._tests.test_extension.MinimumConverter" in repr(proxy) assert "package: (none)" in repr(proxy) # Test the full set of converter methods: converter = FullConverter( tags=[ "asdf://somewhere.org/extensions/test/tags/foo-*", "asdf://somewhere.org/extensions/test/tags/bar-*", ], types=[FooType, BarType], ) extension = FullExtension( tags=[ TagDefinition( "asdf://somewhere.org/extensions/test/tags/foo-1.0", schema_uris="asdf://somewhere.org/extensions/test/schemas/foo-1.0", title="Foo tag title", description="Foo tag description", ), TagDefinition( "asdf://somewhere.org/extensions/test/tags/bar-1.0", schema_uris="asdf://somewhere.org/extensions/test/schemas/bar-1.0", title="Bar tag title", description="Bar tag description", ), ], ) extension_proxy = ExtensionProxy(extension, package_name="foo", package_version="1.2.3") proxy = ConverterProxy(converter, extension_proxy) assert len(proxy.tags) == 2 assert "asdf://somewhere.org/extensions/test/tags/foo-1.0" in proxy.tags assert "asdf://somewhere.org/extensions/test/tags/bar-1.0" in proxy.tags assert proxy.types == [FooType, BarType] assert proxy.to_yaml_tree(None, None, None) == "to_yaml_tree result" assert proxy.from_yaml_tree(None, None, None) == "from_yaml_tree result" assert proxy.select_tag(None, None) == "select_tag result" assert proxy.delegate is converter assert proxy.extension == extension_proxy assert proxy.package_name == "foo" assert proxy.package_version == "1.2.3" assert proxy.class_name == "asdf._tests.test_extension.FullConverter" # Check the __repr__ since it will contain package info now: assert "class: asdf._tests.test_extension.FullConverter" in repr(proxy) assert "package: foo==1.2.3" in repr(proxy) # Should error because object() does fulfill the Converter interface: with pytest.raises(TypeError, match=r"Converter must implement the .*"): ConverterProxy(object(), extension) # Should fail because tags must be str: with pytest.raises(TypeError, match=r"Converter property .* must contain str values"): ConverterProxy(MinimumConverter(tags=[object()]), extension) # Should fail because types must instances of type: with pytest.raises(TypeError, match=r"Converter property .* must contain str or type values"): # as the code will ignore types if no relevant tags are found # include a tag from this extension to make sure the proxy considers # the types ConverterProxy(MinimumConverter(tags=[extension.tags[0].tag_uri], types=[object()]), extension) def test_converter_subclass_with_no_supported_tags(): """ Adding a Converter to an Extension that doesn't list support for the tags associated with the Converter should result in a failure to convert. """ class Foo: pass class FooConverterWithSubclass(Converter): tags = ["asdf://somewhere.org/tags/foo-1.0.0"] types = [Foo] def to_yaml_tree(self, *args): pass def from_yaml_tree(self, *args): pass class FooExtension(Extension): tags = [] converters = [FooConverterWithSubclass()] extension_uri = "asdf://somewhere.org/extensions/foo-1.0.0" tree = {"obj": Foo()} with config_context() as cfg: cfg.add_extension(FooExtension()) with pytest.raises(AsdfSerializationError, match=r"is not serializable by asdf"): roundtrip_object(tree) def test_manifest_extension(): with config_context() as config: minimal_manifest = """%YAML 1.1 --- id: asdf://somewhere.org/manifests/foo extension_uri: asdf://somewhere.org/extensions/foo ... """ config.add_resource_mapping({"asdf://somewhere.org/extensions/foo": minimal_manifest}) extension = ManifestExtension.from_uri("asdf://somewhere.org/extensions/foo") assert isinstance(extension, Extension) assert extension.extension_uri == "asdf://somewhere.org/extensions/foo" assert extension.legacy_class_names == [] assert extension.asdf_standard_requirement is None assert extension.converters == [] assert extension.compressors == [] assert extension.validators == [] assert extension.tags == [] proxy = ExtensionProxy(extension) assert proxy.extension_uri == "asdf://somewhere.org/extensions/foo" assert proxy.legacy_class_names == set() assert proxy.asdf_standard_requirement == SpecifierSet() assert proxy.converters == [] assert proxy.compressors == [] assert proxy.validators == [] assert proxy.tags == [] with config_context() as config: full_manifest = """%YAML 1.1 --- id: asdf://somewhere.org/manifests/foo extension_uri: asdf://somewhere.org/extensions/foo asdf_standard_requirement: gte: 1.6.0 lt: 2.0.0 tags: - asdf://somewhere.org/tags/bar - tag_uri: asdf://somewhere.org/tags/baz schema_uri: asdf://somewhere.org/schemas/baz title: Baz title description: Bar description ... """ config.add_resource_mapping({"asdf://somewhere.org/extensions/foo": full_manifest}) class FooConverter: tags = ["asdf://somewhere.org/tags/bar", "asdf://somewhere.org/tags/baz"] types = [] def select_tag(self, *args): pass def to_yaml_tree(self, *args): pass def from_yaml_tree(self, *args): pass converter = FooConverter() validator = MinimalValidator() compressor = MinimalCompressor() extension = ManifestExtension.from_uri( "asdf://somewhere.org/extensions/foo", legacy_class_names=["foo.extension.LegacyExtension"], converters=[converter], compressors=[compressor], validators=[validator], ) assert extension.extension_uri == "asdf://somewhere.org/extensions/foo" assert extension.legacy_class_names == ["foo.extension.LegacyExtension"] assert extension.asdf_standard_requirement == SpecifierSet(">=1.6.0,<2.0.0") assert extension.converters == [converter] assert extension.compressors == [compressor] assert extension.validators == [validator] assert len(extension.tags) == 2 assert extension.tags[0] == "asdf://somewhere.org/tags/bar" assert extension.tags[1].tag_uri == "asdf://somewhere.org/tags/baz" assert extension.tags[1].schema_uris == ["asdf://somewhere.org/schemas/baz"] assert extension.tags[1].title == "Baz title" assert extension.tags[1].description == "Bar description" proxy = ExtensionProxy(extension) assert proxy.extension_uri == "asdf://somewhere.org/extensions/foo" assert proxy.legacy_class_names == {"foo.extension.LegacyExtension"} assert proxy.asdf_standard_requirement == SpecifierSet(">=1.6.0,<2.0.0") assert proxy.converters == [ConverterProxy(converter, proxy)] assert proxy.compressors == [compressor] assert proxy.validators == [validator] assert len(proxy.tags) == 2 assert proxy.tags[0].tag_uri == "asdf://somewhere.org/tags/bar" assert proxy.tags[1].tag_uri == "asdf://somewhere.org/tags/baz" assert proxy.tags[1].schema_uris == ["asdf://somewhere.org/schemas/baz"] assert proxy.tags[1].title == "Baz title" assert proxy.tags[1].description == "Bar description" with config_context() as config: simple_asdf_standard_manifest = """%YAML 1.1 --- id: asdf://somewhere.org/manifests/foo extension_uri: asdf://somewhere.org/extensions/foo asdf_standard_requirement: 1.6.0 ... """ config.add_resource_mapping({"asdf://somewhere.org/extensions/foo": simple_asdf_standard_manifest}) extension = ManifestExtension.from_uri("asdf://somewhere.org/extensions/foo") assert extension.asdf_standard_requirement == SpecifierSet("==1.6.0") proxy = ExtensionProxy(extension) assert proxy.asdf_standard_requirement == SpecifierSet("==1.6.0") def test_validator(): validator = MinimalValidator() extension = FullExtension(validators=[validator]) failing_schema = """ type: object properties: foo: fail: true """ passing_schema = """ type: object properties: foo: fail: false """ with config_context() as config: config.add_extension(extension) config.add_resource_mapping( { "asdf://somewhere.org/schemas/failing": failing_schema, "asdf://somewhere.org/schemas/passing": passing_schema, }, ) with AsdfFile(custom_schema="asdf://somewhere.org/schemas/passing") as af: af["foo"] = "bar" af.validate() with AsdfFile(custom_schema="asdf://somewhere.org/schemas/failing") as af: af.validate() af["foo"] = "bar" with pytest.raises(ValidationError, match=r"Node was doomed to fail"): af.validate() def test_converter_deferral(): class Bar: def __init__(self, value): self.value = value class Foo(Bar): pass class Baz(Bar): pass class FooConverter: tags = [] types = [Foo] def select_tag(self, *args): return None def to_yaml_tree(self, obj, tag, ctx): # convert Foo instance to Bar return Bar(obj.value) def from_yaml_tree(self, node, tag, ctx): raise NotImplementedError() class BarConverter: tags = ["asdf://somewhere.org/tags/bar"] types = [Bar] def to_yaml_tree(self, obj, tag, ctx): return {"value": obj.value} def from_yaml_tree(self, node, tag, ctx): return Bar(node["value"]) class BazConverter: tags = [] types = [Baz] def select_tag(self, *args): return None def to_yaml_tree(self, obj, tag, ctx): return Foo(obj.value) def from_yaml_tree(self, node, tag, ctx): raise NotImplementedError() extension = FullExtension(converters=[FooConverter(), BarConverter(), BazConverter()], tags=BarConverter.tags) with config_context() as config: config.add_extension(extension) foo = Foo(26) bar = Bar(42) baz = Baz(720) bar_rt = roundtrip_object(bar) assert isinstance(bar_rt, Bar) assert bar_rt.value == bar.value foo_rt = roundtrip_object(foo) assert isinstance(foo_rt, Bar) assert foo_rt.value == foo.value baz_rt = roundtrip_object(baz) assert isinstance(baz_rt, Bar) assert baz_rt.value == baz.value def test_converter_loop(): class Bar: def __init__(self, value): self.value = value class Foo(Bar): pass class Baz(Bar): pass class FooConverter: tags = [] types = [Foo] def select_tag(self, *args): return None def to_yaml_tree(self, obj, tag, ctx): return Bar(obj.value) def from_yaml_tree(self, node, tag, ctx): raise NotImplementedError() class BarConverter: tags = [] types = [Bar] def select_tag(self, *args): return None def to_yaml_tree(self, obj, tag, ctx): return Baz(obj.value) def from_yaml_tree(self, node, tag, ctx): raise NotImplementedError() class BazConverter: tags = [] types = [Baz] def select_tag(self, *args): return None def to_yaml_tree(self, obj, tag, ctx): return Foo(obj.value) def from_yaml_tree(self, node, tag, ctx): raise NotImplementedError() extension = FullExtension(converters=[FooConverter(), BarConverter(), BazConverter()]) with config_context() as config: config.add_extension(extension) for typ in (Foo, Bar, Baz): obj = typ(42) with pytest.raises(TypeError, match=r"Conversion cycle detected"): roundtrip_object(obj) @pytest.mark.parametrize("is_subclass", [True, False]) @pytest.mark.parametrize("indirect", [True, False]) def test_warning_or_error_for_default_select_tag(is_subclass, indirect): class Foo: pass ParentClass = Converter if is_subclass else object if indirect: class IntermediateClass(ParentClass): pass ParentClass = IntermediateClass class FooConverter(ParentClass): tags = ["asdf://somewhere.org/tags/foo-*"] types = [Foo] def to_yaml_tree(self, obj, tag, ctx): return {} def from_yaml_tree(self, node, tag, ctx): return Foo() tags = [ "asdf://somewhere.org/tags/foo-1.0.0", "asdf://somewhere.org/tags/foo-2.0.0", ] extension = FullExtension(converters=[FooConverter()], tags=tags) ctx_type = pytest.warns if is_subclass else pytest.raises exception_class = AsdfWarning if is_subclass else RuntimeError with config_context() as config: with ctx_type(exception_class, match="Converter handles multiple tags"): config.add_extension(extension) def test_reference_cycle(tmp_path, with_lazy_tree): class FractionWithInverse(fractions.Fraction): def __init__(self, *args, **kwargs): self._inverse = None @property def inverse(self): return self._inverse @inverse.setter def inverse(self, value): self._inverse = value class FractionWithInverseConverter: tags = ["asdf://example.com/fractions/tags/fraction-1.0.0"] types = [FractionWithInverse] def to_yaml_tree(self, obj, tag, ctx): return { "numerator": obj.numerator, "denominator": obj.denominator, "inverse": obj.inverse, } def from_yaml_tree(self, node, tag, ctx): obj = FractionWithInverse(node["numerator"], node["denominator"]) yield obj obj.inverse = node["inverse"] class FractionWithInverseExtension: tags = FractionWithInverseConverter.tags converters = [FractionWithInverseConverter()] extension_uri = "asdf://example.com/fractions/extensions/fraction-1.0.0" with config_context() as cfg: cfg.add_extension(FractionWithInverseExtension()) f1 = FractionWithInverse(3, 5) f2 = FractionWithInverse(5, 3) f1.inverse = f2 f2.inverse = f1 fn = tmp_path / "test.asdf" asdf.AsdfFile({"obj": f1}).write_to(fn) with asdf.open(fn) as af: read_f1 = af["obj"] assert read_f1.inverse.inverse is read_f1 def test_manifest_uri_id_mismatch_warning(tmp_path): with config_context() as config: # make an extension with a manifest (where id doesn't match the registered uri) full_manifest = """%YAML 1.1 --- id: asdf://somewhere.org/manifests/foo extension_uri: asdf://somewhere.org/extensions/foo tags: - asdf://somewhere.org/tags/bar ... """ config.add_resource_mapping({"asdf://somewhere.org/extensions/foo": full_manifest}) class Foo: pass class FooConverter: tags = ["asdf://somewhere.org/tags/bar"] types = [Foo] def to_yaml_tree(self, *args): return {} def from_yaml_tree(self, *args): return Foo() extension = ManifestExtension.from_uri( "asdf://somewhere.org/extensions/foo", converters=[FooConverter()], ) # use the extension to write out a file config.add_extension(extension) af = AsdfFile() af["foo"] = Foo() fn = tmp_path / "foo.asdf" with pytest.warns(AsdfManifestURIMismatchWarning): af.write_to(fn) def test_resolve_type_not_imported(): path = "mailbox.Mailbox" if "mailbox" in sys.modules: del sys.modules["mailbox"] assert _resolve_type(path) is None import mailbox assert _resolve_type(path) is mailbox.Mailbox @pytest.mark.parametrize( "path, obj", (("sys", sys), ("asdf.AsdfFile", AsdfFile), ("asdf.Missing", None), ("not_a_module", None)) ) def test_resolve_type(path, obj): assert _resolve_type(path) is obj def test_extension_converter_by_class_path(): class MailboxConverter: tags = ["asdf://example.com/tags/mailbox-1.0.0"] types = ["mailbox.Mailbox"] def to_yaml_tree(self, obj, tag, ctx): return {} def from_yaml_tree(self, node, tag, ctx): return None class MailboxExtension: tags = MailboxConverter.tags converters = [MailboxConverter()] extension_uri = "asdf://example.com/extensions/mailbox-1.0.0" # grab the type so we can use it for extension_manager.get_converter_for_type import mailbox typ = mailbox.Mailbox del sys.modules["mailbox"], mailbox with config_context() as cfg: cfg.add_extension(MailboxExtension()) extension_manager = AsdfFile().extension_manager # make sure that registering the extension did not load the module assert "mailbox" not in sys.modules # as the module hasn't been loaded, the converter shouldn't be found with pytest.raises(KeyError, match="No support available for Python type 'mailbox.Mailbox'"): extension_manager.get_converter_for_type(typ) # make sure inspecting the type didn't import the module assert "mailbox" not in sys.modules # finally, import the module and check that the converter can now be found import mailbox converter = extension_manager.get_converter_for_type(mailbox.Mailbox) assert isinstance(converter.delegate, MailboxConverter) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_file_format.py0000644000175100001770000001070414653725311020167 0ustar00runnerdockerimport io import os import pytest import asdf from asdf import generic_io def test_no_yaml_end_marker(tmp_path): content = b"""#ASDF 1.0.0 %YAML 1.1 %TAG ! tag:stsci.edu:asdf/ --- !core/asdf-1.0.0 foo: bar...baz baz: 42 """ path = os.path.join(str(tmp_path), "test.asdf") buff = io.BytesIO(content) with pytest.raises(ValueError, match=r"End of YAML marker not found"), asdf.open(buff): pass buff.seek(0) fd = generic_io.InputStream(buff, "r") with pytest.raises(ValueError, match=r"End of YAML marker not found"), asdf.open(buff): pass with open(path, "wb") as fd: fd.write(content) with open(path, "rb") as fd, pytest.raises(ValueError, match=r"End of YAML marker not found"), asdf.open(fd): pass def test_no_final_newline(tmp_path): content = b"""#ASDF 1.0.0 %YAML 1.1 %TAG ! tag:stsci.edu:asdf/ --- !core/asdf-1.0.0 foo: ...bar... baz: 42 ...""" path = os.path.join(str(tmp_path), "test.asdf") buff = io.BytesIO(content) with asdf.open(buff) as ff: assert len(ff.tree) == 2 buff.seek(0) fd = generic_io.InputStream(buff, "r") with asdf.open(fd) as ff: assert len(ff.tree) == 2 with open(path, "wb") as fd: fd.write(content) with open(path, "rb") as fd, asdf.open(fd) as ff: assert len(ff.tree) == 2 def test_no_asdf_header(tmp_path): content = b"What? This ain't no ASDF file" path = os.path.join(str(tmp_path), "test.asdf") buff = io.BytesIO(content) with pytest.raises( ValueError, match=r"Does not appear to be a ASDF file.", ): asdf.open(buff) with open(path, "wb") as fd: fd.write(content) with ( open(path, "rb") as fd, pytest.raises( ValueError, match=r"Does not appear to be a ASDF file.", ), ): asdf.open(fd) def test_empty_file(): buff = io.BytesIO(b"#ASDF 1.0.0\n") buff.seek(0) with asdf.open(buff) as ff: assert ff.tree == {} assert len(ff._blocks.blocks) == 0 buff = io.BytesIO(b"#ASDF 1.0.0\n#ASDF_STANDARD 1.0.0") buff.seek(0) with asdf.open(buff) as ff: assert ff.tree == {} assert len(ff._blocks.blocks) == 0 @pytest.mark.filterwarnings("ignore::asdf.exceptions.AsdfDeprecationWarning") def test_not_asdf_file(): buff = io.BytesIO(b"SIMPLE") buff.seek(0) with ( pytest.raises( ValueError, match=r"Does not appear to be a ASDF file.", ), asdf.open(buff), ): pass buff = io.BytesIO(b"SIMPLE\n") buff.seek(0) with ( pytest.raises( ValueError, match=r"Does not appear to be a ASDF file.", ), asdf.open(buff), ): pass def test_junk_file(): buff = io.BytesIO(b"#ASDF 1.0.0\nFOO") buff.seek(0) with pytest.raises(ValueError, match=r"Invalid content between header and tree"), asdf.open(buff): pass def test_invalid_header_version(): buff = io.BytesIO(b"#ASDF foo\n") buff.seek(0) with pytest.raises(ValueError, match=r"Unparsable version in ASDF file"), asdf.open(buff): pass def test_block_mismatch(): # This is a file with a single small block, followed by something # that has an invalid block magic number. buff = io.BytesIO( b"#ASDF 1.0.0\n\xd3BLK\x00\x28\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\x01" b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0FOOBAR", ) buff.seek(0) with pytest.raises(ValueError, match=r"Header size must be >= 48"), asdf.open(buff): pass def test_block_header_too_small(): # The block header size must be at least 40 buff = io.BytesIO(b"#ASDF 1.0.0\n\xd3BLK\0\0") buff.seek(0) with pytest.raises(ValueError, match=r"Header size must be >= 48"), asdf.open(buff): pass def test_invalid_version(tmp_path): content = b"""#ASDF 0.1.0 %YAML 1.1 %TAG ! tag:stsci.edu:asdf/ --- !core/asdf-0.1.0 foo : bar ...""" buff = io.BytesIO(content) with pytest.raises(ValueError, match=r"Unsupported ASDF file format version*"), asdf.open(buff): pass def test_valid_version(tmp_path): content = b"""#ASDF 1.0.0 %YAML 1.1 %TAG ! tag:stsci.edu:asdf/ --- !core/asdf-1.0.0 foo : bar ...""" buff = io.BytesIO(content) with asdf.open(buff) as ff: version = ff.file_format_version assert version.major == 1 assert version.minor == 0 assert version.patch == 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_generic_io.py0000644000175100001770000006542714653725311020017 0ustar00runnerdockerimport io import os import re import stat import sys import urllib.request as urllib_request import numpy as np import pytest import asdf from asdf import exceptions, generic_io from asdf.config import config_context from . import _helpers as helpers from . import create_large_tree, create_small_tree @pytest.fixture(params=[create_small_tree, create_large_tree]) def tree(request): return request.param() def _roundtrip(tree, get_write_fd, get_read_fd, write_options=None, read_options=None): write_options = {} if write_options is None else write_options read_options = {} if read_options is None else read_options # Since we're testing with small arrays, force all arrays to be stored # in internal blocks rather than letting some of them be automatically put # inline. write_options.setdefault("all_array_storage", "internal") with get_write_fd() as fd: asdf.AsdfFile(tree).write_to(fd, **write_options) # Work around the fact that generic_io's get_file doesn't have a way of # determining whether or not the underlying file handle should be # closed as part of the exit handler if isinstance(fd._fd, io.FileIO): fd._fd.close() with get_read_fd() as fd: ff = asdf.open(fd, **read_options) helpers.assert_tree_match(tree, ff.tree) return ff def test_mode_fail(tmp_path): path = os.path.join(str(tmp_path), "test.asdf") with pytest.raises(ValueError, match=r"mode must be 'r', 'w' or 'rw'"): generic_io.get_file(path, mode="r+") @pytest.mark.parametrize("mode", ["r", "w", "rw"]) def test_missing_directory(tmp_path, mode): path = str(tmp_path / "missing" / "test.asdf") regex_path = re.escape(path.replace("\\", "\\\\")) with pytest.raises(FileNotFoundError, match=f".*: '{regex_path}'$"): generic_io.get_file(path, mode=mode) @pytest.mark.skipif(sys.platform.startswith("win"), reason="paths with two leading slashes are valid on windows") @pytest.mark.parametrize("mode", ["r", "w", "rw"]) def test_two_leading_slashes(mode): """ Providing a path with two leading slashes '//' will be parsed by urllib as having a netloc (unhandled by generic_io) and an invalid path. This creates an unhelpful error message on write (related to a missing atomic write file) and should be cause beforehand and provided with a more helpful error message Regression test for issue: https://github.com/asdf-format/asdf/issues/1353 """ path = "//bad/two/slashes" with pytest.raises(ValueError, match="Invalid path"): generic_io.get_file(path, mode=mode) def test_open(tmp_path, small_tree): from asdf import open path = os.path.join(str(tmp_path), "test.asdf") # Simply tests the high-level "open" function ff = asdf.AsdfFile(small_tree) ff.write_to(path) with open(path) as ff2: helpers.assert_tree_match(ff2.tree, ff.tree) def test_path(tree, tmp_path): path = tmp_path / "test.asdf" def get_write_fd(): f = generic_io.get_file(path, mode="w") assert isinstance(f, generic_io.RealFile) assert f._uri == path.as_uri() return f def get_read_fd(): # Must open with mode=rw in order to get memmapped data f = generic_io.get_file(path, mode="rw") assert isinstance(f, generic_io.RealFile) assert f._uri == path.as_uri() # This is to check for a "feature" in Python 3.x that reading zero # bytes from a socket causes it to stop. We have code in generic_io.py # to workaround it. f.read(0) return f with _roundtrip(tree, get_write_fd, get_read_fd) as ff: assert len(ff._blocks.blocks) == 2 assert isinstance(ff._blocks.blocks[0].cached_data, np.memmap) def test_open2(tree, tmp_path): path = tmp_path / "test.asdf" def get_write_fd(): # cannot use context manager here because it closes the file f = generic_io.get_file(open(path, "wb"), mode="w", close=True) assert isinstance(f, generic_io.RealFile) assert f._uri == path.as_uri() return f def get_read_fd(): # Must open with mode=rw in order to get memmapped data # cannot use context manager here because it closes the file f = generic_io.get_file(open(path, "r+b"), mode="rw", close=True) assert isinstance(f, generic_io.RealFile) assert f._uri == path.as_uri() return f with _roundtrip(tree, get_write_fd, get_read_fd) as ff: assert len(ff._blocks.blocks) == 2 assert isinstance(ff._blocks.blocks[0].cached_data, np.memmap) @pytest.mark.parametrize("mode", ["r", "w", "rw"]) def test_open_not_binary_fail(tmp_path, mode): path = tmp_path / "test.asdf" with open(path, "w") as fd: fd.write("\n\n\n") file_mode = mode if mode != "rw" else "r+" with ( open(path, file_mode) as fd, pytest.raises( ValueError, match=r"File-like object must be opened in binary mode.", ), ): generic_io.get_file(fd, mode=mode) def test_io_open(tree, tmp_path): path = tmp_path / "test.asdf" def get_write_fd(): # cannot use context manager here because it closes the file f = generic_io.get_file(open(path, "wb"), mode="w", close=True) assert isinstance(f, generic_io.RealFile) assert f._uri == path.as_uri() return f def get_read_fd(): # cannot use context manager here because it closes the file f = generic_io.get_file(open(path, "r+b"), mode="rw", close=True) assert isinstance(f, generic_io.RealFile) assert f._uri == path.as_uri() return f with _roundtrip(tree, get_write_fd, get_read_fd) as ff: assert len(ff._blocks.blocks) == 2 assert isinstance(ff._blocks.blocks[0].cached_data, np.memmap) ff.tree["science_data"][0] = 42 def test_close_underlying(tmp_path): path = os.path.join(str(tmp_path), "test.asdf") with generic_io.get_file(open(path, "wb"), mode="w", close=True) as ff: pass assert ff.is_closed() is True assert ff._fd.closed is True with generic_io.get_file(open(path, "rb"), close=True) as ff2: pass assert ff2.is_closed() is True assert ff2._fd.closed is True def test_bytes_io(tree): buff = io.BytesIO() def get_write_fd(): f = generic_io.get_file(buff, mode="w") assert isinstance(f, generic_io.MemoryIO) return f def get_read_fd(): buff.seek(0) f = generic_io.get_file(buff, mode="rw") assert isinstance(f, generic_io.MemoryIO) return f with _roundtrip(tree, get_write_fd, get_read_fd) as ff: assert len(ff._blocks.blocks) == 2 assert not isinstance(ff._blocks.blocks[0].cached_data, np.memmap) ff.tree["science_data"][0] = 42 def test_streams(tree): buff = io.BytesIO() def get_write_fd(): return generic_io.OutputStream(buff) def get_read_fd(): buff.seek(0) return generic_io.InputStream(buff, "rw") with _roundtrip(tree, get_write_fd, get_read_fd) as ff: assert len(ff._blocks.blocks) == 2 assert not isinstance(ff._blocks.blocks[0].cached_data, np.memmap) ff.tree["science_data"][0] = 42 def test_streams2(): buff = io.BytesIO(b"\0" * 60) buff.seek(0) fd = generic_io.InputStream(buff, "r") x = fd.peek(10) x = fd.read() assert len(x) == 60 @pytest.mark.remote_data() def test_urlopen(tree, httpserver): path = os.path.join(httpserver.tmpdir, "test.asdf") def get_write_fd(): # cannot use context manager here because it closes the file return generic_io.get_file(open(path, "wb"), mode="w") def get_read_fd(): return generic_io.get_file(urllib_request.urlopen(httpserver.url + "test.asdf")) with _roundtrip(tree, get_write_fd, get_read_fd) as ff: assert len(ff._blocks.blocks) == 2 assert not isinstance(ff._blocks.blocks[0].cached_data, np.memmap) @pytest.mark.remote_data() def test_http_connection(tree, httpserver): path = os.path.join(httpserver.tmpdir, "test.asdf") def get_write_fd(): # cannot use context manager here because it closes the file return generic_io.get_file(open(path, "wb"), mode="w") def get_read_fd(): fd = generic_io.get_file(httpserver.url + "test.asdf") # This is to check for a "feature" in Python 3.x that reading zero # bytes from a socket causes it to stop. We have code in generic_io.py # to workaround it. fd.read(0) return fd with _roundtrip(tree, get_write_fd, get_read_fd) as ff: assert len(ff._blocks.blocks) == 2 assert (ff.tree["science_data"] == tree["science_data"]).all() def test_exploded_filesystem(tree, tmp_path): path = os.path.join(str(tmp_path), "test.asdf") def get_write_fd(): return generic_io.get_file(path, mode="w") def get_read_fd(): return generic_io.get_file(path, mode="r") with _roundtrip(tree, get_write_fd, get_read_fd, write_options={"all_array_storage": "external"}) as ff: assert len(ff._blocks.blocks) == 0 def test_exploded_filesystem_fail(tree, tmp_path): path = os.path.join(str(tmp_path), "test.asdf") def get_write_fd(): return generic_io.get_file(path, mode="w") def get_read_fd(): fd = io.BytesIO() with open(path, mode="rb") as fd2: fd.write(fd2.read()) fd.seek(0) return fd with get_write_fd() as fd: asdf.AsdfFile(tree).write_to(fd, all_array_storage="external") with get_read_fd() as fd, asdf.open(fd) as ff, pytest.raises(ValueError, match=r"Resolved to relative URL"): helpers.assert_tree_match(tree, ff.tree) @pytest.mark.remote_data() def test_exploded_http(tree, httpserver): path = os.path.join(httpserver.tmpdir, "test.asdf") def get_write_fd(): return generic_io.get_file(path, mode="w") def get_read_fd(): return generic_io.get_file(httpserver.url + "test.asdf") with _roundtrip(tree, get_write_fd, get_read_fd, write_options={"all_array_storage": "external"}) as ff: assert len(list(ff._blocks.blocks)) == 0 def test_exploded_stream_write(small_tree): # Writing an exploded file to an output stream should fail, since # we can't write "files" alongside it. ff = asdf.AsdfFile(small_tree) with pytest.raises(ValueError, match=r"Can't write external blocks, since URI of main file is unknown."): ff.write_to(io.BytesIO(), all_array_storage="external") def test_exploded_stream_read(tmp_path, small_tree): # Reading from an exploded input file should fail, but only once # the data block is accessed. This behavior is important so that # the tree can still be accessed even if the data is missing. path = os.path.join(str(tmp_path), "test.asdf") ff = asdf.AsdfFile(small_tree) ff.write_to(path, all_array_storage="external") with open(path, "rb") as fd: # This should work, so we can get the tree content x = generic_io.InputStream(fd, "r") # It's only when trying to access external data that an error occurs with asdf.open(x) as ff, pytest.raises(ValueError, match=r"Resolved to relative URL"): ff.tree["science_data"][:] def test_unicode_open(tmp_path, small_tree): path = os.path.join(str(tmp_path), "test.asdf") ff = asdf.AsdfFile(small_tree) ff.write_to(path) with ( open(path, encoding="utf-8") as fd, pytest.raises( ValueError, match=r"File-like object must be opened in binary mode.", ), asdf.open(fd), ): pass def test_open_stdout(): """Test ability to open/write stdout as an output stream""" with generic_io.get_file(sys.__stdout__, "w", close=True): pass def test_invalid_obj(tmp_path): with pytest.raises(ValueError, match=r"Can't handle .* as a file for mode 'r'"): generic_io.get_file(42) path = os.path.join(str(tmp_path), "test.asdf") with ( generic_io.get_file(path, "w") as fd, pytest.raises( ValueError, match=r"File is opened as 'w', but 'r' was requested", ), ): generic_io.get_file(fd, "r") with pytest.raises(ValueError, match=r"HTTP connections can not be opened for writing"): generic_io.get_file("http://www.google.com", "w") with pytest.raises(TypeError, match=r"io.StringIO objects are not supported. Use io.BytesIO instead."): generic_io.get_file(io.StringIO()) with open(path, "rb") as fd, pytest.raises(ValueError, match=r"File is opened as 'rb', but 'w' was requested"): generic_io.get_file(fd, "w") def test_nonseekable_file(tmp_path): base = io.FileIO class FileWrapper(base): def tell(self): raise OSError def seekable(self): return False def readable(self): return True def writable(self): return True with FileWrapper(os.path.join(str(tmp_path), "test.asdf"), "wb") as fd: assert isinstance(generic_io.get_file(fd, "w"), generic_io.OutputStream) with pytest.raises(ValueError, match=r"File .* could not be opened in 'rw' mode"): generic_io.get_file(fd, "rw") with FileWrapper(os.path.join(str(tmp_path), "test.asdf"), "rb") as fd: assert isinstance(generic_io.get_file(fd, "r"), generic_io.InputStream) def test_relative_uri(): assert generic_io.relative_uri("http://www.google.com", "file://local") == "file://local" @pytest.mark.parametrize("protocol", ["http", "asdf"]) def test_resolve_uri(protocol): """ Confirm that the patched urllib.parse is handling asdf:// URIs correctly. """ assert ( generic_io.resolve_uri(f"{protocol}://somewhere.org/some-schema", "#/definitions/foo") == f"{protocol}://somewhere.org/some-schema#/definitions/foo" ) assert ( generic_io.resolve_uri( f"{protocol}://somewhere.org/path/to/some-schema", "../../some/other/path/to/some-other-schema", ) == f"{protocol}://somewhere.org/some/other/path/to/some-other-schema" ) def test_arbitrary_file_object(): class Wrapper: def __init__(self, init): self._fd = init class Random: def seek(self, *args): return self._fd.seek(*args) def tell(self, *args): return self._fd.tell(*args) class Reader(Wrapper): def read(self, *args): return self._fd.read(*args) class RandomReader(Reader, Random): pass class Writer(Wrapper): def write(self, *args): return self._fd.write(*args) class RandomWriter(Writer, Random): pass class All(Reader, Writer, Random): pass buff = io.BytesIO() assert isinstance(generic_io.get_file(Reader(buff), "r"), generic_io.InputStream) assert isinstance(generic_io.get_file(Writer(buff), "w"), generic_io.OutputStream) assert isinstance(generic_io.get_file(RandomReader(buff), "r"), generic_io.MemoryIO) assert isinstance(generic_io.get_file(RandomWriter(buff), "w"), generic_io.MemoryIO) assert isinstance(generic_io.get_file(All(buff), "rw"), generic_io.MemoryIO) assert isinstance(generic_io.get_file(All(buff), "r"), generic_io.MemoryIO) assert isinstance(generic_io.get_file(All(buff), "w"), generic_io.MemoryIO) with pytest.raises(ValueError, match=r"Can't handle .* as a file for mode 'w'"): generic_io.get_file(Reader(buff), "w") with pytest.raises(ValueError, match=r"Can't handle .* as a file for mode 'r'"): generic_io.get_file(Writer(buff), "r") def test_check_bytes(tmp_path): with open(os.path.join(str(tmp_path), "test.asdf"), "w", encoding="utf-8") as fd: assert generic_io._check_bytes(fd, "r") is False assert generic_io._check_bytes(fd, "rw") is False assert generic_io._check_bytes(fd, "w") is False with open(os.path.join(str(tmp_path), "test.asdf"), "wb") as fd: assert generic_io._check_bytes(fd, "r") is True assert generic_io._check_bytes(fd, "rw") is True assert generic_io._check_bytes(fd, "w") is True def test_truncated_reader(): """ Tests several edge cases for _TruncatedReader.read() Includes regression test for https://github.com/asdf-format/asdf/pull/181 """ # TODO: Should probably break this up into multiple test cases fd = generic_io.RandomAccessFile(io.BytesIO(), "rw") content = b"a" * 100 + b"b" fd.write(content) fd.seek(0) # Simple cases where the delimiter is not found at all tr = generic_io._TruncatedReader(fd, b"x", 1) with pytest.raises(exceptions.DelimiterNotFoundError, match=r"b'x' not found"): tr.read() fd.seek(0) tr = generic_io._TruncatedReader(fd, b"x", 1) assert tr.read(100) == content[:100] assert tr.read(1) == content[100:] with pytest.raises(exceptions.DelimiterNotFoundError, match=r"b'x' not found"): tr.read() fd.seek(0) tr = generic_io._TruncatedReader(fd, b"x", 1, exception=False) assert tr.read() == content # No delimiter but with 'initial_content' init = b"abcd" fd.seek(0) tr = generic_io._TruncatedReader(fd, b"x", 1, initial_content=init, exception=False) assert tr.read(100) == (init + content)[:100] assert tr.read() == (init + content)[100:] fd.seek(0) tr = generic_io._TruncatedReader(fd, b"x", 1, initial_content=init, exception=False) assert tr.read() == init + content fd.seek(0) tr = generic_io._TruncatedReader(fd, b"x", 1, initial_content=init, exception=False) assert tr.read(2) == init[:2] assert tr.read() == init[2:] + content # Some tests of a single character delimiter # Add some trailing data after the delimiter fd.seek(0, 2) fd.write(b"ffff") # Delimiter not included in read fd.seek(0) tr = generic_io._TruncatedReader(fd, b"b", 1) assert tr.read(100) == content[:100] assert tr.read() == b"" fd.seek(0) tr = generic_io._TruncatedReader(fd, b"b", 1) assert tr.read() == content[:100] # Delimiter included fd.seek(0) tr = generic_io._TruncatedReader(fd, b"b", 1, include=True) assert tr.read() == content[:101] assert tr.read() == b"" fd.seek(0) tr = generic_io._TruncatedReader(fd, b"b", 1, include=True) assert tr.read(101) == content[:101] assert tr.read() == b"" fd.seek(0) tr = generic_io._TruncatedReader(fd, b"b", 1, include=True) assert tr.read(102) == content[:101] assert tr.read() == b"" fd.seek(0) tr = generic_io._TruncatedReader(fd, b"b", 1, include=True) assert tr.read(100) == content[:100] assert tr.read(1) == content[100:101] assert tr.read() == b"" # Longer delimiter with variable length content = b"a" * 100 + b"\n...\n" + b"ffffff" delimiter = rb"\r?\n\.\.\.((\r?\n)|$)" readahead = 7 fd = generic_io.RandomAccessFile(io.BytesIO(), "rw") fd.write(content) # Delimiter not included in read fd.seek(0) tr = generic_io._TruncatedReader(fd, delimiter, readahead) assert tr.read() == content[:100] assert tr.read() == b"" fd.seek(0) tr = generic_io._TruncatedReader(fd, delimiter, readahead) assert tr.read(100) == content[:100] assert tr.read() == b"" # (read just up to the delimiter) fd.seek(0) tr = generic_io._TruncatedReader(fd, delimiter, readahead) assert tr.read(99) == content[:99] assert tr.read() == content[99:100] assert tr.read() == b"" # (read partway into the delimiter) fd.seek(0) tr = generic_io._TruncatedReader(fd, delimiter, readahead) assert tr.read(99) == content[:99] assert tr.read(2) == content[99:100] assert tr.read() == b"" # (read well past the delimiter) fd.seek(0) tr = generic_io._TruncatedReader(fd, delimiter, readahead) assert tr.read(99) == content[:99] assert tr.read(50) == content[99:100] assert tr.read() == b"" # Same as the previous set of tests, but including the delimiter fd.seek(0) tr = generic_io._TruncatedReader(fd, delimiter, readahead, include=True) assert tr.read() == content[:105] assert tr.read() == b"" fd.seek(0) tr = generic_io._TruncatedReader(fd, delimiter, readahead, include=True) assert tr.read(105) == content[:105] assert tr.read() == b"" # (read just up to the delimiter) fd.seek(0) tr = generic_io._TruncatedReader(fd, delimiter, readahead, include=True) assert tr.read(99) == content[:99] assert tr.read() == content[99:105] assert tr.read() == b"" # (read partway into the delimiter) fd.seek(0) tr = generic_io._TruncatedReader(fd, delimiter, readahead, include=True) assert tr.read(99) == content[:99] assert tr.read(2) == content[99:101] assert tr.read() == content[101:105] assert tr.read() == b"" # (read well past the delimiter) fd.seek(0) tr = generic_io._TruncatedReader(fd, delimiter, readahead, include=True) assert tr.read(99) == content[:99] assert tr.read(50) == content[99:105] assert tr.read() == b"" # Same sequence of tests but with some 'initial_content' init = b"abcd" # Delimiter not included in read fd.seek(0) tr = generic_io._TruncatedReader(fd, delimiter, readahead, initial_content=init) assert tr.read() == (init + content[:100]) assert tr.read() == b"" fd.seek(0) tr = generic_io._TruncatedReader(fd, delimiter, readahead, initial_content=init) assert tr.read(100) == (init + content[:96]) assert tr.read() == content[96:100] assert tr.read() == b"" # (read just up to the delimiter) fd.seek(0) tr = generic_io._TruncatedReader(fd, delimiter, readahead, initial_content=init) assert tr.read(99) == (init + content[:95]) assert tr.read() == content[95:100] assert tr.read() == b"" # (read partway into the delimiter) fd.seek(0) tr = generic_io._TruncatedReader(fd, delimiter, readahead, initial_content=init) assert tr.read(99) == (init + content[:95]) assert tr.read(6) == content[95:100] assert tr.read() == b"" # (read well past the delimiter) fd.seek(0) tr = generic_io._TruncatedReader(fd, delimiter, readahead, initial_content=init) assert tr.read(99) == (init + content[:95]) assert tr.read(50) == content[95:100] assert tr.read() == b"" # Same as the previous set of tests, but including the delimiter fd.seek(0) tr = generic_io._TruncatedReader(fd, delimiter, readahead, include=True, initial_content=init) assert tr.read() == (init + content[:105]) assert tr.read() == b"" fd.seek(0) tr = generic_io._TruncatedReader(fd, delimiter, readahead, include=True, initial_content=init) assert tr.read(105) == (init + content[:101]) assert tr.read() == content[101:105] assert tr.read() == b"" # (read just up to the delimiter) fd.seek(0) tr = generic_io._TruncatedReader(fd, delimiter, readahead, include=True, initial_content=init) assert tr.read(103) == (init + content[:99]) assert tr.read() == content[99:105] assert tr.read() == b"" # (read partway into the delimiter) fd.seek(0) tr = generic_io._TruncatedReader(fd, delimiter, readahead, include=True, initial_content=init) assert tr.read(99) == (init + content[:95]) assert tr.read(6) == content[95:101] assert tr.read() == content[101:105] assert tr.read() == b"" # (read well past the delimiter) fd.seek(0) tr = generic_io._TruncatedReader(fd, delimiter, readahead, include=True, initial_content=init) assert tr.read(99) == (init + content[:95]) assert tr.read(50) == content[95:105] assert tr.read() == b"" def test_blocksize(tree, tmp_path): path = os.path.join(str(tmp_path), "test.asdf") def get_write_fd(): # cannot use context manager here because it closes the file return generic_io.get_file(open(path, "wb"), mode="w", close=True) def get_read_fd(): # Must open with mode=rw in order to get memmapped data # cannot use context manager here because it closes the file return generic_io.get_file(open(path, "r+b"), mode="rw", close=True) with config_context() as config: config.io_block_size = 1233 # make sure everything works with a strange blocksize with _roundtrip(tree, get_write_fd, get_read_fd) as ff: assert ff._fd.block_size == 1233 def test_io_subclasses(tmp_path): ref = b"0123456789" b = io.BytesIO(b"0123456789") b.seek(0) f = generic_io.get_file(b) r = f.read(len(ref)) assert r == ref, (r, ref) f.close() b = io.BytesIO(b"0123456789") b.seek(0) br = io.BufferedReader(io.BytesIO(ref)) f = generic_io.get_file(b) assert r == ref, (r, ref) f.close() b = io.BytesIO(b"") bw = io.BufferedWriter(b) f = generic_io.get_file(bw, mode="w") f.write(ref) b.seek(0) r = b.read(len(ref)) assert r == ref, (r, ref) f.close() b = io.BytesIO(b"") br = io.BufferedRandom(b) f = generic_io.get_file(br, mode="rw") f.write(ref) f.seek(0) r = f.read(len(ref)) assert r == ref, (r, ref) f.close() def test_fsspec(tmp_path): """ Issue #1146 reported errors when opening a fsspec 'file' This is a regression test for the fix in PR #1226 """ fsspec = pytest.importorskip("fsspec") ref = b"01234567890" fn = tmp_path / "test" with fsspec.open(fn, mode="bw+") as f: f.write(ref) f.seek(0) gf = generic_io.get_file(f) r = gf.read(len(ref)) assert r == ref, (r, ref) gf.seek(0) arr = gf.read_into_array(len(ref)) for ai, i in zip(arr, ref): assert ai == i @pytest.mark.remote_data() def test_fsspec_http(httpserver): """ Issue #1146 reported errors when opening a fsspec url (using the http filesystem) This is a regression test for the fix in PR #1228 """ fsspec = pytest.importorskip("fsspec") ref = b"01234567890" path = os.path.join(httpserver.tmpdir, "test") with open(path, "wb") as f: f.write(ref) fn = httpserver.url + "test" with fsspec.open(fn) as f: gf = generic_io.get_file(f) r = gf.read(len(ref)) assert r == ref, (r, ref) gf.seek(0) arr = gf.read_into_array(len(ref)) for ai, i in zip(arr, ref): assert ai == i @pytest.mark.skipif( sys.platform.startswith("win"), reason="Cannot test write file permissions on windows", ) @pytest.mark.parametrize("umask", range(512)) def test_write_file_permissions(tmp_path, umask): previous_umask = os.umask(umask) fn = tmp_path / "foo" with generic_io.get_file(fn, mode="w"): pass permissions = os.stat(fn)[stat.ST_MODE] & 0o777 os.umask(previous_umask) target_permissions = generic_io._FILE_PERMISSIONS_NO_EXECUTE & ~umask assert permissions == target_permissions ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_history.py0000644000175100001770000002072514653725311017405 0ustar00runnerdockerimport datetime import fractions import warnings import pytest import asdf from asdf.exceptions import AsdfWarning, ValidationError from asdf.extension import Converter, Extension, ExtensionProxy from asdf.tags.core import HistoryEntry from asdf.testing import helpers def test_history(): ff = asdf.AsdfFile() assert "history" not in ff.tree ff.add_history_entry( "This happened", {"name": "my_tool", "homepage": "http://nowhere.org", "author": "John Doe", "version": "2.0"}, ) assert len(ff.tree["history"]["entries"]) == 1 with pytest.raises(ValidationError, match=r".* is not valid under any of the given schemas"): ff.add_history_entry("That happened", {"author": "John Doe", "version": "2.0"}) assert len(ff.tree["history"]["entries"]) == 1 ff.add_history_entry("This other thing happened") assert len(ff.tree["history"]["entries"]) == 2 assert isinstance(ff.tree["history"]["entries"][0]["time"], datetime.datetime) def test_history_to_file(tmp_path): file_path = tmp_path / "history.asdf" with asdf.AsdfFile() as ff: ff.add_history_entry( "This happened", {"name": "my_tool", "homepage": "http://nowhere.org", "author": "John Doe", "version": "2.0"}, ) ff.write_to(file_path) with asdf.open(file_path) as ff: assert "entries" in ff.tree["history"] assert "extensions" in ff.tree["history"] assert len(ff.tree["history"]["entries"]) == 1 entry = ff.tree["history"]["entries"][0] assert entry["description"] == "This happened" assert entry["software"]["name"] == "my_tool" assert entry["software"]["version"] == "2.0" # Test the history entry retrieval API entries = ff.get_history_entries() assert len(entries) == 1 assert isinstance(entries, list) assert isinstance(entries[0], HistoryEntry) assert entries[0]["description"] == "This happened" assert entries[0]["software"]["name"] == "my_tool" def test_old_history(): """Make sure that old versions of the history format are still accepted""" yaml = """ history: - !core/history_entry-1.0.0 description: "Here's a test of old history entries" software: !core/software-1.0.0 name: foo version: 1.2.3 """ buff = helpers.yaml_to_asdf(yaml) with asdf.open(buff) as af: assert len(af.tree["history"]) == 1 # Test the history entry retrieval API entries = af.get_history_entries() assert len(entries) == 1 assert isinstance(entries, list) assert isinstance(entries[0], HistoryEntry) assert entries[0]["description"] == "Here's a test of old history entries" assert entries[0]["software"]["name"] == "foo" def test_get_history_entries(tmp_path): """ Test edge cases for the get_history_entries API. Other cases tested above """ file_path = tmp_path / "empty.asdf" with asdf.AsdfFile() as af: af.write_to(file_path) # Make sure this works when there is no history section at all with asdf.open(file_path) as af: assert len(af["history"]["extensions"]) > 0 assert len(af.get_history_entries()) == 0 def test_extension_metadata(tmp_path): file_path = tmp_path / "extension.asdf" ff = asdf.AsdfFile() ff.write_to(file_path) with asdf.open(file_path) as af: assert len(af.tree["history"]["extensions"]) == 1 metadata = af.tree["history"]["extensions"][0] assert metadata.extension_uri == "asdf://asdf-format.org/core/extensions/core-1.5.0" assert metadata.extension_class == "asdf.extension._manifest.ManifestExtension" assert metadata.software["name"] == "asdf" assert metadata.software["version"] == asdf.__version__ def test_missing_extension_warning(): yaml = """ history: extensions: - !core/extension_metadata-1.0.0 extension_class: foo.bar.FooBar software: !core/software-1.0.0 name: foo version: 1.2.3 """ buff = helpers.yaml_to_asdf(yaml) with pytest.warns(AsdfWarning, match=r"File was created with extension class 'foo.bar.FooBar'"), asdf.open(buff): pass def test_extension_version_warning(): uri = "asdf://somewhere.org/extensions/foo-1.0.0" package_name = "foo" file_package_version = "2.0.0" installed_package_version = "1.0.0" class FooExtension: extension_uri = uri yaml = f""" history: extensions: - !core/extension_metadata-1.0.0 extension_class: {FooExtension.__qualname__} extension_uri: {uri} software: !core/software-1.0.0 name: {package_name} version: {file_package_version} """ buff = helpers.yaml_to_asdf(yaml) with asdf.config_context() as cfg: cfg.add_extension(ExtensionProxy(FooExtension(), package_name, installed_package_version)) with ( pytest.warns( AsdfWarning, match=f"older package \\({package_name}=={installed_package_version}\\)", ), asdf.open(buff), ): pass buff.seek(0) # Make sure suppressing the warning works too with warnings.catch_warnings(): warnings.simplefilter("error") with asdf.open(buff, ignore_missing_extensions=True): pass def test_strict_extension_check(): yaml = """ history: extensions: - !core/extension_metadata-1.0.0 extension_class: foo.bar.FooBar software: !core/software-1.0.0 name: foo version: 1.2.3 """ buff = helpers.yaml_to_asdf(yaml) with ( pytest.raises( RuntimeError, match=r"File was created with extension class .*, which is not currently installed", ), asdf.open(buff, strict_extension_check=True), ): pass # Make sure to test for incompatibility with ignore_missing_extensions buff.seek(0) with ( pytest.raises( ValueError, match=r"'strict_extension_check' and 'ignore_missing_extensions' are incompatible options", ), asdf.open(buff, strict_extension_check=True, ignore_missing_extensions=True), ): pass def test_metadata_with_custom_extension(tmp_path): class FractionConverter(Converter): tags = ["asdf://nowhere.org/tags/fraction-1.0.0"] types = [fractions.Fraction] def to_yaml_tree(self, obj, tag, ctx): return [obj.numerator, obj.denominator] def from_yaml_tree(self, node, tag, ctx): return fractions.Fraction(node[0], node[1]) class FractionExtension(Extension): extension_uri = "asdf://nowhere.org/extensions/fraction-1.0.0" converters = [FractionConverter()] tags = FractionConverter.tags file_path = tmp_path / "custom_extension.asdf" with asdf.config_context() as config: config.add_extension(FractionExtension()) tree = {"fraction": fractions.Fraction(2, 3)} with asdf.AsdfFile(tree) as ff: ff.write_to(file_path) # We expect metadata about both the Builtin extension and the custom one with asdf.open(file_path) as af: assert len(af["history"]["extensions"]) == 2 with ( pytest.warns(AsdfWarning, match=r"was created with extension"), asdf.open( file_path, ignore_unrecognized_tag=True, ), ): pass file_path_2 = tmp_path / "no_extension.asdf" # If we use the extension but we don't serialize any types that require it, # no metadata about this extension should be added to the file with asdf.config_context() as config: config.add_extension(FractionExtension()) tree2 = {"x": list(range(10))} with asdf.AsdfFile(tree2) as ff: ff.write_to(file_path_2) with asdf.open(file_path_2) as af: assert len(af["history"]["extensions"]) == 1 with warnings.catch_warnings(): warnings.simplefilter("error") with asdf.open(file_path_2): pass file_path_3 = tmp_path / "custom_extension2.asdf" with asdf.config_context() as config: config.add_extension(FractionExtension()) # Make sure that this works even when constructing the tree on-the-fly with asdf.AsdfFile() as ff: ff.tree["fraction"] = fractions.Fraction(4, 5) ff.write_to(file_path_3) with asdf.open(file_path_3) as af: assert len(af["history"]["extensions"]) == 2 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_info.py0000644000175100001770000005564714653725311016652 0ustar00runnerdockerimport os import pathlib import re import tempfile import numpy as np import asdf from asdf.extension import ExtensionManager, ExtensionProxy, ManifestExtension from asdf.resource import DirectoryResourceMapping def test_info_module(capsys, tmp_path): tree = { "foo": 42, "bar": "hello", "baz": np.arange(20), "nested": {"woo": "hoo", "yee": "haw"}, "long_line": "a" * 100, } af = asdf.AsdfFile(tree) def _assert_correct_info(node_or_path): asdf.info(node_or_path) captured = capsys.readouterr() assert "foo" in captured.out assert "bar" in captured.out assert "baz" in captured.out _assert_correct_info(af) _assert_correct_info(af.tree) tmpfile = str(tmp_path / "written.asdf") af.write_to(tmpfile) af.close() _assert_correct_info(tmpfile) _assert_correct_info(pathlib.Path(tmpfile)) for i in range(1, 10): asdf.info(af, max_rows=i) lines = capsys.readouterr().out.strip().split("\n") assert len(lines) <= i asdf.info(af, max_cols=80) assert "(truncated)" in capsys.readouterr().out asdf.info(af, max_cols=None) captured = capsys.readouterr().out assert "(truncated)" not in captured assert "a" * 100 in captured asdf.info(af, show_values=True) assert "hello" in capsys.readouterr().out asdf.info(af, show_values=False) assert "hello" not in capsys.readouterr().out tree = {"foo": ["alpha", "bravo", "charlie", "delta", "eagle"]} af = asdf.AsdfFile(tree) asdf.info(af, max_rows=(None,)) assert "alpha" not in capsys.readouterr().out for i in range(1, 5): asdf.info(af, max_rows=(None, i)) captured = capsys.readouterr() for val in tree["foo"][0 : i - 1]: assert val in captured.out for val in tree["foo"][i - 1 :]: assert val not in captured.out class ObjectWithInfoSupport: def __init__(self, clown="", the_meaning=0, anyof=None, allof=None, oneof=None, **kw): self._tag = "asdf://somewhere.org/asdf/tags/foo-1.0.0" self.clown = clown self.the_meaning_of_life_the_universe_and_everything = the_meaning self.anyof = anyof self.allof = allof self.oneof = oneof self.patt = {} for key in kw: if re.search("^S_", key): if not isinstance(kw[key], str): msg = "S_ pattern object must be a string" raise ValueError(msg) self.patt[key] = kw[key] if re.search("^I_", key): if not isinstance(kw[key], int): msg = "I_ pattern object must be an int" raise ValueError(msg) self.patt[key] = kw[key] def __asdf_traverse__(self): returnval = { "the_meaning_of_life_the_universe_and_everything": self.the_meaning_of_life_the_universe_and_everything, "clown": self.clown, } if self.anyof is not None: returnval["anyof_attribute"] = self.anyof if self.allof is not None: returnval["allof_attribute"] = self.allof if self.oneof is not None: returnval["oneof_attribute"] = self.oneof for key in self.patt: returnval[key] = self.patt[key] return returnval class ObjectWithInfoSupport2: def __init__(self, attribute1="", attribute2=""): self._tag = "asdf://somewhere.org/asdf/tags/bar-1.0.0" self.attribute1 = attribute1 self.attribute2 = attribute2 def __asdf_traverse__(self): return { "attribute1": self.attribute1, "attribute2": self.attribute2, } class ObjectWithInfoSupport3: def __init__(self, attribute_one="", attribute_two=""): self._tag = "asdf://somewhere.org/asdf/tags/drink-1.0.0" self.attribute_one = attribute_one self.attribute_two = attribute_two def __asdf_traverse__(self): return { "attributeOne": self.attribute_one, "attributeTwo": self.attribute_two, } def manifest_extension(tmp_path): foo_manifest = """%YAML 1.1 --- id: asdf://somewhere.org/asdf/manifests/foo_manifest-1.0 extension_uri: asdf://somewhere.org/asdf/extensions/foo_manifest-1.0 asdf_standard_requirement: gte: 1.6.0 lt: 2.0.0 tags: - tag_uri: asdf://somewhere.org/asdf/tags/foo-1.0.0 schema_uri: asdf://somewhere.org/asdf/schemas/foo-1.0.0 title: Foo title description: Foo description - tag_uri: asdf://somewhere.org/asdf/tags/bar-1.0.0 schema_uri: asdf://somewhere.org/asdf/schemas/bar-1.0.0 title: Bar title description: Bar Description - tag_uri: asdf://somewhere.org/asdf/tags/drink-1.0.0 schema_uri: asdf://somewhere.org/asdf/schemas/drink-1.0.0 title: Drink title description: Drink Description ... """ foo_schema = """ %YAML 1.1 --- $schema: "asdf://stsci.edu/schemas/asdf/asdf-schema-1.0.0" id: "asdf://somewhere.org/asdf/schemas/foo-1.0.0" type: object title: object with info support title description: object with info support description properties: the_meaning_of_life_the_universe_and_everything: title: Some silly title description: Some silly description type: integer archive_catalog: datatype: int destination: [ScienceCommon.silly] clown: title: clown name description: clown description type: string archive_catalog: datatype: str destination: [ScienceCommon.clown] anyof_attribute: title: anyOf example attribute description: anyOf description anyOf: - type: string - type: number - type: object properties: value: title: nested object in anyof example description: nested object description type: integer comment: title: comment for property description: comment description type: string - tag: asdf://somewhere.org/tags/bar-1.0.0 oneof_attribute: title: oneOf example attribute description: oneOf description oneOf: - type: integer multipleOf: 5 - type: integer multipleOf: 3 allof_attribute: title: allOf example attribute description: allOf description allOf: - type: string - maxLength: 5 patternProperties: "^S_": title: string pattern property type: string "^I_": title: integer pattern property type: integer ... """ bar_schema = """ %YAML 1.1 --- $schema: "asdf://stsci.edu/schemas/asdf/asdf-schema-1.0.0" id: "asdf://somewhere.org/asdf/schemas/bar-1.0.0" type: object title: object with info support 2 title properties: attribute1: title: Attribute1 Title type: string archive_catalog: datatype: str destination: [ScienceCommon.attribute1] attribute2: title: Attribute2 Title type: string archive_catalog: datatype: str destination: [ScienceCommon.attribute2] ... """ drink_schema = """ %YAML 1.1 --- $schema: "asdf://stsci.edu/schemas/asdf/asdf-schema-1.0.0" id: "asdf://somewhere.org/asdf/schemas/drink-1.0.0" type: object title: object with info support 3 title description: object description properties: attributeOne: title: AttributeOne Title description: AttributeOne description type: string archive_catalog: datatype: str destination: [ScienceCommon.attributeOne] attributeTwo: title: AttributeTwo Title description: AttributeTwo description type: string archive_catalog: datatype: str destination: [ScienceCommon.attributeTwo] ... """ os.mkdir(tmp_path / "schemas") spath = tmp_path / "schemas" / "foo-1.0.0.yaml" with open(spath, "w") as fschema: fschema.write(foo_schema) spath = tmp_path / "schemas" / "bar-1.0.0.yaml" with open(spath, "w") as fschema: fschema.write(bar_schema) spath = tmp_path / "schemas" / "drink-1.0.0.yaml" with open(spath, "w") as fschema: fschema.write(drink_schema) os.mkdir(tmp_path / "manifests") mpath = str(tmp_path / "manifests" / "foo_manifest-1.0.yaml") with open(mpath, "w") as fmanifest: fmanifest.write(foo_manifest) config = asdf.get_config() config.add_resource_mapping( DirectoryResourceMapping(str(tmp_path / "manifests"), "asdf://somewhere.org/asdf/manifests/"), ) config.add_resource_mapping( DirectoryResourceMapping(str(tmp_path / "schemas"), "asdf://somewhere.org/asdf/schemas/"), ) class FooConverter: tags = ["asdf://somewhere.org/asdf/tags/foo-1.0.0"] types = [ObjectWithInfoSupport] def to_yaml_tree(self, obj, tag, ctx): node = { "the_meaning_of_life_the_universe_and_everything": obj.the_meaning_of_life_the_universe_and_everything, "clown": obj.clown, } if obj.anyof is not None: node["anyof_attribute"] = obj.anyof if obj.oneof is not None: node["oneof_attribute"] = obj.oneof if obj.allof is not None: node["allof_attribute"] = obj.allof return node def from_yaml_tree(self, node, tag, ctx): return ObjectWithInfoSupport( the_meaning=node["the_meaning_of_life_the_universe_and_everything"], clown=node["clown"], ) class BarConverter: tags = ["asdf://somewhere.org/asdf/tags/bar-1.0.0"] types = [ObjectWithInfoSupport2] def to_yaml_tree(self, obj, tag, ctx): return { "attribute1": obj.attribute1, "attribute2": obj.attribute2, } def from_yaml_tree(self, node, tag, ctx): return ObjectWithInfoSupport(attribute1="value1", attribute2="value2") class DrinkConverter: tags = ["asdf://somewhere.org/asdf/tags/drink-1.0.0"] types = [ObjectWithInfoSupport3] def to_yaml_tree(self, obj, tag, ctx): return { "attributeOne": obj.attribute_one, "attributeTwo": obj.attribute_two, } def from_yaml_tree(self, node, tag, ctx): return ObjectWithInfoSupport(attribute_one="value1", attribute_two="value2") converter1 = FooConverter() converter2 = BarConverter() converter3 = DrinkConverter() extension = ManifestExtension.from_uri( "asdf://somewhere.org/asdf/manifests/foo_manifest-1.0", converters=[converter1, converter2, converter3], ) config = asdf.get_config() proxy = ExtensionProxy(extension) config.add_extension(proxy) def create_tree(): return { "random": 3.14159, "object": ObjectWithInfoSupport( "Bozo", 42, anyof=ObjectWithInfoSupport2("VAL1", "VAL2"), oneof=20, allof="good", S_example="beep", I_example=1, ), "list_of_stuff": [ ObjectWithInfoSupport3("v1", "v2"), ObjectWithInfoSupport3("x1", "x2"), ], } def test_schema_info_support(tmp_path): manifest_extension(tmp_path) config = asdf.get_config() af = asdf.AsdfFile() af._extension_manager = ExtensionManager(config.extensions) af.tree = create_tree() assert af.schema_info("title", refresh_extension_manager=True) == { "list_of_stuff": [ { "attributeOne": { "title": ("AttributeOne Title", "v1"), }, "attributeTwo": { "title": ("AttributeTwo Title", "v2"), }, "title": ("object with info support 3 title", af.tree["list_of_stuff"][0]), }, { "attributeOne": { "title": ("AttributeOne Title", "x1"), }, "attributeTwo": { "title": ("AttributeTwo Title", "x2"), }, "title": ("object with info support 3 title", af.tree["list_of_stuff"][1]), }, ], "object": { "I_example": {"title": ("integer pattern property", 1)}, "S_example": {"title": ("string pattern property", "beep")}, "allof_attribute": {"title": ("allOf example attribute", "good")}, "anyof_attribute": { "attribute1": { "title": ("Attribute1 Title", "VAL1"), }, "attribute2": { "title": ("Attribute2 Title", "VAL2"), }, "title": ("object with info support 2 title", af.tree["object"].anyof), }, "clown": {"title": ("clown name", "Bozo")}, "oneof_attribute": {"title": ("oneOf example attribute", 20)}, "the_meaning_of_life_the_universe_and_everything": {"title": ("Some silly title", 42)}, "title": ("object with info support title", af.tree["object"]), }, } assert af.schema_info("archive_catalog", refresh_extension_manager=True) == { "list_of_stuff": [ { "attributeOne": { "archive_catalog": ({"datatype": "str", "destination": ["ScienceCommon.attributeOne"]}, "v1"), }, "attributeTwo": { "archive_catalog": ({"datatype": "str", "destination": ["ScienceCommon.attributeTwo"]}, "v2"), }, }, { "attributeOne": { "archive_catalog": ({"datatype": "str", "destination": ["ScienceCommon.attributeOne"]}, "x1"), }, "attributeTwo": { "archive_catalog": ({"datatype": "str", "destination": ["ScienceCommon.attributeTwo"]}, "x2"), }, }, ], "object": { "anyof_attribute": { "attribute1": { "archive_catalog": ({"datatype": "str", "destination": ["ScienceCommon.attribute1"]}, "VAL1"), }, "attribute2": { "archive_catalog": ({"datatype": "str", "destination": ["ScienceCommon.attribute2"]}, "VAL2"), }, }, "clown": { "archive_catalog": ({"datatype": "str", "destination": ["ScienceCommon.clown"]}, "Bozo"), }, "the_meaning_of_life_the_universe_and_everything": { "archive_catalog": ({"datatype": "int", "destination": ["ScienceCommon.silly"]}, 42), }, }, } assert af.schema_info("archive_catalog", preserve_list=False, refresh_extension_manager=True) == { "list_of_stuff": { 0: { "attributeOne": { "archive_catalog": ({"datatype": "str", "destination": ["ScienceCommon.attributeOne"]}, "v1"), }, "attributeTwo": { "archive_catalog": ({"datatype": "str", "destination": ["ScienceCommon.attributeTwo"]}, "v2"), }, }, 1: { "attributeOne": { "archive_catalog": ({"datatype": "str", "destination": ["ScienceCommon.attributeOne"]}, "x1"), }, "attributeTwo": { "archive_catalog": ({"datatype": "str", "destination": ["ScienceCommon.attributeTwo"]}, "x2"), }, }, }, "object": { "anyof_attribute": { "attribute1": { "archive_catalog": ({"datatype": "str", "destination": ["ScienceCommon.attribute1"]}, "VAL1"), }, "attribute2": { "archive_catalog": ({"datatype": "str", "destination": ["ScienceCommon.attribute2"]}, "VAL2"), }, }, "clown": { "archive_catalog": ({"datatype": "str", "destination": ["ScienceCommon.clown"]}, "Bozo"), }, "the_meaning_of_life_the_universe_and_everything": { "archive_catalog": ({"datatype": "int", "destination": ["ScienceCommon.silly"]}, 42), }, }, } assert af.schema_info("title", "list_of_stuff", refresh_extension_manager=True) == [ { "attributeOne": { "title": ("AttributeOne Title", "v1"), }, "attributeTwo": { "title": ("AttributeTwo Title", "v2"), }, "title": ("object with info support 3 title", af.tree["list_of_stuff"][0]), }, { "attributeOne": { "title": ("AttributeOne Title", "x1"), }, "attributeTwo": { "title": ("AttributeTwo Title", "x2"), }, "title": ("object with info support 3 title", af.tree["list_of_stuff"][1]), }, ] assert af.schema_info("title", "object", refresh_extension_manager=True) == { "I_example": {"title": ("integer pattern property", 1)}, "S_example": {"title": ("string pattern property", "beep")}, "allof_attribute": {"title": ("allOf example attribute", "good")}, "anyof_attribute": { "attribute1": { "title": ("Attribute1 Title", "VAL1"), }, "attribute2": { "title": ("Attribute2 Title", "VAL2"), }, "title": ("object with info support 2 title", af.tree["object"].anyof), }, "clown": {"title": ("clown name", "Bozo")}, "oneof_attribute": {"title": ("oneOf example attribute", 20)}, "the_meaning_of_life_the_universe_and_everything": {"title": ("Some silly title", 42)}, "title": ("object with info support title", af.tree["object"]), } assert af.schema_info("title", "object.anyof_attribute", refresh_extension_manager=True) == { "attribute1": { "title": ("Attribute1 Title", "VAL1"), }, "attribute2": { "title": ("Attribute2 Title", "VAL2"), }, "title": ("object with info support 2 title", af.tree["object"].anyof), } assert af.schema_info("title", "object.anyof_attribute.attribute2", refresh_extension_manager=True) == { "title": ("Attribute2 Title", "VAL2"), } # Test printing the schema_info assert ( af.schema_info("title", "object.anyof_attribute.attribute2", refresh_extension_manager=True).__repr__() == "{'title': Attribute2 Title}" ) assert af.schema_info("title", "object.anyof_attribute.attribute2.foo", refresh_extension_manager=True) is None assert af.schema_info(refresh_extension_manager=True) == { "list_of_stuff": [ { "attributeOne": {"description": ("AttributeOne description", "v1")}, "attributeTwo": {"description": ("AttributeTwo description", "v2")}, "description": ("object description", af.tree["list_of_stuff"][0]), }, { "attributeOne": {"description": ("AttributeOne description", "x1")}, "attributeTwo": {"description": ("AttributeTwo description", "x2")}, "description": ("object description", af.tree["list_of_stuff"][1]), }, ], "object": { "allof_attribute": { "description": ("allOf description", "good"), }, "clown": { "description": ("clown description", "Bozo"), }, "description": ("object with info support description", af.tree["object"]), "oneof_attribute": { "description": ("oneOf description", 20), }, "the_meaning_of_life_the_universe_and_everything": { "description": ("Some silly description", 42), }, }, } # Test using a search result search = af.search("clown") assert af.schema_info("description", search, refresh_extension_manager=True) == { "object": { "clown": { "description": ("clown description", "Bozo"), }, "description": ("object with info support description", af.tree["object"]), }, } def test_info_object_support(capsys, tmp_path): manifest_extension(tmp_path) config = asdf.get_config() af = asdf.AsdfFile() af._extension_manager = ExtensionManager(config.extensions) af.tree = create_tree() af.info(refresh_extension_manager=True) captured = capsys.readouterr() assert "the_meaning_of_life_the_universe_and_everything" in captured.out assert "clown" in captured.out assert "42" in captured.out assert "Bozo" in captured.out assert "clown name" in captured.out assert "silly" in captured.out assert "info support 2" in captured.out assert "Attribute2 Title" in captured.out assert "allOf example attribute" in captured.out assert "oneOf example attribute" in captured.out assert "string pattern property" in captured.out assert "integer pattern property" in captured.out assert "AttributeOne" in captured.out assert "AttributeTwo" in captured.out class RecursiveObjectWithInfoSupport: def __init__(self): self._tag = "asdf://somewhere.org/asdf/tags/bar-1.0.0" self.the_meaning = 42 self.clown = "Bozo" self.recursive = None def __asdf_traverse__(self): return {"the_meaning": self.the_meaning, "clown": self.clown, "recursive": self.recursive} def __str__(self): return "rec ref" def test_recursive_info_object_support(capsys, tmp_path): tempdir = pathlib.Path(tempfile.mkdtemp()) manifest_extension(tempdir) config = asdf.get_config() af = asdf.AsdfFile() af._extension_manager = ExtensionManager(config.extensions) recursive_obj = RecursiveObjectWithInfoSupport() recursive_obj.recursive = recursive_obj tree = {"random": 3.14159, "rtest": recursive_obj} af = asdf.AsdfFile(tree) af.info(refresh_extension_manager=True) captured = capsys.readouterr() assert "recursive reference" in captured.out def test_search(): tree = {"foo": 42, "bar": "hello", "baz": np.arange(20)} af = asdf.AsdfFile(tree) result = af.search("foo") assert result.node == 42 result = af.search(type_="ndarray") assert (result.node == tree["baz"]).all() result = af.search(value="hello") assert result.node == "hello" def test_info_str(capsys): class BadStr: def __str__(self): raise Exception() class NewlineStr: def __str__(self): return "a\nb" class CarriageReturnStr: def __str__(self): return "a\rb" class NiceStr: def __str__(self): return "nice" af = asdf.AsdfFile() af["a"] = BadStr() af["b"] = NewlineStr() af["c"] = CarriageReturnStr() af["d"] = NiceStr() af.info() captured = capsys.readouterr() assert "(BadStr)\n" in captured.out assert "(NewlineStr)\n" in captured.out assert "(CarriageReturnStr)\n" in captured.out assert "(NiceStr): nice\n" in captured.out ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_integration.py0000644000175100001770000001031414653725311020220 0ustar00runnerdocker""" Integration tests for the new plugin APIs. """ import pytest import asdf from asdf.extension import TagDefinition FOO_SCHEMA_URI = "asdf://somewhere.org/extensions/foo/schemas/foo-1.0" FOO_SCHEMA = f""" id: {FOO_SCHEMA_URI} type: object properties: value: type: string required: ["value"] """ class Foo: def __init__(self, value): self._value = value @property def value(self): return self._value class FooConverter: types = [Foo] tags = ["asdf://somewhere.org/extensions/foo/tags/foo-*"] def to_yaml_tree(self, obj, tag, ctx): return {"value": obj.value} def from_yaml_tree(self, obj, tag, ctx): return Foo(obj["value"]) class FooExtension: extension_uri = "asdf://somewhere.org/extensions/foo-1.0" converters = [FooConverter()] tags = [ TagDefinition( "asdf://somewhere.org/extensions/foo/tags/foo-1.0", schema_uris=FOO_SCHEMA_URI, ), ] def test_serialize_custom_type(tmp_path): with asdf.config_context() as config: config.add_resource_mapping({FOO_SCHEMA_URI: FOO_SCHEMA}) config.add_extension(FooExtension()) path = str(tmp_path / "test.asdf") af = asdf.AsdfFile() af["foo"] = Foo("bar") af.write_to(path) with asdf.open(path) as af2: assert af2["foo"].value == "bar" af["foo"] = Foo(12) with pytest.raises(asdf.ValidationError, match=r".* is not of type .*"): af.write_to(path) FOOFOO_SCHEMA_URI = "asdf://somewhere.org/extensions/foo/schemas/foo_foo-1.0" FOOFOO_SCHEMA = f""" id: {FOOFOO_SCHEMA_URI} type: object properties: value_value: type: string required: ["value_value"] """ class FooFoo(Foo): def __init__(self, value, value_value): super().__init__(value) self._value_value = value_value @property def value_value(self): return self._value_value class FooFooConverter: types = [FooFoo] tags = ["asdf://somewhere.org/extensions/foo/tags/foo_foo-*"] def to_yaml_tree(self, obj, tag, ctx): return {"value": obj.value, "value_value": obj.value_value} def from_yaml_tree(self, obj, tag, ctx): return FooFoo(obj["value"], obj["value_value"]) class FooFooExtension: extension_uri = "asdf://somewhere.org/extensions/foo_foo-1.0" converters = [FooFooConverter()] tags = [ TagDefinition( "asdf://somewhere.org/extensions/foo/tags/foo_foo-1.0", schema_uris=[FOO_SCHEMA_URI, FOOFOO_SCHEMA_URI], ), ] def test_serialize_with_multiple_schemas(tmp_path): with asdf.config_context() as config: config.add_resource_mapping({FOO_SCHEMA_URI: FOO_SCHEMA, FOOFOO_SCHEMA_URI: FOOFOO_SCHEMA}) config.add_extension(FooFooExtension()) path = str(tmp_path / "test.asdf") af = asdf.AsdfFile() af["foo_foo"] = FooFoo("bar", "bar_bar") af.write_to(path) with asdf.open(path) as af2: assert af2["foo_foo"].value == "bar" assert af2["foo_foo"].value_value == "bar_bar" af["foo_foo"] = FooFoo(12, "bar_bar") with pytest.raises(asdf.ValidationError, match=r".* is not of type .*"): af.write_to(path) af["foo_foo"] = FooFoo("bar", 34) with pytest.raises(asdf.ValidationError, match=r".* is not of type .*"): af.write_to(path) class FooFooConverterlessExtension: extension_uri = "asdf://somewhere.org/extensions/foo_foo-1.0" converters = [] tags = [ TagDefinition( "asdf://somewhere.org/extensions/foo/tags/foo_foo-1.0", schema_uris=[FOO_SCHEMA_URI, FOOFOO_SCHEMA_URI], ), ] def test_converterless_serialize_with_multiple_schemas(tmp_path): with asdf.config_context() as config: config.add_resource_mapping({FOO_SCHEMA_URI: FOO_SCHEMA, FOOFOO_SCHEMA_URI: FOOFOO_SCHEMA}) config.add_extension(FooFooConverterlessExtension()) path = str(tmp_path / "test.asdf") af = asdf.AsdfFile() af["foo_foo"] = "asdf://somewhere.org/extensions/foo/tags/foo_foo-1.0 {bar: bar_bar}" af.write_to(path) with asdf.open(path) as af2: assert af2["foo_foo"] == af["foo_foo"] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_lazy_nodes.py0000644000175100001770000002534614653725311020057 0ustar00runnerdockerimport collections import copy import gc import weakref import numpy as np import pytest import asdf from asdf.lazy_nodes import AsdfDictNode, AsdfListNode, AsdfOrderedDictNode, _resolve_af_ref, _to_lazy_node def test_slice_access(): af = asdf.AsdfFile() node = AsdfListNode([0, 1, 2], weakref.ref(af)) assert node[0] == 0 assert node[1] == 1 assert node[2] == 2 assert node[:2] == [0, 1] assert isinstance(node[:2], AsdfListNode) assert node[1:2] == [ 1, ] assert isinstance(node[1:2], AsdfListNode) assert node[:-1] == [0, 1] assert isinstance(node[:-1], AsdfListNode) assert node[::-1] == [2, 1, 0] assert isinstance(node[::-1], AsdfListNode) assert node[::2] == [0, 2] assert isinstance(node[::2], AsdfListNode) assert node[1::2] == [ 1, ] assert isinstance(node[1::2], AsdfListNode) def test_nested_node_conversion(): tree = { # lll = list in list in list, etc... "lll": [[[0]]], "lld": [[{"a": 0}]], "ldl": [{"a": [0]}], "ldd": [{"a": {"a": [0]}}], "dll": {"a": [[0]]}, "dld": {"a": [{"a": 0}]}, "ddl": {"a": {"a": [0]}}, "ddd": {"a": {"a": {"a": 0}}}, } af = asdf.AsdfFile() node = AsdfDictNode(tree, weakref.ref(af)) for key in node: obj = node[key] for code in key: if code == "l": assert isinstance(obj, AsdfListNode) obj = obj[0] else: assert isinstance(obj, AsdfDictNode) obj = obj["a"] def test_lazy_tree_ref(tmp_path): fn = tmp_path / "test.asdf" arr = np.arange(42) tree = { "a": arr, "b": {"c": arr}, "d": [ arr, ], } af = asdf.AsdfFile(tree) af.write_to(fn) with asdf.open(fn, lazy_tree=True) as af: assert isinstance(af.tree.data.tagged["a"], asdf.tagged.Tagged) assert isinstance(af.tree.data.tagged["b"]["c"], asdf.tagged.Tagged) assert isinstance(af.tree.data.tagged["d"][0], asdf.tagged.Tagged) assert isinstance(af["b"], AsdfDictNode) assert isinstance(af["d"], AsdfListNode) np.testing.assert_array_equal(af["a"], arr) assert af["a"] is af["b"]["c"] assert af["a"] is af["d"][0] def test_ordered_dict(): tree = {"a": collections.OrderedDict({"b": [1, 2, collections.OrderedDict({"c": 3})]})} af = asdf.AsdfFile() node = AsdfDictNode(tree, weakref.ref(af)) assert isinstance(node["a"], AsdfOrderedDictNode) assert isinstance(node["a"]["b"], AsdfListNode) assert isinstance(node["a"]["b"][2], AsdfOrderedDictNode) @pytest.mark.parametrize( "NodeClass,data,base", [ (AsdfDictNode, {"a": 1}, collections.abc.Mapping), (AsdfListNode, [1, 2], collections.abc.Sequence), (AsdfOrderedDictNode, {"a": 1}, collections.OrderedDict), ], ) def test_node_inheritance(NodeClass, data, base): node = NodeClass(data) assert isinstance(node, base) @pytest.mark.parametrize( "NodeClass,base", [ (AsdfDictNode, dict), (AsdfListNode, list), (AsdfOrderedDictNode, dict), ], ) def test_node_empty_init(NodeClass, base): node = NodeClass() assert type(node.tagged) == base @pytest.mark.parametrize( "node", [ AsdfDictNode({"a": 1, "b": 2}), AsdfListNode([1, 2, 3]), AsdfOrderedDictNode({"a": 1, "b": 2}), ], ) @pytest.mark.parametrize("copy_operation", [copy.copy, copy.deepcopy]) def test_copy(node, copy_operation): copied_node = copy_operation(node) assert isinstance(copied_node, type(node)) assert copied_node == node @pytest.mark.parametrize( "NodeClass,data", [ (AsdfDictNode, {1: "a", 2: "b"}), (AsdfListNode, [1, 2]), (AsdfOrderedDictNode, collections.OrderedDict({1: "a", 2: "b"})), ], ) def test_node_equality(NodeClass, data): node = NodeClass(data) assert node == node assert not node != node assert node == data data.pop(1) assert node != data def test_cache_clear_on_close(tmp_path): fn = tmp_path / "test.asdf" arr = np.arange(42) tree = {"a": arr} asdf.AsdfFile(tree).write_to(fn) with asdf.open(fn, lazy_tree=True) as af: # grab a weakref to this array, it should fail # to resolve after the with exits ref = weakref.ref(af["a"]) gc.collect() assert ref() is None def test_access_after_del(tmp_path): fn = tmp_path / "test.asdf" arr = np.arange(42) tree = {"a": {"b": arr}} asdf.AsdfFile(tree).write_to(fn) with asdf.open(fn, lazy_tree=True) as af: d = af["a"] del af with pytest.raises(asdf.exceptions.AsdfLazyReferenceError, match="Failed to resolve"): d["b"] def test_lazy_tree_option(tmp_path): fn = tmp_path / "test.asdf" arr = np.arange(42) tree = {"a": {"b": arr}} asdf.AsdfFile(tree).write_to(fn) with asdf.open(fn, lazy_tree=True) as af: assert isinstance(af["a"], AsdfDictNode) with asdf.open(fn, lazy_tree=False) as af: assert not isinstance(af["a"], AsdfDictNode) # test default (False) with asdf.open(fn) as af: assert not isinstance(af["a"], AsdfDictNode) with asdf.config_context() as cfg: cfg.lazy_tree = True with asdf.open(fn) as af: assert isinstance(af["a"], AsdfDictNode) cfg.lazy_tree = False with asdf.open(fn) as af: assert not isinstance(af["a"], AsdfDictNode) def test_resolve_af_ref(): with pytest.raises(asdf.exceptions.AsdfLazyReferenceError, match="Failed to resolve"): _resolve_af_ref(None) af = asdf.AsdfFile() af_ref = weakref.ref(af) assert _resolve_af_ref(af_ref) is af del af with pytest.raises(asdf.exceptions.AsdfLazyReferenceError, match="Failed to resolve"): _resolve_af_ref(af_ref) @pytest.mark.parametrize( "NodeClass,data", [ (AsdfDictNode, {1: "a", 2: "b"}), (AsdfListNode, [1, 2]), (AsdfOrderedDictNode, collections.OrderedDict({1: "a", 2: "b"})), (int, 1), # a non-wrappable class ], ) def test_to_lazy_node(NodeClass, data): node = _to_lazy_node(data, None) assert isinstance(node, NodeClass) def test_lazy_node_treeutil_support(): af = asdf.AsdfFile() af_ref = weakref.ref(af) tree = { "ordered_dict": AsdfOrderedDictNode({"a": 1}, af_ref), "dict": AsdfDictNode({"b": 2}, af_ref), "list": AsdfListNode([3, 4], af_ref), } seen_ints = set() def callback(node): if isinstance(node, int): seen_ints.add(node) asdf.treeutil.walk_and_modify(tree, callback) assert seen_ints == set([1, 2, 3, 4]) @pytest.fixture() def cache_test_tree_path(tmp_path): my_array = np.arange(3, dtype="uint8") my_list = [my_array, my_array] tree = {"a": my_list, "b": my_list} af = asdf.AsdfFile(tree) fn = tmp_path / "test.asdf" af.write_to(fn) return fn def test_cache_resolves_ref(cache_test_tree_path): with asdf.open(cache_test_tree_path, lazy_tree=True) as af: # since 'a' and 'b' were the same list when the file was saved # they should be the same list on read assert af["a"] is af["b"] # same for the arrays in the list assert af["a"][0] is af["a"][1] def test_cache_frees_deleted_object(cache_test_tree_path): with asdf.open(cache_test_tree_path, lazy_tree=True) as af: # load 1 of the 2 lists l0 = af["a"] # grab a weakref to the list (to not hold onto the list) lref = weakref.ref(l0) # now delete all references to the list (including the one in the tree) del l0, af.tree["a"] # trigger garbage collection gc.collect() # check that the weakref fails to resolve (so the list was freed) assert lref() is None # and we can no longer access 'a' with pytest.raises(KeyError, match="'a'"): af["a"] # but can get 'b' assert af["b"][0] is af["b"][1] def test_cache_non_weakref(): """ Test that an object that cannot weak reference can be cached """ tagged_node = {} obj = complex(1, 1) cache_item = asdf.lazy_nodes._TaggedObjectCacheItem(tagged_node, obj) del obj gc.collect() assert cache_item.custom_object == complex(1, 1) @pytest.fixture(params=[True, False, None], ids=["lazy", "not-lazy", "undefined"]) def lazy_test_class(request): class Foo: def __init__(self, data): self.data = data tag_uri = "asdf://somewhere.org/tags/foo-1.0.0" class FooConverter: tags = [tag_uri] types = [Foo] def to_yaml_tree(self, obj, tag, ctx): return obj.data def from_yaml_tree(self, node, tag, ctx): return Foo(node) lazy = request.param if lazy is not None: FooConverter.lazy = lazy # also set lazy on the class to pass it to the test Foo.lazy = lazy class FooExtension: extension_uri = "asdf://somewhere.org/extensions/minimum-1.0.0" converters = [FooConverter()] tags = [tag_uri] with asdf.config_context() as cfg: cfg.add_extension(FooExtension()) yield Foo def test_lazy_converter(tmp_path, lazy_test_class): obj = lazy_test_class({"a": 1}) fn = tmp_path / "test.asdf" af = asdf.AsdfFile({"obj": obj}) af.write_to(fn) with asdf.open(fn, lazy_tree=True) as af: if lazy_test_class.lazy is None or not lazy_test_class.lazy: target_class = dict else: target_class = AsdfDictNode assert isinstance(af["obj"].data, target_class) @pytest.fixture() def lazy_generator_class(request): class Foo: def __init__(self, data=None): self.data = data or {} tag_uri = "asdf://somewhere.org/tags/foo-1.0.0" class FooConverter: tags = [tag_uri] types = [Foo] lazy = True def to_yaml_tree(self, obj, tag, ctx): return obj.data def from_yaml_tree(self, node, tag, ctx): obj = Foo() yield obj obj.data = node class FooExtension: extension_uri = "asdf://somewhere.org/extensions/minimum-1.0.0" converters = [FooConverter()] tags = [tag_uri] with asdf.config_context() as cfg: cfg.add_extension(FooExtension()) yield Foo def test_lazy_generator_converter(tmp_path, lazy_generator_class): """ Test that a converter that returns a generator is not lazy (even if it's marked as lazy). """ obj = lazy_generator_class({"a": 1}) fn = tmp_path / "test.asdf" af = asdf.AsdfFile({"obj": obj}) af.write_to(fn) with asdf.open(fn, lazy_tree=True) as af: assert isinstance(af["obj"].data, dict) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_reference.py0000644000175100001770000002306014653725311017635 0ustar00runnerdockerimport io import os import numpy as np import pytest from numpy.testing import assert_array_equal import asdf from asdf import reference from asdf.exceptions import AsdfDeprecationWarning from asdf.tags.core import ndarray from ._helpers import assert_tree_match def test_external_reference(tmp_path): exttree = { "cool_stuff": {"a": np.array([0, 1, 2], float), "b": np.array([3, 4, 5], float)}, "list_of_stuff": ["foobar", 42, np.array([7, 8, 9], float)], } external_path = os.path.join(str(tmp_path), "external.asdf") ext = asdf.AsdfFile(exttree) # Since we're testing with small arrays, force all arrays to be stored # in internal blocks rather than letting some of them be automatically put # inline. ext.write_to(external_path, all_array_storage="internal") external_path = os.path.join(str(tmp_path), "external2.asdf") ff = asdf.AsdfFile(exttree) ff.write_to(external_path, all_array_storage="internal") tree = { # The special name "data" here must be an array. This is # included so that such validation can be ignored when we just # have a "$ref". "data": {"$ref": "external.asdf#/cool_stuff/a"}, "science_data": {"$ref": "external.asdf#/cool_stuff/a"}, "science_data2": {"$ref": "external2.asdf#/cool_stuff/a"}, "foobar": { "$ref": "external.asdf#/list_of_stuff/0", }, "answer": {"$ref": "external.asdf#/list_of_stuff/1"}, "array": { "$ref": "external.asdf#/list_of_stuff/2", }, "whole_thing": {"$ref": "external.asdf#"}, "myself": { "$ref": "#", }, "internal": {"$ref": "#science_data"}, } def do_asserts(ff): assert "unloaded" in repr(ff.tree["science_data"]) assert "unloaded" in str(ff.tree["science_data"]) assert len(ff._external_asdf_by_uri) == 0 assert_array_equal(ff.tree["science_data"], exttree["cool_stuff"]["a"]) assert len(ff._external_asdf_by_uri) == 1 with pytest.raises((ValueError, RuntimeError), match=r"assignment destination is read-only"): # Assignment destination is readonly ff.tree["science_data"][0] = 42 assert_array_equal(ff.tree["science_data2"], exttree["cool_stuff"]["a"]) assert len(ff._external_asdf_by_uri) == 2 assert ff.tree["foobar"]() == "foobar" assert ff.tree["answer"]() == 42 assert_array_equal(ff.tree["array"], exttree["list_of_stuff"][2]) assert_tree_match(ff.tree["whole_thing"](), exttree) assert_array_equal(ff.tree["whole_thing"]["cool_stuff"]["a"], exttree["cool_stuff"]["a"]) assert_array_equal(ff.tree["myself"]["science_data"], exttree["cool_stuff"]["a"]) # Make sure that referencing oneself doesn't make another call # to disk. assert len(ff._external_asdf_by_uri) == 2 assert_array_equal(ff.tree["internal"], exttree["cool_stuff"]["a"]) with asdf.AsdfFile({}, uri=(tmp_path / "main.asdf").as_uri()) as ff: # avoid passing tree to AsdfFile to avoid the deprecation warning, this can be updated # when automatic find_references on AsdfFile.__init__ is removed ff.tree = tree ff.find_references() do_asserts(ff) internal_path = os.path.join(str(tmp_path), "main.asdf") ff.write_to(internal_path) with pytest.warns(AsdfDeprecationWarning, match="find_references during open"), asdf.open(internal_path) as ff: # this can be updated to add a find_references call when the deprecated automatic # find_references on open is removed do_asserts(ff) with pytest.warns(AsdfDeprecationWarning, match="find_references during open"), asdf.open(internal_path) as ff: # this can be updated to add a find_references call when the deprecated automatic # find_references on open is removed assert len(ff._external_asdf_by_uri) == 0 ff.resolve_references() assert len(ff._external_asdf_by_uri) == 2 assert isinstance(ff.tree["data"], ndarray.NDArrayType) assert isinstance(ff.tree["science_data"], ndarray.NDArrayType) assert_array_equal(ff.tree["science_data"], exttree["cool_stuff"]["a"]) assert_array_equal(ff.tree["science_data2"], exttree["cool_stuff"]["a"]) assert ff.tree["foobar"] == "foobar" assert ff.tree["answer"] == 42 assert_array_equal(ff.tree["array"], exttree["list_of_stuff"][2]) assert_tree_match(ff.tree["whole_thing"], exttree) assert_array_equal(ff.tree["whole_thing"]["cool_stuff"]["a"], exttree["cool_stuff"]["a"]) assert_array_equal(ff.tree["myself"]["science_data"], exttree["cool_stuff"]["a"]) assert_array_equal(ff.tree["internal"], exttree["cool_stuff"]["a"]) @pytest.mark.remote_data() def test_external_reference_invalid(tmp_path): tree = {"foo": {"$ref": "fail.asdf"}} # avoid passing tree to AsdfFile to avoid the deprecation warning, this can be updated # when automatic find_references on AsdfFile.__init__ is removed ff = asdf.AsdfFile() ff.tree = tree ff.find_references() with pytest.raises(ValueError, match=r"Resolved to relative URL"): ff.resolve_references() # avoid passing tree to AsdfFile to avoid the deprecation warning, this can be updated # when automatic find_references on AsdfFile.__init__ is removed ff = asdf.AsdfFile({}, uri="http://httpstat.us/404") ff.tree = tree ff.find_references() msg = r"[HTTP Error 404: Not Found, HTTP Error 502: Bad Gateway]" # if httpstat.us is down 502 is returned. with pytest.raises(IOError, match=msg): ff.resolve_references() # avoid passing tree to AsdfFile to avoid the deprecation warning, this can be updated # when automatic find_references on AsdfFile.__init__ is removed ff = asdf.AsdfFile({}, uri=(tmp_path / "main.asdf").as_uri()) ff.tree = tree ff.find_references() with pytest.raises(IOError, match=r"No such file or directory: .*"): ff.resolve_references() def test_external_reference_invalid_fragment(tmp_path): exttree = {"list_of_stuff": ["foobar", 42, np.array([7, 8, 9], float)]} external_path = os.path.join(str(tmp_path), "external.asdf") ff = asdf.AsdfFile(exttree) ff.write_to(external_path) tree = {"foo": {"$ref": "external.asdf#/list_of_stuff/a"}} # avoid passing tree to AsdfFile to avoid the deprecation warning, this can be updated # when automatic find_references on AsdfFile.__init__ is removed with asdf.AsdfFile({}, uri=(tmp_path / "main.asdf").as_uri()) as ff: ff.tree = tree ff.find_references() with pytest.raises(ValueError, match=r"Unresolvable reference: .*"): ff.resolve_references() tree = {"foo": {"$ref": "external.asdf#/list_of_stuff/3"}} # avoid passing tree to AsdfFile to avoid the deprecation warning, this can be updated # when automatic find_references on AsdfFile.__init__ is removed with asdf.AsdfFile({}, uri=(tmp_path / "main.asdf").as_uri()) as ff: ff.tree = tree ff.find_references() with pytest.raises(ValueError, match=r"Unresolvable reference: .*"): ff.resolve_references() def test_make_reference(tmp_path): exttree = { # Include some ~ and / in the name to make sure that escaping # is working correctly "f~o~o/": {"a": np.array([0, 1, 2], float), "b": np.array([3, 4, 5], float)}, } external_path = os.path.join(str(tmp_path), "external.asdf") ext = asdf.AsdfFile(exttree) ext.write_to(external_path) with asdf.open(external_path) as ext: ff = asdf.AsdfFile() ff.tree["ref"] = ext.make_reference(["f~o~o/", "a"]) assert_array_equal(ff.tree["ref"], ext.tree["f~o~o/"]["a"]) ff.write_to(os.path.join(str(tmp_path), "source.asdf")) with ( pytest.warns(AsdfDeprecationWarning, match="find_references during open"), asdf.open(os.path.join(str(tmp_path), "source.asdf")) as ff, ): # this can be updated to add a find_references call when the deprecated automatic # find_references on open is removed assert ff.tree["ref"]._uri == "external.asdf#f~0o~0o~1/a" def test_internal_reference(tmp_path): testfile = tmp_path / "test.asdf" tree = {"foo": 2, "bar": {"$ref": "#"}} with pytest.warns(AsdfDeprecationWarning, match="find_references during AsdfFile.__init__"): ff = asdf.AsdfFile(tree) ff.find_references() assert isinstance(ff.tree["bar"], reference.Reference) ff.resolve_references() assert ff.tree["bar"]["foo"] == 2 tree = {"foo": 2} ff = asdf.AsdfFile(tree, uri=testfile.as_uri()) ff.tree["bar"] = ff.make_reference([]) buff = io.BytesIO() ff.write_to(buff) buff.seek(0) ff = asdf.AsdfFile() assert b"{$ref: ''}" in buff.getvalue() def test_implicit_internal_reference(tmp_path, with_lazy_tree): target = {"foo": "bar"} nested_in_dict = {"target": target} nested_in_list = [target] tree = {"target": target, "nested_in_dict": nested_in_dict, "nested_in_list": nested_in_list} assert tree["target"] is tree["nested_in_dict"]["target"] assert tree["target"] is tree["nested_in_list"][0] af = asdf.AsdfFile(tree) assert af["target"] is af["nested_in_dict"]["target"] assert af["target"] is af["nested_in_list"][0] output_path = os.path.join(str(tmp_path), "test.asdf") af.write_to(output_path) with asdf.open(output_path) as af: assert af["target"] is af["nested_in_dict"]["target"] assert af["target"] is af["nested_in_list"][0] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_reference_files.py0000644000175100001770000000460214653725311021020 0ustar00runnerdockerimport os import sys import pytest from asdf import open as asdf_open from asdf import versioning from ._helpers import assert_tree_match _REFFILE_PATH = os.path.join(os.path.dirname(__file__), "..", "..", "asdf-standard", "reference_files") def get_test_id(reference_file_path): """Helper function to return the informative part of a schema path""" path = os.path.normpath(str(reference_file_path)) return os.path.sep.join(path.split(os.path.sep)[-3:]) def collect_reference_files(): """Function used by pytest to collect ASDF reference files for testing.""" for version in versioning.supported_versions: version_dir = os.path.join(_REFFILE_PATH, str(version)) if os.path.exists(version_dir): for filename in os.listdir(version_dir): if filename.endswith(".asdf"): filepath = os.path.join(version_dir, filename) basename, _ = os.path.splitext(filepath) if os.path.exists(basename + ".yaml"): yield filepath def _compare_trees(name_without_ext, expect_warnings=False): asdf_path = name_without_ext + ".asdf" yaml_path = name_without_ext + ".yaml" with asdf_open(asdf_path) as af_handle: af_handle.resolve_references() with asdf_open(yaml_path) as ref: def _compare_func(): assert_tree_match(af_handle.tree, ref.tree, funcname="assert_allclose") if expect_warnings: # Make sure to only suppress warnings when they are expected. # However, there's still a chance of missing warnings that we # actually care about here. with pytest.warns(RuntimeWarning): _compare_func() else: _compare_func() @pytest.mark.parametrize("reference_file", collect_reference_files(), ids=get_test_id) def test_reference_file(reference_file): basename = os.path.basename(reference_file) name_without_ext, _ = os.path.splitext(reference_file) known_fail = False expect_warnings = "complex" in reference_file if sys.maxunicode <= 65535: known_fail = known_fail or (basename in ("unicode_spp.asdf")) try: _compare_trees(name_without_ext, expect_warnings=expect_warnings) except Exception: if known_fail: pytest.xfail() else: raise ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_resource.py0000644000175100001770000001004214653725311017522 0ustar00runnerdockerfrom collections.abc import Mapping import pytest from asdf.resource import JsonschemaResourceMapping, ResourceManager, ResourceMappingProxy def test_resource_manager(): mapping1 = { "http://somewhere.org/schemas/foo-1.0.0": b"foo", "http://somewhere.org/schemas/bar-1.0.0": b"bar", } mapping2 = { "http://somewhere.org/schemas/foo-1.0.0": b"duplicate foo", "http://somewhere.org/schemas/baz-1.0.0": b"baz", "http://somewhere.org/schemas/foz-1.0.0": "foz", } manager = ResourceManager([mapping1, mapping2]) assert isinstance(manager, Mapping) assert len(manager) == 4 assert set(manager) == { "http://somewhere.org/schemas/foo-1.0.0", "http://somewhere.org/schemas/bar-1.0.0", "http://somewhere.org/schemas/baz-1.0.0", "http://somewhere.org/schemas/foz-1.0.0", } assert "http://somewhere.org/schemas/foo-1.0.0" in manager assert manager["http://somewhere.org/schemas/foo-1.0.0"] == b"foo" assert "http://somewhere.org/schemas/bar-1.0.0" in manager assert manager["http://somewhere.org/schemas/bar-1.0.0"] == b"bar" assert "http://somewhere.org/schemas/baz-1.0.0" in manager assert manager["http://somewhere.org/schemas/baz-1.0.0"] == b"baz" assert "http://somewhere.org/schemas/foz-1.0.0" in manager assert manager["http://somewhere.org/schemas/foz-1.0.0"] == b"foz" with pytest.raises(KeyError, match=r"http://somewhere.org/schemas/missing-1.0.0"): manager["http://somewhere.org/schemas/missing-1.0.0"] # Confirm that the repr string is reasonable: assert "len: 4" in repr(manager) def test_jsonschema_resource_mapping(): mapping = JsonschemaResourceMapping() assert isinstance(mapping, Mapping) assert len(mapping) == 1 assert set(mapping) == {"http://json-schema.org/draft-04/schema"} assert "http://json-schema.org/draft-04/schema" in mapping assert b"http://json-schema.org/draft-04/schema" in mapping["http://json-schema.org/draft-04/schema"] assert repr(mapping) == "JsonschemaResourceMapping()" def test_proxy_is_mapping(): assert isinstance(ResourceMappingProxy({}), Mapping) def test_proxy_maybe_wrap(): mapping = { "http://somewhere.org/resources/foo": "foo", "http://somewhere.org/resources/bar": "bar", } proxy = ResourceMappingProxy.maybe_wrap(mapping) assert proxy.delegate is mapping assert ResourceMappingProxy.maybe_wrap(proxy) is proxy with pytest.raises(TypeError, match=r"Resource mapping must implement the Mapping interface"): ResourceMappingProxy.maybe_wrap([]) def test_proxy_properties(): mapping = { "http://somewhere.org/resources/foo": "foo", "http://somewhere.org/resources/bar": "bar", } proxy = ResourceMappingProxy(mapping, package_name="foo", package_version="1.2.3") assert len(proxy) == len(mapping) assert set(proxy.keys()) == set(mapping.keys()) for uri in mapping: assert proxy[uri] is mapping[uri] assert proxy.package_name == "foo" assert proxy.package_version == "1.2.3" assert proxy.class_name.endswith("dict") def test_proxy_hash_and_eq(): mapping = { "http://somewhere.org/resources/foo": "foo", "http://somewhere.org/resources/bar": "bar", } proxy1 = ResourceMappingProxy(mapping) proxy2 = ResourceMappingProxy(mapping, package_name="foo", package_version="1.2.3") assert proxy1 == proxy2 assert hash(proxy1) == hash(proxy2) assert proxy1 != mapping assert proxy2 != mapping def test_proxy_repr(): mapping = { "http://somewhere.org/resources/foo": "foo", "http://somewhere.org/resources/bar": "bar", } proxy = ResourceMappingProxy(mapping, package_name="foo", package_version="1.2.3") assert ".dict" in repr(proxy) assert "package: foo==1.2.3" in repr(proxy) assert "len: 2" in repr(proxy) empty_proxy = ResourceMappingProxy({}) assert ".dict" in repr(empty_proxy) assert "package: (none)" in repr(empty_proxy) assert "len: 0" in repr(empty_proxy) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_schema.py0000644000175100001770000011154714653725311017147 0ustar00runnerdockerimport contextlib import io from datetime import datetime import numpy as np import pytest from numpy.testing import assert_array_equal import asdf from asdf import config_context, constants, get_config, schema, tagged, util, yamlutil from asdf.exceptions import AsdfConversionWarning, AsdfDeprecationWarning, AsdfWarning, ValidationError from asdf.extension import TagDefinition from asdf.testing.helpers import yaml_to_asdf @contextlib.contextmanager def tag_reference_extension(): class TagReference: def __init__(self, name, things): self.name = name self.things = things tag_uri = "tag:nowhere.org:custom/tag_reference-1.0.0" schema_uri = "http://nowhere.org/schemas/custom/tag_reference-1.0.0" tag_def = asdf.extension.TagDefinition(tag_uri, schema_uris=schema_uri) class TagReferenceConverter: tags = [tag_uri] types = [TagReference] def to_yaml_tree(self, obj, tag, ctx): return {"name": obj.name, "things": obj.things} def from_yaml_tree(self, node, tag, ctx): return TagReference(node["name"], node["things"]) class TagReferenceExtension: tags = [tag_def] extension_uri = "asdf://nowhere.org/extensions/tag_reference-1.0.0" converters = [TagReferenceConverter()] tag_schema = f""" %YAML 1.1 --- $schema: "http://stsci.edu/schemas/yaml-schema/draft-01" id: {schema_uri} title: An example custom type for testing tag references type: object properties: name: type: string things: $ref: "http://stsci.edu/schemas/asdf/core/ndarray-1.0.0" required: [name, things] ... """ with config_context() as cfg: cfg.add_resource_mapping({schema_uri: tag_schema}) cfg.add_extension(TagReferenceExtension()) yield def test_tagging_scalars(): class Scalar: def __init__(self, value): self.value = value scalar_tag = "http://somewhere.org/tags/scalar-1.0.0" class ScalarConverter: tags = [scalar_tag] types = [Scalar] def to_yaml_tree(self, obj, tag, ctx): return obj.value def from_yaml_tree(self, node, tag, ctx): return Scalar(node) class ScalarExtension: tags = [scalar_tag] converters = [ScalarConverter()] extension_uri = "http://somewhere.org/extensions/scalar-1.0.0" yaml = f""" tagged: !<{scalar_tag}> m not_tagged: m """ with asdf.config_context() as cfg: cfg.add_extension(ScalarExtension()) buff = yaml_to_asdf(yaml) with asdf.open(buff) as ff: assert isinstance(ff.tree["tagged"], Scalar) assert not isinstance(ff.tree["not_tagged"], Scalar) assert isinstance(ff.tree["not_tagged"], str) assert ff.tree["tagged"].value == "m" assert ff.tree["not_tagged"] == "m" def test_read_json_schema(test_data_path): """Pytest to make sure reading JSON schemas succeeds. This was known to fail on Python 3.5 See issue #314 at https://github.com/asdf-format/asdf/issues/314 for more details. """ json_schema = test_data_path / "example_schema.json" schema_tree = schema.load_schema(json_schema, resolve_references=True) schema.check_schema(schema_tree) def test_load_schema(tmp_path): schema_def = """ %YAML 1.1 --- $schema: "http://stsci.edu/schemas/asdf/asdf-schema-1.0.0" id: "http://stsci.edu/schemas/asdf/nugatory/nugatory-1.0.0" tag: "tag:stsci.edu:asdf/nugatory/nugatory-1.0.0" type: object properties: foobar: $ref: "../core/ndarray-1.0.0" required: [foobar] ... """ schema_path = tmp_path / "nugatory.yaml" schema_path.write_bytes(schema_def.encode()) schema_tree = schema.load_schema(str(schema_path), resolve_references=True) schema.check_schema(schema_tree) def test_load_schema_with_full_tag(tmp_path): schema_def = """ %YAML 1.1 --- $schema: "http://stsci.edu/schemas/asdf/asdf-schema-1.0.0" id: "http://stsci.edu/schemas/asdf/nugatory/nugatory-1.0.0" tag: "tag:stsci.edu:asdf/nugatory/nugatory-1.0.0" type: object properties: foobar: $ref: "tag:stsci.edu:asdf/core/ndarray-1.0.0" required: [foobar] ... """ schema_path = tmp_path / "nugatory.yaml" schema_path.write_bytes(schema_def.encode()) with pytest.warns(AsdfDeprecationWarning, match="Resolving by tag is deprecated"): schema_tree = schema.load_schema(str(schema_path), resolve_references=True) schema.check_schema(schema_tree) def test_load_schema_with_file_url(tmp_path): schema_def = """ %YAML 1.1 %TAG !asdf! tag:stsci.edu:asdf/ --- $schema: "http://stsci.edu/schemas/asdf/asdf-schema-1.0.0" id: "http://stsci.edu/schemas/asdf/nugatory/nugatory-1.0.0" tag: "tag:stsci.edu:asdf/nugatory/nugatory-1.0.0" type: object properties: foobar: $ref: "http://stsci.edu/schemas/asdf/core/ndarray-1.0.0" required: [foobar] ... """ schema_path = tmp_path / "nugatory.yaml" schema_path.write_bytes(schema_def.encode()) schema_tree = schema.load_schema(str(schema_path), resolve_references=True) schema.check_schema(schema_tree) def test_load_schema_with_asdf_uri_scheme(): subschema_content = """%YAML 1.1 --- $schema: http://stsci.edu/schemas/asdf/asdf-schema-1.0.0 id: asdf://somewhere.org/schemas/bar bar: type: string ... """ content = """%YAML 1.1 --- $schema: http://stsci.edu/schemas/asdf/asdf-schema-1.0.0 id: asdf://somewhere.org/schemas/foo definitions: local_bar: type: string type: object properties: bar: $ref: asdf://somewhere.org/schemas/bar#/bar local_bar: $ref: '#/definitions/local_bar' ... """ with asdf.config_context() as config: config.add_resource_mapping({"asdf://somewhere.org/schemas/foo": content}) config.add_resource_mapping({"asdf://somewhere.org/schemas/bar": subschema_content}) schema_tree = schema.load_schema("asdf://somewhere.org/schemas/foo") instance = {"bar": "baz", "local_bar": "foz"} schema.validate(instance, schema=schema_tree) with pytest.raises(ValidationError, match=r".* is not of type .*"): schema.validate({"bar": 12}, schema=schema_tree) def test_load_schema_with_stsci_id(): """ This tests the following edge case: - schema references a subschema provided by the new extension API - subschema URI shares a prefix with one of the old-style extension resolvers - resolve_references is enabled If we're not careful, the old-style resolver will mangle the URI and we won't be able to retrieve the schema content. """ subschema_content = """%YAML 1.1 --- $schema: http://stsci.edu/schemas/asdf/asdf-schema-1.0.0 id: http://stsci.edu/schemas/bar bar: type: string ... """ content = """%YAML 1.1 --- $schema: http://stsci.edu/schemas/asdf/asdf-schema-1.0.0 id: http://stsci.edu/schemas/foo definitions: local_bar: type: string type: object properties: bar: $ref: http://stsci.edu/schemas/bar#/bar local_bar: $ref: '#/definitions/local_bar' ... """ with asdf.config_context() as config: config.add_resource_mapping({"http://stsci.edu/schemas/foo": content}) config.add_resource_mapping({"http://stsci.edu/schemas/bar": subschema_content}) schema_tree = schema.load_schema("http://stsci.edu/schemas/foo", resolve_references=True) instance = {"bar": "baz", "local_bar": "foz"} schema.validate(instance, schema=schema_tree) with pytest.raises(ValidationError, match=r".* is not of type .*"): schema.validate({"bar": 12}, schema=schema_tree) def test_schema_caching(): # Make sure that if we request the same URL, we get a different object # (despite the caching internal to load_schema). Changes to a schema # dict should not impact other uses of that schema. s1 = schema.load_schema("http://stsci.edu/schemas/asdf/core/asdf-1.0.0") s2 = schema.load_schema("http://stsci.edu/schemas/asdf/core/asdf-1.0.0") assert s1 is not s2 def test_load_schema_from_resource_mapping(): content = b""" id: http://somewhere.org/schemas/razmataz-1.0.0 type: object properties: foo: type: string bar: type: boolean """ get_config().add_resource_mapping({"http://somewhere.org/schemas/razmataz-1.0.0": content}) s = schema.load_schema("http://somewhere.org/schemas/razmataz-1.0.0") assert s["id"] == "http://somewhere.org/schemas/razmataz-1.0.0" def test_flow_style(): class CustomFlow: def __init__(self, a, b): self.a = a self.b = b tag_uri = "http://nowhere.org/tags/custom/custom_flow-1.0.0" class CustomFlowConverter: tags = [tag_uri] types = [CustomFlow] def to_yaml_tree(self, obj, tag, ctx): return {"a": obj.a, "b": obj.b} def from_yaml_tree(self, node, tag, ctx): return CustomFlow(node["a"], node["b"]) schema_uri = "http://nowhere.org/schemas/custom/custom_flow-1.0.0" tag_schema = f""" %YAML 1.1 --- $schema: "http://stsci.edu/schemas/yaml-schema/draft-01" id: "{schema_uri}" type: object properties: a: type: number b: type: number flowStyle: block """ tag_def = TagDefinition(tag_uri, schema_uris=[schema_uri]) class CustomFlowExtension: extension_uri = "http://nowhere.org/extensions/custom/custom_flow-1.0.0" tags = [tag_def] converters = [CustomFlowConverter()] with config_context() as cfg: cfg.add_extension(CustomFlowExtension()) cfg.add_resource_mapping({schema_uri: tag_schema}) buff = io.BytesIO() ff = asdf.AsdfFile({"custom_flow": CustomFlow(42, 43)}) ff.write_to(buff) assert b" a: 42\n b: 43" in buff.getvalue() def test_style(): class CustomStyle: def __init__(self, message): self.message = message tag_uri = "http://nowhere.org/tags/custom/custom_style-1.0.0" class CustomStyleConverter: tags = [tag_uri] types = [CustomStyle] def to_yaml_tree(self, obj, tag, ctx): return obj.message def from_yaml_tree(self, node, tag, ctx): return CustomStyle(node) schema_uri = "http://nowhere.org/schemas/custom/custom_style-1.0.0" tag_schema = f""" %YAML 1.1 --- $schema: "http://stsci.edu/schemas/yaml-schema/draft-01" id: "{schema_uri}" type: string style: literal """ tag_def = TagDefinition(tag_uri, schema_uris=[schema_uri]) class CustomStyleExtension: extension_uri = "http://nowhere.org/extensions/custom/custom_style-1.0.0" tags = [tag_def] converters = [CustomStyleConverter()] with config_context() as cfg: cfg.add_extension(CustomStyleExtension()) cfg.add_resource_mapping({schema_uri: tag_schema}) tree = {"custom_style": CustomStyle("short")} buff = io.BytesIO() ff = asdf.AsdfFile(tree) ff.write_to(buff) assert b"|-\n short\n" in buff.getvalue() def test_property_order(): tree = {"foo": np.ndarray([1, 2, 3])} buff = io.BytesIO() ff = asdf.AsdfFile(tree) ff.write_to(buff) ndarray_schema = schema.load_schema("http://stsci.edu/schemas/asdf/core/ndarray-1.0.0") property_order = ndarray_schema["anyOf"][1]["propertyOrder"] last_index = 0 for prop in property_order: index = buff.getvalue().find(prop.encode("utf-8") + b":") if index != -1: assert index > last_index last_index = index def test_invalid_nested(): tag_uri = "http://nowhere.org/tags/custom/custom-1.0.0" schema_uri = "http://nowhere.org/schemas/custom/custom-1.0.0" tag_schema = f""" %YAML 1.1 --- $schema: "http://stsci.edu/schemas/yaml-schema/draft-01" id: "{schema_uri}" type: integer default: 42 """ class Custom: def __init__(self, value): self.value = value class CustomConverter: tags = [tag_uri] types = [Custom] def to_yaml_tree(self, obj, tag, ctx): return obj.value def from_yaml_tree(self, node, tag, ctx): return Custom(node) tag_def = TagDefinition(tag_uri, schema_uris=[schema_uri]) class CustomExtension: extension_uri = "http://nowhere.org/extensions/custom/custom-1.0.0" tags = [tag_def] converters = [CustomConverter()] yaml = f""" custom: !<{tag_uri}> foo """ buff = yaml_to_asdf(yaml) # This should cause a warning but not an error because without explicitly # providing an extension, our custom type will not be recognized and will # simply be converted to a raw type. with pytest.warns(AsdfConversionWarning, match=tag_uri): with asdf.open(buff) as af: af["custom"] buff.seek(0) with config_context() as cfg: cfg.add_extension(CustomExtension()) cfg.add_resource_mapping({schema_uri: tag_schema}) with ( pytest.raises(ValidationError, match=r".* is not of type .*"), asdf.open( buff, ), ): pass # Make sure tags get validated inside of other tags that know # nothing about them. yaml = f""" array: !core/ndarray-1.0.0 data: [0, 1, 2] custom: !<{tag_uri}> foo """ buff = yaml_to_asdf(yaml) with ( pytest.raises(ValidationError, match=r".* is not of type .*"), asdf.open( buff, ), ): pass def test_invalid_schema(): s = {"type": "integer"} schema.check_schema(s) s = {"type": "foobar"} with pytest.raises(ValidationError, match=r".* is not valid under any of the given schemas.*"): schema.check_schema(s) def test_defaults(): s = {"type": "object", "properties": {"a": {"type": "integer", "default": 42}}} t = {} cls = schema._create_validator(schema.FILL_DEFAULTS) validator = cls(s) validator.validate(t) assert t["a"] == 42 cls = schema._create_validator(schema.REMOVE_DEFAULTS) validator = cls(s) validator.validate(t) assert t == {} def test_default_check_in_schema(): s = {"type": "object", "properties": {"a": {"type": "integer", "default": "foo"}}} with pytest.raises(ValidationError, match=r".* is not of type .*"): schema.check_schema(s) schema.check_schema(s, validate_default=False) def test_check_complex_default(): default_software = tagged.TaggedDict({"name": "asdf", "version": "2.7.0"}, "tag:stsci.edu/asdf/core/software-1.0.0") s = { "type": "object", "properties": { "a": {"type": "object", "tag": "tag:stsci.edu/asdf/core/software-1.0.0", "default": default_software}, }, } schema.check_schema(s) s["properties"]["a"]["tag"] = "tag:stsci.edu/asdf/core/ndarray-1.0.0" with pytest.raises(ValidationError, match=r"mismatched tags, wanted .*, got .*"): schema.check_schema(s) def test_fill_and_remove_defaults(): tag_uri = "http://nowhere.org/tags/custom/default-1.0.0" schema_uri = "http://nowhere.org/schemas/custom/default-1.0.0" tag_schema = f""" %YAML 1.1 --- $schema: "http://stsci.edu/schemas/yaml-schema/draft-01" id: "{schema_uri}" type: object properties: a: type: integer default: 42 b: type: object properties: c: type: integer default: 82 d: allOf: - type: object properties: e: type: integer default: 122 - type: object properties: f: type: integer default: 162 g: anyOf: - type: object properties: h: type: integer default: 202 - type: object properties: i: type: integer default: 242 j: oneOf: - type: object properties: k: type: integer default: 282 required: [k] additionalProperties: false - type: object properties: l: type: integer default: 322 required: [l] additionalProperties: false """ class Default(dict): pass class DefaultConverter: tags = [tag_uri] types = [Default] def to_yaml_tree(self, obj, tag, ctx): return dict(obj) def from_yaml_tree(self, node, tag, ctx): return Default(**node) tag_def = TagDefinition(tag_uri, schema_uris=[schema_uri]) class DefaultExtension: tags = [tag_def] converters = [DefaultConverter()] extension_uri = "http://nowhere.org/extensions/custom/default-1.0.0" with config_context() as cfg: cfg.add_extension(DefaultExtension()) cfg.add_resource_mapping({schema_uri: tag_schema}) yaml = """ custom: ! b: {} d: {} g: {} j: l: 362 """ buff = yaml_to_asdf(yaml) with asdf.open(buff) as ff: assert "a" in ff.tree["custom"] assert ff.tree["custom"]["a"] == 42 assert ff.tree["custom"]["b"]["c"] == 82 # allOf combiner should fill defaults from all subschemas: assert ff.tree["custom"]["d"]["e"] == 122 assert ff.tree["custom"]["d"]["f"] == 162 # anyOf combiners should be ignored: assert "h" not in ff.tree["custom"]["g"] assert "i" not in ff.tree["custom"]["g"] # oneOf combiners should be ignored: assert "k" not in ff.tree["custom"]["j"] assert ff.tree["custom"]["j"]["l"] == 362 buff.seek(0) with config_context() as config: config.legacy_fill_schema_defaults = False with asdf.open(buff) as ff: assert "a" not in ff.tree["custom"] assert "c" not in ff.tree["custom"]["b"] assert "e" not in ff.tree["custom"]["d"] assert "f" not in ff.tree["custom"]["d"] assert "h" not in ff.tree["custom"]["g"] assert "i" not in ff.tree["custom"]["g"] assert "k" not in ff.tree["custom"]["j"] assert ff.tree["custom"]["j"]["l"] == 362 ff.fill_defaults() assert "a" in ff.tree["custom"] assert ff.tree["custom"]["a"] == 42 assert "c" in ff.tree["custom"]["b"] assert ff.tree["custom"]["b"]["c"] == 82 assert ff.tree["custom"]["b"]["c"] == 82 assert ff.tree["custom"]["d"]["e"] == 122 assert ff.tree["custom"]["d"]["f"] == 162 assert "h" not in ff.tree["custom"]["g"] assert "i" not in ff.tree["custom"]["g"] assert "k" not in ff.tree["custom"]["j"] assert ff.tree["custom"]["j"]["l"] == 362 ff.remove_defaults() assert "a" not in ff.tree["custom"] assert "c" not in ff.tree["custom"]["b"] assert "e" not in ff.tree["custom"]["d"] assert "f" not in ff.tree["custom"]["d"] assert "h" not in ff.tree["custom"]["g"] assert "i" not in ff.tree["custom"]["g"] assert "k" not in ff.tree["custom"]["j"] assert ff.tree["custom"]["j"]["l"] == 362 def test_one_of(): """ Covers https://github.com/asdf-format/asdf/issues/809 """ class OneOf: def __init__(self, value): self.value = value tag_uri = "http://nowhere.org/custom/one_of-1.0.0" class OneOfConverter: tags = [tag_uri] types = [OneOf] def to_yaml_tree(self, obj, tag, ctx): return {"value": obj.value} def from_yaml_tree(self, node, tag, ctx): return OneOf(node["value"]) schema_uri = "http://nowhere.org/schemas/custom/one_of-1.0.0" tag_schema = f""" %YAML 1.1 --- $schema: "http://stsci.edu/schemas/yaml-schema/draft-01" id: "{schema_uri}" title: | oneOf test schema oneOf: - type: object properties: value: type: number required: [value] additionalProperties: false - type: object properties: value: type: string required: [value] additionalProperties: false ... """ tag_def = TagDefinition(tag_uri, schema_uris=[schema_uri]) class OneOfExtension: extension_uri = "http://nowhere.org/extensions/custom/one_of-1.0.0" tags = [tag_def] converters = [OneOfConverter()] yaml = f""" one_of: !<{tag_uri}> value: foo """ with config_context() as cfg: cfg.add_extension(OneOfExtension()) cfg.add_resource_mapping({schema_uri: tag_schema}) buff = yaml_to_asdf(yaml) with asdf.open(buff) as ff: assert ff["one_of"].value == "foo" def test_tag_reference_validation(): yaml = """ custom: ! name: "Something" things: !core/ndarray-1.0.0 data: [1, 2, 3] """ with tag_reference_extension(): buff = yaml_to_asdf(yaml) with asdf.open(buff) as ff: custom = ff.tree["custom"] assert custom.name == "Something" assert_array_equal(custom.things, [1, 2, 3]) def test_foreign_tag_reference_validation(): class ForeignTagReference: def __init__(self, a): self.a = a tag_uri = "tag:nowhere.org:custom/foreign_tag_reference-1.0.0" schema_uri = "http://nowhere.org/schemas/custom/foreign_tag_reference-1.0.0" tag_def = asdf.extension.TagDefinition(tag_uri, schema_uris=schema_uri) class ForeignTagReferenceConverter: tags = [tag_uri] types = [ForeignTagReference] def to_yaml_tree(self, obj, tag, ctx): return {"a": obj.a} def from_yaml_tree(self, node, tag, ctx): return ForeignTagReference(node["a"]) class ForeignTagReferenceExtension: tags = [tag_def] extension_uri = "asdf://nowhere.org/extensions/foreign_tag_reference-1.0.0" converters = [ForeignTagReferenceConverter()] tag_schema = f""" %YAML 1.1 --- $schema: "http://stsci.edu/schemas/yaml-schema/draft-01" id: {schema_uri} title: An example custom type for testing tag references type: object properties: a: # Test foreign tag reference using tag URI $ref: "http://nowhere.org/schemas/custom/tag_reference-1.0.0" required: [a] ... """ yaml = """ custom: ! a: ! name: "Something" things: !core/ndarray-1.0.0 data: [1, 2, 3] """ with tag_reference_extension(): cfg = asdf.get_config() cfg.add_resource_mapping({schema_uri: tag_schema}) cfg.add_extension(ForeignTagReferenceExtension()) buff = yaml_to_asdf(yaml) with asdf.open(buff) as ff: a = ff.tree["custom"].a assert a.name == "Something" assert_array_equal(a.things, [1, 2, 3]) def test_self_reference_resolution(test_data_path): s = schema.load_schema( test_data_path / "self_referencing-1.0.0.yaml", resolve_references=True, ) assert "$ref" not in repr(s) assert s["anyOf"][1] == s["anyOf"][0] def test_schema_resolved_via_entry_points(): """Test that entry points mappings to core schema works""" tag = "tag:stsci.edu:asdf/fits/fits-1.0.0" extension_manager = asdf.extension.get_cached_extension_manager(get_config().extensions) schema_uris = extension_manager.get_tag_definition(tag).schema_uris assert len(schema_uris) > 0 s = schema.load_schema(schema_uris[0]) assert s["id"] == schema_uris[0] @pytest.mark.parametrize("num", [constants.MAX_NUMBER + 1, constants.MIN_NUMBER - 1]) def test_max_min_literals(num): msg = r"Integer value .* is too large to safely represent as a literal in ASDF" af = asdf.AsdfFile() af["test_int"] = num with pytest.raises(ValidationError, match=msg): af.validate() af = asdf.AsdfFile() af["test_list"] = [num] with pytest.raises(ValidationError, match=msg): af.validate() af = asdf.AsdfFile() af[num] = "test_key" with pytest.raises(ValidationError, match=msg): af.validate() @pytest.mark.parametrize("num", [constants.MAX_NUMBER + 1, constants.MIN_NUMBER - 1]) @pytest.mark.parametrize("ttype", ["val", "list", "key"]) def test_max_min_literals_write(num, ttype, tmp_path): outfile = tmp_path / "test.asdf" af = asdf.AsdfFile() # Validation doesn't occur here, so no warning/error will be raised. if ttype == "val": af.tree["test_int"] = num elif ttype == "list": af.tree["test_int"] = [num] else: af.tree[num] = "test_key" # Validation will occur on write, though, so detect it. msg = r"Integer value .* is too large to safely represent as a literal in ASDF" with pytest.raises(ValidationError, match=msg): af.write_to(outfile) af.close() @pytest.mark.parametrize("value", [constants.MAX_NUMBER + 1, constants.MIN_NUMBER - 1]) def test_read_large_literal(value): yaml = f"integer: {value}" buff = yaml_to_asdf(yaml) with pytest.warns(AsdfWarning, match=r"Invalid integer literal value"), asdf.open(buff) as af: assert af["integer"] == value yaml = f"{value}: foo" buff = yaml_to_asdf(yaml) with pytest.warns(AsdfWarning, match=r"Invalid integer literal value"), asdf.open(buff) as af: assert af[value] == "foo" @pytest.mark.parametrize( ("version", "keys"), [ ("1.6.0", ["foo", 42, True]), ("1.5.0", ["foo", 42, True, 3.14159, datetime.now(), b"foo", None]), ], ) def test_mapping_supported_key_types(keys, version): for key in keys: af = asdf.AsdfFile({key: "value"}, version=version) buff = io.BytesIO() af.write_to(buff) buff.seek(0) with asdf.open(buff) as af: assert af[key] == "value" @pytest.mark.parametrize( ("version", "keys"), [ ("1.6.0", [3.14159, datetime.now(), b"foo", None, ("foo", "bar")]), ], ) def test_mapping_unsupported_key_types(keys, version): for key in keys: af = asdf.AsdfFile(version=version) af[key] = "value" with pytest.raises(ValidationError, match=r"Mapping key .* is not permitted"): af.validate() def test_nested_array(): s = { "type": "object", "properties": { "stuff": { "type": "array", "items": { "type": "array", "items": [ {"type": "integer"}, {"type": "string"}, {"type": "number"}, ], "minItems": 3, "maxItems": 3, }, }, }, } good = {"stuff": [[1, "hello", 2], [4, "world", 9.7]]} schema.validate(good, schema=s) bads = [ {"stuff": [[1, 2, 3]]}, {"stuff": [12, "dldl"]}, {"stuff": [[12, "dldl"]]}, {"stuff": [[1, "hello", 2], [4, 5]]}, {"stuff": [[1, "hello", 2], [4, 5, 6]]}, ] for b in bads: with pytest.raises(ValidationError, match=r"[.* is not of type .*, .* is too short]"): schema.validate(b, schema=s) def test_nested_array_yaml(tmp_path): schema_def = """ %YAML 1.1 --- type: object properties: stuff: type: array items: type: array items: - type: integer - type: string - type: number minItems: 3 maxItems: 3 ... """ schema_path = tmp_path / "nested.yaml" schema_path.write_bytes(schema_def.encode()) schema_tree = schema.load_schema(str(schema_path)) schema.check_schema(schema_tree) good = {"stuff": [[1, "hello", 2], [4, "world", 9.7]]} schema.validate(good, schema=schema_tree) bads = [ {"stuff": [[1, 2, 3]]}, {"stuff": [12, "dldl"]}, {"stuff": [[12, "dldl"]]}, {"stuff": [[1, "hello", 2], [4, 5]]}, {"stuff": [[1, "hello", 2], [4, 5, 6]]}, ] for b in bads: with pytest.raises(ValidationError, match=r"[.* is not of type .*, .* is too short]"): schema.validate(b, schema=schema_tree) def test_custom_validation_bad(tmp_path, test_data_path): custom_schema_path = test_data_path / "custom_schema.yaml" asdf_file = str(tmp_path / "out.asdf") # This tree does not conform to the custom schema tree = {"stuff": 42, "other_stuff": "hello"} # Creating file without custom schema should pass with asdf.AsdfFile(tree) as ff: ff.write_to(asdf_file) # Creating file using custom schema should fail af = asdf.AsdfFile(custom_schema=custom_schema_path) af._tree = asdf.tags.core.AsdfObject(tree) with pytest.raises(ValidationError, match=r".* is a required property"): af.validate() pass # Opening file without custom schema should pass with asdf.open(asdf_file): pass # Opening file with custom schema should fail with ( pytest.raises(ValidationError, match=r".* is a required property"), asdf.open( asdf_file, custom_schema=custom_schema_path, ), ): pass def test_custom_validation_good(tmp_path, test_data_path): custom_schema_path = test_data_path / "custom_schema.yaml" asdf_file = str(tmp_path / "out.asdf") # This tree conforms to the custom schema tree = {"foo": {"x": 42, "y": 10}, "bar": {"a": "hello", "b": "banjo"}} with asdf.AsdfFile(tree, custom_schema=custom_schema_path) as ff: ff.write_to(asdf_file) with asdf.open(asdf_file, custom_schema=custom_schema_path): pass def test_custom_validation_pathlib(tmp_path, test_data_path): """ Make sure custom schema paths can be pathlib.Path objects See https://github.com/asdf-format/asdf/issues/653 for discussion. """ custom_schema_path = test_data_path / "custom_schema.yaml" asdf_file = str(tmp_path / "out.asdf") # This tree conforms to the custom schema tree = {"foo": {"x": 42, "y": 10}, "bar": {"a": "hello", "b": "banjo"}} with asdf.AsdfFile(tree, custom_schema=custom_schema_path) as ff: ff.write_to(asdf_file) with asdf.open(asdf_file, custom_schema=custom_schema_path): pass def test_custom_validation_with_definitions_good(tmp_path, test_data_path): custom_schema_path = test_data_path / "custom_schema_definitions.yaml" asdf_file = str(tmp_path / "out.asdf") # This tree conforms to the custom schema tree = {"thing": {"biz": "hello", "baz": "world"}} with asdf.AsdfFile(tree, custom_schema=custom_schema_path) as ff: ff.write_to(asdf_file) with asdf.open(asdf_file, custom_schema=custom_schema_path): pass def test_custom_validation_with_definitions_bad(tmp_path, test_data_path): custom_schema_path = test_data_path / "custom_schema_definitions.yaml" asdf_file = str(tmp_path / "out.asdf") # This tree does NOT conform to the custom schema tree = {"forb": {"biz": "hello", "baz": "world"}} # Creating file without custom schema should pass with asdf.AsdfFile(tree) as ff: ff.write_to(asdf_file) # Creating file with custom schema should fail af = asdf.AsdfFile(custom_schema=custom_schema_path) af._tree = asdf.tags.core.AsdfObject(tree) with pytest.raises(ValidationError, match=r".* is a required property"): af.validate() # Opening file without custom schema should pass with asdf.open(asdf_file): pass # Opening file with custom schema should fail with ( pytest.raises(ValidationError, match=r".* is a required property"), asdf.open( asdf_file, custom_schema=custom_schema_path, ), ): pass def test_custom_validation_with_external_ref_good(tmp_path, test_data_path): custom_schema_path = test_data_path / "custom_schema_external_ref.yaml" asdf_file = str(tmp_path / "out.asdf") # This tree conforms to the custom schema tree = {"foo": asdf.tags.core.Software(name="Microsoft Windows", version="95")} with asdf.AsdfFile(tree, custom_schema=custom_schema_path) as ff: ff.write_to(asdf_file) with asdf.open(asdf_file, custom_schema=custom_schema_path): pass def test_custom_validation_with_external_ref_bad(tmp_path, test_data_path): custom_schema_path = test_data_path / "custom_schema_external_ref.yaml" asdf_file = str(tmp_path / "out.asdf") # This tree does not conform to the custom schema tree = {"foo": False} # Creating file without custom schema should pass with asdf.AsdfFile(tree) as ff: ff.write_to(asdf_file) # Creating file with custom schema should fail af = asdf.AsdfFile(custom_schema=custom_schema_path) af["foo"] = False with pytest.raises(ValidationError, match=r"False is not valid under any of the given schemas"): af.validate() # Opening file without custom schema should pass with asdf.open(asdf_file): pass # Opening file with custom schema should fail with ( pytest.raises(ValidationError, match=r"False is not valid under any of the given schemas"), asdf.open( asdf_file, custom_schema=custom_schema_path, ), ): pass @pytest.mark.parametrize( ("numpy_value", "valid_types"), [ (np.str_("foo"), {"string"}), (np.bytes_("foo"), set()), (np.float16(3.14), {"number"}), (np.float32(3.14159), {"number"}), (np.float64(3.14159), {"number"}), # Evidently float128 is not available on Windows: (getattr(np, "float128", np.float64)(3.14159), {"number"}), (np.int8(42), {"number", "integer"}), (np.int16(42), {"number", "integer"}), (np.int32(42), {"number", "integer"}), (np.longlong(42), {"number", "integer"}), (np.uint8(42), {"number", "integer"}), (np.uint16(42), {"number", "integer"}), (np.uint32(42), {"number", "integer"}), (np.uint64(42), {"number", "integer"}), (np.ulonglong(42), {"number", "integer"}), ], ) def test_numpy_scalar_type_validation(numpy_value, valid_types): def _assert_validation(jsonschema_type, expected_valid): validator = schema.get_validator(schema={"type": jsonschema_type}) try: validator.validate(numpy_value) except ValidationError: valid = False else: valid = True if valid is not expected_valid: description = "valid" if expected_valid else "invalid" msg = ( f"Expected numpy.{type(numpy_value).__name__} " f"to be {description} against jsonschema type " f"'{jsonschema_type}'" ) raise AssertionError(msg) for jsonschema_type in valid_types: _assert_validation(jsonschema_type, True) invalid_types = {"string", "number", "integer", "boolean", "null", "object"} - valid_types for jsonschema_type in invalid_types: _assert_validation(jsonschema_type, False) def test_validator_visit_repeat_nodes(): ctx = asdf.AsdfFile() node = asdf.tags.core.Software(name="Minesweeper") tree = yamlutil.custom_tree_to_tagged_tree({"node": node, "other_node": node, "nested": {"node": node}}, ctx) visited_nodes = [] def _test_validator(validator, value, instance, schema): visited_nodes.append(instance) validator = schema.get_validator(ctx=ctx, validators=util.HashableDict(type=_test_validator)) validator.validate(tree) assert len(visited_nodes) == 1 visited_nodes.clear() validator = schema.get_validator(validators=util.HashableDict(type=_test_validator), _visit_repeat_nodes=True) validator.validate(tree) assert len(visited_nodes) == 3 def test_tag_validator(): content = """%YAML 1.1 --- $schema: http://stsci.edu/schemas/asdf/asdf-schema-1.0.0 id: asdf://somewhere.org/schemas/foo tag: asdf://somewhere.org/tags/foo ... """ with asdf.config_context() as config: config.add_resource_mapping({"asdf://somewhere.org/schemas/foo": content}) schema_tree = schema.load_schema("asdf://somewhere.org/schemas/foo") instance = tagged.TaggedDict(tag="asdf://somewhere.org/tags/foo") schema.validate(instance, schema=schema_tree) with pytest.raises(ValidationError, match=r"mismatched tags, wanted .*, got .*"): schema.validate(tagged.TaggedDict(tag="asdf://somewhere.org/tags/bar"), schema=schema_tree) content = """%YAML 1.1 --- $schema: http://stsci.edu/schemas/asdf/asdf-schema-1.0.0 id: asdf://somewhere.org/schemas/bar tag: asdf://somewhere.org/tags/bar-* ... """ with asdf.config_context() as config: config.add_resource_mapping({"asdf://somewhere.org/schemas/bar": content}) schema_tree = schema.load_schema("asdf://somewhere.org/schemas/bar") instance = tagged.TaggedDict(tag="asdf://somewhere.org/tags/bar-2.5") schema.validate(instance, schema=schema_tree) with pytest.raises(ValidationError, match=r"mismatched tags, wanted .*, got .*"): schema.validate(tagged.TaggedDict(tag="asdf://somewhere.org/tags/foo-1.0"), schema=schema_tree) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_search.py0000644000175100001770000001261414653725311017147 0ustar00runnerdockerimport re import numpy as np import pytest from asdf import AsdfFile @pytest.fixture() def asdf_file(): tree = { "foo": 42, "nested": {"foo": 24, "foible": "whoops", "folicle": "yup", "moo": 24}, "bar": "hello", "list": [{"index": 0}, {"index": 1}, {"index": 2}], } return AsdfFile(tree) def test_no_arguments(asdf_file): result = asdf_file.search() assert len(result.paths) == 15 assert len(result.nodes) == 15 def test_repr(asdf_file): result = asdf_file.search() assert "foo" in repr(result) assert "nested" in repr(result) assert "bar" in repr(result) assert "list" in repr(result) def test_single_result(asdf_file): result = asdf_file.search("bar") assert len(result.paths) == 1 assert len(result.nodes) == 1 assert result.node == "hello" assert result.path == "root['bar']" result.replace("goodbye") assert asdf_file["bar"] == "goodbye" def test_multiple_results(asdf_file): result = asdf_file.search("foo") assert len(result.paths) == 2 assert len(result.nodes) == 2 assert 42 in result.nodes assert 24 in result.nodes assert "root['foo']" in result.paths assert "root['nested']['foo']" in result.paths with pytest.raises(RuntimeError, match=r"More than one result"): result.path with pytest.raises(RuntimeError, match=r"More than one result"): result.node result.replace(54) assert asdf_file["foo"] == 54 assert asdf_file["nested"]["foo"] == 54 def test_by_key(asdf_file): result = asdf_file.search("bar") assert result.node == "hello" result = asdf_file.search("^b.r$") assert result.node == "hello" result = asdf_file.search(re.compile("fo[oi]")) assert set(result.nodes) == {42, 24, "whoops"} result = asdf_file.search(0) assert result.node == {"index": 0} def test_by_type(asdf_file): result = asdf_file.search(type_=str) assert sorted(result.nodes) == sorted(["hello", "whoops", "yup"]) result = asdf_file.search(type_="int") assert result.nodes == [42, 24, 24, 0, 1, 2] result = asdf_file.search(type_="dict|list") assert len(result.nodes) == 5 result = asdf_file.search(type_=re.compile("^i.t$")) assert result.nodes == [42, 24, 24, 0, 1, 2] with pytest.raises(TypeError, match=r"type must be .*"): asdf_file.search(type_=4) def test_by_value(asdf_file): result = asdf_file.search(value=42) assert result.node == 42 def test_by_value_with_ndarray(): """ Check some edge cases when comparing integers and booleans to numpy arrays. """ tree = {"foo": np.arange(10)} af = AsdfFile(tree) result = af.search(value=True) assert len(result.nodes) == 0 result = af.search(value=42) assert len(result.nodes) == 0 def test_by_filter(asdf_file): with pytest.raises(ValueError, match=r"filter must accept 1 or 2 arguments"): asdf_file.search(filter_=lambda: True) result = asdf_file.search(filter_=lambda n: isinstance(n, int) and n % 2 == 0) assert result.nodes == [42, 24, 24, 0, 2] result = asdf_file.search(filter_=lambda n, k: k == "foo" and n > 30) assert result.node == 42 def test_multiple_conditions(asdf_file): result = asdf_file.search("foo", value=24) assert len(result.nodes) == 1 assert result.node == 24 result.replace(19) assert len(result.nodes) == 0 assert asdf_file["foo"] == 42 assert asdf_file["nested"]["foo"] == 19 def test_chaining(asdf_file): result = asdf_file.search("foo").search(value=24) assert len(result.nodes) == 1 assert result.node == 24 result.replace(19) assert len(result.nodes) == 0 assert asdf_file["foo"] == 42 assert asdf_file["nested"]["foo"] == 19 def test_index_operator(asdf_file): result = asdf_file.search()["nested"].search("foo") assert len(result.nodes) == 1 assert result.node == 24 with pytest.raises(TypeError, match=r"This node cannot be indexed"): asdf_file.search()["foo"][0] def test_format(asdf_file): result = asdf_file.search() original_len = len(repr(result).split("\n")) result = result.format(max_rows=original_len - 5) new_len = len(repr(result).split("\n")) assert new_len < original_len result = result.format(max_rows=(None, 5)) new_len = len(repr(result).split("\n")) assert new_len < original_len assert repr(result) == repr(result.format()) def test_no_results(asdf_file): result = asdf_file.search("missing") assert len(result.nodes) == 0 assert "No results found." in repr(result) assert result.node is None assert result.path is None # Testing no exceptions here: result.replace("foo") def test_recursive_tree(): tree = {"foo": {"bar": "baz"}} af = AsdfFile(tree) af.tree["foo"]["nested"] = af.tree["foo"] result = af.search() assert "(recursive reference)" in repr(result) result = af.search("bar") assert len(result.nodes) == 1 assert result.node == "baz" result.replace("zap") assert af["foo"]["bar"] == "zap" assert af["foo"]["nested"]["bar"] == "zap" def test_search(): tree = {"foo": 42, "bar": "hello", "baz": np.arange(20)} af = AsdfFile(tree) result = af.search("foo") assert result.node == 42 result = af.search(type_="ndarray") assert (result.node == tree["baz"]).all() result = af.search(value="hello") assert result.node == "hello" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_serialization_context.py0000644000175100001770000001555714653725311022334 0ustar00runnerdockerimport numpy as np import pytest import asdf from asdf import get_config from asdf.extension import ExtensionManager from asdf.extension._serialization_context import BlockAccess, SerializationContext def test_serialization_context(): extension_manager = ExtensionManager([]) context = SerializationContext("1.4.0", extension_manager, "file://test.asdf", None) assert context.version == "1.4.0" assert context.extension_manager is extension_manager assert context._extensions_used == set() extension = get_config().extensions[0] context._mark_extension_used(extension) assert context._extensions_used == {extension} context._mark_extension_used(extension) assert context._extensions_used == {extension} context._mark_extension_used(extension.delegate) assert context._extensions_used == {extension} assert context.url == context._url == "file://test.asdf" with pytest.raises(TypeError, match=r"Extension must implement the Extension interface"): context._mark_extension_used(object()) with pytest.raises(ValueError, match=r"ASDF Standard version .* is not supported by asdf==.*"): SerializationContext("0.5.4", extension_manager, None, None) def test_get_block_data_callback(tmp_path): fn = tmp_path / "test.asdf" # make a file with 2 blocks arr0 = np.arange(3, dtype="uint8") arr1 = np.arange(10, dtype="uint8") asdf.AsdfFile({"arr0": arr0, "arr1": arr1}).write_to(fn) with asdf.open(fn) as af: context = af._create_serialization_context() with pytest.raises(NotImplementedError, match="abstract"): context.get_block_data_callback(0) op_ctx = af._create_serialization_context(BlockAccess.READ) cb0 = op_ctx.get_block_data_callback(0) # getting the same callback should pass and return the same object assert op_ctx.get_block_data_callback(0) is cb0 # since we accessed block 0 we shouldn't be allowed to access block 1 with pytest.raises(OSError, match=r"Converters accessing >1.*"): op_ctx.get_block_data_callback(1) # unless we use a key key = op_ctx.generate_block_key() cb1 = op_ctx.get_block_data_callback(1, key) assert op_ctx.get_block_data_callback(1, key) is cb1 # we don't know the order of blocks, so find which block # was used for which array by looking at the size d0 = cb0() d1 = cb1() if d0.size == arr1.size: arr0, arr1 = arr1, arr0 np.testing.assert_array_equal(d0, arr0) np.testing.assert_array_equal(d1, arr1) for access in (BlockAccess.NONE, BlockAccess.WRITE): op_ctx = af._create_serialization_context(access) with pytest.raises(NotImplementedError, match="abstract"): op_ctx.get_block_data_callback(0) def test_find_available_block_index(): af = asdf.AsdfFile() context = af._create_serialization_context() def cb(): return np.arange(3, dtype="uint8") with pytest.raises(NotImplementedError, match="abstract"): context.find_available_block_index(cb) class Foo: pass op_ctx = af._create_serialization_context(BlockAccess.WRITE) op_ctx.assign_object(Foo()) assert op_ctx.find_available_block_index(cb) == 0 for access in (BlockAccess.NONE, BlockAccess.READ): op_ctx = af._create_serialization_context(access) with pytest.raises(NotImplementedError, match="abstract"): op_ctx.find_available_block_index(cb) def test_generate_block_key(): af = asdf.AsdfFile() context = af._create_serialization_context() with pytest.raises(NotImplementedError, match="abstract"): context.generate_block_key() class Foo: pass obj = Foo() op_ctx = af._create_serialization_context(BlockAccess.WRITE) op_ctx.assign_object(obj) key = op_ctx.generate_block_key() assert key._is_valid() assert key._matches_object(obj) obj = Foo() op_ctx = af._create_serialization_context(BlockAccess.READ) # because this test generates but does not assign a key # it should raise an exception with pytest.raises(OSError, match=r"Converter generated a key.*"): key = op_ctx.generate_block_key() # the key does not yet have an assigned object assert not key._is_valid() op_ctx.assign_blocks() @pytest.mark.parametrize("block_access", [None, *list(BlockAccess)]) def test_get_set_array_storage(block_access): af = asdf.AsdfFile() if block_access is None: context = af._create_serialization_context() else: context = af._create_serialization_context(block_access) arr = np.zeros(3) storage = "external" assert af.get_array_storage(arr) != storage context.set_array_storage(arr, storage) assert af.get_array_storage(arr) == storage assert context.get_array_storage(arr) == storage @pytest.mark.parametrize("block_access", [None, *list(BlockAccess)]) def test_get_set_array_compression(block_access): af = asdf.AsdfFile() if block_access is None: context = af._create_serialization_context() else: context = af._create_serialization_context(block_access) arr = np.zeros(3) compression = "bzp2" kwargs = {"a": 1} assert af.get_array_compression(arr) != compression assert af.get_array_compression_kwargs(arr) != kwargs context.set_array_compression(arr, compression, **kwargs) assert af.get_array_compression(arr) == compression assert af.get_array_compression_kwargs(arr) == kwargs assert context.get_array_compression(arr) == compression assert context.get_array_compression_kwargs(arr) == kwargs def test_get_set_array_save_base(): af = asdf.AsdfFile() context = af._create_serialization_context() arr = np.zeros(3) cfg = asdf.get_config() save_base = cfg.default_array_save_base assert af.get_array_save_base(arr) == save_base assert context.get_array_save_base(arr) == save_base save_base = not save_base context.set_array_save_base(arr, save_base) assert af.get_array_save_base(arr) == save_base assert context.get_array_save_base(arr) == save_base save_base = not save_base af.set_array_save_base(arr, save_base) assert af.get_array_save_base(arr) == save_base assert context.get_array_save_base(arr) == save_base af.set_array_save_base(arr, None) assert af.get_array_save_base(arr) is None assert context.get_array_save_base(arr) is None @pytest.mark.parametrize("value", [1, "true"]) def test_invalid_set_array_save_base(value): af = asdf.AsdfFile() context = af._create_serialization_context() arr = np.zeros(3) with pytest.raises(ValueError, match="save_base must be a bool or None"): af.set_array_save_base(arr, value) with pytest.raises(ValueError, match="save_base must be a bool or None"): context.set_array_save_base(arr, value) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_stream.py0000644000175100001770000001267114653725311017200 0ustar00runnerdockerimport io import os import numpy as np import pytest from numpy.testing import assert_array_equal import asdf from asdf import Stream, generic_io def test_stream(): buff = io.BytesIO() tree = {"stream": Stream([6, 2], np.float64)} ff = asdf.AsdfFile(tree) ff.write_to(buff) for i in range(100): buff.write(np.array([i] * 12, np.float64).tobytes()) buff.seek(0) with asdf.open(buff) as ff: assert len(ff._blocks.blocks) == 1 assert ff.tree["stream"].shape == (100, 6, 2) for i, row in enumerate(ff.tree["stream"]): assert np.all(row == i) def test_stream_write_nothing(): """ Test that if you write nothing, you get a zero-length array """ buff = io.BytesIO() tree = {"stream": Stream([6, 2], np.float64)} ff = asdf.AsdfFile(tree) ff.write_to(buff) buff.seek(0) with asdf.open(buff) as ff: assert len(ff._blocks.blocks) == 1 assert ff.tree["stream"].shape == (0, 6, 2) def test_stream_twice(): """ Test that if you write nothing, you get a zero-length array """ buff = io.BytesIO() tree = {"stream": Stream([6, 2], np.uint8), "stream2": Stream([12, 2], np.uint8)} ff = asdf.AsdfFile(tree) ff.write_to(buff) for i in range(100): buff.write(np.array([i] * 12, np.uint8).tobytes()) buff.seek(0) ff = asdf.open(buff) assert len(ff._blocks.blocks) == 1 assert ff.tree["stream"].shape == (100, 6, 2) assert ff.tree["stream2"].shape == (50, 12, 2) def test_stream_with_nonstream(): buff = io.BytesIO() tree = {"nonstream": np.array([1, 2, 3, 4], np.int64), "stream": Stream([6, 2], np.float64)} ff = asdf.AsdfFile(tree) # Since we're testing with small arrays, force this array to be stored in # an internal block rather than letting it be automatically put inline. ff.set_array_storage(ff["nonstream"], "internal") ff.write_to(buff) for i in range(100): buff.write(np.array([i] * 12, np.float64).tobytes()) buff.seek(0) with asdf.open(buff) as ff: assert len(ff._blocks.blocks) == 2 assert_array_equal(ff.tree["nonstream"], np.array([1, 2, 3, 4], np.int64)) assert ff.tree["stream"].shape == (100, 6, 2) for i, row in enumerate(ff.tree["stream"]): assert np.all(row == i) def test_stream_real_file(tmp_path): path = os.path.join(str(tmp_path), "test.asdf") tree = {"nonstream": np.array([1, 2, 3, 4], np.int64), "stream": Stream([6, 2], np.float64)} with open(path, "wb") as fd: ff = asdf.AsdfFile(tree) # Since we're testing with small arrays, force this array to be stored # in an internal block rather than letting it be automatically put # inline. ff.set_array_storage(ff["nonstream"], "internal") ff.write_to(fd) for i in range(100): fd.write(np.array([i] * 12, np.float64).tobytes()) with asdf.open(path) as ff: assert len(ff._blocks.blocks) == 2 assert_array_equal(ff.tree["nonstream"], np.array([1, 2, 3, 4], np.int64)) assert ff.tree["stream"].shape == (100, 6, 2) for i, row in enumerate(ff.tree["stream"]): assert np.all(row == i) def test_stream_to_stream(): tree = {"nonstream": np.array([1, 2, 3, 4], np.int64), "stream": Stream([6, 2], np.float64)} buff = io.BytesIO() fd = generic_io.OutputStream(buff) ff = asdf.AsdfFile(tree) ff.write_to(fd) for i in range(100): fd.write(np.array([i] * 12, np.float64).tobytes()) buff.seek(0) with asdf.open(generic_io.InputStream(buff, "r")) as ff: assert len(ff._blocks.blocks) == 2 assert_array_equal(ff.tree["nonstream"], np.array([1, 2, 3, 4], np.int64)) assert ff.tree["stream"].shape == (100, 6, 2) for i, row in enumerate(ff.tree["stream"]): assert np.all(row == i) def test_array_to_stream(tmp_path): tree = { "stream": np.array([1, 2, 3, 4], np.int64), } buff = io.BytesIO() ff = asdf.AsdfFile(tree) ff.set_array_storage(tree["stream"], "streamed") ff.write_to(buff) buff.write(np.array([5, 6, 7, 8], np.int64).tobytes()) buff.seek(0) ff = asdf.open(generic_io.InputStream(buff)) assert_array_equal(ff.tree["stream"], [1, 2, 3, 4, 5, 6, 7, 8]) buff.seek(0) ff2 = asdf.AsdfFile(ff) ff2.set_array_storage(ff2["stream"], "streamed") ff2.write_to(buff) assert b"shape: ['*']" in buff.getvalue() with open(os.path.join(str(tmp_path), "test.asdf"), "wb") as fd: ff = asdf.AsdfFile(tree) ff.set_array_storage(tree["stream"], "streamed") ff.write_to(fd) fd.write(np.array([5, 6, 7, 8], np.int64).tobytes()) with asdf.open(os.path.join(str(tmp_path), "test.asdf")) as ff: assert_array_equal(ff.tree["stream"], [1, 2, 3, 4, 5, 6, 7, 8]) ff2 = asdf.AsdfFile(ff) ff2.write_to(buff) assert b"shape: ['*']" in buff.getvalue() def test_too_many_streams(): tree = {"stream1": np.array([1, 2, 3, 4], np.int64), "stream2": np.array([1, 2, 3, 4], np.int64)} ff = asdf.AsdfFile(tree) ff.set_array_storage(tree["stream1"], "streamed") with pytest.raises(ValueError, match=r"Can not add second streaming block"): ff.set_array_storage(tree["stream2"], "streamed") def test_stream_repr_and_str(): tree = {"stream": Stream([16], np.int64)} ff = asdf.AsdfFile(tree) repr(ff.tree["stream"]) str(ff.tree["stream"]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_tagged.py0000644000175100001770000001264214653725311017136 0ustar00runnerdockerfrom copy import copy, deepcopy import pytest import asdf from asdf.tagged import TaggedDict, TaggedList, TaggedString def test_tagged_list_deepcopy(): original = TaggedList([0, 1, 2, ["foo"]], "tag:nowhere.org:custom/foo-1.0.0") result = deepcopy(original) assert result == original assert result.data == original.data assert result._tag == original._tag original.append(4) assert len(result) == 4 original[3].append("bar") assert len(result[3]) == 1 def test_tagged_list_copy(): original = TaggedList([0, 1, 2, ["foo"]], "tag:nowhere.org:custom/foo-1.0.0") result = copy(original) assert result == original assert result.data == original.data assert result._tag == original._tag original.append(4) assert len(result) == 4 original[3].append("bar") assert len(result[3]) == 2 def test_tagged_list_isinstance(): value = TaggedList([0, 1, 2, ["foo"]], "tag:nowhere.org:custom/foo-1.0.0") assert isinstance(value, list) def test_tagged_list_base(): value = TaggedList([0, 1, 2, ["foo"]], "tag:nowhere.org:custom/foo-1.0.0") assert not (value == value.base) # base is not a tagged list assert value.data == value.base # but the data is assert isinstance(value.base, list) assert not isinstance(value.base, TaggedList) assert value.base.__class__ == list def test_tagged_dict_deepcopy(): original = TaggedDict({"a": 0, "b": 1, "c": 2, "nested": {"d": 3}}, "tag:nowhere.org:custom/foo-1.0.0") result = deepcopy(original) assert result == original assert result.data == original.data assert result._tag == original._tag original["e"] = 4 assert len(result) == 4 original["nested"]["f"] = 5 assert len(result["nested"]) == 1 def test_tagged_dict_copy(): original = TaggedDict({"a": 0, "b": 1, "c": 2, "nested": {"d": 3}}, "tag:nowhere.org:custom/foo-1.0.0") result = copy(original) assert result == original assert result.data == original.data assert result._tag == original._tag original["e"] = 4 assert len(result) == 4 original["nested"]["f"] = 5 assert len(result["nested"]) == 2 def test_tagged_dict_isinstance(): value = TaggedDict({"a": 0, "b": 1, "c": 2, "nested": {"d": 3}}, "tag:nowhere.org:custom/foo-1.0.0") assert isinstance(value, dict) def test_tagged_dict_base(): value = TaggedDict({"a": 0, "b": 1, "c": 2, "nested": {"d": 3}}, "tag:nowhere.org:custom/foo-1.0.0") assert not (value == value.base) # base is not a tagged dict assert value.data == value.base # but the data is assert isinstance(value.base, dict) assert not isinstance(value.base, TaggedDict) assert value.base.__class__ == dict def test_tagged_string_deepcopy(): original = TaggedString("You're it!") original._tag = "tag:nowhere.org:custom/foo-1.0.0" result = deepcopy(original) assert result == original assert result._tag == original._tag def test_tagged_string_copy(): original = TaggedString("You're it!") original._tag = "tag:nowhere.org:custom/foo-1.0.0" result = copy(original) assert result == original assert result._tag == original._tag def test_tagged_string_isinstance(): value = TaggedString("You're it!") assert isinstance(value, str) def test_tagged_string_base(): value = TaggedString("You're it!") value._tag = "tag:nowhere.org:custom/foo-1.0.0" assert not (value == value.base) # base is not a tagged dict assert value.data == value.base # but the data is assert isinstance(value.base, str) assert not isinstance(value.base, TaggedString) assert value.base.__class__ == str ASDF_UNIT_TAG = "stsci.edu:asdf/unit/unit-1.0.0" TAGGED_UNIT_URI = "asdf://stsci.edu/schemas/tagged_unit-1.0.0" TAGGED_UNIT_SCHEMA = f""" %YAML 1.1 --- $schema: http://stsci.edu/schemas/yaml-schema/draft-01 id: {TAGGED_UNIT_URI} properties: unit: tag: {ASDF_UNIT_TAG} enum: [m, kg] ... """ def create_units(): meter = TaggedString("m") meter._tag = ASDF_UNIT_TAG kilogram = TaggedString("kg") kilogram._tag = ASDF_UNIT_TAG return meter, kilogram @pytest.mark.parametrize("unit", create_units()) def test_check_valid_str_enum(unit): """ Regression test for issue #1254 https://github.com/asdf-format/asdf/issues/1256 This ensures that tagged strings can be properly validated against ``enum`` lists. """ with asdf.config_context() as conf: conf.add_resource_mapping({TAGGED_UNIT_URI: TAGGED_UNIT_SCHEMA}) schema = asdf.schema.load_schema(TAGGED_UNIT_URI) # This should not raise an exception (check_schema will raise error) asdf.schema.check_schema(schema) # This should not raise exception (validate will raise error) asdf.schema.validate({"unit": unit}, schema=schema) def test_check_invalid_str_enum(): """ Ensure that a tagged string that is not in the ``enum`` list is properly handled. """ with asdf.config_context() as conf: conf.add_resource_mapping({TAGGED_UNIT_URI: TAGGED_UNIT_SCHEMA}) schema = asdf.schema.load_schema(TAGGED_UNIT_URI) # This should not raise an exception (check_schema will raise error) asdf.schema.check_schema(schema) unit = TaggedString("foo") unit._tag = ASDF_UNIT_TAG with pytest.raises(asdf.ValidationError, match=r"'foo' is not one of \['m', 'kg'\]"): asdf.schema.validate({"unit": unit}, schema=schema) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_testing_helpers.py0000644000175100001770000000060514653725311021076 0ustar00runnerdockerimport warnings import pytest def test_warnings_are_errors(): """ Smoke test to make sure that warnings cause errors. This is here as previously asdf._tests._helpers had an ``assert_no_warnings`` function that was removed in favor of using a warning filter to turn warnings into errors. """ with pytest.raises(UserWarning): warnings.warn("test") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_treeutil.py0000644000175100001770000000272314653725311017537 0ustar00runnerdockerfrom asdf import treeutil def test_get_children(): parent = ["foo", "bar"] assert treeutil.get_children(parent) == [(0, "foo"), (1, "bar")] parent = ("foo", "bar") assert treeutil.get_children(parent) == [(0, "foo"), (1, "bar")] parent = {"foo": "bar", "ding": "dong"} assert sorted(treeutil.get_children(parent)) == sorted([("foo", "bar"), ("ding", "dong")]) parent = "foo" assert treeutil.get_children(parent) == [] parent = None assert treeutil.get_children(parent) == [] def test_is_container(): for value in [[], {}, ()]: assert treeutil.is_container(value) is True for value in ["foo", 12, 13.9827]: assert treeutil.is_container(value) is False def test_walk_and_modify_shared_references(): target = {"foo": "bar"} nested_in_dict = {"target": target} nested_in_list = [target] tree = {"target": target, "nested_in_dict": nested_in_dict, "nested_in_list": nested_in_list} assert tree["target"] is tree["nested_in_dict"]["target"] assert tree["target"] is tree["nested_in_list"][0] def _callback(node): if "foo" in node: return {"foo": "baz"} return node result = treeutil.walk_and_modify(tree, _callback) assert result is not tree assert result["target"] is not target assert result["target"]["foo"] == "baz" assert result["target"] is result["nested_in_dict"]["target"] assert result["target"] is result["nested_in_list"][0] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_types.py0000644000175100001770000000336714653725311017053 0ustar00runnerdockerimport pytest import asdf from asdf.exceptions import AsdfConversionWarning from asdf.testing.helpers import yaml_to_asdf def test_undefined_tag(with_lazy_tree): # This tests makes sure that ASDF still returns meaningful structured data # even when it encounters a schema tag that it does not specifically # implement as an extension from numpy import array yaml = """ undefined_data: ! - 5 - {'message': 'there is no tag'} - !core/ndarray-1.0.0 [[1, 2, 3], [4, 5, 6]] - ! - !core/ndarray-1.0.0 [[7],[8],[9],[10]] - !core/complex-1.0.0 3.14j """ buff = yaml_to_asdf(yaml) with pytest.warns(Warning) as warning: afile = asdf.open(buff) missing = afile.tree["undefined_data"] missing[3] assert missing[0] == 5 assert missing[1] == {"message": "there is no tag"} assert (missing[2] == array([[1, 2, 3], [4, 5, 6]])).all() assert (missing[3][0] == array([[7], [8], [9], [10]])).all() assert missing[3][1] == 3.14j # There are two undefined tags, so we expect two warnings # filter out only AsdfConversionWarning warning = [w for w in warning if w.category == AsdfConversionWarning] assert len(warning) == 2 messages = {str(w.message) for w in warning} match = { f"tag:nowhere.org:custom/{tag} is not recognized, converting to raw Python data structure" for tag in ("undefined_tag-1.0.0", "also_undefined-1.3.0") } assert messages == match # Make sure no warning occurs if explicitly ignored buff.seek(0) # as warnings get turned into errors, nothing to do here afile = asdf.open(buff, ignore_unrecognized_tag=True) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_util.py0000644000175100001770000001205014653725311016651 0ustar00runnerdockerimport contextlib import io import warnings import numpy as np import pytest import asdf from asdf import generic_io, util from asdf.exceptions import AsdfDeprecationWarning def test_is_primitive(): with warnings.catch_warnings(): warnings.filterwarnings("ignore", "asdf.util.is_primitive is deprecated", AsdfDeprecationWarning) for value in [None, "foo", 1, 1.39, 1 + 1j, True]: assert util.is_primitive(value) is True for value in [[], (), {}, set()]: assert util.is_primitive(value) is False def test_not_set(): assert util.NotSet is not None assert repr(util.NotSet) == "NotSet" class SomeClass: class SomeInnerClass: pass def test_get_class_name(): assert util.get_class_name(SomeClass()) == "asdf._tests.test_util.SomeClass" assert util.get_class_name(SomeClass, instance=False) == "asdf._tests.test_util.SomeClass" assert util.get_class_name(SomeClass.SomeInnerClass()) == "asdf._tests.test_util.SomeClass.SomeInnerClass" assert ( util.get_class_name(SomeClass.SomeInnerClass, instance=False) == "asdf._tests.test_util.SomeClass.SomeInnerClass" ) def test_patched_urllib_parse(): assert "asdf" in util._patched_urllib_parse.uses_relative assert "asdf" in util._patched_urllib_parse.uses_netloc import urllib.parse assert urllib.parse is not util._patched_urllib_parse assert "asdf" not in urllib.parse.uses_relative assert "asdf" not in urllib.parse.uses_netloc @pytest.mark.parametrize( ("pattern", "uri", "result"), [ ("asdf://somewhere.org/tags/foo-1.0", "asdf://somewhere.org/tags/foo-1.0", True), ("asdf://somewhere.org/tags/foo-1.0", "asdf://somewhere.org/tags/bar-1.0", False), ("asdf://somewhere.org/tags/foo-*", "asdf://somewhere.org/tags/foo-1.0", True), ("asdf://somewhere.org/tags/foo-*", "asdf://somewhere.org/tags/bar-1.0", False), ("asdf://somewhere.org/tags/foo-*", "asdf://somewhere.org/tags/foo-extras/bar-1.0", False), ("asdf://*/tags/foo-*", "asdf://anywhere.org/tags/foo-4.9", True), ("asdf://*/tags/foo-*", "asdf://anywhere.org/tags/bar-4.9", False), ("asdf://*/tags/foo-*", "asdf://somewhere.org/tags/foo-extras/bar-4.9", False), ("asdf://**/*-1.0", "asdf://somewhere.org/tags/foo-1.0", True), ("asdf://**/*-1.0", "asdf://somewhere.org/tags/foo-2.0", False), ("asdf://**/*-1.0", "asdf://somewhere.org/tags/foo-extras/bar-1.0", True), ("asdf://**/*-1.0", "asdf://somewhere.org/tags/foo-extras/bar-2.0", False), ("asdf://somewhere.org/tags/foo-*", None, False), ("**", None, False), ], ) def test_uri_match(pattern, uri, result): assert util.uri_match(pattern, uri) is result @pytest.mark.parametrize( ("content", "expected_type"), [ (b"#ASDF blahblahblah", util.FileType.ASDF), (b"SIMPLE = T blah blah blah blah", util.FileType.FITS), (b"SIMPLY NOT A FITS FILE", util.FileType.UNKNOWN), (b"#ASDQ", util.FileType.UNKNOWN), ], ) def test_get_file_type(content, expected_type): fd = generic_io.get_file(io.BytesIO(content)) assert util.get_file_type(fd) == expected_type # Confirm that no content was lost assert fd.read() == content # We've historically had a problem detecting file type # of generic_io.InputStream: class OnlyHasAReadMethod: def __init__(self, content): self._fd = io.BytesIO(content) def read(self, size=-1): return self._fd.read(size) fd = generic_io.get_file(OnlyHasAReadMethod(content)) assert util.get_file_type(fd) == expected_type assert fd.read() == content def test_minversion(): import numpy as np import yaml good_versions = ["1.16", "1.16.1", "1.16.0.dev", "1.16dev"] bad_versions = ["100000", "100000.2rc1"] with warnings.catch_warnings(): warnings.filterwarnings("ignore", "asdf.util.minversion", AsdfDeprecationWarning) for version in good_versions: assert util.minversion(np, version) assert util.minversion("numpy", version) for version in bad_versions: assert not util.minversion(np, version) assert not util.minversion("numpy", version) assert util.minversion(yaml, "3.1") assert util.minversion("yaml", "3.1") @pytest.mark.parametrize("input_type", ["filename", "binary_file", "generic_file"]) @pytest.mark.parametrize("tagged", [True, False]) def test_load_yaml(tmp_path, input_type, tagged): fn = tmp_path / "test.asdf" asdf.AsdfFile({"a": np.zeros(3)}).write_to(fn) if input_type == "filename": init = fn ctx = contextlib.nullcontext() elif input_type == "binary_file": init = open(fn, "rb") ctx = init elif input_type == "generic_file": init = generic_io.get_file(fn, "r") ctx = init with ctx: tree = util.load_yaml(init, tagged=tagged) if tagged: assert isinstance(tree["a"], asdf.tagged.TaggedDict) else: assert not isinstance(tree["a"], asdf.tagged.TaggedDict) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_versioning.py0000644000175100001770000001777014653725311020075 0ustar00runnerdockerfrom itertools import combinations import pytest from asdf.exceptions import AsdfDeprecationWarning from asdf.versioning import ( AsdfSpec, AsdfVersion, asdf_standard_development_version, default_version, supported_versions, ) def test_default_in_supported_versions(): assert default_version in supported_versions def test_development_is_not_default(): assert default_version != asdf_standard_development_version def test_version_constructor(): ver0 = AsdfVersion("1.0.0") ver1 = AsdfVersion((1, 0, 0)) ver2 = AsdfVersion([1, 0, 0]) assert str(ver0) == "1.0.0" assert str(ver1) == "1.0.0" assert str(ver2) == "1.0.0" def test_version_and_version_equality(): ver0 = AsdfVersion("1.0.0") ver1 = AsdfVersion("1.0.0") assert ver0 is not ver1 assert ver0 == ver1 assert ver1 == ver0 assert not (ver0 != ver1) assert not (ver1 != ver0) def test_version_and_string_equality(): version = AsdfVersion("1.0.0") string_ver = "1.0.0" assert version == string_ver assert string_ver == version assert not (version != string_ver) assert not (string_ver != version) def test_version_and_tuple_equality(): version = AsdfVersion("1.0.0") tuple_ver = (1, 0, 0) assert version == tuple_ver assert tuple_ver == version assert not (version != tuple_ver) assert not (tuple_ver != version) def test_version_and_version_inequality(): ver0 = AsdfVersion("1.0.0") ver1 = AsdfVersion("1.0.1") ver2 = AsdfVersion("1.1.0") ver3 = AsdfVersion("1.1.1") ver4 = AsdfVersion("2.0.0") ver5 = AsdfVersion("2.0.1") ver6 = AsdfVersion("2.1.0") ver7 = AsdfVersion("2.1.1") versions = [ver0, ver1, ver2, ver3, ver4, ver5, ver6, ver7] for x, y in combinations(versions, 2): assert not (x == y) assert x != y assert ver0 < ver1 < ver2 < ver3 < ver4 < ver5 < ver6 < ver7 assert ver7 > ver6 > ver5 > ver4 > ver3 > ver2 > ver1 > ver0 assert (ver0 < ver1 < ver2 < ver4 < ver3 < ver5 < ver6 < ver7) is False assert (ver7 > ver6 > ver5 > ver3 > ver4 > ver2 > ver1 > ver0) is False assert ver0 <= ver1 <= ver2 <= ver3 <= ver4 <= ver5 <= ver6 <= ver7 assert ver7 >= ver6 >= ver5 >= ver4 >= ver3 >= ver2 >= ver1 >= ver0 def test_version_and_string_inequality(): version = AsdfVersion("2.0.0") assert version > "1.0.0" assert version > "1.0.1" assert version > "1.1.0" assert version > "1.1.1" assert (version > "2.0.0") is False assert (version < "2.0.0") is False assert version < "2.0.1" assert version < "2.1.0" assert version < "2.1.1" assert version >= "1.0.0" assert version >= "1.0.1" assert version >= "1.1.0" assert version >= "1.1.1" assert version >= "2.0.0" assert version <= "2.0.0" assert version <= "2.0.1" assert version <= "2.1.0" assert version <= "2.1.1" assert "1.0.0" < version assert "1.0.1" < version assert "1.1.0" < version assert "1.1.1" < version assert ("2.0.0" < version) is False assert ("2.0.0" > version) is False assert "2.0.1" > version assert "2.1.0" > version assert "2.1.1" > version assert "1.0.0" <= version assert "1.0.1" <= version assert "1.1.0" <= version assert "1.1.1" <= version assert "2.0.0" <= version assert "2.0.0" >= version assert "2.0.1" >= version assert "2.1.0" >= version assert "2.1.1" >= version def test_version_and_tuple_inequality(): version = AsdfVersion("2.0.0") assert version > (1, 0, 0) assert version > (1, 0, 1) assert version > (1, 1, 0) assert version > (1, 1, 1) assert (version > (2, 0, 0)) is False assert (version < (2, 0, 0)) is False assert version < (2, 0, 1) assert version < (2, 1, 0) assert version < (2, 1, 1) assert version >= (1, 0, 0) assert version >= (1, 0, 1) assert version >= (1, 1, 0) assert version >= (1, 1, 1) assert version >= (2, 0, 0) assert version <= (2, 0, 0) assert version <= (2, 0, 1) assert version <= (2, 1, 0) assert version <= (2, 1, 1) assert (1, 0, 0) < version assert (1, 0, 1) < version assert (1, 1, 0) < version assert (1, 1, 1) < version assert ((2, 0, 0) < version) is False assert ((2, 0, 0) > version) is False assert (2, 0, 1) > version assert (2, 1, 0) > version assert (2, 1, 1) > version assert (1, 0, 0) <= version assert (1, 0, 1) <= version assert (1, 1, 0) <= version assert (1, 1, 1) <= version assert (2, 0, 0) <= version assert (2, 0, 0) >= version assert (2, 0, 1) >= version assert (2, 1, 0) >= version assert (2, 1, 1) >= version def test_spec_version_match(): with pytest.warns(AsdfDeprecationWarning, match="AsdfSpec is deprecated"): spec = AsdfSpec(">=1.1.0") assert spec.match(AsdfVersion("1.1.0")) assert spec.match(AsdfVersion("1.2.0")) assert not spec.match(AsdfVersion("1.0.0")) assert not spec.match(AsdfVersion("1.0.9")) def test_spec_version_select(): with pytest.warns(AsdfDeprecationWarning, match="AsdfSpec is deprecated"): spec = AsdfSpec(">=1.1.0") versions = [AsdfVersion(x) for x in ["1.0.0", "1.0.9", "1.1.0", "1.2.0"]] assert spec.select(versions) == "1.2.0" assert spec.select(versions[:-1]) == "1.1.0" assert spec.select(versions[:-2]) is None def test_spec_version_filter(): with pytest.warns(AsdfDeprecationWarning, match="AsdfSpec is deprecated"): spec = AsdfSpec(">=1.1.0") versions = [AsdfVersion(x) for x in ["1.0.0", "1.0.9", "1.1.0", "1.2.0"]] for x, y in zip(spec.filter(versions), ["1.1.0", "1.2.0"]): assert x == y def test_spec_string_match(): with pytest.warns(AsdfDeprecationWarning, match="AsdfSpec is deprecated"): spec = AsdfSpec(">=1.1.0") assert spec.match("1.1.0") assert spec.match("1.2.0") assert not spec.match("1.0.0") assert not spec.match("1.0.9") def test_spec_string_select(): with pytest.warns(AsdfDeprecationWarning, match="AsdfSpec is deprecated"): spec = AsdfSpec(">=1.1.0") versions = ["1.0.0", "1.0.9", "1.1.0", "1.2.0"] assert spec.select(versions) == "1.2.0" assert spec.select(versions[:-1]) == "1.1.0" assert spec.select(versions[:-2]) is None def test_spec_string_filter(): with pytest.warns(AsdfDeprecationWarning, match="AsdfSpec is deprecated"): spec = AsdfSpec(">=1.1.0") versions = ["1.0.0", "1.0.9", "1.1.0", "1.2.0"] for x, y in zip(spec.filter(versions), ["1.1.0", "1.2.0"]): assert x == y def test_spec_tuple_match(): with pytest.warns(AsdfDeprecationWarning, match="AsdfSpec is deprecated"): spec = AsdfSpec(">=1.1.0") assert spec.match((1, 1, 0)) assert spec.match((1, 2, 0)) assert not spec.match((1, 0, 0)) assert not spec.match((1, 0, 9)) def test_spec_tuple_select(): with pytest.warns(AsdfDeprecationWarning, match="AsdfSpec is deprecated"): spec = AsdfSpec(">=1.1.0") versions = [(1, 0, 0), (1, 0, 9), (1, 1, 0), (1, 2, 0)] assert spec.select(versions) == "1.2.0" assert spec.select(versions[:-1]) == "1.1.0" assert spec.select(versions[:-2]) is None def test_spec_tuple_filter(): with pytest.warns(AsdfDeprecationWarning, match="AsdfSpec is deprecated"): spec = AsdfSpec(">=1.1.0") versions = [(1, 0, 0), (1, 0, 9), (1, 1, 0), (1, 2, 0)] for x, y in zip(spec.filter(versions), ["1.1.0", "1.2.0"]): assert x == y def test_spec_equal(): """Make sure that equality means match""" with pytest.warns(AsdfDeprecationWarning, match="AsdfSpec is deprecated"): spec = AsdfSpec(">=1.2.0") version0 = AsdfVersion("1.1.0") version1 = AsdfVersion("1.3.0") assert spec != version0 assert version0 != spec assert spec == version1 assert version1 == spec assert spec != "1.1.0" assert "1.1.0" != spec assert spec == "1.3.0" assert "1.3.0" == spec assert spec != (1, 1, 0) assert (1, 1, 0) != spec assert spec == (1, 3, 0) assert (1, 3, 0) == spec ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/_tests/test_yaml.py0000644000175100001770000002411414653725311016642 0ustar00runnerdockerimport contextlib import io import re from collections import OrderedDict, namedtuple from typing import NamedTuple import numpy as np import pytest import yaml import asdf from asdf import tagged, treeutil, yamlutil from asdf.exceptions import AsdfConversionWarning, AsdfDeprecationWarning, AsdfSerializationError, AsdfWarning from asdf.testing.helpers import yaml_to_asdf def _roundtrip(obj, init_kwargs=None): """ Parameters ---------- obj : object object to write to ASDF file (under key 'obj') Returns ------- file_contents: bytes contents of written file read_tree : object object read back from ASDF file """ init_kwargs = init_kwargs or {} buff = io.BytesIO() af = asdf.AsdfFile(**init_kwargs) af["obj"] = obj af.write_to(buff) buff.seek(0) open_kwargs = { "lazy_load": False, "copy_arrays": True, } with asdf.open(buff, **open_kwargs) as af: return buff.getvalue(), af["obj"] def test_ordered_dict(): """ Test that we can write out and read in ordered dicts. """ input_tree = { "ordered_dict": OrderedDict([("first", "foo"), ("second", "bar"), ("third", "baz")]), "unordered_dict": {"first": "foo", "second": "bar", "third": "baz"}, } content, tree = _roundtrip(input_tree) assert b"OrderedDict" not in content assert isinstance(tree["ordered_dict"], OrderedDict) assert tree["ordered_dict"] == input_tree["ordered_dict"] assert not isinstance(tree["unordered_dict"], OrderedDict) assert isinstance(tree["unordered_dict"], dict) assert tree["unordered_dict"] == input_tree["unordered_dict"] def test_unicode_write(): """ We want to write unicode out as regular utf-8-encoded characters, not as escape sequences """ input_tree = {"ÉʇÉp‾Çpoɔıun": 42, "ascii_only": "this is ascii"} # noqa: RUF001 content, tree = _roundtrip(input_tree) # Ensure that unicode is written out as UTF-8 without escape # sequences assert "ÉʇÉp‾Çpoɔıun".encode() in content # noqa: RUF001 # Ensure that the unicode "tag" is not used assert b"unicode" not in content assert tree["ÉʇÉp‾Çpoɔıun"] == input_tree["ÉʇÉp‾Çpoɔıun"] # noqa: RUF001 assert isinstance(tree["ascii_only"], str) assert tree["ascii_only"] == input_tree["ascii_only"] def test_arbitrary_python_object(): """ Putting "just any old" Python object in the tree should raise an exception. """ class Foo: pass tree = {"object": Foo()} buff = io.BytesIO() ff = asdf.AsdfFile(tree) with pytest.raises(AsdfSerializationError, match=r".*is not serializable by asdf.*"): ff.write_to(buff) def run_tuple_test(input_tree, **kwargs): content, tree = _roundtrip(input_tree, **kwargs) assert b"tuple" not in content assert isinstance(tree["val"], list) return content, tree def test_python_tuple(): """ We don't want to store tuples as tuples, because that's not a built-in YAML data type. This test ensures that they are converted to lists. """ input_tree = {"val": (1, 2, 3)} run_tuple_test(input_tree) @contextlib.contextmanager def multi_warn(category, matches): with pytest.warns(category) as record: yield for match in matches: found = False for r in record: msg = str(r.message) if re.match(match, msg): found = True break assert found, f"Did not raise {category} with message matching {match}" def test_named_tuple_collections(): """ Ensure that we are able to serialize a collections.namedtuple. """ nt = namedtuple("TestNamedTuple1", ("one", "two", "three")) input_tree = {"val": nt(1, 2, 3)} with multi_warn(AsdfDeprecationWarning, ["ignore_implicit_conversion", "implicit conversion is deprecated"]): run_tuple_test(input_tree, init_kwargs={"ignore_implicit_conversion": True}) def test_named_tuple_typing(): """ Ensure that we are able to serialize a typing.NamedTuple. """ class NT(NamedTuple): one: int two: int three: int input_tree = {"val": NT(1, 2, 3)} with multi_warn(AsdfDeprecationWarning, ["ignore_implicit_conversion", "implicit conversion is deprecated"]): run_tuple_test(input_tree, init_kwargs={"ignore_implicit_conversion": True}) def test_named_tuple_collections_recursive(): nt = namedtuple("TestNamedTuple3", ("one", "two", "three")) input_tree = {"val": nt(1, 2, np.ones(3))} with multi_warn(AsdfDeprecationWarning, ["ignore_implicit_conversion", "implicit conversion is deprecated"]): _, tree = run_tuple_test(input_tree, init_kwargs={"ignore_implicit_conversion": True}) assert (tree["val"][2] == np.ones(3)).all() def test_named_tuple_typing_recursive(tmp_path): class NT(NamedTuple): one: int two: int three: np.ndarray input_tree = {"val": NT(1, 2, np.ones(3))} with multi_warn(AsdfDeprecationWarning, ["ignore_implicit_conversion", "implicit conversion is deprecated"]): _, tree = run_tuple_test(input_tree, init_kwargs={"ignore_implicit_conversion": True}) assert (tree["val"][2] == np.ones(3)).all() def test_implicit_conversion_warning(): nt = namedtuple("TestTupleWarning", ("one", "two", "three")) tree = {"val": nt(1, 2, np.ones(3))} with ( pytest.warns(AsdfWarning, match=r"Failed to serialize instance"), pytest.warns(AsdfDeprecationWarning, match=r"implicit conversion is deprecated"), asdf.AsdfFile(tree), ): pass with multi_warn(AsdfDeprecationWarning, ["ignore_implicit_conversion", "implicit conversion is deprecated"]): with asdf.AsdfFile(tree, ignore_implicit_conversion=True): pass @pytest.mark.xfail(reason="pyyaml has a bug and does not support tuple keys") def test_python_tuple_key(): """ This tests whether tuple keys are round-tripped properly. As of this writing, this does not work in pyyaml but does work in ruamel.yaml. If/when we decide to switch to ruamel.yaml, this test should pass. """ input_tree = {(42, 1): "foo"} _, tree = _roundtrip(input_tree) assert tree[(42, 1)] == "foo" def test_tags_removed_after_load(tmp_path): input_tree = {"foo": ["bar", (1, 2, None)]} _, tree = _roundtrip(input_tree) for node in treeutil.iter_tree(tree): if node != tree: assert not isinstance(node, tagged.Tagged) def test_explicit_tags(): yaml = b"""#ASDF 1.0.0 #ASDF_STANDARD 1.5.0 %YAML 1.1 --- ! foo: ! [1, 2, 3] ...""" # Check that fully qualified explicit tags work buff = io.BytesIO(yaml) with asdf.open(buff) as ff: assert all(ff.tree["foo"] == [1, 2, 3]) def test_yaml_internal_reference(tmp_path): """ Test that YAML internal references (anchors and aliases) work, as well as recursive data structures. """ d = { "foo": "2", } d["bar"] = d _list = [] _list.append(_list) input_tree = {"first": d, "second": d, "list": _list} content, tree = _roundtrip(input_tree) assert b"list:&id002-*id002" in b"".join(content.split()) assert tree["list"][0] == tree["list"] for k in ("first", "second"): assert tree[k]["foo"] == input_tree[k]["foo"] assert tree[k]["bar"] is tree[k] def test_yaml_nan_inf(): tree = {"a": np.nan, "b": np.inf, "c": -np.inf} buff = io.BytesIO() ff = asdf.AsdfFile(tree) ff.write_to(buff) buff.seek(0) with asdf.open(buff) as ff: assert np.isnan(ff.tree["a"]) assert np.isinf(ff.tree["b"]) assert np.isinf(ff.tree["c"]) def test_tag_object(): class SomeObject: pass tag = "tag:nowhere.org:none/some/thing" instance = tagged.tag_object(tag, SomeObject()) assert instance._tag == tag @pytest.mark.parametrize( ("numpy_value", "expected_value"), [ (np.str_("foo"), "foo"), (np.bytes_("foo"), b"foo"), (np.float16(3.14), 3.14), (np.float32(3.14159), 3.14159), (np.float64(3.14159), 3.14159), # Evidently float128 is not available on Windows: (getattr(np, "float128", np.float64)(3.14159), 3.14159), (np.int8(42), 42), (np.int16(42), 42), (np.int32(42), 42), (np.int64(42), 42), (np.longlong(42), 42), (np.uint8(42), 42), (np.uint16(42), 42), (np.uint32(42), 42), (np.uint64(42), 42), (np.ulonglong(42), 42), ], ) def test_numpy_scalar(numpy_value, expected_value): ctx = asdf.AsdfFile({"value": numpy_value}) tree = ctx.tree buffer = io.BytesIO() yamlutil.dump_tree(tree, buffer, ctx) buffer.seek(0) loaded_value = yamlutil.load_tree(buffer)["value"] if isinstance(numpy_value, np.floating): abs_diff = abs(expected_value - loaded_value) eps = np.finfo(numpy_value.dtype).eps assert abs_diff < eps, abs_diff else: assert loaded_value == expected_value def test_ndarray_subclass_conversion(tmp_path): class MyNDArray(np.ndarray): pass fn = tmp_path / "test.asdf" af = asdf.AsdfFile() af["a"] = MyNDArray([1, 2, 3]) with pytest.warns(AsdfConversionWarning, match=r"A ndarray subclass .*"): af.write_to(fn) with asdf.config.config_context() as cfg: cfg.convert_unknown_ndarray_subclasses = False with pytest.raises(AsdfSerializationError, match=r".*is not serializable by asdf.*"): af.write_to(fn) @pytest.mark.parametrize( "payload", [ " 1: a", # not a sequence "- !!omap\n - 1", # sequence item, not a mapping "- !!omap\n 1: a\n 2: a", # sequence item, not a one element mapping ], ) def test_invalid_omap(payload): test_yaml = f"""od: !!omap {payload} """ # Check that fully qualified explicit tags work buff = yaml_to_asdf(test_yaml) with pytest.raises(yaml.constructor.ConstructorError): with asdf.open(buff) as ff: ff["od"] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788568.0 asdf-3.4.0/asdf/_version.py0000644000175100001770000000063314653725330015165 0ustar00runnerdocker# file generated by setuptools_scm # don't change, don't track in version control TYPE_CHECKING = False if TYPE_CHECKING: from typing import Tuple, Union VERSION_TUPLE = Tuple[Union[int, str], ...] else: VERSION_TUPLE = object version: str __version__: str __version_tuple__: VERSION_TUPLE version_tuple: VERSION_TUPLE __version__ = version = '3.4.0' __version_tuple__ = version_tuple = (3, 4, 0) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/asdf.py0000644000175100001770000000073014653725311014253 0ustar00runnerdockerimport warnings from . import _asdf from .exceptions import AsdfDeprecationWarning warnings.warn( "asdf.asdf is deprecated. Please use asdf.AsdfFile and asdf.open", AsdfDeprecationWarning, ) def __getattr__(name): if hasattr(_asdf, name): return getattr(_asdf, name) warnings.warn( "asdf.asdf is deprecated", AsdfDeprecationWarning, ) msg = f"module {__name__!r} has no attribute {name!r}" raise AttributeError(msg) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1490982 asdf-3.4.0/asdf/commands/0000755000175100001770000000000014653725331014567 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/commands/__init__.py0000644000175100001770000000054214653725311016677 0ustar00runnerdockerfrom .defragment import defragment from .diff import diff from .edit import edit from .exploded import explode, implode from .extension import find_extensions from .info import info from .tags import list_tags from .to_yaml import to_yaml __all__ = ["implode", "explode", "to_yaml", "defragment", "diff", "list_tags", "find_extensions", "info", "edit"] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/commands/defragment.py0000644000175100001770000000364314653725311017261 0ustar00runnerdocker""" Defragment command. """ import asdf from asdf import AsdfFile from .main import Command __all__ = ["defragment"] class Defragment(Command): @classmethod def setup_arguments(cls, subparsers): parser = subparsers.add_parser( "defragment", help="Defragment an ASDF file..", description="""Removes any unused blocks and unused space.""", ) parser.add_argument("filename", nargs=1, help="""The ASDF file to collect.""") parser.add_argument("--output", "-o", type=str, nargs="?", help="""The name of the output file.""") parser.add_argument( "--resolve-references", "-r", action="store_true", help="""Resolve all references and store them directly in the output file.""", ) parser.add_argument( "--compress", "-c", type=str, nargs="?", choices=["zlib", "bzp2", "lz4"], help="""Compress blocks using one of "zlib", "bzp2" or "lz4".""", ) parser.set_defaults(func=cls.run) return parser @classmethod def run(cls, args): return defragment(args.filename[0], args.output, args.resolve_references, args.compress) def defragment(input_, output=None, resolve_references=False, compress=None): """ Defragment a given ASDF file. Parameters ---------- input_ : str or file-like object The input file. output : str of file-like object The output file. resolve_references : bool, optional If `True` resolve all external references before saving. compress : str, optional Compression to use. """ with asdf.open(input_) as ff: ff2 = AsdfFile(ff) if resolve_references: ff2.resolve_references() ff2.write_to(output, all_array_storage="internal", all_array_compression=compress) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/commands/diff.py0000644000175100001770000003234514653725311016056 0ustar00runnerdocker""" Implementation of command for displaying differences between two ASDF files. """ import argparse import sys import jmespath import numpy as np from numpy import array_equal try: # Provides cross-platform color support import colorama colorama.init() RED = colorama.Fore.RED GREEN = colorama.Fore.GREEN RESET = colorama.Style.RESET_ALL except ImportError: from sys import platform # These platforms should support ansi color codes if platform.startswith("linux") or platform.startswith("darwin"): RED = "\x1b[31m" GREEN = "\x1b[32m" RESET = "\x1b[0m" else: RED = "" GREEN = "" RESET = "" import asdf from asdf.extension._serialization_context import BlockAccess from asdf.tagged import Tagged from .main import Command __all__ = ["diff"] RESET_NEWLINE = RESET + "\n" NDARRAY_TAG = "core/ndarray" LIST_MARKER = "-" THIS_MARKER = GREEN + "> " THAT_MARKER = RED + "< " class Diff(Command): # pragma: no cover """This class is the plugin implementation for the asdftool runner.""" @classmethod def setup_arguments(cls, subparsers): epilog = """ examples: diff two files: asdftool diff file_before.asdf file_after.asdf ignore differences in the file's ASDF metadata: asdftool diff file_before.asdf file_after.asdf -i '[asdf_library,history]' ignore differences in the 'foo' field of all objects in a list: asdftool diff file_before.asdf file_after.asdf -i 'path.to.some_list[*].foo' See https://jmespath.org/ for more information on constructing JMESPath expressions. """.strip() parser = subparsers.add_parser( "diff", description="Report differences between two ASDF files", epilog=epilog, formatter_class=argparse.RawDescriptionHelpFormatter, help="Report differences between two ASDF files", ) parser.add_argument("filenames", metavar="asdf_file", nargs=2, help="The ASDF files to compare.") parser.add_argument( "-m", "--minimal", action="store_true", help="Show minimal differences between the two files.", ) parser.add_argument( "-i", "--ignore", action="append", dest="ignore", help="JMESPath expression indicating tree nodes that should be ignored.", ) parser.set_defaults(func=cls.run) return parser @classmethod def run(cls, args): return diff(args.filenames, args.minimal, ignore=args.ignore) class ArrayNode: """This class is used to represent unique dummy nodes in the diff tree. In general these dummy nodes will be list elements that we want to keep track of but not necessarily display. This allows the diff output to be cleaner.""" def __init__(self, name, index): self.name = name self.index = index def __hash__(self): return hash(self.name) class PrintTree: """This class is used to remember the nodes in the tree that have already been displayed in the diff output. """ def __init__(self): self.__tree = {"visited": False, "children": {}} def get_print_list(self, node_list): at_end = False print_list = [] current = self.__tree for node in ["tree", *node_list]: if at_end: print_list.append(node) elif node not in current["children"]: print_list.append(node) at_end = True elif not current["children"][node]["visited"]: print_list.append(node) else: print_list.append(None) if not at_end: current = current["children"][node] return print_list def __setitem__(self, node_list, visit): if not isinstance(node_list, list): msg = "node_list parameter must be an instance of list" raise TypeError(msg) current = self.__tree for node in ["tree", *node_list]: if node not in current["children"]: current["children"][node] = {"visited": True, "children": {}} current = current["children"][node] class DiffContext: """Class that contains context data of the diff to be computed""" def __init__(self, asdf0, asdf1, iostream, minimal=False, ignore_ids=None): self.asdf0 = asdf0 self.asdf1 = asdf1 self.iostream = iostream self.minimal = minimal self.print_tree = PrintTree() if ignore_ids is None: self.ignore_ids = set() else: self.ignore_ids = ignore_ids def print_tree_context(diff_ctx, node_list, other, use_marker, last_was_list): """Print context information indicating location in ASDF tree.""" prefix = "" marker = THAT_MARKER if other else THIS_MARKER for node in diff_ctx.print_tree.get_print_list(node_list): if node is not None: node_ = LIST_MARKER if isinstance(node, ArrayNode) else node + ":" # All of this logic is just to make the display of arrays prettier if use_marker: line_prefix = " " if last_was_list else marker + prefix[2:] line_suffix = "" if node_ == LIST_MARKER else RESET_NEWLINE else: line_prefix = prefix line_suffix = RESET_NEWLINE diff_ctx.iostream.write(line_prefix + node_ + line_suffix) last_was_list = node_ == LIST_MARKER prefix += " " diff_ctx.print_tree[node_list] = True return last_was_list def print_in_tree(diff_ctx, node_list, thing, other, use_marker=False, last_was_list=False, ignore_lwl=False): """Recursively print tree context and diff information about object.""" last_was_list = print_tree_context(diff_ctx, node_list, other, use_marker, last_was_list) # If tree element is list, recursively print list contents if isinstance(thing, list): for i, subthing in enumerate(thing): key = ArrayNode(f"{node_list[-1]}_{i}", i) last_was_list = print_in_tree( diff_ctx, [*node_list, key], subthing, other, use_marker=True, last_was_list=last_was_list, ignore_lwl=ignore_lwl, ) # If tree element is dictionary, recursively print dictionary contents elif isinstance(thing, dict): for key in sorted(thing.keys()): last_was_list = print_in_tree( diff_ctx, [*node_list, key], thing[key], other, use_marker=True, last_was_list=last_was_list, ignore_lwl=ignore_lwl, ) # Print difference between leaf objects (no need to recurse further) else: use_marker = not last_was_list or ignore_lwl marker = THAT_MARKER if other else THIS_MARKER prefix = marker + " " * len(node_list) if use_marker else " " diff_ctx.iostream.write(prefix + str(thing) + RESET_NEWLINE) last_was_list = False return last_was_list def compare_objects(diff_ctx, obj0, obj1, keys=None): """Displays diff of two objects if they are not equal""" keys = [] if keys is None else keys if obj0 != obj1: print_in_tree(diff_ctx, keys, obj0, False, ignore_lwl=True) print_in_tree(diff_ctx, keys, obj1, True, ignore_lwl=True) def print_dict_diff(diff_ctx, tree, node_list, keys, other): """Recursively traverses dictionary object and displays differences""" for key in keys: if diff_ctx.minimal: nodes = node_list key_ = key else: nodes = [*node_list, key] key_ = tree[key] use_marker = not diff_ctx.minimal print_in_tree(diff_ctx, nodes, key_, other, use_marker=use_marker) def _load_array(asdf_file, array_dict): # the array_dict may not be tagged if the array is inline # in this case just use what's in "data" if not hasattr(array_dict, "_tag"): return array_dict["data"] conv = asdf_file.extension_manager.get_converter_for_type(np.ndarray) sctx = asdf_file._create_serialization_context(BlockAccess.READ) return conv.from_yaml_tree(array_dict, array_dict._tag, sctx) def _human_list(line, separator="and"): """ Formats a list for human readability. Parameters ---------- line : sequence A sequence of strings separator : string, optional The word to use between the last two entries. Default: ``"and"``. Returns ------- formatted_list : string Examples -------- >>> _human_list(["vanilla", "strawberry", "chocolate"], "or") 'vanilla, strawberry or chocolate' """ if len(line) == 1: return line[0] return ", ".join(line[:-1]) + " " + separator + " " + line[-1] def compare_ndarrays(diff_ctx, array0, array1, keys): """Compares two ndarray objects""" if isinstance(array0, list): array0 = {"data": array0} if isinstance(array1, list): array1 = {"data": array1} ignore_keys = {"source", "data"} compare_dicts(diff_ctx, array0, array1, keys, ignore_keys) differences = [] for field in ["shape", "datatype"]: if array0.get(field) != array1.get(field): differences.append(field) value0 = _load_array(diff_ctx.asdf0, array0) value1 = _load_array(diff_ctx.asdf1, array1) if not array_equal(value0, value1): differences.append("contents") if differences: msg = f"ndarrays differ by {_human_list(differences)}" print_in_tree(diff_ctx, keys, msg, False, ignore_lwl=True) print_in_tree(diff_ctx, keys, msg, True, ignore_lwl=True) def both_are_ndarrays(tree0, tree1): """Returns True if both inputs correspond to ndarrays, False otherwise""" if not (isinstance(tree0, Tagged) and isinstance(tree1, Tagged)): return False if not (NDARRAY_TAG in tree0._tag and NDARRAY_TAG in tree1._tag): return False return True def compare_dicts(diff_ctx, dict0, dict1, keys, ignores=None): """Recursively compares two dictionary objects""" ignores = set() if ignores is None else ignores keys0 = set(dict0.keys()) - ignores keys1 = set(dict1.keys()) - ignores # Recurse into subtree elements that are shared by both trees for key in sorted(keys0 & keys1): obj0 = dict0[key] obj1 = dict1[key] compare_trees(diff_ctx, obj0, obj1, keys=[*keys, key]) # Display subtree elements existing only in this tree print_dict_diff(diff_ctx, dict0, keys, sorted(keys0 - keys1), False) # Display subtree elements existing only in that tree print_dict_diff(diff_ctx, dict1, keys, sorted(keys1 - keys0), True) def compare_trees(diff_ctx, tree0, tree1, keys=None): """Recursively traverses two ASDF tree and compares them""" keys = [] if keys is None else keys if id(tree0) in diff_ctx.ignore_ids and id(tree1) in diff_ctx.ignore_ids: return if both_are_ndarrays(tree0, tree1): compare_ndarrays(diff_ctx, tree0, tree1, keys) elif isinstance(tree0, dict) and isinstance(tree1, dict): compare_dicts(diff_ctx, tree0, tree1, keys) elif isinstance(tree0, list) and isinstance(tree1, list): for i, (obj0, obj1) in enumerate(zip(tree0, tree1)): key = ArrayNode(f"item_{i}", i) compare_trees(diff_ctx, obj0, obj1, [*keys, key]) else: compare_objects(diff_ctx, tree0, tree1, keys) def diff(filenames, minimal, iostream=sys.stdout, ignore=None): """ Compare two ASDF files and write diff output to the stdout or the specified I/O stream. filenames : list of str List of ASDF filenames to compare. Must be length 2. minimal : boolean Set to True to forego some pretty-printing to minimize the diff output. iostream : io.TextIOBase, optional Text-mode stream to write the diff, e.g., sys.stdout or an io.StringIO instance. Defaults to stdout. ignore : list of str, optional List of JMESPath expressions indicating tree nodes that should be ignored. """ ignore_expressions = [] if ignore is None else [jmespath.compile(e) for e in ignore] try: with ( asdf.open(filenames[0], _force_raw_types=True) as asdf0, asdf.open( filenames[1], _force_raw_types=True, ) as asdf1, ): ignore_ids = set() for expression in ignore_expressions: for tree in [asdf0.tree, asdf1.tree]: result = expression.search(tree) if result is not None: ignore_ids.add(id(result)) if isinstance(result, list): for elem in result: ignore_ids.add(id(elem)) elif isinstance(result, dict): for value in result.values(): ignore_ids.add(id(value)) diff_ctx = DiffContext(asdf0, asdf1, iostream, minimal=minimal, ignore_ids=ignore_ids) compare_trees(diff_ctx, asdf0.tree, asdf1.tree) except ValueError as err: raise RuntimeError(str(err)) from err ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/commands/edit.py0000644000175100001770000003123414653725311016067 0ustar00runnerdocker""" Contains commands for lightweight text editing of an ASDF file. """ import io import os import re import shutil # Marked safe because the editor command is specified by an # environment variable that the user controls. import subprocess # nosec import sys import tempfile import yaml from asdf import constants, generic_io, schema, util from asdf._asdf import AsdfFile from asdf._block import io as bio from asdf._block.exceptions import BlockIndexError from .main import Command __all__ = ["edit"] if sys.platform.startswith("win"): DEFAULT_EDITOR = "notepad" else: DEFAULT_EDITOR = "vi" class Edit(Command): @classmethod def setup_arguments(cls, subparsers): """ Set up a command line argument parser for the edit subcommand. """ # Set up the parser parser = subparsers.add_parser( "edit", description="Edit the YAML portion of an ASDF file in-place.", ) # Need an input file parser.add_argument( "filename", help="Path to an ASDF file.", ) parser.set_defaults(func=cls.run) return parser @classmethod def run(cls, args): """ Execute the edit subcommand. """ return edit(args.filename) def read_yaml(fd): """ Read the YAML portion of an open ASDF file's content. Parameters ---------- fd : GenericFile Returns ------- bytes YAML content int total number of bytes available for YAML area bool True if the file contains binary blocks """ # All ASDF files produced by this library, even the binary files # of an exploded ASDF file, include a YAML header, so we'll just # let this raise an error if the end marker can't be found. # Revisit this if someone starts producing files without a # YAML section, which the standard permits but is not possible # with current software. reader = fd.reader_until( constants.YAML_END_MARKER_REGEX, 7, "End of YAML marker", include=True, ) content = reader.read() reader = fd.reader_until( constants.BLOCK_MAGIC, len(constants.BLOCK_MAGIC), include=False, exception=False, ) buffer = reader.read() contains_blocks = fd.peek(len(constants.BLOCK_MAGIC)) == constants.BLOCK_MAGIC return content, len(content) + len(buffer), contains_blocks def write_edited_yaml_larger(path, new_content, version): """ Rewrite an ASDF file, replacing the YAML portion with the specified YAML content and updating the block index if present. The file is assumed to contain binary blocks. Parameters ---------- path : str Path to ASDF file content : bytes Updated YAML content """ prefix = os.path.splitext(os.path.basename(path))[0] + "-" # Since the original file may be large, create the temporary # file in the same directory to avoid filling up the system # temporary area. temp_file = tempfile.NamedTemporaryFile(dir=os.path.dirname(path), prefix=prefix, suffix=".asdf", delete=False) try: temp_file.close() with generic_io.get_file(temp_file.name, mode="w") as fd: fd.write(new_content) # Allocate additional space for future YAML updates: pad_length = util.calculate_padding(len(new_content), True, fd.block_size) fd.fast_forward(pad_length) # now copy over ASDF block contents with generic_io.get_file(path) as original_fd: original_fd.seek_until(constants.BLOCK_MAGIC, len(constants.BLOCK_MAGIC)) old_first_block_offset = original_fd.tell() - len(constants.BLOCK_MAGIC) new_first_block_offset = fd.tell() # check if the original file has a block index which we will need to update # as we're moving the blocks block_index_offset = bio.find_block_index(original_fd) if block_index_offset is None: block_index = None original_fd.seek(0, generic_io.SEEK_END) blocks_end = original_fd.tell() else: blocks_end = block_index_offset try: block_index = bio.read_block_index(original_fd, block_index_offset) except BlockIndexError: # the original index was invalid block_index = None # copy over blocks byte-for-byte from old_first_block_offset to block_index_offset original_fd.seek(old_first_block_offset) block_size = min(fd.block_size, original_fd.block_size) n_bytes = blocks_end - old_first_block_offset for offset in range(0, n_bytes, block_size): this_size = min(block_size, n_bytes - offset) fd.write(original_fd.read(this_size)) # update index if block_index is not None: offset = new_first_block_offset - old_first_block_offset updated_block_index = [i + offset for i in block_index] bio.write_block_index(fd, updated_block_index) # Swap in the new version of the file atomically: shutil.copy(temp_file.name, path) finally: os.unlink(temp_file.name) def write_edited_yaml(path, new_content, available_bytes): """ Overwrite the YAML portion of an ASDF tree with the specified YAML content. The content must fit in the space available. Parameters ---------- path : str Path to ASDF file yaml_content : bytes Updated YAML content available_bytes : int Number of bytes available for YAML """ # generic_io mode "rw" opens the file as "r+b": with generic_io.get_file(path, mode="rw") as fd: fd.write(new_content) pad_length = available_bytes - len(new_content) if pad_length > 0: fd.write(b"\0" * pad_length) def edit(path): """ Copy the YAML portion of an ASDF file to a temporary file, present the file to the user for editing, then update the original file with the modified YAML. Parameters ---------- path : str Path to ASDF file """ # Extract the YAML portion of the original file: with generic_io.get_file(path, mode="r") as fd: if fd.peek(len(constants.ASDF_MAGIC)) != constants.ASDF_MAGIC: print(f"Error: '{path}' is not an ASDF file.") return 1 original_content, available_bytes, contains_blocks = read_yaml(fd) original_asdf_version = parse_asdf_version(original_content) original_yaml_version = parse_yaml_version(original_content) prefix = os.path.splitext(os.path.basename(path))[0] + "-" # We can't use temp_file's automatic delete because Windows # won't allow reading the file from the editor process unless # it is closed here. temp_file = tempfile.NamedTemporaryFile(prefix=prefix, suffix=".yaml", delete=False) try: # Write the YAML to a temporary path: temp_file.write(original_content) temp_file.close() # Loop so that the user can correct errors in the edited file: while True: open_editor(temp_file.name) with open(temp_file.name, "rb") as f: new_content = f.read() if new_content == original_content: print("No changes made to file") return 0 try: new_asdf_version = parse_asdf_version(new_content) new_yaml_version = parse_yaml_version(new_content) except Exception as e: print(f"Error: failed to parse ASDF header: {e!s}") choice = request_input("(c)ontinue editing or (a)bort? ", ["c", "a"]) if choice == "a": return 1 continue if new_asdf_version != original_asdf_version or new_yaml_version != original_yaml_version: print("Error: cannot modify ASDF Standard or YAML version using this tool.") choice = request_input("(c)ontinue editing or (a)bort? ", ["c", "a"]) if choice == "a": return 1 continue try: # check this is an ASDF file if new_content[: len(constants.ASDF_MAGIC)] != constants.ASDF_MAGIC: msg = "Does not appear to be a ASDF file." raise ValueError(msg) # read the tagged tree (which also checks if the YAML is valid) tagged_tree = util.load_yaml(io.BytesIO(new_content), tagged=True) # validate the tagged tree ctx = AsdfFile(version=new_asdf_version) schema.validate(tagged_tree, ctx=ctx, reading=True) except yaml.YAMLError as e: print("Error: failed to parse updated YAML:") print_exception(e) choice = request_input("(c)ontinue editing or (a)bort? ", ["c", "a"]) if choice == "a": return 1 continue except schema.ValidationError as e: print("Warning: updated ASDF tree failed validation:") print_exception(e) choice = request_input("(c)ontinue editing, (f)orce update, or (a)bort? ", ["c", "f", "a"]) if choice == "a": return 1 if choice == "c": continue except Exception as e: print("Error: failed to read updated file as ASDF:") print_exception(e) choice = request_input("(c)ontinue editing or (a)bort? ", ["c", "a"]) if choice == "a": return 1 continue # We've either opened the file without error, or # the user has agreed to ignore validation errors. # Break out of the loop so that we can update the # original file. break finally: os.unlink(temp_file.name) if len(new_content) <= available_bytes: # File has sufficient space allocated in the YAML area. write_edited_yaml(path, new_content, available_bytes) elif not contains_blocks: # File does not have sufficient space, but there are # no binary blocks, so we can just expand the file. write_edited_yaml(path, new_content, len(new_content)) else: # File does not have sufficient space, and binary blocks # are present. print("Warning: updated YAML larger than allocated space. File must be rewritten.") choice = request_input("(c)ontinue or (a)bort? ", ["c", "a"]) if choice == "a": return 1 write_edited_yaml_larger(path, new_content, new_asdf_version) return None def parse_asdf_version(content): """ Extract the ASDF Standard version from YAML content. Parameters ---------- content : bytes Returns ------- asdf.versioning.AsdfVersion ASDF Standard version """ comments = AsdfFile._read_comment_section(generic_io.get_file(io.BytesIO(content))) return AsdfFile._find_asdf_version_in_comments(comments) def parse_yaml_version(content): """ Extract the YAML version from YAML content. Parameters ---------- content : bytes Returns ------- bytes YAML version string. """ match = re.search(b"^%YAML (.*)$", content, flags=re.MULTILINE) if match is None: msg = "YAML version number not found" raise ValueError(msg) return match.group(1) def print_exception(e): """ Print an exception, indented 4 spaces and elided if too many lines. """ lines = str(e).split("\n") if len(lines) > 20: lines = lines[0:20] + ["..."] for line in lines: print(f" {line}") def request_input(message, choices): """ Request user input. Parameters ---------- message : str Message to display choices : list of str List of recognized inputs """ while True: choice = input(message).strip().lower() if choice in choices: return choice print(f"Invalid choice: {choice}") return None def open_editor(path): """ Launch an editor process with the file at path opened. """ editor = os.environ.get("EDITOR", DEFAULT_EDITOR) # Marked safe because the editor command is specified by an # environment variable that the user controls. subprocess.run(f"{editor} {path}", check=True, shell=True) # noqa: S602 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/commands/exploded.py0000644000175100001770000000656014653725311016752 0ustar00runnerdocker""" Contains commands for dealing with exploded and imploded forms. """ import os import asdf from asdf import AsdfFile from .main import Command __all__ = ["implode", "explode"] class Implode(Command): @classmethod def setup_arguments(cls, subparsers): parser = subparsers.add_parser( "implode", help="Implode a ASDF file.", description="""Combine a ASDF file, where the data may be stored in multiple ASDF files, into a single ASDF file.""", ) parser.add_argument("filename", nargs=1, help="""The ASDF file to implode.""") parser.add_argument( "--output", "-o", type=str, nargs="?", help="""The name of the output file. If not provided, it will be the name of the input file with "_all" appended.""", ) parser.add_argument( "--resolve-references", "-r", action="store_true", help="""Resolve all references and store them directly in the output file.""", ) parser.set_defaults(func=cls.run) return parser @classmethod def run(cls, args): return implode(args.filename[0], args.output, args.resolve_references) def implode(input_, output=None, resolve_references=False): """ Implode a given ASDF file, which may reference external data, back into a single ASDF file. Parameters ---------- input_ : str or file-like object The input file. output : str of file-like object The output file. resolve_references : bool, optional If `True` resolve all external references before saving. """ if output is None: base, ext = os.path.splitext(input_) output = base + "_all" + ".asdf" with asdf.open(input_) as ff: ff2 = AsdfFile(ff) if resolve_references: ff2.resolve_references() ff2.write_to(output, all_array_storage="internal") class Explode(Command): @classmethod def setup_arguments(cls, subparsers): parser = subparsers.add_parser( "explode", help="Explode a ASDF file.", description="""From a single ASDF file, create a set of ASDF files where each data block is stored in a separate file.""", ) parser.add_argument("filename", nargs=1, help="""The ASDF file to explode.""") parser.add_argument( "--output", "-o", type=str, nargs="?", help="""The name of the output file. If not provided, it will be the name of the input file with "_exploded" appended.""", ) parser.set_defaults(func=cls.run) return parser @classmethod def run(cls, args): return explode(args.filename[0], args.output) def explode(input_, output=None): """ Explode a given ASDF file so each data block is in a separate file. Parameters ---------- input_ : str or file-like object The input file. output : str of file-like object The output file. """ if output is None: base, ext = os.path.splitext(input_) output = base + "_exploded" + ".asdf" with asdf.open(input_) as ff: ff.write_to(output, all_array_storage="external") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/commands/extension.py0000644000175100001770000000515014653725311017154 0ustar00runnerdocker""" Implementation of command for reporting information about installed extensions. """ from asdf._entry_points import get_extensions from .main import Command __all__ = ["find_extensions"] class QueryExtension(Command): # pragma: no cover """This class is the plugin implementation for the asdftool runner.""" @classmethod def setup_arguments(cls, subparsers): parser = subparsers.add_parser( "extensions", help="Show information about installed extensions", description="""Reports information about installed ASDF extensions""", ) display_group = parser.add_mutually_exclusive_group() display_group.add_argument( "-s", "--summary", action="store_true", help="Display only the installed extensions themselves", ) display_group.add_argument( "-t", "--tags-only", action="store_true", help="Display tags from installed extensions, but no other information", ) parser.set_defaults(func=cls.run) return parser @classmethod def run(cls, args): return find_extensions(args.summary, args.tags_only) def _format_extension(ext): uri = "(none)" if ext.extension_uri is None else f"'{ext.extension_uri}'" return f"Extension URI: {uri} package: {ext.package_name} ({ext.package_version}) class: {ext.class_name}" def _format_type_name(type_): if isinstance(type_, str): return type_ return f"{type_.__module__}.{type_.__name__}" def _print_extension_details(ext, tags_only): tag_uris = [t.tag_uri for t in ext.tags] for typ in ext.types: if isinstance(typ.name, list): for name in typ.name: tag_uris.append(typ.make_yaml_tag(name)) elif typ.name is not None: tag_uris.append(typ.make_yaml_tag(typ.name)) if len(tag_uris) > 0: print("tags:") for tag_uri in sorted(tag_uris): print(f" - {tag_uri}") if not tags_only: types = [] for converter in ext.converters: for typ in converter.types: types.append(typ) for typ in ext.types: types.extend(typ.types) if len(types) > 0: print("types:") for typ in sorted(types, key=_format_type_name): print(f" - {_format_type_name(typ)}") def find_extensions(summary, tags_only): for ext in get_extensions(): print(_format_extension(ext)) if not summary: _print_extension_details(ext, tags_only) print() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/commands/info.py0000644000175100001770000000227214653725311016075 0ustar00runnerdocker""" Commands for displaying summaries of ASDF trees """ from asdf import _convenience as convenience from .main import Command __all__ = ["info"] class Info(Command): @classmethod def setup_arguments(cls, subparsers): parser = subparsers.add_parser( "info", help="Print a rendering of an ASDF tree.", description="Print a rendering of an ASDF tree.", ) parser.add_argument("filename", help="ASDF file to render") parser.add_argument("--max-rows", type=int, help="maximum number of lines") parser.add_argument("--max-cols", type=int, help="maximum length of line") parser.add_argument("--show-values", dest="show_values", action="store_true") parser.add_argument("--no-show-values", dest="show_values", action="store_false") parser.set_defaults(show_values=True) parser.set_defaults(func=cls.run) return parser @classmethod def run(cls, args): info(args.filename, args.max_rows, args.max_cols, args.show_values) def info(filename, max_rows, max_cols, show_values): convenience.info(filename, max_rows=max_rows, max_cols=max_cols, show_values=show_values) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/commands/main.py0000644000175100001770000000354414653725311016071 0ustar00runnerdockerimport argparse import logging import sys from asdf import util # This list is ordered in order of average workflow command_order = ["Explode", "Implode"] class Command: @classmethod def setup_arguments(cls, subparsers): raise NotImplementedError @classmethod def run(cls, args): raise NotImplementedError def make_argparser(): """ Most of the real work is handled by the subcommands in the commands subpackage. """ def help_(args): parser.print_help() return 0 parser = argparse.ArgumentParser("asdftool", description="Commandline utilities for managing ASDF files.") parser.add_argument("--verbose", "-v", action="store_true", help="Increase verbosity") subparsers = parser.add_subparsers(title="subcommands", description="valid subcommands") help_parser = subparsers.add_parser("help", help="Display usage information") help_parser.set_defaults(func=help_) commands = {x.__name__: x for x in util._iter_subclasses(Command)} for command in command_order: commands[str(command)].setup_arguments(subparsers) del commands[command] for _, command in sorted(commands.items()): command.setup_arguments(subparsers) return parser, subparsers def main_from_args(args): parser, subparsers = make_argparser() args = parser.parse_args(args) # Only needed for Python 3, apparently, but can't hurt if not hasattr(args, "func"): parser.print_help() return 2 try: result = args.func(args) except RuntimeError as e: logging.error(str(e)) return 1 except OSError as e: logging.error(str(e)) return e.errno if result is None: result = 0 return result def main(args=None): if args is None: args = sys.argv[1:] sys.exit(main_from_args(args)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/commands/tags.py0000644000175100001770000000276714653725311016111 0ustar00runnerdocker""" Implementation of command for displaying available tags in asdf """ import sys from asdf import AsdfFile from .main import Command __all__ = ["list_tags"] class TagLister(Command): # pragma: no cover """This class is the plugin implementation for the asdftool runner.""" @classmethod def setup_arguments(cls, subparsers): parser = subparsers.add_parser( "tags", help="List currently available tags", description="""Lists currently available tags.""", ) parser.add_argument( "-d", "--display-classes", action="store_true", help="""Display associated class names in addition to tags""", ) parser.set_defaults(func=cls.run) return parser @classmethod def run(cls, args): return list_tags(display_classes=args.display_classes) def _format_type(typ): if isinstance(typ, str): return typ return f"{typ.__module__}.{typ.__name__}" def list_tags(display_classes=False, iostream=sys.stdout): """Function to list tags""" af = AsdfFile() tag_pairs = [] for tag in af.extension_manager._converters_by_tag: tag_pairs.append((tag, af.extension_manager.get_converter_for_tag(tag).types)) for tag, types in sorted(tag_pairs, key=lambda pair: pair[0]): string = str(tag) if display_classes: string += ": " + ", ".join(_format_type(t) for t in types) iostream.write(string + "\n") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/commands/to_yaml.py0000644000175100001770000000373314653725311016611 0ustar00runnerdocker""" Contains commands for dealing with exploded and imploded forms. """ import os import asdf from asdf import AsdfFile from .main import Command __all__ = ["to_yaml"] class ToYaml(Command): @classmethod def setup_arguments(cls, subparsers): parser = subparsers.add_parser( "to_yaml", help="Convert as ASDF file to pure YAML.", description="""Convert all data to inline YAML so the ASDF file contains no binary blocks.""", ) parser.add_argument("filename", nargs=1, help="""The ASDF file to convert to YAML.""") parser.add_argument( "--output", "-o", type=str, nargs="?", help="""The name of the output file. If not provided, it will be the name of the input file with a '.yaml' extension.""", ) parser.add_argument( "--resolve-references", "-r", action="store_true", help="""Resolve all references and store them directly in the output file.""", ) parser.set_defaults(func=cls.run) return parser @classmethod def run(cls, args): return to_yaml(args.filename[0], args.output, args.resolve_references) def to_yaml(input_, output=None, resolve_references=False): """ Implode a given ASDF file, which may reference external data, back into a single ASDF file. Parameters ---------- input_ : str or file-like object The input file. output : str of file-like object The output file. resolve_references : bool, optional If `True` resolve all external references before saving. """ if output is None: base, _ = os.path.splitext(input_) output = base + ".yaml" with asdf.open(input_) as ff: ff2 = AsdfFile(ff) if resolve_references: ff2.resolve_references() ff2.write_to(output, all_array_storage="inline") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/config.py0000644000175100001770000004147614653725311014617 0ustar00runnerdocker""" Methods for getting and setting asdf global configuration options. """ import collections import copy import threading from contextlib import contextmanager from . import _entry_points, util, versioning from ._helpers import validate_version from .extension import ExtensionProxy from .resource import ResourceManager, ResourceMappingProxy __all__ = ["AsdfConfig", "get_config", "config_context"] DEFAULT_VALIDATE_ON_READ = True DEFAULT_DEFAULT_VERSION = str(versioning.default_version) DEFAULT_LEGACY_FILL_SCHEMA_DEFAULTS = True DEFAULT_IO_BLOCK_SIZE = -1 # auto DEFAULT_ARRAY_INLINE_THRESHOLD = None DEFAULT_ALL_ARRAY_STORAGE = None DEFAULT_ALL_ARRAY_COMPRESSION = "input" DEFAULT_ALL_ARRAY_COMPRESSION_KWARGS = None DEFAULT_DEFAULT_ARRAY_SAVE_BASE = True DEFAULT_CONVERT_UNKNOWN_NDARRAY_SUBCLASSES = True DEFAULT_LAZY_TREE = False class AsdfConfig: """ Container for ASDF configuration options. Users are not intended to construct this object directly; instead, use the `asdf.get_config` and `asdf.config_context` module methods. """ def __init__(self): self._resource_mappings = None self._resource_manager = None self._extensions = None self._validate_on_read = DEFAULT_VALIDATE_ON_READ self._default_version = DEFAULT_DEFAULT_VERSION self._legacy_fill_schema_defaults = DEFAULT_LEGACY_FILL_SCHEMA_DEFAULTS self._io_block_size = DEFAULT_IO_BLOCK_SIZE self._array_inline_threshold = DEFAULT_ARRAY_INLINE_THRESHOLD self._all_array_storage = DEFAULT_ALL_ARRAY_STORAGE self._all_array_compression = DEFAULT_ALL_ARRAY_COMPRESSION self._all_array_compression_kwargs = DEFAULT_ALL_ARRAY_COMPRESSION_KWARGS self._default_array_save_base = DEFAULT_DEFAULT_ARRAY_SAVE_BASE self._convert_unknown_ndarray_subclasses = DEFAULT_CONVERT_UNKNOWN_NDARRAY_SUBCLASSES self._lazy_tree = DEFAULT_LAZY_TREE self._lock = threading.RLock() @property def resource_mappings(self): """ Get the list of registered resource mapping instances. Unless overridden by user configuration, this list contains every mapping registered with an entry point. Returns ------- list of asdf.resource.ResourceMappingProxy """ if self._resource_mappings is None: with self._lock: if self._resource_mappings is None: self._resource_mappings = _entry_points.get_resource_mappings() return self._resource_mappings def add_resource_mapping(self, mapping): """ Register a new resource mapping. The new mapping will take precedence over all previously registered mappings. Parameters ---------- mapping : collections.abc.Mapping Map of `str` resource URI to `bytes` content """ with self._lock: mapping = ResourceMappingProxy.maybe_wrap(mapping) # Insert at the beginning of the list so that # ResourceManager uses the new mapping first. resource_mappings = [mapping] + [r for r in self.resource_mappings if r != mapping] self._resource_mappings = resource_mappings self._resource_manager = None def remove_resource_mapping(self, mapping=None, *, package=None): """ Remove a registered resource mapping. Parameters ---------- mapping : collections.abc.Mapping, optional Mapping to remove. package : str, optional Remove only extensions provided by this package. If the ``mapping`` argument is omitted, then all mappings from this package will be removed. """ if mapping is None and package is None: msg = "Must specify at least one of mapping or package" raise ValueError(msg) if mapping is not None: mapping = ResourceMappingProxy.maybe_wrap(mapping) def _remove_condition(m): result = True if mapping is not None: result = result and m == mapping if package is not None: result = result and m.package_name == package return result with self._lock: self._resource_mappings = [m for m in self.resource_mappings if not _remove_condition(m)] self._resource_manager = None def reset_resources(self): """ Reset registered resource mappings to the default list provided as entry points. """ with self._lock: self._resource_mappings = None self._resource_manager = None @property def resource_manager(self): """ Get the `asdf.resource.ResourceManager` instance. Includes resources from registered resource mappings and any mappings added at runtime. Returns ------- `asdf.resource.ResourceManager` """ if self._resource_manager is None: with self._lock: if self._resource_manager is None: self._resource_manager = ResourceManager(self.resource_mappings) return self._resource_manager @property def extensions(self): """ Get the list of registered extensions. Returns ------- list of asdf.extension.ExtensionProxy """ if self._extensions is None: with self._lock: if self._extensions is None: self._extensions = _entry_points.get_extensions() return self._extensions def add_extension(self, extension): """ Register a new extension. The new extension will take precedence over all previously registered extensions. Parameters ---------- extension : asdf.extension.Extension """ with self._lock: extension = ExtensionProxy.maybe_wrap(extension) self._extensions = [extension] + [e for e in self.extensions if e != extension] def remove_extension(self, extension=None, *, package=None): """ Remove a registered extension. Parameters ---------- extension : asdf.extension.Extension or str, optional An extension instance or URI pattern to remove. package : str, optional Remove only extensions provided by this package. If the ``extension`` argument is omitted, then all extensions from this package will be removed. """ if extension is None and package is None: msg = "Must specify at least one of extension or package" raise ValueError(msg) if extension is not None and not isinstance(extension, str): extension = ExtensionProxy.maybe_wrap(extension) def _remove_condition(e): result = True if isinstance(extension, str): result = result and util.uri_match(extension, e.extension_uri) elif isinstance(extension, ExtensionProxy): result = result and e == extension if package is not None: result = result and e.package_name == package return result with self._lock: self._extensions = [e for e in self.extensions if not _remove_condition(e)] def reset_extensions(self): """ Reset extensions to the default list registered via entry points. """ with self._lock: self._extensions = None @property def default_version(self): """ Get the default ASDF Standard version used for new files. Returns ------- str """ return self._default_version @default_version.setter def default_version(self, value): """ Set the default ASDF Standard version used for new files. Parameters ---------- value : str """ self._default_version = validate_version(value) @property def io_block_size(self): """ Get the block size used when reading and writing files. Returns ------- int Block size, or -1 to use the filesystem's preferred block size. """ return self._io_block_size @io_block_size.setter def io_block_size(self, value): """ Set the block size used when reading and writing files. Parameters ---------- value : int Block size, or -1 to use the filesystem's preferred block size. """ self._io_block_size = value @property def legacy_fill_schema_defaults(self): """ Get the configuration that controls filling defaults from schemas for older ASDF Standard versions. If `True`, missing default values will be filled from the schema when reading files from ASDF Standard <= 1.5.0. Later versions of the standard do not support removing or filling schema defaults. Returns ------- bool """ return self._legacy_fill_schema_defaults @legacy_fill_schema_defaults.setter def legacy_fill_schema_defaults(self, value): """ Set the flag that controls filling defaults from schemas for older ASDF Standard versions. Parameters ---------- value : bool """ self._legacy_fill_schema_defaults = value @property def array_inline_threshold(self): """ Get the threshold below which arrays are automatically written as inline YAML literals instead of binary blocks. This number is compared to number of elements in the array. Returns ------- int or None Integer threshold, or None to disable automatic selection of the array storage type. """ return self._array_inline_threshold @array_inline_threshold.setter def array_inline_threshold(self, value): """ Set the threshold below which arrays are automatically written as inline YAML literals instead of binary blocks. This number is compared to number of elements in the array. Parameters ---------- value : int or None Integer threshold, or None to disable automatic selection of the array storage type. """ self._array_inline_threshold = value @property def all_array_storage(self): """ Override the array storage type of all blocks in the file immediately before writing. Must be one of the following strings or `None`: - ``internal``: The default. The array data will be stored in a binary block in the same ASDF file. - ``external``: Store the data in a binary block in a separate ASDF file. - ``inline``: Store the data as YAML inline in the tree. """ return self._all_array_storage @all_array_storage.setter def all_array_storage(self, value): if value not in (None, "internal", "external", "inline"): msg = f"Invalid value for all_array_storage: '{value}'" raise ValueError(msg) self._all_array_storage = value @property def all_array_compression(self): """ Override the compression type on all binary blocks in the file. Must be one of the following strings, `None` or a label supported by a `asdf.extension.Compressor`: - ``''`` or `None`: No compression. - ``zlib``: Use zlib compression. - ``bzp2``: Use bzip2 compression. - ``lz4``: Use lz4 compression. - ``input``: Use the same compression as in the file read. If there is no prior file, acts as None """ return self._all_array_compression @all_array_compression.setter def all_array_compression(self, value): # local to avoid circular import from asdf._compression import validate self._all_array_compression = validate(value) @property def all_array_compression_kwargs(self): """ Dictionary of keyword arguments provided to the compressor during block compression (or `None` for no keyword arguments) """ return self._all_array_compression_kwargs @all_array_compression_kwargs.setter def all_array_compression_kwargs(self, value): if value is not None and not isinstance(value, collections.abc.Mapping): msg = f"Invalid value for all_array_compression_kwargs: '{value}'" raise ValueError(msg) self._all_array_compression_kwargs = value @property def default_array_save_base(self): """ Option to control if when saving arrays the base array should be saved (so views of the same array will refer to offsets/strides of the same block). """ return self._default_array_save_base @default_array_save_base.setter def default_array_save_base(self, value): if not isinstance(value, bool): msg = "default_array_save_base must be a bool" raise ValueError(msg) self._default_array_save_base = value @property def validate_on_read(self): """ Get configuration that controls schema validation of ASDF files on read. Returns ------- bool """ return self._validate_on_read @validate_on_read.setter def validate_on_read(self, value): """ Set the configuration that controls schema validation of ASDF files on read. If `True`, newly opened files will be validated. Parameters ---------- value : bool """ self._validate_on_read = value @property def convert_unknown_ndarray_subclasses(self): """ Get configuration that controls if ndarray subclasses (subclasses that aren't otherwise handled by a specific converter) are serialized as ndarray. If `True`, instances of these subclasses will appear in ASDF files as ndarrays and when loaded, will load as ndarrays. Note that these conversions will result in an AsdfConversionWarning being issued as this support for converting subclasses will be removed in a future version of ASDF. Returns ------- bool """ return self._convert_unknown_ndarray_subclasses @convert_unknown_ndarray_subclasses.setter def convert_unknown_ndarray_subclasses(self, value): self._convert_unknown_ndarray_subclasses = value @property def lazy_tree(self): """ Get configuration that controls if ASDF tree contents are lazily converted to custom objects or if all custom objects are created when the file is opened. See the ``lazy_tree`` argument for `asdf.open`. Returns ------- bool """ return self._lazy_tree @lazy_tree.setter def lazy_tree(self, value): self._lazy_tree = value def __repr__(self): return ( "" ) class _ConfigLocal(threading.local): def __init__(self): self.config_stack = [] _global_config = AsdfConfig() _local = _ConfigLocal() def get_config(): """ Get the current config, which may have been altered by one or more surrounding calls to `asdf.config_context`. Returns ------- asdf.config.AsdfConfig """ if len(_local.config_stack) == 0: return _global_config return _local.config_stack[-1] @contextmanager def config_context(): """ Context manager that temporarily overrides asdf configuration. The context yields an `asdf.config.AsdfConfig` instance that can be modified without affecting code outside of the context. """ base_config = _global_config if len(_local.config_stack) == 0 else _local.config_stack[-1] config = copy.copy(base_config) _local.config_stack.append(config) try: yield config finally: _local.config_stack.pop() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/conftest.py0000644000175100001770000000214214653725311015162 0ustar00runnerdockerimport os import pytest # We ignore these files because these modules create deprecation warnings on # import. When warnings are turned into errors this will completely prevent # test collection collect_ignore = ["asdf.py", "stream.py"] def pytest_collection_modifyitems(items): # Turn warnings into errors for all tests, this is needed # as running tests through pyargs will not use settings # defined in pyproject.toml for item in items: item.add_marker(pytest.mark.filterwarnings("error"), False) @pytest.fixture(scope="session", autouse=True) def _temp_cwd(tmp_path_factory): """ This fixture creates a temporary current working directory for the test session, so that docstring tests that write files don't clutter up the real cwd. """ original_cwd = os.getcwd() try: os.chdir(tmp_path_factory.mktemp("cwd")) yield finally: os.chdir(original_cwd) def pytest_addoption(parser): parser.addoption( "--jsonschema", action="store_true", default=False, help="Run jsonschema test suite tests", ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/constants.py0000644000175100001770000000121214653725311015346 0ustar00runnerdockerimport numpy as np ASDF_MAGIC = b"#ASDF" BLOCK_MAGIC = b"\xd3BLK" FITS_MAGIC = b"SIMPLE" BLOCK_HEADER_BOILERPLATE_SIZE = 6 ASDF_STANDARD_COMMENT = b"ASDF_STANDARD" INDEX_HEADER = b"#ASDF BLOCK INDEX" # The maximum number of blocks supported MAX_BLOCKS = 2**16 MAX_BLOCKS_DIGITS = int(np.ceil(np.log10(MAX_BLOCKS) + 1)) YAML_TAG_PREFIX = "tag:yaml.org,2002:" YAML_END_MARKER_REGEX = rb"\r?\n\.\.\.((\r?\n)|$)" STSCI_SCHEMA_URI_BASE = "http://stsci.edu/schemas/" STSCI_SCHEMA_TAG_BASE = "tag:stsci.edu:asdf" BLOCK_FLAG_STREAMED = 0x1 # ASDF max number size MAX_BITS = 63 MAX_NUMBER = (1 << MAX_BITS) - 1 MIN_NUMBER = -((1 << MAX_BITS) - 2) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/exceptions.py0000644000175100001770000000443214653725311015522 0ustar00runnerdockerfrom yaml.representer import RepresenterError from asdf._jsonschema import ValidationError __all__ = [ "AsdfConversionWarning", "AsdfDeprecationWarning", "AsdfLazyReferenceError", "AsdfManifestURIMismatchWarning", "AsdfPackageVersionWarning", "AsdfProvisionalAPIWarning", "AsdfSerializationError", "AsdfWarning", "DelimiterNotFoundError", "ValidationError", ] class AsdfWarning(Warning): """ The base warning class from which all ASDF warnings should inherit. """ class AsdfDeprecationWarning(AsdfWarning, DeprecationWarning): """ A warning class to indicate a deprecated feature. """ class AsdfConversionWarning(AsdfWarning): """ Warning class used for failures to convert data into custom types. """ class AsdfBlockIndexWarning(AsdfWarning): """ Warning class to indicate that a file was read with an invalid block index """ class DelimiterNotFoundError(ValueError): """ Indicates that a delimiter was not found when reading or seeking through a file. """ class AsdfProvisionalAPIWarning(AsdfWarning, FutureWarning): """ Used for provisional features where breaking API changes might be introduced at any point (including minor releases). These features are likely to be added in a future ASDF version. However, Use of provisional features is highly discouraged for production code. """ class AsdfPackageVersionWarning(AsdfWarning): """ A warning indicating a package version mismatch """ class AsdfManifestURIMismatchWarning(AsdfWarning): """ A warning indicaing that an extension registered with a manifest contains a id that does not match the uri of the manifest. """ class AsdfLazyReferenceError(ReferenceError): """ Indicates that the lazy tree node failed to resolve a reference to an AsdfFile instance. This likely means the AsdfFile was garbage collected and you may need to update your code to keep the AsdfFile in memory (by keeping a reference). """ class AsdfSerializationError(RepresenterError): """ An object failed serialization by asdf and by yaml. This likely indicates that the object does not have a supporting asdf Converter and needs to be manually converted to a supported type. """ ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1530983 asdf-3.4.0/asdf/extension/0000755000175100001770000000000014653725331015002 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/extension/__init__.py0000644000175100001770000000133114653725311017107 0ustar00runnerdocker""" Support for plugins that extend asdf to serialize additional custom types. """ from ._compressor import Compressor from ._converter import Converter, ConverterProxy from ._extension import Extension, ExtensionProxy from ._manager import ExtensionManager, get_cached_extension_manager from ._manifest import ManifestExtension from ._serialization_context import SerializationContext from ._tag import TagDefinition from ._validator import Validator __all__ = [ # New API "Compressor", "Converter", "ConverterProxy", "Extension", "ExtensionManager", "ExtensionProxy", "ManifestExtension", "SerializationContext", "TagDefinition", "Validator", "get_cached_extension_manager", ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/extension/_compressor.py0000644000175100001770000000471514653725311017714 0ustar00runnerdocker""" Compressor is an interface to implement extensions to the compression module. Extensions will typically subclass the Compressor ABC and provide that subclass as a setuptools entry point. Note that this interface has similar patterns to Converter. This interface is designed for compression and decompression of ASDF binary array blocks, while Converter is designed for serialization of custom Python types into the YAML tree. """ import abc class Compressor(abc.ABC): """ Abstract base class for plugins that compress binary data. Implementing classes must provide the ``labels`` property, and at least one of the `compress()` and `decompress()` methods. May also provide a constructor. """ @classmethod def __subclasshook__(cls, class_): if cls is Compressor: return hasattr(class_, "label") and (hasattr(class_, "compress") or hasattr(class_, "decompress")) return NotImplemented # pragma: no cover @property @abc.abstractmethod def label(self): """ Get the 4-byte label identifying this compression Returns ------- label : bytes The compression label """ def compress(self, data, **kwargs): """ Compress ``data``, yielding the results. The yield may be block-by-block, or all at once. Parameters ---------- data : memoryview The data to compress. Must be contiguous and 1D, with the underlying ``itemsize`` preserved. **kwargs Keyword arguments to be passed to the underlying compression function Yields ------ compressed : bytes-like A block of compressed data """ raise NotImplementedError def decompress(self, data, out, **kwargs): """ Decompress ``data``, writing the result into ``out``. Parameters ---------- data : Iterable of bytes-like An Iterable of bytes-like objects containing chunks of compressed data. out : read-write bytes-like A contiguous, 1D output array, of equal or greater length than the decompressed data. **kwargs Keyword arguments to be passed to the underlying decompression function Returns ------- nbytes : int The number of bytes written to ``out`` """ raise NotImplementedError ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/extension/_converter.py0000644000175100001770000003020714653725311017522 0ustar00runnerdocker""" Support for Converter, the new API for serializing custom types. Will eventually replace the `asdf.types` module. """ import abc import warnings from asdf.exceptions import AsdfWarning from asdf.util import get_class_name, uri_match class Converter(abc.ABC): """ Abstract base class for plugins that convert nodes from the parsed YAML tree into custom objects, and vice versa. Implementing classes must provide the `tags` and `types` properties and `to_yaml_tree` and `from_yaml_tree` methods. The ``select_tag`` method is optional. If implemented, ``select_tag`` should accept 3 parameters obj : object Instance of the custom type being converted. Guaranteed to be an instance of one of the types listed in the `types` property. tags : list of str List of active tags to choose from. Guaranteed to match one of the tag patterns listed in the 'tags' property. ctx : asdf.asdf.SerializationContext Context of the current serialization request. and return a str, the selected tag (should be one of tags) or `None` which will trigger the result of ``to_yaml_tree`` to be used to look up the next converter for this object. The ``lazy`` attribute is optional. If ``True`` asdf will pass "lazy" objects to the converter. If ``False`` (or not defined) asdf will convert all child objects before calling `from_yaml_tree`. """ @classmethod def __subclasshook__(cls, class_): if cls is Converter: return ( hasattr(class_, "tags") and hasattr(class_, "types") and hasattr(class_, "to_yaml_tree") and hasattr(class_, "from_yaml_tree") ) return NotImplemented # pragma: no cover @property @abc.abstractmethod def tags(self): """ Get the YAML tags that this converter is capable of handling. URI patterns are permitted, see `asdf.util.uri_match` for details. Returns ------- iterable of str Tag URIs or URI patterns. """ @property @abc.abstractmethod def types(self): """ Get the Python types that this converter is capable of handling. Returns ------- iterable of str or type If str, the fully qualified class name of the type. """ @abc.abstractmethod def to_yaml_tree(self, obj, tag, ctx): """ Convert an object into a node suitable for YAML serialization. This method is not responsible for writing actual YAML; rather, it converts an instance of a custom type to a built-in Python object type (such as dict, list, str, or number), which can then be automatically serialized to YAML as needed. For container types returned by this method (dict or list), the children of the container need not themselves be converted. Any list elements or dict values will be converted by subsequent calls to to_yaml_tree implementations. The returned node must be an instance of `dict`, `list`, or `str`. Children may be any type supported by an available Converter. Parameters ---------- obj : object Instance of a custom type to be serialized. Guaranteed to be an instance of one of the types listed in the `types` property. tag : str The tag identifying the YAML type that ``obj`` should be converted into. Selected by a call to this converter's select_tag method. ctx : asdf.extension.SerializationContext The context of the current serialization request. Returns ------- dict or list or str The YAML node representation of the object. """ @abc.abstractmethod def from_yaml_tree(self, node, tag, ctx): """ Convert a YAML node into an instance of a custom type. For container types received by this method (dict or list), the children of the container will have already been converted by prior calls to from_yaml_tree implementations unless ``lazy_tree`` was set to ``True`` for `asdf.open`. With a lazy tree the container types will be `asdf.lazy_nodes` (which act like dict or list but convert child objects when accessed). Note on circular references: trees that reference themselves among their descendants must be handled with care. Most implementations need not concern themselves with this case, but if the custom type supports circular references, then the implementation of this method will need to return a generator. Consult the documentation for more details. Parameters ---------- node : dict or list or str The YAML node to convert. tag : str The YAML tag of the object being converted. ctx : asdf.extension.SerializationContext The context of the current deserialization request. Returns ------- object An instance of one of the types listed in the `types` property, or a generator that yields such an instance. """ class ConverterProxy(Converter): """ Proxy that wraps a `Converter` and provides default implementations of optional methods. """ def __init__(self, delegate, extension): if not isinstance(delegate, Converter): msg = "Converter must implement the asdf.extension.Converter interface" raise TypeError(msg) self._delegate = delegate self._extension = extension self._class_name = get_class_name(delegate) # Sort these out up-front so that errors are raised when the extension is loaded # and not in the middle of the user's session. The extension will fail to load # and a warning will be emitted, but it won't crash the program. relevant_tags = set() for tag in delegate.tags: if isinstance(tag, str): relevant_tags.update(t.tag_uri for t in extension.tags if uri_match(tag, t.tag_uri)) else: msg = "Converter property 'tags' must contain str values" raise TypeError(msg) if len(relevant_tags) > 1 and not hasattr(delegate, "select_tag"): # we cannot use isinstance here because Converter supports # virtual subclasses if Converter in delegate.__class__.__mro__: # prior to asdf 3.0 Converter provided a default select_tag # to provide backwards compatibility allow Converter subclasses # to be registered with >1 tag but produce a warning msg = ( "Converter handles multiple tags for this extension, " "but does not implement a select_tag method. " "This previously worked because Converter subclasses inherited " "the now removed select_tag. This will be an error in a future " "version of asdf" ) warnings.warn(msg, AsdfWarning) else: msg = "Converter handles multiple tags for this extension, but does not implement a select_tag method." raise RuntimeError(msg) self._tags = sorted(relevant_tags) self._types = [] if not len(self._tags) and not hasattr(delegate, "select_tag"): # this converter supports no tags so don't inspect the types return for typ in delegate.types: if isinstance(typ, (str, type)): self._types.append(typ) else: msg = "Converter property 'types' must contain str or type values" raise TypeError(msg) @property def lazy(self): """ Boolean indicating if this Converter supports "lazy" node objects Returns ------- bool """ return getattr(self._delegate, "lazy", False) @property def tags(self): """ Get the list of tag URIs that this converter is capable of handling. Returns ------- list of str """ return self._tags @property def types(self): """ Get the Python types that this converter is capable of handling. Returns ------- list of type or str """ return self._types def select_tag(self, obj, ctx): """ Select the tag to use when converting an object to YAML. Parameters ---------- obj : object Instance of the custom type being converted. ctx : asdf.extension.SerializationContext Serialization parameters. Returns ------- str or None Selected tag or `None` to defer conversion. """ method = getattr(self._delegate, "select_tag", None) if method is None: return self._tags[0] return method(obj, self._tags, ctx) def to_yaml_tree(self, obj, tag, ctx): """ Convert an object into a node suitable for YAML serialization. Parameters ---------- obj : object Instance of a custom type to be serialized. tag : str The tag identifying the YAML type that ``obj`` should be converted into. ctx : asdf.extension.SerializationContext Serialization parameters. Returns ------- object The YAML node representation of the object. """ return self._delegate.to_yaml_tree(obj, tag, ctx) def from_yaml_tree(self, node, tag, ctx): """ Convert a YAML node into an instance of a custom type. Parameters ---------- tree : dict or list or str The YAML node to convert. tag : str The YAML tag of the object being converted. ctx : asdf.extension.SerializationContext Serialization parameters. Returns ------- object """ return self._delegate.from_yaml_tree(node, tag, ctx) @property def delegate(self): """ Get the wrapped converter instance. Returns ------- asdf.extension.Converter """ return self._delegate @property def extension(self): """ Get the extension that provided this converter. Returns ------- asdf.extension.ExtensionProxy """ return self._extension @property def package_name(self): """ Get the name of the Python package of this converter's extension. This may not be the same package that implements the converter's class. Returns ------- str or None Package name, or `None` if the extension was added at runtime. """ return self.extension.package_name @property def package_version(self): """ Get the version of the Python package of this converter's extension. This may not be the same package that implements the converter's class. Returns ------- str or None Package version, or `None` if the extension was added at runtime. """ return self.extension.package_version @property def class_name(self): """ Get the fully qualified class name of this converter. Returns ------- str """ return self._class_name def __eq__(self, other): if isinstance(other, ConverterProxy): return other.delegate is self.delegate and other.extension is self.extension return False def __hash__(self): return hash((id(self.delegate), id(self.extension))) def __repr__(self): package_description = "(none)" if self.package_name is None else f"{self.package_name}=={self.package_version}" return f"" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/extension/_extension.py0000644000175100001770000002635114653725311017534 0ustar00runnerdockerimport abc from packaging.specifiers import SpecifierSet from asdf.util import get_class_name from ._compressor import Compressor from ._converter import ConverterProxy from ._tag import TagDefinition from ._validator import Validator class Extension(abc.ABC): """ Abstract base class defining an extension to ASDF. Implementing classes must provide the `extension_uri`. Other properties are optional. """ @classmethod def __subclasshook__(cls, class_): if cls is Extension: return hasattr(class_, "extension_uri") return NotImplemented # pragma: no cover @property @abc.abstractmethod def extension_uri(self): """ Get the URI of the extension to the ASDF Standard implemented by this class. Note that this may not uniquely identify the class itself. Returns ------- str """ @property def legacy_class_names(self): """ Get the set of fully-qualified class names used by older versions of this extension. This allows a new-style implementation of an extension to prevent warnings when a legacy extension is missing. Returns ------- iterable of str """ return set() @property def asdf_standard_requirement(self): """ Get the ASDF Standard version requirement for this extension. Returns ------- str or None If str, PEP 440 version specifier. If None, support all versions. """ return @property def converters(self): """ Get the `asdf.extension.Converter` instances for tags and Python types supported by this extension. Returns ------- iterable of asdf.extension.Converter """ return [] @property def tags(self): """ Get the YAML tags supported by this extension. Returns ------- iterable of str or asdf.extension.TagDefinition """ return [] @property def compressors(self): """ Get the `asdf.extension.Compressor` instances for compression schemes supported by this extension. Returns ------- iterable of asdf.extension.Compressor """ return [] @property def yaml_tag_handles(self): """ Get a dictionary of custom yaml TAG handles defined by the extension. The dictionary key indicates the TAG handles to be placed in the YAML header, the value defines the string for tag replacement. See https://yaml.org/spec/1.1/#tag%20shorthand/ Example: ``{"!foo!": "tag:nowhere.org:custom/"}`` Returns ------- dict """ return {} @property def validators(self): """ Get the `asdf.extension.Validator` instances for additional schema properties supported by this extension. Returns ------- iterable of asdf.extension.Validator """ return [] class ExtensionProxy(Extension): """ Proxy that wraps an extension, provides default implementations of optional methods, and carries additional information on the package that provided the extension. """ @classmethod def maybe_wrap(cls, delegate): if isinstance(delegate, ExtensionProxy): return delegate return ExtensionProxy(delegate) def __init__(self, delegate, package_name=None, package_version=None): if not isinstance(delegate, Extension): msg = "Extension must implement the Extension interface" raise TypeError(msg) self._delegate = delegate self._package_name = package_name self._package_version = package_version self._class_name = get_class_name(delegate) self._legacy = False # Sort these out up-front so that errors are raised when the extension is loaded # and not in the middle of the user's session. The extension will fail to load # and a warning will be emitted, but it won't crash the program. self._legacy_class_names = set() for class_name in getattr(self._delegate, "legacy_class_names", []): if isinstance(class_name, str): self._legacy_class_names.add(class_name) else: msg = "Extension property 'legacy_class_names' must contain str values" raise TypeError(msg) if self._legacy: self._legacy_class_names.add(self._class_name) value = getattr(self._delegate, "asdf_standard_requirement", None) if isinstance(value, str): self._asdf_standard_requirement = SpecifierSet(value) elif value is None: self._asdf_standard_requirement = SpecifierSet() else: msg = "Extension property 'asdf_standard_requirement' must be str or None" raise TypeError(msg) self._tags = [] for tag in getattr(self._delegate, "tags", []): if isinstance(tag, str): self._tags.append(TagDefinition(tag)) elif isinstance(tag, TagDefinition): self._tags.append(tag) else: msg = "Extension property 'tags' must contain str or asdf.extension.TagDefinition values" raise TypeError(msg) self._yaml_tag_handles = getattr(delegate, "yaml_tag_handles", {}) # Process the converters last, since they expect ExtensionProxy # properties to already be available. self._converters = [ConverterProxy(c, self) for c in getattr(self._delegate, "converters", [])] self._compressors = [] if hasattr(self._delegate, "compressors"): for compressor in self._delegate.compressors: if not isinstance(compressor, Compressor): msg = "Extension property 'compressors' must contain instances of asdf.extension.Compressor" raise TypeError(msg) self._compressors.append(compressor) self._validators = [] if hasattr(self._delegate, "validators"): for validator in self._delegate.validators: if not isinstance(validator, Validator): msg = "Extension property 'validators' must contain instances of asdf.extension.Validator" raise TypeError(msg) self._validators.append(validator) @property def extension_uri(self): """ Get the URI of the extension to the ASDF Standard implemented by this class. Note that this may not uniquely identify the class itself. Returns ------- str or None """ return getattr(self._delegate, "extension_uri", None) @property def legacy_class_names(self): """ Get the set of fully-qualified class names used by older versions of this extension. This allows a new-style implementation of an extension to prevent warnings when a legacy extension is missing. Returns ------- set of str """ return self._legacy_class_names @property def asdf_standard_requirement(self): """ Get the extension's ASDF Standard requirement. Returns ------- packaging.specifiers.SpecifierSet """ return self._asdf_standard_requirement @property def converters(self): """ Get the extension's converters. Returns ------- list of asdf.extension.Converter """ return self._converters @property def compressors(self): """ Get the extension's compressors. Returns ------- list of asdf.extension.Compressor """ return self._compressors @property def tags(self): """ Get the YAML tags supported by this extension. Returns ------- list of asdf.extension.TagDefinition """ return self._tags @property def types(self): """ Get the legacy extension's ExtensionType subclasses. Returns ------- iterable of asdf.type.ExtensionType """ return getattr(self._delegate, "types", []) @property def tag_mapping(self): """ Get the legacy extension's tag-to-schema-URI mapping. Returns ------- iterable of tuple or callable """ return getattr(self._delegate, "tag_mapping", []) @property def url_mapping(self): """ Get the legacy extension's schema-URI-to-URL mapping. Returns ------- iterable of tuple or callable """ return getattr(self._delegate, "url_mapping", []) @property def delegate(self): """ Get the wrapped extension instance. Returns ------- asdf.extension.Extension """ return self._delegate @property def package_name(self): """ Get the name of the Python package that provided this extension. Returns ------- str or None `None` if the extension was added at runtime. """ return self._package_name @property def package_version(self): """ Get the version of the Python package that provided the extension Returns ------- str or None `None` if the extension was added at runtime. """ return self._package_version @property def class_name(self): """ Get the fully qualified class name of the extension. Returns ------- str """ return self._class_name @property def legacy(self): """ False """ return self._legacy @property def yaml_tag_handles(self): """ Get a dictionary of custom yaml TAG handles defined by the extension. The dictionary key indicates the TAG handles to be placed in the YAML header, the value defines the string for tag replacement. See https://yaml.org/spec/1.1/#tag%20shorthand/ Example: ``{"!foo!": "tag:nowhere.org:custom/"}`` Returns ------- dict """ return self._yaml_tag_handles @property def validators(self): """ Get the `asdf.extension.Validator` instances for additional schema properties supported by this extension. Returns ------- list of asdf.extension.Validator """ return self._validators def __eq__(self, other): if isinstance(other, ExtensionProxy): return other.delegate is self.delegate return False def __hash__(self): return hash(id(self.delegate)) def __repr__(self): package_description = "(none)" if self.package_name is None else f"{self.package_name}=={self.package_version}" uri_description = "(none)" if self.extension_uri is None else self.extension_uri return ( f"" ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/extension/_manager.py0000644000175100001770000003100214653725311017117 0ustar00runnerdockerimport sys from functools import lru_cache from asdf.tagged import Tagged from asdf.util import get_class_name, uri_match from ._extension import ExtensionProxy def _resolve_type(path): """ Convert a class path (like the string "asdf.AsdfFile") to a class (``asdf.AsdfFile``) only if the module implementing the class has already been imported. Parameters ---------- path : str Path/name of class (for example, "asdf.AsdfFile") Returns ------- typ : class or None The class (if it's already been imported) or None """ if "." not in path: # check if this path is a module if path in sys.modules: return sys.modules[path] return None # this type is part of a module module_name, type_name = path.rsplit(".", maxsplit=1) # if the module is not imported, don't index it if module_name not in sys.modules: return None module = sys.modules[module_name] if not hasattr(module, type_name): # the imported module does not have this class, perhaps # it is dynamically created so do not index it yet return None return getattr(module, type_name) class ExtensionManager: """ Wraps a list of extensions and indexes their converters by tag and by Python type. Parameters ---------- extensions : iterable of asdf.extension.Extension List of enabled extensions to manage. Extensions placed earlier in the list take precedence. """ def __init__(self, extensions): self._extensions = [ExtensionProxy.maybe_wrap(e) for e in extensions] self._tag_defs_by_tag = {} self._converters_by_tag = {} # To optimize performance converters can be registered using either: # - the class/type they convert # - the name/path (string) of the class/type they convert # This allows the registration to continue without importing # every module for every extension (which would be needed to turn # the class paths into proper classes). Using class paths can be # complicated by packages that have private implementations of # classes that are exposed at a different 'public' location. # These private classes may change between minor versions # and would break converters that are registered using the private # class path. However, often libraries do not modify the module # of the 'public' class (so inspecting the class path returns # the private class path). One example of this in asdf is # Converter (exposed as ``asdf.extension.Converter`` but with # a class path of ``asdf.extension._converter.Converter``). # To allow converters to be registered with the public location # we will need to attempt to import the public class path # and then register the private class path after the class is # imported. We don't want to do this unnecessarily and since # class instances do not contain the public class path # we adopt a strategy of checking class paths and only # registering those that have already been imported. Thiss # is ok because asdf will only use the converter type # when attempting to serialize an object in memory (so the # public class path will already be imported at the time # the converter is needed). # first we store the converters in the order they are discovered # the key here can either be a class path (str) or class (type) converters_by_type = {} validators = set() for extension in self._extensions: for tag_def in extension.tags: if tag_def.tag_uri not in self._tag_defs_by_tag: self._tag_defs_by_tag[tag_def.tag_uri] = tag_def for converter in extension.converters: for tag in converter.tags: if tag not in self._converters_by_tag: self._converters_by_tag[tag] = converter for typ in converter.types: if typ not in converters_by_type: converters_by_type[typ] = converter validators.update(extension.validators) self._converters_by_class_path = {} self._converters_by_type = {} for type_or_path, converter in converters_by_type.items(): if isinstance(type_or_path, str): path = type_or_path typ = _resolve_type(path) if typ is None: if path not in self._converters_by_class_path: self._converters_by_class_path[path] = converter continue else: typ = type_or_path if typ not in self._converters_by_type: self._converters_by_type[typ] = converter self._validator_manager = _get_cached_validator_manager(tuple(validators)) @property def extensions(self): """ Get the list of extensions. Returns ------- list of asdf.extension.ExtensionProxy """ return self._extensions def handles_tag(self, tag): """ Return `True` if the specified tag is handled by a converter. Parameters ---------- tag : str Tag URI. Returns ------- bool """ return tag in self._converters_by_tag def handles_type(self, typ): """ Returns `True` if the specified Python type is handled by a converter. Parameters ---------- typ : type Returns ------- bool """ if typ in self._converters_by_type: return True self._index_converters() return typ in self._converters_by_type def handles_tag_definition(self, tag): """ Return `True` if the specified tag has a definition. Parameters ---------- tag : str Tag URI. Returns ------- bool """ return tag in self._tag_defs_by_tag def get_tag_definition(self, tag): """ Get the tag definition for the specified tag. Parameters ---------- tag : str Tag URI. Returns ------- asdf.extension.TagDefinition Raises ------ KeyError Unrecognized tag URI. """ try: return self._tag_defs_by_tag[tag] except KeyError: msg = f"No support available for YAML tag '{tag}'. You may need to install a missing extension." raise KeyError(msg) from None def get_converter_for_tag(self, tag): """ Get the converter for the specified tag. Parameters ---------- tag : str Tag URI. Returns ------- asdf.extension.Converter Raises ------ KeyError Unrecognized tag URI. """ try: return self._converters_by_tag[tag] except KeyError: msg = f"No support available for YAML tag '{tag}'. You may need to install a missing extension." raise KeyError(msg) from None def get_converter_for_type(self, typ): """ Get the converter for the specified Python type. Parameters ---------- typ : type Returns ------- asdf.extension.Converter Raises ------ KeyError Unrecognized type. """ if typ not in self._converters_by_type: self._index_converters() try: return self._converters_by_type[typ] except KeyError: msg = ( f"No support available for Python type '{get_class_name(typ, instance=False)}'. " "You may need to install or enable an extension." ) raise KeyError(msg) from None def _index_converters(self): """ Search _converters_by_class_path for paths (strings) that refer to classes that are currently imported. For imported classes, add them to _converters_by_class (if the class doesn't already have a converter). """ # search class paths to find ones that are imported for class_path in list(self._converters_by_class_path): typ = _resolve_type(class_path) if typ is None: continue if typ not in self._converters_by_type: self._converters_by_type[typ] = self._converters_by_class_path[class_path] del self._converters_by_class_path[class_path] @property def validator_manager(self): return self._validator_manager def get_cached_extension_manager(extensions): """ Get a previously created ExtensionManager for the specified extensions, or create and cache one if necessary. Building the manager is expensive, so it helps performance to reuse it when possible. Parameters ---------- extensions : list of asdf.extension.Extension Returns ------- asdf.extension.ExtensionManager """ from ._extension import ExtensionProxy # The tuple makes the extensions hashable so that we # can pass them to the lru_cache method. The ExtensionProxy # overrides __hash__ to return the hashed object id of the wrapped # extension, so this will method will only return the same # ExtensionManager if the list contains identical extension # instances in identical order. extensions = tuple(ExtensionProxy.maybe_wrap(e) for e in extensions) return _get_cached_extension_manager(extensions) @lru_cache def _get_cached_extension_manager(extensions): return ExtensionManager(extensions) class ValidatorManager: """ Wraps a list of custom validators and indexes them by schema property. Parameters ---------- validators : iterable of asdf.extension.Validator List of validators to manage. """ def __init__(self, validators): self._validators = list(validators) self._validators_by_schema_property = {} for validator in self._validators: if validator.schema_property not in self._validators_by_schema_property: self._validators_by_schema_property[validator.schema_property] = set() self._validators_by_schema_property[validator.schema_property].add(validator) self._jsonschema_validators_by_schema_property = {} for schema_property in self._validators_by_schema_property: self._jsonschema_validators_by_schema_property[schema_property] = self._get_jsonschema_validator( schema_property, ) def validate(self, schema_property, schema_property_value, node, schema): """ Validate an ASDF tree node against custom validators for a schema property. Parameters ---------- schema_property : str Name of the schema property (identifies the validator(s) to use). schema_property_value : object Value of the schema property. node : asdf.tagged.Tagged The ASDF node to validate. schema : dict The schema object that contains the property that triggered the validation. Yields ------ asdf.exceptions.ValidationError """ if schema_property in self._validators_by_schema_property: for validator in self._validators_by_schema_property[schema_property]: if _validator_matches(validator, node): yield from validator.validate(schema_property_value, node, schema) def get_jsonschema_validators(self): """ Get a dictionary of validator methods suitable for use with the jsonschema library. Returns ------- dict of str: callable """ return dict(self._jsonschema_validators_by_schema_property) def _get_jsonschema_validator(self, schema_property): def _validator(_, schema_property_value, node, schema): return self.validate(schema_property, schema_property_value, node, schema) return _validator def _validator_matches(validator, node): if any(t == "**" for t in validator.tags): return True if not isinstance(node, Tagged): return False return any(uri_match(t, node._tag) for t in validator.tags) @lru_cache def _get_cached_validator_manager(validators): return ValidatorManager(validators) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/extension/_manifest.py0000644000175100001770000000737114653725311017327 0ustar00runnerdockerimport yaml from ._extension import Extension from ._tag import TagDefinition class ManifestExtension(Extension): """ Extension implementation that reads the extension URI, ASDF Standard requirement, and tag list from a manifest document. Parameters ---------- manifest : dict Parsed manifest. converters : iterable of asdf.extension.Converter, optional Converter instances for the tags and Python types supported by this extension. compressors : iterable of asdf.extension.Compressor, optional Compressor instances to support additional binary block compression options. validators : iterable of asdf.extension.Validator, optional Validator instances to support validation of custom schema properties. legacy_class_names : iterable of str, optional Fully-qualified class names used by older versions of this extension. """ @classmethod def from_uri(cls, manifest_uri, **kwargs): """ Construct the extension using the manifest with the specified URI. The manifest document must be registered with ASDF's resource manager. Parameters ---------- manifest_uri : str Manifest URI. See the class docstring for details on keyword parameters. """ from asdf.config import get_config manifest = yaml.safe_load(get_config().resource_manager[manifest_uri]) return cls(manifest, **kwargs) def __init__(self, manifest, *, legacy_class_names=None, converters=None, compressors=None, validators=None): self._manifest = manifest if legacy_class_names is None: self._legacy_class_names = [] else: self._legacy_class_names = legacy_class_names if converters is None: self._converters = [] else: self._converters = converters if compressors is None: self._compressors = [] else: self._compressors = compressors if validators is None: self._validators = [] else: self._validators = validators @property def extension_uri(self): return self._manifest["extension_uri"] @property def legacy_class_names(self): return self._legacy_class_names @property def asdf_standard_requirement(self): version = self._manifest.get("asdf_standard_requirement", None) if version is None: return None if isinstance(version, str): return f"=={version}" specifiers = [] for prop, operator in [("gt", ">"), ("gte", ">="), ("lt", "<"), ("lte", "<=")]: value = version.get(prop) if value: specifiers.append(f"{operator}{value}") return ",".join(specifiers) @property def converters(self): return self._converters @property def compressors(self): return self._compressors @property def validators(self): return self._validators @property def tags(self): result = [] for tag in self._manifest.get("tags", []): if isinstance(tag, str): # ExtensionProxy knows how to handle str tags. result.append(tag) elif isinstance(tag, dict): result.append( TagDefinition( tag["tag_uri"], schema_uris=tag.get("schema_uri"), title=tag.get("title"), description=tag.get("description"), ), ) else: msg = "Malformed manifest document" raise TypeError(msg) return result ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/extension/_serialization_context.py0000644000175100001770000002575714653725311022152 0ustar00runnerdockerimport enum from asdf._block.key import Key as BlockKey from asdf._helpers import validate_version from asdf.extension._extension import ExtensionProxy class SerializationContext: """ Container for parameters of the current (de)serialization. This class should not be instantiated directly and instead will be created by the AsdfFile object and provided to extension classes (like Converters) via method arguments. """ def __init__(self, version, extension_manager, url, blocks): self._version = validate_version(version) self._extension_manager = extension_manager self._url = url self._blocks = blocks self._obj = None self.__extensions_used = set() @property def url(self): """ The URL (if any) of the file being read or written. Used to compute relative locations of external files referenced by this ASDF file. The URL will not exist in some cases (e.g. when the file is written to an `io.BytesIO`). Returns ------- str or None """ return self._url @property def version(self): """ Get the ASDF Standard version. Returns ------- str """ return self._version @property def extension_manager(self): """ Get the ExtensionManager for enabled extensions. Returns ------- asdf.extension.ExtensionManager """ return self._extension_manager def _mark_extension_used(self, extension): """ Note that an extension was used when reading or writing the file. Parameters ---------- extension : asdf.extension.Extension """ self.__extensions_used.add(ExtensionProxy.maybe_wrap(extension)) @property def _extensions_used(self): """ Get the set of extensions that were used when reading or writing the file. Returns ------- set of asdf.extension.Extension """ return self.__extensions_used def get_block_data_callback(self, index, key=None): """ Generate a callable that when called will read data from an ASDF block at the provided index. Parameters ---------- index : int Index of ASDF block. key : BlockKey, optional BlockKey generated using self.generate_block_key. Only needed for a Converter that uses multiple blocks. Returns ------- callback : callable A callable that when called (with no arguments) returns the block data as a one dimensional array of uint8 """ raise NotImplementedError("abstract") def find_available_block_index(self, data_callback, key=None): """ Find the index of an available ASDF block to write data. This is typically used inside asdf.extension.Converter.to_yaml_tree. Parameters ---------- data_callback: callable Callable that when called will return data (ndarray) that will be written to a block. key : BlockKey, optional BlockKey generated using self.generate_block_key. Only needed for a Converter that uses multiple blocks. Returns ------- block_index: int Index of the ASDF block where data returned from data_callback will be written. """ raise NotImplementedError("abstract") def generate_block_key(self): """ Generate a BlockKey used for Converters that wish to use multiple blocks Returns ------- key : BlockKey A hashable object that will be associated with the serialized/deserialized object and can be used to access multiple blocks within a Converter """ raise NotImplementedError("abstract") def assign_object(self, obj): self._obj = obj def assign_blocks(self): pass def set_array_storage(self, arr, array_storage): """ Set the block type to use for the given array data. Parameters ---------- arr : numpy.ndarray The array to set. If multiple views of the array are in the tree, only the most recent block type setting will be used, since all views share a single block. array_storage : str Must be one of: - ``internal``: The default. The array data will be stored in a binary block in the same ASDF file. - ``external``: Store the data in a binary block in a separate ASDF file. - ``inline``: Store the data as YAML inline in the tree. """ self._blocks._set_array_storage(arr, array_storage) def get_array_storage(self, arr): """ Get the block type for the given array data. Parameters ---------- arr : numpy.ndarray """ return self._blocks._get_array_storage(arr) def set_array_compression(self, arr, compression, **compression_kwargs): """ Set the compression to use for the given array data. Parameters ---------- arr : numpy.ndarray The array to set. If multiple views of the array are in the tree, only the most recent compression setting will be used, since all views share a single block. compression : str or None Must be one of: - ``''`` or `None`: no compression - ``zlib``: Use zlib compression - ``bzp2``: Use bzip2 compression - ``lz4``: Use lz4 compression - ``input``: Use the same compression as in the file read. If there is no prior file, acts as None. """ self._blocks._set_array_compression(arr, compression, **compression_kwargs) def get_array_compression(self, arr): """ Get the compression type for the given array data. Parameters ---------- arr : numpy.ndarray Returns ------- compression : str or None """ return self._blocks._get_array_compression(arr) def get_array_compression_kwargs(self, arr): """ """ return self._blocks._get_array_compression_kwargs(arr) def set_array_save_base(self, arr, save_base): """ Set the ``save_base`` option for ``arr``. When ``arr`` is written to a file, if ``save_base`` is ``True`` the base array for ``arr`` will be saved. Note that similar to other array options this setting is linked to the base array if ``arr`` is a view. Parameters ---------- arr : numpy.ndarray save_base : bool or None if ``None`` the ``default_array_save_base`` value from asdf config will be used """ self._blocks._set_array_save_base(arr, save_base) def get_array_save_base(self, arr): """ Returns the ``save_base`` option for ``arr``. When ``arr`` is written to a file, if ``save_base`` is ``True`` the base array for ``arr`` will be saved. Parameters ---------- arr : numpy.ndarray Returns ------- save_base : bool """ return self._blocks._get_array_save_base(arr) class ReadBlocksContext(SerializationContext): """ Perform deserialization (reading) with a `SerializationContext`. To allow for block access, `ReadBlocksContext` implements: - `SerializationContext.generate_block_key` - `SerializationContext.get_block_data_callback` and tracks which blocks (and keys) are accessed, assigning them to the deserialized object after `assign_object` and `assign_blocks` are called. """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.assign_object(None) def assign_object(self, obj): super().assign_object(obj) if obj is None: self._cb = None self._keys_to_assign = {} def assign_blocks(self): super().assign_blocks() if self._cb is not None: self._blocks._data_callbacks.assign_object(self._obj, self._cb) for key, cb in self._keys_to_assign.items(): if cb is None: msg = "Converter generated a key that was never used" raise OSError(msg) # now that we have an object, make the key valid key._assign_object(self._obj) # assign the key to the callback self._blocks._data_callbacks.assign_object(key, cb) # now that we've assigned blocks, remove the reference to the # assigned object self.assign_object(None) def get_block_data_callback(self, index, key=None): if key is None: if self._cb is not None: # this operation has already accessed a block without using # a key so check if the same index was accessed if self._cb._index == index: return self._cb msg = "Converters accessing >1 block must provide a key for each block" raise OSError(msg) self._cb = self._blocks._get_data_callback(index) return self._cb if self._keys_to_assign.get(key, None) is not None: return self._keys_to_assign[key] cb = self._blocks._get_data_callback(index) # mark this as a key to later assign self._keys_to_assign[key] = cb return cb def generate_block_key(self): key = BlockKey() self._keys_to_assign[key] = None return key class WriteBlocksContext(SerializationContext): """ Perform serialization (writing) with a `SerializationContext`. To allow for block access, `WriteBlocksContext` implements: - `SerializationContext.generate_block_key` - `SerializationContext.find_available_block_index` and assigns any accessed blocks (and keys) to the object being serialized. """ def find_available_block_index(self, data_callback, key=None): if key is None: key = self._obj return self._blocks.make_write_block(data_callback, None, key) def generate_block_key(self): return BlockKey(self._obj) class BlockAccess(enum.Enum): """ Block access enumerated values that define how a SerializationContext can access ASDF blocks. """ NONE = SerializationContext WRITE = WriteBlocksContext READ = ReadBlocksContext def create(asdf_file, block_access=BlockAccess.NONE): """ Create a SerializationContext instance (or subclass) using an AsdfFile instance, asdf_file. Parameters ---------- asdf_file : asdf.AsdfFile block_access : BlockAccess, optional Defaults to BlockAccess.NONE """ return block_access.value(asdf_file.version_string, asdf_file.extension_manager, asdf_file.uri, asdf_file._blocks) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/extension/_tag.py0000644000175100001770000000342114653725311016264 0ustar00runnerdockerclass TagDefinition: """ Container for properties of a custom YAML tag. Parameters ---------- tag_uri : str Tag URI. schema_uris : str, optional URI of the schema that should be used to validate objects with this tag. title : str, optional Short description of the tag. description : str, optional Long description of the tag. """ def __init__(self, tag_uri, *, schema_uris=None, title=None, description=None): if "*" in tag_uri: msg = "URI patterns are not permitted in TagDefinition" raise ValueError(msg) self._tag_uri = tag_uri if schema_uris is None: self._schema_uris = [] elif isinstance(schema_uris, list): self._schema_uris = schema_uris else: self._schema_uris = [schema_uris] self._title = title self._description = description @property def tag_uri(self): """ Get the tag URI. Returns ------- str """ return self._tag_uri @property def schema_uris(self): """ Get the URIs of the schemas that should be used to validate objects with this tag. Returns ------- list """ return self._schema_uris @property def title(self): """ Get the short description of the tag. Returns ------- str or None """ return self._title @property def description(self): """ Get the long description of the tag. Returns ------- str or None """ return self._description def __repr__(self): return f"" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/extension/_validator.py0000644000175100001770000000341514653725311017501 0ustar00runnerdockerimport abc class Validator(abc.ABC): """ Abstract base class for plugins that handle custom validators in ASDF schemas. """ @abc.abstractproperty def schema_property(self): """ Name of the schema property used to invoke this validator. """ @abc.abstractproperty def tags(self): """ Get the YAML tags that are appropriate to this validator. URI patterns are permitted, see `asdf.util.uri_match` for details. Returns ------- iterable of str Tag URIs or URI patterns. """ @abc.abstractmethod def validate(self, schema_property_value, node, schema): """ Validate the given node from the ASDF tree. Parameters ---------- schema_property_value : object The value assigned to the schema property associated with this valdiator. node : asdf.tagged.Tagged A tagged node from the tree. Guaranteed to bear a tag that matches one of the URIs returned by this validator's tags property. schema : dict The schema object that contains the property that triggered the validation. Typically implementations of this method do not need to make use of this object, but sometimes the behavior of a validator depends on other schema properties. An example is the built-in "additionalProperties" property, which needs to know the contents of the "properties" property in order to determine which node properties are additional. Yields ------ asdf.exceptions.ValidationError Yield an instance of ValidationError for each error present in the node. """ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/generic_io.py0000644000175100001770000010707014653725311015446 0ustar00runnerdocker""" This provides abstractions around a number of different file and stream types available to Python so that they are always used in the most efficient way. The classes in this module should not be instantiated directly, but instead, one should use the factory function `get_file`. """ import io import mmap import os import pathlib import re import sys import tempfile from os import SEEK_CUR, SEEK_END, SEEK_SET from urllib.request import url2pathname, urlopen import numpy as np from . import util from ._extern import atomicfile from .exceptions import DelimiterNotFoundError from .util import _patched_urllib_parse __all__ = ["get_file", "get_uri", "resolve_uri", "relative_uri"] _FILE_PERMISSIONS_DEFAULT_UMASK = 0o22 _FILE_PERMISSIONS_ALL = 0o777 _FILE_PERMISSIONS_NO_EXECUTE = 0o666 _local_file_schemes = ["", "file"] if sys.platform.startswith("win"): # pragma: no cover import string _local_file_schemes.extend(string.ascii_letters) def _check_bytes(fd, mode): """ Checks whether a given file-like object is opened in binary mode. """ # On Python 3, doing fd.read(0) on an HTTPResponse object causes # it to not be able to read any further, so we do this different # kind of check, which, unfortunately, is not as robust. if isinstance(fd, io.IOBase): if isinstance(fd, io.TextIOBase): return False return True if "r" in mode: x = fd.read(0) if not isinstance(x, bytes): return False elif "w" in mode: try: fd.write(b"") except TypeError: return False return True def resolve_uri(base, uri): """ Resolve a URI against a base URI. """ if base is None: base = "" resolved = _patched_urllib_parse.urljoin(base, uri) parsed = _patched_urllib_parse.urlparse(resolved) if parsed.path != "" and not parsed.path.startswith("/"): msg = "Resolved to relative URL" raise ValueError(msg) return resolved def relative_uri(source, target): """ Make a relative URI from source to target. """ su = _patched_urllib_parse.urlparse(source) tu = _patched_urllib_parse.urlparse(target) extra = list(tu[3:]) relative = None if tu[0] == "" and tu[1] == "": if tu[2] == su[2]: relative = "" elif not tu[2].startswith("/"): relative = tu[2] elif su[0:2] != tu[0:2]: return target if relative is None: relative = "" if tu[2] == su[2] else os.path.relpath(tu[2], os.path.dirname(su[2])) if relative == ".": relative = "" return _patched_urllib_parse.urlunparse(["", "", relative, *extra]) class _TruncatedReader: """ Reads until a given delimiter is found. Only works with RandomAccessFile and InputStream, though as this is a private class, this is not explicitly enforced. """ def __init__( self, fd, delimiter, readahead_bytes, delimiter_name=None, include=False, initial_content=b"", exception=True, ): self._fd = fd self._delimiter = delimiter self._readahead_bytes = readahead_bytes if delimiter_name is None: delimiter_name = delimiter self._delimiter_name = delimiter_name self._include = include self._initial_content = initial_content self._trailing_content = b"" self._exception = exception self._past_end = False def read(self, nbytes=None): if self._past_end: content = self._trailing_content[:nbytes] if nbytes is None: self._trailing_content = b"" else: self._trailing_content = self._trailing_content[nbytes:] return content if nbytes is None: content = self._fd.peek() elif nbytes > len(self._initial_content): content = self._fd.peek(nbytes - len(self._initial_content) + self._readahead_bytes) else: content = self._initial_content[:nbytes] self._initial_content = self._initial_content[nbytes:] return content if content == b"": if self._exception: msg = f"{self._delimiter_name} not found" raise DelimiterNotFoundError(msg) self._past_end = True return content index = re.search(self._delimiter, content) if index is not None: index = index.end() if self._include else index.start() content = content[:index] self._past_end = True elif not (nbytes is None and self._exception): if nbytes: content = content[: nbytes - len(self._initial_content)] else: # Read the whole file and didn't find the delimiter msg = f"{self._delimiter_name} not found" raise DelimiterNotFoundError(msg) self._fd.fast_forward(len(content)) if self._initial_content: content = self._initial_content + content self._initial_content = b"" if self._past_end and nbytes: self._trailing_content = content[nbytes:] content = content[:nbytes] return content class GenericFile(metaclass=util._InheritDocstrings): """ Base class for an abstraction layer around a number of different file-like types. Each of its subclasses handles a particular kind of file in the most efficient way possible. This class should not be instantiated directly, but instead the factory function `get_file` should be used to get the correct subclass for the given file-like object. """ def __init__(self, fd, mode, close=False, uri=None): """ Parameters ---------- fd : file-like object The particular kind of file-like object must match the subclass of `GenericFile` being instantiated. mode : str Must be ``"r"`` (read), ``"w"`` (write), or ``"rw"`` (read/write). close : bool, optional When ``True``, close the given `fd` in the ``__exit__`` method, i.e. at the end of the with block. Should be set to ``True`` when this object "owns" the file object. Default: ``False``. uri : str, optional The file path or URI used to open the file. This is used to resolve relative URIs when the file refers to external sources. """ if not _check_bytes(fd, mode): msg = "File-like object must be opened in binary mode." raise ValueError(msg) # can't import at the top level due to circular import from .config import get_config self._asdf_get_config = get_config self._fd = fd self._mode = mode self._close = close self._uri = uri self.block_size = get_config().io_block_size def __enter__(self): return self def __exit__(self, type_, value, traceback): if self._close: if hasattr(self._fd, "__exit__"): self._fd.__exit__(type_, value, traceback) else: self._fd.close() @property def block_size(self): return self._blksize @block_size.setter def block_size(self, block_size): if block_size == -1: try: block_size = os.fstat(self._fd.fileno()).st_blksize except Exception: block_size = io.DEFAULT_BUFFER_SIZE if block_size <= 0: msg = f"block_size ({block_size}) must be > 0" raise ValueError(msg) self._blksize = block_size @property def mode(self): """ The mode of the file. Will be ``'r'``, ``'w'`` or ``'rw'``. """ return self._mode @property def uri(self): """ The base uri of the file. """ return self._uri def read(self, size=-1): """ Read at most size bytes from the file (less if the read hits EOF before obtaining size bytes). If the size argument is negative or omitted, read all data until EOF is reached. The bytes are returned as a `bytes` object. An empty `bytes` object is returned when EOF is encountered immediately. Only available if `readable` returns `True`. """ # On Python 3, reading 0 bytes from a socket causes it to stop # working, so avoid doing that at all costs. if size == 0: return b"" return self._fd.read(size) def read_block(self): """ Read a "block" from the file. For real filesystem files, the block is the size of a native filesystem block. """ return self.read(self._blksize) def read_blocks(self, size): """ Read ``size`` bytes of data from the file, one block at a time. The result is a generator where each value is a bytes object. """ for i in range(0, size, self._blksize): thissize = min(self._blksize, size - i) yield self.read(thissize) def write(self, content): self._fd.write(content) write.__doc__ = """ Write a string to the file. There is no return value. Due to buffering, the string may not actually show up in the file until the flush() or close() method is called. Only available if `writable` returns `True`. """ def write_array(self, array): """ Write array content to the file. Array must be 1D contiguous so that this method can avoid making assumptions about the intended memory layout. Endianness is preserved. Parameters ---------- array : np.ndarray Must be 1D contiguous. """ if len(array.shape) != 1 or not array.flags.contiguous: msg = "Requires 1D contiguous array." raise ValueError(msg) self.write(array.data) def peek(self, size=-1): """ Read bytes of the file without consuming them. This method must be implemented by all GenericFile implementations that provide ASDF input (those that aren't seekable should use a buffer to store peeked bytes). Parameters ---------- size : int Number of bytes to peek, or -1 to peek all remaining bytes. """ if self.seekable(): cursor = self.tell() content = self.read(size) self.seek(cursor, SEEK_SET) return content msg = "Non-seekable file" raise RuntimeError(msg) def seek(self, offset, whence=0): """ Set the file's current position. Only available if `seekable` returns `True`. Parameters ---------- offset : integer Offset, in bytes. whence : integer, optional The `whence` argument is optional and defaults to SEEK_SET or 0 (absolute file positioning); other values are SEEK_CUR or 1 (seek relative to the current position) and SEEK_END or 2 (seek relative to the file`s end). """ result = self._fd.seek(offset, whence) return result def tell(self): """ Return the file's current position, in bytes. Only available in `seekable` returns `True`. """ return self._fd.tell() def flush(self): """ Flush the internal buffer. """ self._fd.flush() def close(self): """ Close the file. The underlying file-object will only be closed if ``close=True`` was passed to the constructor. """ if self._close: self._fd.close() self._fix_permissions() def truncate(self, size=None): """ Truncate the file to the given size. """ raise NotImplementedError def writable(self): """ Returns `True` if the file can be written to. """ return "w" in self.mode def readable(self): """ Returns `True` if the file can be read from. """ return "r" in self.mode def seekable(self): """ Returns `True` if the file supports random access (`seek` and `tell`). """ return False def can_memmap(self): """ Returns `True` if the file supports memmapping. """ return False def is_closed(self): """ Returns `True` if the underlying file object is closed. """ return self._fd.closed def read_until( self, delimiter, readahead_bytes, delimiter_name=None, include=True, initial_content=b"", exception=True, ): """ Reads until a match for a given regular expression is found. Parameters ---------- delimiter : str A regular expression. readahead_bytes : int The number of bytes to read ahead to make sure the delimiter isn't on a block boundary. delimiter_name : str, optional The name of the delimiter. Used in error messages if the delimiter is not found. If not provided, the raw content of `delimiter` will be used. include : bool, optional When ``True``, include the delimiter in the result. initial_content : bytes, optional Additional content to include at the beginning of the first read. exception : bool, optional If ``True`` (default), raise an exception if the end marker isn't found. Returns ------- content : bytes The content from the current position in the file, up to the delimiter. Includes the delimiter if `include` is ``True``. Raises ------ DelimiterNotFoundError : If the delimiter is not found before the end of the file. """ buff = io.BytesIO() reader = self.reader_until( delimiter, readahead_bytes, delimiter_name=delimiter_name, include=include, initial_content=initial_content, exception=exception, ) while True: content = reader.read(self.block_size) buff.write(content) if len(content) < self.block_size: break return buff.getvalue() def reader_until( self, delimiter, readahead_bytes, delimiter_name=None, include=True, initial_content=b"", exception=True, ): """ Returns a readable file-like object that treats the given delimiter as the end-of-file. Parameters ---------- delimiter : str A regular expression. readahead_bytes : int The number of bytes to read ahead to make sure the delimiter isn't on a block boundary. delimiter_name : str, optional The name of the delimiter. Used in error messages if the delimiter is not found. If not provided, the raw content of `delimiter` will be used. include : bool, optional When ``True``, include the delimiter in the result. initial_content : bytes, optional Additional content to include at the beginning of the first read. exception : bool, optional If ``True`` (default), raise an exception if the end marker isn't found. Raises ------ DelimiterNotFoundError : If the delimiter is not found before the end of the file. """ raise NotImplementedError def seek_until( self, delimiter, readahead_bytes, delimiter_name=None, include=True, initial_content=b"", exception=True, ): """ Seeks in the file until a match for a given regular expression is found. This is similar to ``read_until``, except the intervening content is not retained. Parameters ---------- delimiter : str A regular expression. readahead_bytes : int The number of bytes to read ahead to make sure the delimiter isn't on a block boundary. delimiter_name : str, optional The name of the delimiter. Used in error messages if the delimiter is not found. If not provided, the raw content of `delimiter` will be used. include : bool, optional When ``True``, include the delimiter in the result. initial_content : bytes, optional Additional content to include at the beginning of the first read. exception : bool, optional If ``True`` (default), raise an exception if the end marker isn't found. Returns ------- bool ``True`` if the delimiter was found. Raises ------ DelimiterNotFoundError : If ``exception`` is enabled and the delimiter is not found before the end of the file. """ reader = self.reader_until( delimiter, readahead_bytes, delimiter_name=delimiter_name, include=include, initial_content=initial_content, exception=True, ) try: while reader.read(self.block_size) != b"": pass except DelimiterNotFoundError: if exception: raise return False return True def fast_forward(self, size): """ Move the file position forward by `size`. """ raise NotImplementedError def clear(self, nbytes): """ Write nbytes of zeros. """ blank_data = b"\0" * self.block_size for i in range(0, nbytes, self.block_size): length = min(nbytes - i, self.block_size) self.write(blank_data[:length]) def memmap_array(self, offset, size): """ Memmap a chunk of the file into a `np.memmap` object. Parameters ---------- offset : integer The offset, in bytes, in the file. size : integer The size of the data to memmap. Returns ------- array : np.memmap """ msg = f"memmapping is not implemented for {self.__class__.__name__}" raise NotImplementedError(msg) def close_memmap(self): """ Close the memmapped file (if one was mapped with memmap_array) """ msg = f"memmapping is not implemented for {self.__class__.__name__}" raise NotImplementedError(msg) def flush_memmap(self): """ Flush any pending writes to the memmapped file (if one was mapped with memmap_array) """ msg = f"memmapping is not implemented for {self.__class__.__name__}" raise NotImplementedError(msg) def read_into_array(self, size): """ Read a chunk of the file into a uint8 array. Parameters ---------- size : integer The size of the data. Returns ------- array : np.memmap """ buff = self.read(size) return np.frombuffer(buff, np.uint8, size, 0) class GenericWrapper: """ A wrapper around a `GenericFile` object so that closing only happens in the very outer layer. """ def __init__(self, fd): self._fd = fd def __enter__(self): return self def __exit__(self, type_, value, traceback): pass def __getattr__(self, attr): return getattr(self._fd, attr) class RandomAccessFile(GenericFile): """ The base class of file types that support random access. """ def seekable(self): return True def reader_until( self, delimiter, readahead_bytes, delimiter_name=None, include=True, initial_content=b"", exception=True, ): return _TruncatedReader( self, delimiter, readahead_bytes, delimiter_name=delimiter_name, include=include, initial_content=initial_content, exception=exception, ) def fast_forward(self, size): if size < 0: self.seek(0, SEEK_END) self.seek(size, SEEK_CUR) def truncate(self, size=None): if size is None: self._fd.truncate() else: self._fd.truncate(size) self.seek(size, SEEK_SET) class RealFile(RandomAccessFile): """ Handles "real" files on a filesystem. """ def __init__(self, fd, mode, close=False, uri=None): super().__init__(fd, mode, close=close, uri=uri) if uri is None and hasattr(fd, "name") and isinstance(fd.name, str): self._uri = pathlib.Path(fd.name).expanduser().absolute().as_uri() def write_array(self, arr): if isinstance(arr, np.memmap) and getattr(arr, "fd", None) is self: arr.flush() self.fast_forward(len(arr.data)) else: if len(arr.shape) != 1 or not arr.flags.contiguous: msg = "Requires 1D contiguous array." raise ValueError(msg) self._fd.write(arr.data) def can_memmap(self): return True def memmap_array(self, offset, size): if not hasattr(self, "_mmap"): loc = self._fd.tell() acc = mmap.ACCESS_WRITE if "w" in self._mode else mmap.ACCESS_READ self._fd.seek(0, 2) nbytes = self._fd.tell() self._mmap = mmap.mmap(self._fd.fileno(), nbytes, access=acc) # on windows mmap seeks to the start of the file so return the file # pointer to this previous location self._fd.seek(loc, 0) return np.ndarray.__new__(np.memmap, shape=size, offset=offset, dtype="uint8", buffer=self._mmap) def close_memmap(self): if hasattr(self, "_mmap"): # we no longer close the _mmap here. This does mean that views of arrays # that are backed by _mmap will keep the _mmap alive (and open). This is # the cost of avoiding segfaults as np.memmap does not check if mmap is # closed. del self._mmap def flush_memmap(self): if hasattr(self, "_mmap"): self._mmap.flush() def read_into_array(self, size): return np.fromfile(self._fd, dtype=np.uint8, count=size) def _fix_permissions(self): """ atomicfile internally uses tempfile.NamedTemporaryFile which uses tempfile.mkstemp which makes a file that is "readable and writable only by the creating user ID." this creates files with mode 0o600 regardless of umask Rather than modify atomicfile, this will use the umask to determine the file permissions and modify the resulting file permission bits """ if isinstance(self._fd, atomicfile._AtomicWFile): fn = self._fd._filename if not os.path.exists(fn): return # there is no way to read the umask without setting it # so set it to the typical default 0o22 umask = os.umask(_FILE_PERMISSIONS_DEFAULT_UMASK) if umask != _FILE_PERMISSIONS_DEFAULT_UMASK: # restore the read value if it differs from the default os.umask(umask) permissions = _FILE_PERMISSIONS_ALL if os.path.isdir(fn) else _FILE_PERMISSIONS_NO_EXECUTE os.chmod(self._fd._filename, permissions & ~umask) def __exit__(self, type_, value, traceback): super().__exit__(type_, value, traceback) if self._close: self._fix_permissions() def close(self): self.flush_memmap() super().close() self.close_memmap() if self._close: self._fix_permissions() def truncate(self, size=None): # windows supports truncating as long as the file not opened # more than once. So this must be called after closing all # memmaps if sys.platform.startswith("win") and hasattr(self, "_mmap"): self._mmap.close() self.close_memmap() super().truncate(size=size) class MemoryIO(RandomAccessFile): """ Handles random-access memory buffers, mainly `io.BytesIO` and `StringIO.StringIO`. """ def __init__(self, fd, mode, uri=None): super().__init__(fd, mode, uri=uri) def read_into_array(self, size): buf = self._fd.getvalue() offset = self._fd.tell() result = np.frombuffer(buf, np.uint8, size, offset) # Copy the buffer so the original memory can be released. result = result.copy() self.seek(size, SEEK_CUR) return result class InputStream(GenericFile): """ Handles an input stream, such as stdin. """ def __init__(self, fd, mode="r", close=False, uri=None): super().__init__(fd, mode, close=close, uri=uri) self._fd = fd self._buffer = b"" def peek(self, size=-1): if size < 0: self._buffer += self._fd.read() else: len_buffer = len(self._buffer) if len_buffer < size: self._buffer += self._fd.read(size - len_buffer) return self._buffer def read(self, size=-1): # On Python 3, reading 0 bytes from a socket causes it to stop # working, so avoid doing that at all costs. if size == 0: return b"" len_buffer = len(self._buffer) if len_buffer == 0: return self._fd.read(size) if size < 0: self._buffer += self._fd.read() buffer = self._buffer self._buffer = b"" return buffer if len_buffer < size: if len_buffer < size: self._buffer += self._fd.read(size - len(self._buffer)) buffer = self._buffer self._buffer = b"" return buffer buffer = self._buffer[:size] self._buffer = self._buffer[size:] return buffer def reader_until( self, delimiter, readahead_bytes, delimiter_name=None, include=True, initial_content=b"", exception=True, ): return _TruncatedReader( self, delimiter, readahead_bytes, delimiter_name=delimiter_name, include=include, initial_content=initial_content, exception=exception, ) def fast_forward(self, size): if size >= 0 and len(self.read(size)) != size: msg = "Read past end of file" raise OSError(msg) def read_into_array(self, size): try: # See if Numpy can handle this as a real file first... return np.fromfile(self._fd, np.uint8, size) except (OSError, AttributeError): # Else, fall back to reading into memory and then # returning the Numpy array. data = self.read(size) # We need to copy the array, so it is writable result = np.frombuffer(data, np.uint8, size) # When creating an array from a buffer, it is read-only. # If we need a read/write array, we have to copy it. if "w" in self._mode: result = result.copy() return result class OutputStream(GenericFile): """ Handles an output stream, such as stdout. """ def __init__(self, fd, close=False, uri=None): super().__init__(fd, "w", close=close, uri=uri) self._fd = fd def fast_forward(self, size): if size < 0: return self.clear(size) def _http_to_temp(init, mode, uri=None): """ Stream the content of an http or https URL to a temporary file. Parameters ---------- init : str HTTP or HTTPS URL. mode : str ASDF file mode. The temporary file will always be opened in w+b mode, but the resulting GenericFile will report itself writable based on this value. uri : str, optional URI against which relative paths within the file are resolved. If None, the init value will be used. Returns ------- RealFile Temporary file. """ from asdf import get_config fd = tempfile.NamedTemporaryFile("w+b") block_size = get_config().io_block_size if block_size == -1: try: block_size = os.fstat(fd.fileno()).st_blksize except Exception: block_size = io.DEFAULT_BUFFER_SIZE try: # This method is only called with http and https schemes: with urlopen(init) as response: # nosec chunk = response.read(block_size) while len(chunk) > 0: fd.write(chunk) chunk = response.read(block_size) fd.seek(0) except Exception: fd.close() raise return RealFile(fd, mode, close=True, uri=uri or init) def get_uri(file_obj): """ Returns the uri of the given file object Parameters ---------- uri : object """ if isinstance(file_obj, str): return file_obj if isinstance(file_obj, GenericFile): return file_obj.uri # A catch-all for types from Python's io module that have names return getattr(file_obj, "name", "") def get_file(init, mode="r", uri=None, close=False): """ Returns a `GenericFile` instance suitable for wrapping the given object `init`. If passed an already open file-like object, it must be opened for reading/writing in binary mode. It is the caller's responsibility to close it. Parameters ---------- init : object `init` may be: - A `bytes` or `unicode` file path or ``file:`` or ``http:`` url. - A Python 2 `file` object. - An `io.IOBase` object (the default file object on Python 3). - A ducktyped object that looks like a file object. If `mode` is ``"r"``, it must have a ``read`` method. If `mode` is ``"w"``, it must have a ``write`` method. If `mode` is ``"rw"`` it must have the ``read``, ``write``, ``tell`` and ``seek`` methods. - A `GenericFile` instance, in which case it is wrapped in a `GenericWrapper` instance, so that the file is closed when only when the final layer is unwrapped. mode : str Must be one of ``"r"``, ``"w"`` or ``"rw"``. uri : str Sets the base URI of the file object. This will be used to resolve any relative URIs contained in the file. This is redundant if `init` is a `bytes` or `unicode` object (since it will be the uri), and it may be determined automatically if `init` refers to a regular filesystem file. It is not required if URI resolution is not used in the file. close : bool If ``True``, closes the underlying file handle when this object is closed. Defaults to ``False``. Returns ------- fd : GenericFile Raises ------ ValueError, TypeError, IOError """ if mode not in ("r", "w", "rw"): msg = "mode must be 'r', 'w' or 'rw'" raise ValueError(msg) if init in (sys.__stdout__, sys.__stdin__, sys.__stderr__): init = os.fdopen(init.fileno(), init.mode + "b") if isinstance(init, (GenericFile, GenericWrapper)): if mode not in init.mode: msg = f"File is opened as '{init.mode}', but '{mode}' was requested" raise ValueError(msg) return GenericWrapper(init) if isinstance(init, (str, pathlib.Path)): parsed = _patched_urllib_parse.urlparse(str(init)) if parsed.scheme in ["http", "https"]: if "w" in mode: msg = "HTTP connections can not be opened for writing" raise ValueError(msg) return _http_to_temp(init, mode, uri=uri) if parsed.scheme in _local_file_schemes: realmode = "r+b" if mode == "rw" else mode + "b" # if paths have an extra leading '/' urlparse will # parse them even though they violate rfc8089. This will # lead to errors or writing files to unexpected locations # on non-windows systems if not sys.platform.startswith("win") and parsed.scheme == "" and parsed.netloc != "": msg = f"Invalid path {init}" raise ValueError(msg) # Windows paths are not URIs, and so they should not be parsed as # such. Otherwise, the drive component of the path can get lost. # This is not an ideal solution, but we can't use pathlib here # because it doesn't handle URIs properly. realpath = ( str(init) if sys.platform.startswith("win") and parsed.scheme in string.ascii_letters else url2pathname(parsed.path) ) try: fd = atomicfile.atomic_open(realpath, realmode) if mode == "w" else open(realpath, realmode) fd = fd.__enter__() except FileNotFoundError as e: # atomic_open will create an Exception with an odd looking path # overwrite the error message to make it more informative e.filename = realpath raise e return RealFile(fd, mode, close=True, uri=uri) if isinstance(init, io.BytesIO): return MemoryIO(init, mode, uri=uri) if isinstance(init, io.StringIO): msg = "io.StringIO objects are not supported. Use io.BytesIO instead." raise TypeError(msg) if isinstance(init, io.IOBase): if ("r" in mode and not init.readable()) or ("w" in mode and not init.writable()): msg = f"File is opened as '{init.mode}', but '{mode}' was requested" raise ValueError(msg) if init.seekable(): init2 = init.raw if hasattr(init, "raw") else init if hasattr(init2, "getvalue"): result = MemoryIO(init2, mode, uri=uri) else: # can we call 'fileno'? if not, we can't memmap so don't # make a RealFile try: init2.fileno() result = RealFile(init2, mode, uri=uri, close=close) except io.UnsupportedOperation: result = RandomAccessFile(init2, mode, uri=uri, close=close) result._secondary_fd = init return result if mode == "w": return OutputStream(init, uri=uri, close=close) if mode == "r": return InputStream(init, mode, uri=uri, close=close) msg = f"File '{init}' could not be opened in 'rw' mode" raise ValueError(msg) if mode == "w" and (hasattr(init, "write") and hasattr(init, "seek") and hasattr(init, "tell")): return MemoryIO(init, mode, uri=uri) if mode == "r" and (hasattr(init, "read") and hasattr(init, "seek") and hasattr(init, "tell")): return MemoryIO(init, mode, uri=uri) if mode == "rw" and ( hasattr(init, "read") and hasattr(init, "write") and hasattr(init, "seek") and hasattr(init, "tell") ): return MemoryIO(init, mode, uri=uri) if mode == "w" and hasattr(init, "write"): return OutputStream(init, uri=uri, close=close) if mode == "r" and hasattr(init, "read"): return InputStream(init, mode, uri=uri, close=close) msg = f"Can't handle '{init}' as a file for mode '{mode}'" raise ValueError(msg) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/lazy_nodes.py0000644000175100001770000002401114653725311015503 0ustar00runnerdocker""" Objects that act like dict, list, OrderedDict but allow lazy conversion of tagged ASDF tree nodes to custom objects. """ import collections import inspect import warnings import weakref from . import tagged, yamlutil from .exceptions import AsdfConversionWarning, AsdfLazyReferenceError from .extension._serialization_context import BlockAccess __all__ = ["AsdfDictNode", "AsdfListNode", "AsdfOrderedDictNode"] class _TaggedObjectCacheItem: """ A tagged node and a (weakref) to the converted custom object """ def __init__(self, tagged_node, custom_object): self.tagged_node = tagged_node try: self._custom_object_ref = weakref.ref(custom_object) except TypeError: # if a weakref is not possible, store the object self._custom_object_ref = lambda obj=custom_object: obj @property def custom_object(self): return self._custom_object_ref() class _TaggedObjectCache: """ A cache of tagged nodes and their corresponding custom objects. This is critical for trees that contain references/pointers to the same object at multiple locations in the tree. Only weakrefs are key to the custom objects to allow large items deleted from the tree to be garbage collected. This means that an item added to the cache may later fail to retrieve (if the weakref-ed custom object was deleted). """ def __init__(self): # start with a clear cache self.clear() def clear(self): self._cache = {} def retrieve(self, tagged_node): """ Check the cache for a previously converted object. Parameters ---------- tagged_node : Tagged The tagged representation of the custom object Returns ------- custom_object : None or the converted object The custom object previously converted from the tagged_node or ``None`` if the object hasn't been converted (or was previously deleted from the tree). """ key = id(tagged_node) if key not in self._cache: return None item = self._cache[key] custom_object = item.custom_object if custom_object is None: del self._cache[key] return custom_object def store(self, tagged_node, custom_object): """ Store a converted custom object in the cache. Parameters ---------- tagged_node : Tagged The tagged representation of the custom object custom_object : converted object The custom object (a weakref to this object will be kept in the cache). """ self._cache[id(tagged_node)] = _TaggedObjectCacheItem(tagged_node, custom_object) def _resolve_af_ref(af_ref): msg = "Failed to resolve AsdfFile reference" if af_ref is None: raise AsdfLazyReferenceError(msg) af = af_ref() if af is None: raise AsdfLazyReferenceError(msg) return af def _to_lazy_node(node, af_ref): """ Convert an object to a _AsdfNode subclass. If the object does not have a corresponding subclass it will be returned unchanged. """ if isinstance(node, list): return AsdfListNode(node, af_ref) elif isinstance(node, collections.OrderedDict): return AsdfOrderedDictNode(node, af_ref) elif isinstance(node, dict): return AsdfDictNode(node, af_ref) return node class _AsdfNode: """ The "lazy node" base class that handles object conversion and wrapping and contains a weak reference to the `asdf.AsdfFile` that triggered the creation of this node (when the "lazy tree" was loaded). """ def __init__(self, data=None, af_ref=None): self._af_ref = af_ref self.data = data @property def tagged(self): """ Return the tagged tree backing this node """ return self.data def _convert_and_cache(self, value, key): """ Convert ``value`` to either: - a custom object if ``value`` is `asdf.tagged.Tagged` - an ``asdf.lazy_nodes.AsdfListNode` if ``value`` is a ``list`` - an ``asdf.lazy_nodes.AsdfDictNode` if ``value`` is a ``dict`` - an ``asdf.lazy_nodes.AsdfOrderedDictNode` if ``value`` is a ``OrderedDict`` - otherwise return ``value`` unmodified After conversion the result (``obj``) will be stored in this `asdf.lazy_nodes._AsdfNode` using the provided key and cached in the corresponding `asdf.AsdfFile` instance (so other references to ``value`` in the tree will return the same ``obj``). Parameters ---------- value : The object to convert from a Tagged to custom object or wrap with an _AsdfNode or return unmodified. key : The key under which the converted/wrapped object will be stored. Returns ------- obj : The converted or wrapped (or the value if no conversion or wrapping is required). """ # if the value has already been wrapped, return it if isinstance(value, _AsdfNode): return value if not isinstance(value, tagged.Tagged) and type(value) not in _base_type_to_node_map: return value af = _resolve_af_ref(self._af_ref) # if the obj that will be returned from this value # is already cached, use the cached obj if (obj := af._tagged_object_cache.retrieve(value)) is not None: self[key] = obj return obj # for Tagged instances, convert them to their custom obj if isinstance(value, tagged.Tagged): extension_manager = af.extension_manager tag = value._tag if not extension_manager.handles_tag(tag): if not af._ignore_unrecognized_tag: warnings.warn( f"{tag} is not recognized, converting to raw Python data structure", AsdfConversionWarning, ) obj = _to_lazy_node(value, self._af_ref) else: converter = extension_manager.get_converter_for_tag(tag) if not getattr(converter, "lazy", False) or inspect.isgeneratorfunction( converter._delegate.from_yaml_tree ): obj = yamlutil.tagged_tree_to_custom_tree(value, af) else: data = _to_lazy_node(value.data, self._af_ref) sctx = af._create_serialization_context(BlockAccess.READ) obj = converter.from_yaml_tree(data, tag, sctx) sctx.assign_object(obj) sctx.assign_blocks() sctx._mark_extension_used(converter.extension) else: # for non-tagged objects, wrap in an _AsdfNode node_type = _base_type_to_node_map[type(value)] obj = node_type(value, self._af_ref) # cache the converted/wrapped obj with the AsdfFile so other # references to the same Tagged value will result in the # same obj af._tagged_object_cache.store(value, obj) self[key] = obj return obj class AsdfListNode(_AsdfNode, collections.UserList): """ An class that acts like a ``list``. The items in this ``list`` will start out as tagged nodes which will only be converted to custom objects the first time they are indexed (the custom object will then be cached for later reuse). If sliced, this will return a new instance of `AsdfListNode` for the sliced portion of the list. """ def __init__(self, data=None, af_ref=None): if data is None: data = [] _AsdfNode.__init__(self, data, af_ref) collections.UserList.__init__(self, data) def __copy__(self): return AsdfListNode(self.data.copy(), self._af_ref) def __eq__(self, other): if self is other: return True return list(self) == list(other) def __ne__(self, other): return not self.__eq__(other) def __getitem__(self, key): # key might be an int or slice value = super().__getitem__(key) if isinstance(key, slice): return AsdfListNode(value, self._af_ref) return self._convert_and_cache(value, key) class AsdfDictNode(_AsdfNode, collections.UserDict): """ An class that acts like a ``dict``. The values for this ``dict`` will start out as tagged nodes which will only be converted to custom objects the first time the corresponding key is used (the custom object will then be cached for later reuse). """ def __init__(self, data=None, af_ref=None): if data is None: data = {} _AsdfNode.__init__(self, data, af_ref) collections.UserDict.__init__(self, data) def __copy__(self): return AsdfDictNode(self.data.copy(), self._af_ref) def __eq__(self, other): if self is other: return True return dict(self) == dict(other) def __ne__(self, other): return not self.__eq__(other) def __getitem__(self, key): return self._convert_and_cache(super().__getitem__(key), key) class AsdfOrderedDictNode(AsdfDictNode, collections.OrderedDict): """ An class that acts like a ``collections.OrderedDict``. The values for this ``OrderedDict`` will start out as tagged nodes which will only be converted to custom objects the first time the corresponding key is used (the custom object will then be cached for later reuse). """ def __init__(self, data=None, af_ref=None): if data is None: data = collections.OrderedDict() AsdfDictNode.__init__(self, data, af_ref) def __copy__(self): return AsdfOrderedDictNode(self.data.copy(), self._af_ref) _base_type_to_node_map = { dict: AsdfDictNode, list: AsdfListNode, collections.OrderedDict: AsdfOrderedDictNode, } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/reference.py0000644000175100001770000001161014653725311015273 0ustar00runnerdocker""" Manages external references in the YAML tree using the `JSON Reference standard `__ and `JSON Pointer standard `__. """ import warnings import weakref from collections.abc import Sequence from contextlib import suppress import numpy as np from . import generic_io, treeutil, util from .exceptions import AsdfDeprecationWarning from .util import _patched_urllib_parse __all__ = ["resolve_fragment", "Reference", "find_references", "resolve_references", "make_reference"] def resolve_fragment(tree, pointer): """ Resolve a JSON Pointer within the tree. """ pointer = pointer.lstrip("/") parts = _patched_urllib_parse.unquote(pointer).split("/") if pointer else [] for part in parts: part_ = part.replace("~1", "/").replace("~0", "~") if isinstance(tree, Sequence): # Array indexes should be turned into integers with suppress(ValueError): part_ = int(part_) try: tree = tree[part_] except (TypeError, LookupError) as err: msg = f"Unresolvable reference: '{pointer}'" raise ValueError(msg) from err return tree class Reference: def __init__(self, uri, base_uri=None, asdffile=None, target=None): self._uri = uri if asdffile is not None: self._asdffile = weakref.ref(asdffile) self._base_uri = base_uri self._target = target def _get_target(self, **kwargs): if self._target is None: base_uri = self._base_uri if base_uri is None: base_uri = self._asdffile().uri uri = generic_io.resolve_uri(base_uri, self._uri) asdffile = self._asdffile().open_external(uri, **kwargs) parts = _patched_urllib_parse.urlparse(self._uri) fragment = parts.fragment self._target = resolve_fragment(asdffile.tree, fragment) return self._target def __repr__(self): # repr alone should not force loading of the reference if self._target is None: return f"" return f"" def __str__(self): # str alone should not force loading of the reference if self._target is None: return f"" return str(self._target) def __len__(self): return len(self._get_target()) def __getattr__(self, attr): if attr == "_tag": return None try: return getattr(self._get_target(), attr) except Exception as err: msg = f"No attribute '{attr}'" raise AttributeError(msg) from err def __getitem__(self, item): return self._get_target()[item] def __setitem__(self, item, val): self._get_target()[item] = val def __array__(self): return np.asarray(self._get_target()) def __call__(self, **kwargs): return self._get_target(**kwargs) def __contains__(self, item): return item in self._get_target() def find_references(tree, ctx, _warning_msg=False): """ Find all of the JSON references in the tree, and convert them into `Reference` objects. """ def do_find(tree): if isinstance(tree, dict) and "$ref" in tree: if _warning_msg: warnings.warn(_warning_msg, AsdfDeprecationWarning) return Reference(tree["$ref"], asdffile=ctx) return tree return treeutil.walk_and_modify(tree, do_find, ignore_implicit_conversion=ctx._ignore_implicit_conversion) def resolve_references(tree, ctx, **kwargs): """ Resolve all of the references in the tree, by loading the external data and inserting it directly into the tree. """ def do_resolve(tree): if isinstance(tree, Reference): return tree(**kwargs) return tree tree = find_references(tree, ctx) return treeutil.walk_and_modify(tree, do_resolve, ignore_implicit_conversion=ctx._ignore_implicit_conversion) def make_reference(asdffile, path): """ Make a reference to a subtree of the given ASDF file. Parameters ---------- asdffile : AsdfFile path : list of str and int, optional The parts of the path pointing to an item in this tree. If omitted, points to the root of the tree. Returns ------- reference : reference.Reference A reference object. """ path_str = "/".join(x.replace("~", "~0").replace("/", "~1") for x in path) target = resolve_fragment(asdffile.tree, path_str) if asdffile.uri is None: msg = "Can not make a reference to a AsdfFile without an associated URI." raise ValueError(msg) base_uri = util.get_base_uri(asdffile.uri) uri = base_uri + "#" + path_str return Reference(uri, target=target) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/resource.py0000644000175100001770000001171214653725311015167 0ustar00runnerdocker""" Support for plugins that provide access to resources such as schemas. """ import pkgutil from collections.abc import Mapping from asdf_standard import DirectoryResourceMapping as _DirectoryResourceMapping from .util import get_class_name __all__ = [ "ResourceMappingProxy", "DirectoryResourceMapping", "ResourceManager", "JsonschemaResourceMapping", ] class DirectoryResourceMapping(_DirectoryResourceMapping): """ A resource mapping that reads resource content from a directory or directory tree. See :class:`~asdf_standard.resource.DirectoryResourceMapping` for details. """ class ResourceMappingProxy(Mapping): """ Wrapper around a resource mapping that carries additional information on the package that provided the mapping. """ @classmethod def maybe_wrap(cls, delegate): if isinstance(delegate, ResourceMappingProxy): return delegate return ResourceMappingProxy(delegate) def __init__(self, delegate, package_name=None, package_version=None): if not isinstance(delegate, Mapping): msg = "Resource mapping must implement the Mapping interface" raise TypeError(msg) self._delegate = delegate self._package_name = package_name self._package_version = package_version self._class_name = get_class_name(delegate) def __getitem__(self, uri): return self._delegate.__getitem__(uri) def __len__(self): return self._delegate.__len__() def __iter__(self): return self._delegate.__iter__() @property def delegate(self): """ Get the wrapped mapping instance. Returns ------- collections.abc.Mapping """ return self._delegate @property def package_name(self): """ Get the name of the Python package that provided this mapping. Returns ------- str or None `None` if the mapping was added at runtime. """ return self._package_name @property def package_version(self): """ Get the version of the Python package that provided the mapping. Returns ------- str or None `None` if the mapping was added at runtime. """ return self._package_version @property def class_name(self): """ " Get the fully qualified class name of the mapping. Returns ------- str """ return self._class_name def __eq__(self, other): if isinstance(other, ResourceMappingProxy): return other.delegate is self.delegate return False def __hash__(self): return hash(id(self.delegate)) def __repr__(self): if self.package_name is not None: package_description = f"{self.package_name}=={self.package_version}" else: package_description = "(none)" return f"" class ResourceManager(Mapping): """ Wraps multiple resource mappings into a single interface with some friendlier error handling. Parameters ---------- resource_mappings : iterable of collections.abc.Mapping Underlying resource mappings. In the case of a duplicate URI, the first mapping takes precedence. """ def __init__(self, resource_mappings): self._resource_mappings = resource_mappings self._mappings_by_uri = {} for mapping in resource_mappings: for uri in mapping: if uri not in self._mappings_by_uri: self._mappings_by_uri[uri] = mapping def __getitem__(self, uri): if uri not in self._mappings_by_uri: msg = f"Resource unavailable for URI: {uri}" raise KeyError(msg) content = self._mappings_by_uri[uri][uri] if isinstance(content, str): content = content.encode("utf-8") return content def __len__(self): return len(self._mappings_by_uri) def __iter__(self): yield from self._mappings_by_uri def __contains__(self, uri): # Implement __contains__ only for efficiency. return uri in self._mappings_by_uri def __repr__(self): return f"" _JSONSCHEMA_URI_TO_FILENAME = { "http://json-schema.org/draft-04/schema": "draft4.json", } class JsonschemaResourceMapping(Mapping): """ Resource mapping that fetches metaschemas from the jsonschema package. """ def __getitem__(self, uri): filename = _JSONSCHEMA_URI_TO_FILENAME[uri] return pkgutil.get_data("asdf._jsonschema", f"schemas/{filename}") def __len__(self): return len(_JSONSCHEMA_URI_TO_FILENAME) def __iter__(self): yield from _JSONSCHEMA_URI_TO_FILENAME def __repr__(self): return "JsonschemaResourceMapping()" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/schema.py0000644000175100001770000006173014653725311014605 0ustar00runnerdockerimport copy import datetime import json import warnings from collections import OrderedDict from collections.abc import Mapping from functools import lru_cache from numbers import Integral from operator import methodcaller import numpy as np import yaml from asdf._jsonschema import validators as mvalidators from asdf._jsonschema.exceptions import RefResolutionError, ValidationError from . import constants, generic_io, reference, tagged, treeutil, util, versioning, yamlutil from .config import get_config from .exceptions import AsdfDeprecationWarning, AsdfWarning from .util import _patched_urllib_parse YAML_SCHEMA_METASCHEMA_ID = "http://stsci.edu/schemas/yaml-schema/draft-01" __all__ = ["validate", "fill_defaults", "remove_defaults", "check_schema", "load_schema"] PYTHON_TYPE_TO_YAML_TAG = { None: "null", str: "str", bytes: "str", bool: "bool", int: "int", float: "float", list: "seq", dict: "map", set: "set", OrderedDict: "omap", } # Prepend full YAML tag prefix for k, v in PYTHON_TYPE_TO_YAML_TAG.items(): PYTHON_TYPE_TO_YAML_TAG[k] = constants.YAML_TAG_PREFIX + v def _type_to_tag(type_): for base in type_.mro(): if base in PYTHON_TYPE_TO_YAML_TAG: return PYTHON_TYPE_TO_YAML_TAG[base] return None def _tag_to_uri(input_str): if not input_str.startswith(constants.STSCI_SCHEMA_TAG_BASE): return input_str warnings.warn( "Resolving by tag is deprecated. Use uris instead of tags", AsdfDeprecationWarning, ) return f"http://stsci.edu/schemas/asdf{input_str[len(constants.STSCI_SCHEMA_TAG_BASE):]}" def validate_tag(validator, tag_pattern, instance, schema): """ Implements the tag validation directive, which checks the tag against a pattern that may include wildcards. See `asdf.util.uri_match` for details on the matching behavior. """ instance_tag = instance._tag if hasattr(instance, "_tag") else _type_to_tag(type(instance)) if instance_tag is None: yield ValidationError( f"mismatched tags, wanted '{tag_pattern}', got unhandled object type '{util.get_class_name(instance)}'", ) if not util.uri_match(tag_pattern, instance_tag): yield ValidationError(f"mismatched tags, wanted '{tag_pattern}', got '{instance_tag}'") def validate_propertyOrder(validator, order, instance, schema): """ Stores a value on the `tagged.TaggedDict` instance so that properties can be written out in the preferred order. In that sense this isn't really a "validator", but using the `jsonschema` library's extensible validation system is the easiest way to get this property assigned. """ if not validator.is_type(instance, "object"): return if not order: # propertyOrder may be an empty list return instance.property_order = order def validate_flowStyle(validator, flow_style, instance, schema): """ Sets a flag on the `tagged.TaggedList` or `tagged.TaggedDict` object so that the YAML generator knows which style to use to write the element. In that sense this isn't really a "validator", but using the `jsonschema` library's extensible validation system is the easiest way to get this property assigned. """ if not (validator.is_type(instance, "object") or validator.is_type(instance, "array")): return instance.flow_style = flow_style def validate_style(validator, style, instance, schema): """ Sets a flag on the `tagged.TaggedString` object so that the YAML generator knows which style to use to write the string. In that sense this isn't really a "validator", but using the `jsonschema` library's extensible validation system is the easiest way to get this property assigned. """ if not validator.is_type(instance, "string"): return instance.style = style def validate_type(validator, types, instance, schema): """ PyYAML returns strings that look like dates as datetime objects. However, as far as JSON is concerned, this is type==string and format==date-time. That detects for that case and doesn't raise an error, otherwise falling back to the default type checker. """ if isinstance(instance, datetime.datetime) and schema.get("format") == "date-time" and "string" in types: return None return mvalidators.Draft4Validator.VALIDATORS["type"](validator, types, instance, schema) def validate_enum(validator, enums, instance, schema): """ `asdf.tagged.Tagged` objects will fail in the default enum validator """ if isinstance(instance, tagged.Tagged): instance = instance.base yield from mvalidators.Draft4Validator.VALIDATORS["enum"](validator, enums, instance, schema) YAML_VALIDATORS = util.HashableDict(mvalidators.Draft4Validator.VALIDATORS.copy()) YAML_VALIDATORS.update( { "tag": validate_tag, "propertyOrder": validate_propertyOrder, "flowStyle": validate_flowStyle, "style": validate_style, "type": validate_type, "enum": validate_enum, }, ) def validate_fill_default(validator, properties, instance, schema): if not validator.is_type(instance, "object"): return for property_, subschema in properties.items(): if "default" in subschema: instance.setdefault(property_, subschema["default"]) yield from mvalidators.Draft4Validator.VALIDATORS["properties"](validator, properties, instance, schema) FILL_DEFAULTS = util.HashableDict() for key in ("allOf", "items"): FILL_DEFAULTS[key] = mvalidators.Draft4Validator.VALIDATORS[key] FILL_DEFAULTS["properties"] = validate_fill_default def validate_remove_default(validator, properties, instance, schema): if not validator.is_type(instance, "object"): return for property_, subschema in properties.items(): if subschema.get("default", None) is not None and instance.get(property_, None) == subschema["default"]: del instance[property_] yield from mvalidators.Draft4Validator.VALIDATORS["properties"](validator, properties, instance, schema) REMOVE_DEFAULTS = util.HashableDict() for key in ("allOf", "items"): REMOVE_DEFAULTS[key] = mvalidators.Draft4Validator.VALIDATORS[key] REMOVE_DEFAULTS["properties"] = validate_remove_default class _ValidationContext: """ Context that tracks (tree node, schema fragment) pairs that have already been validated. Instances of this class are context managers that track how many times they have been entered, and only reset themselves when exiting the outermost context. """ __slots__ = ["_depth", "_seen"] def __init__(self): self._depth = 0 self._seen = set() def add(self, instance, schema): """ Inform the context that an instance has been validated against a schema fragment. """ self._seen.add(self._make_seen_key(instance, schema)) def seen(self, instance, schema): """ Return True if an instance has already been validated against a schema fragment. """ return self._make_seen_key(instance, schema) in self._seen def __enter__(self): self._depth += 1 return self def __exit__(self, exc_type, exc_value, traceback): self._depth -= 1 if self._depth == 0: self._seen = set() def _make_seen_key(self, instance, schema): return (id(instance), id(schema)) @lru_cache def _create_validator(validators=YAML_VALIDATORS, visit_repeat_nodes=False): meta_schema = _load_schema_cached(YAML_SCHEMA_METASCHEMA_ID, _tag_to_uri, False) type_checker = mvalidators.Draft4Validator.TYPE_CHECKER.redefine_many( { "array": lambda checker, instance: isinstance(instance, (list, tuple)), "integer": lambda checker, instance: not isinstance(instance, bool) and isinstance(instance, Integral), "string": lambda checker, instance: isinstance(instance, (str, np.str_)), }, ) id_of = mvalidators.Draft4Validator.ID_OF ASDFvalidator = mvalidators.create( meta_schema=meta_schema, validators=validators, type_checker=type_checker, id_of=id_of, ) def _patch_init(cls): original_init = cls.__init__ def init(self, *args, **kwargs): self.ctx = kwargs.pop("ctx", None) self.serialization_context = kwargs.pop("serialization_context", None) original_init(self, *args, **kwargs) cls.__init__ = init def _patch_iter_errors(cls): original_iter_errors = cls.iter_errors cls._context = _ValidationContext() def iter_errors(self, instance, *args, **kwargs): # We can't validate anything that looks like an external reference, # since we don't have the actual content, so we just have to defer # it for now. If the user cares about complete validation, they # can call `AsdfFile.resolve_references`. with self._context: if self._context.seen(instance, self.schema): # We've already validated this instance against this schema, # no need to do it again. return if not visit_repeat_nodes: self._context.add(instance, self.schema) if (isinstance(instance, dict) and "$ref" in instance) or isinstance(instance, reference.Reference): return if not self.schema: tag = getattr(instance, "_tag", None) if tag is not None and self.serialization_context.extension_manager.handles_tag_definition(tag): tag_def = self.serialization_context.extension_manager.get_tag_definition(tag) schema_uris = tag_def.schema_uris # Must validate against all schema_uris for schema_uri in schema_uris: try: with self.resolver.resolving(schema_uri) as resolved: yield from self.descend(instance, resolved) except RefResolutionError: warnings.warn(f"Unable to locate schema file for '{tag}': '{schema_uri}'", AsdfWarning) if isinstance(instance, dict): for val in instance.values(): yield from self.iter_errors(val) elif isinstance(instance, list): for val in instance: yield from self.iter_errors(val) else: yield from original_iter_errors(self, instance) cls.iter_errors = iter_errors _patch_init(ASDFvalidator) _patch_iter_errors(ASDFvalidator) return ASDFvalidator @lru_cache def _load_schema(url): if url.startswith("http://") or url.startswith("https://") or url.startswith("asdf://"): msg = f"Unable to fetch schema from non-file URL: {url}" raise FileNotFoundError(msg) with generic_io.get_file(url) as fd: if isinstance(url, str) and url.endswith("json"): json_data = fd.read().decode("utf-8") result = json.loads(json_data, object_pairs_hook=OrderedDict) else: # The following call to yaml.load is safe because we're # using a loader that inherits from pyyaml's SafeLoader. result = yaml.load(fd, Loader=yamlutil.AsdfLoader) # noqa: S506 return result, fd.uri def _make_schema_loader(resolver): if resolver is None: resolver = _tag_to_uri def load_schema(url): # Check if this is a URI provided by the new # Mapping API: resource_manager = get_config().resource_manager if url not in resource_manager: # Allow the resolvers to do their thing, in case they know # how to turn this string into a URI that the resource manager # recognizes. url = resolver(str(url)) if url in resource_manager: content = resource_manager[url] # The jsonschema metaschemas are JSON, but pyyaml # doesn't mind. # The following call to yaml.load is safe because we're # using a loader that inherits from pyyaml's SafeLoader. result = yaml.load(content, Loader=yamlutil.AsdfLoader) # noqa: S506 return result, url # If not, this must be a URL (or missing). Fall back to fetching # the schema the old way: return _load_schema(url) return load_schema def _make_jsonschema_refresolver(url_mapping): handlers = {} schema_loader = _make_schema_loader(url_mapping) def get_schema(url): return schema_loader(url)[0] for x in ["http", "https", "file", "tag", "asdf"]: handlers[x] = get_schema # Supplying our own implementation of urljoin_cache # allows asdf:// URIs to be resolved correctly. urljoin_cache = lru_cache(1024)(_patched_urllib_parse.urljoin) # We set cache_remote=False here because we do the caching of # remote schemas here in `load_schema`, so we don't need # jsonschema to do it on our behalf. Setting it to `True` # counterintuitively makes things slower. return mvalidators.RefResolver( "", {}, cache_remote=False, handlers=handlers, urljoin_cache=urljoin_cache, ) def load_schema(url, resolver=None, resolve_references=False): """ Load a schema from the given URL. Parameters ---------- url : str The path to the schema resolver : callable, optional A callback function used to map URIs to other URIs. The callable must take a string and return a string or `None`. This is useful, for example, when a remote resource has a mirror on the local filesystem that you wish to use. resolve_references : bool, optional If ``True``, resolve all ``$ref`` references. """ if resolver is None: resolver = _tag_to_uri # We want to cache the work that went into constructing the schema, but returning # the same object is treacherous, because users who mutate the result will not # expect that they're changing the schema everywhere. return copy.deepcopy(_load_schema_cached(url, resolver, resolve_references)) def _safe_resolve(resolver, json_id, uri): """ This function handles the tricky task of resolving a schema URI in the presence of both new and legacy extensions. There are two senses of "resolve" here: one is to resolve the URI to a file:// URL using the legacy extension resolver object. The other is to resolve relative URIs against the id of the current schema document, which is what generic_io.resolve_uri does. For URIs associated with new-style extensions, we want to resolve with generic_io.resolve_uri, but not with the resolver object, otherwise we risk mangling URIs that share a prefix with a resolver mapping. """ # We can't use urllib.parse here because tag: URIs don't # parse correctly. parts = uri.split("#") base = parts[0] fragment = parts[1] if len(parts) > 1 else "" # The generic_io.resolve_uri method cannot operate on tag: URIs. # New-style extensions don't support $ref with a tag URI target anyway, # so it's safe to feed this through the resolver right away. if base.startswith("tag:"): base = resolver(base) # Resolve relative URIs (e.g., #foo/bar, ../foo/bar) against # the current schema id. base = generic_io.resolve_uri(json_id, base) # Use the resolver object only if the URI does not belong to one # of the new-style extensions. if base not in get_config().resource_manager: base = resolver(base) return base, fragment @lru_cache def _load_schema_cached(url, resolver, resolve_references): if resolver is None: resolver = _tag_to_uri loader = _make_schema_loader(resolver) schema, url = loader(url) if resolve_references: def resolve_refs(node, json_id): if json_id is None: json_id = url if isinstance(node, dict) and "$ref" in node: suburl_base, suburl_fragment = _safe_resolve(resolver, json_id, node["$ref"]) if suburl_base == url or suburl_base == schema.get("id"): # This is a local ref, which we'll resolve in both cases. subschema = schema else: subschema = load_schema(suburl_base, resolver, True) return reference.resolve_fragment(subschema, suburl_fragment) return node schema = treeutil.walk_and_modify(schema, resolve_refs) return schema def get_validator( schema=None, ctx=None, validators=None, url_mapping=None, *args, _visit_repeat_nodes=False, _serialization_context=None, **kwargs, ): """ Get a JSON schema validator object for the given schema. The additional *args and **kwargs are passed along to `~jsonschema.protocols.Validator.validate`. Parameters ---------- schema : schema, optional Explicit schema to use. If not provided, the schema to use is determined by the tag on instance (or subinstance). ctx : AsdfFile context Used to resolve tags and urls validators : dict, optional A dictionary mapping properties to validators to use (instead of the built-in ones and ones provided by extension types). url_mapping : callable, optional A callable that takes one string argument and returns a string to convert remote URLs into local ones. _visit_repeat_nodes : bool, optional Force the validator to visit nodes that it has already seen. This flag is a temporary hack to support a specific project that uses a custom validator to update a .fits file. Setting `True` is discouraged and will lead to RecursionError in trees containing reference cycles. Returns ------- validator : jsonschema.Validator """ if ctx is None: from ._asdf import AsdfFile ctx = AsdfFile() if _serialization_context is None: _serialization_context = ctx._create_serialization_context() if validators is None: validators = util.HashableDict(YAML_VALIDATORS.copy()) validators.update(ctx._extension_manager.validator_manager.get_jsonschema_validators()) kwargs["resolver"] = _make_jsonschema_refresolver(url_mapping) # We don't just call validators.validate() directly here, because # that validates the schema itself, wasting a lot of time (at the # time of this writing, it was half of the runtime of the unit # test suite!!!). Instead, we assume that the schemas are valid # through the running of the unit tests, not at run time. cls = _create_validator(validators=validators, visit_repeat_nodes=_visit_repeat_nodes) return cls({} if schema is None else schema, *args, ctx=ctx, serialization_context=_serialization_context, **kwargs) def _validate_large_literals(instance, reading): """ Validate that the tree has no large numeric literals. """ def _validate(value): if value <= constants.MAX_NUMBER and value >= constants.MIN_NUMBER: return if reading: warnings.warn( f"Invalid integer literal value {value} detected while reading file. " "The value has been read safely, but the file should be " "fixed.", AsdfWarning, ) else: msg = f"Integer value {value} is too large to safely represent as a literal in ASDF" raise ValidationError(msg) if isinstance(instance, Integral): _validate(instance) elif isinstance(instance, Mapping): for key in instance: if isinstance(key, Integral): _validate(key) def _validate_mapping_keys(instance, reading): """ Validate that mappings do not contain illegal key types (as of ASDF Standard 1.6.0, only str, int, and bool are permitted). """ if not isinstance(instance, Mapping): return for key in instance: if isinstance(key, tagged.Tagged) or not isinstance(key, (str, int, bool)): if reading: warnings.warn( f"Invalid mapping key {key} detected while reading file. " "The value has been read safely, but the file should be " "fixed.", AsdfWarning, ) else: msg = f"Mapping key {key} is not permitted. Valid types: str, int, bool." raise ValidationError(msg) def validate(instance, ctx=None, schema=None, validators=None, reading=False, *args, **kwargs): """ Validate the given instance (which must be a tagged tree) against the appropriate schema. The schema itself is located using the tag on the instance. The additional ``*args`` and ``**kwargs`` are passed along to `~jsonschema.protocols.Validator.validate`. Parameters ---------- instance : tagged tree ctx : AsdfFile context Used to resolve tags and urls schema : schema, optional Explicit schema to use. If not provided, the schema to use is determined by the tag on instance (or subinstance). validators : dict, optional A dictionary mapping properties to validators to use (instead of the built-in ones and ones provided by extension types). reading: bool, optional Indicates whether validation is being performed when the file is being read. This is useful to allow for different validation behavior when reading vs writing files. """ if ctx is None: from ._asdf import AsdfFile ctx = AsdfFile() validator = get_validator({} if schema is None else schema, ctx, validators, None, *args, **kwargs) validator.validate(instance) additional_validators = [_validate_large_literals] if ctx.version >= versioning.RESTRICTED_KEYS_MIN_VERSION: additional_validators.append(_validate_mapping_keys) def _callback(instance): for validator in additional_validators: validator(instance, reading) treeutil.walk(instance, _callback) def fill_defaults(instance, ctx, reading=False): """ For any default values in the schema, add them to the tree if they don't exist. Parameters ---------- instance : tagged tree ctx : AsdfFile context Used to resolve tags and urls reading: bool, optional Indicates whether the ASDF file is being read (in contrast to being written). """ validate(instance, ctx, validators=FILL_DEFAULTS, reading=reading) def remove_defaults(instance, ctx): """ For any values in the tree that are the same as the default values specified in the schema, remove them from the tree. Parameters ---------- instance : tagged tree ctx : AsdfFile context Used to resolve tags and urls """ validate(instance, ctx, validators=REMOVE_DEFAULTS) def check_schema(schema, validate_default=True): """ Check a given schema to make sure it is valid YAML schema. Parameters ---------- schema : dict The schema object, as returned by ``load_schema``. validate_default : bool, optional Set to `True` to validate the content of the default field against the schema. """ validators = util.HashableDict(mvalidators.Draft4Validator.VALIDATORS.copy()) if validate_default: # The jsonschema library doesn't validate defaults # on its own. instance_validator = get_validator(schema) instance_scope = schema.get("id", "") def _validate_default(validator, default, instance, schema): if not validator.is_type(instance, "object"): return if "default" in instance: instance_validator.resolver.push_scope(instance_scope) try: yield from instance_validator.descend(instance["default"], instance) finally: instance_validator.resolver.pop_scope() validators.update({"default": _validate_default}) def applicable_validators(schema): items = list(schema.items()) items.append(("default", "")) return items else: applicable_validators = methodcaller("items") meta_schema_id = schema.get("$schema", YAML_SCHEMA_METASCHEMA_ID) meta_schema = _load_schema_cached(meta_schema_id, _tag_to_uri, False) resolver = _make_jsonschema_refresolver(_tag_to_uri) cls = mvalidators.create( meta_schema=meta_schema, validators=validators, type_checker=mvalidators.Draft4Validator.TYPE_CHECKER, id_of=mvalidators.Draft4Validator.ID_OF, applicable_validators=applicable_validators, ) validator = cls(meta_schema, resolver=resolver) validator.validate(schema) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/search.py0000644000175100001770000003151314653725311014606 0ustar00runnerdocker""" Utilities for searching ASDF trees. """ import builtins import inspect import re import typing from ._display import DEFAULT_MAX_COLS, DEFAULT_MAX_ROWS, DEFAULT_SHOW_VALUES, format_faint, format_italic, render_tree from ._node_info import NodeSchemaInfo, collect_schema_info from .treeutil import get_children, is_container from .util import NotSet __all__ = ["AsdfSearchResult"] class AsdfSearchResult: """ Result of a call to AsdfFile.search. """ def __init__( self, identifiers, node, filters=None, parent_node=None, max_rows=DEFAULT_MAX_ROWS, max_cols=DEFAULT_MAX_COLS, show_values=DEFAULT_SHOW_VALUES, ): self._identifiers = identifiers self._node = node self._filters = [] if filters is None else filters self._parent_node = parent_node self._max_rows = max_rows self._max_cols = max_cols self._show_values = show_values def format(self, max_rows=NotSet, max_cols=NotSet, show_values=NotSet): """ Change formatting parameters of the rendered tree. Parameters ---------- max_rows : int, tuple, None, or NotSet, optional Maximum number of lines to print. Nodes that cannot be displayed will be elided with a message. If int, constrain total number of displayed lines. If tuple, constrain lines per node at the depth corresponding \ to the tuple index. If None, display all lines. If NotSet, retain existing value. max_cols : int, None or NotSet, optional Maximum length of line to print. Nodes that cannot be fully displayed will be truncated with a message. If int, constrain length of displayed lines. If None, line length is unconstrained. If NotSet, retain existing value. show_values : bool or NotSet, optional Set to False to disable display of primitive values in the rendered tree. Set to NotSet to retain existign value. Returns ------- AsdfSearchResult the reformatted search result """ if max_rows is NotSet: max_rows = self._max_rows if max_cols is NotSet: max_cols = self._max_cols if show_values is NotSet: show_values = self._show_values return AsdfSearchResult( self._identifiers, self._node, filters=self._filters, parent_node=self._parent_node, max_rows=max_rows, max_cols=max_cols, show_values=show_values, ) def _maybe_compile_pattern(self, query): if isinstance(query, str): return re.compile(query) return query def _safe_equals(self, a, b): try: result = a == b except Exception: return False if isinstance(result, bool): return result return False def _get_fully_qualified_type(self, value): value_type = type(value) if value_type.__module__ == "builtins": return value_type.__name__ return ".".join([value_type.__module__, value_type.__name__]) def search(self, key=NotSet, type_=NotSet, value=NotSet, filter_=None): """ Further narrow the search. Parameters ---------- key : NotSet, str, or any other object Search query that selects nodes by dict key or list index. If NotSet, the node key is unconstrained. If str, the input is searched among keys/indexes as a regular expression pattern. If any other object, node's key or index must equal the queried key. type_ : NotSet, str, or builtins.type Search query that selects nodes by type. If NotSet, the node type is unconstrained. If str, the input is searched among (fully qualified) node type names as a regular expression pattern. If builtins.type, the node must be an instance of the input. value : NotSet, str, or any other object Search query that selects nodes by value. If NotSet, the node value is unconstrained. If str, the input is searched among values as a regular expression pattern. If any other object, node's value must equal the queried value. filter_ : callable Callable that filters nodes by arbitrary criteria. The callable accepts one or two arguments: - the node - the node's list index or dict key (optional) and returns True to retain the node, or False to remove it from the search results. Returns ------- AsdfSearchResult the subsequent search result """ if not (isinstance(type_, (str, typing.Pattern, builtins.type)) or type_ is NotSet): msg = "type must be NotSet, str, regular expression, or instance of builtins.type" raise TypeError(msg) # value and key arguments can be anything, but pattern and str have special behavior key = self._maybe_compile_pattern(key) type_ = self._maybe_compile_pattern(type_) value = self._maybe_compile_pattern(value) filter_ = _wrap_filter(filter_) def _filter(node, identifier): if isinstance(key, typing.Pattern): if key.search(str(identifier)) is None: return False elif key is not NotSet and not self._safe_equals(identifier, key): return False if isinstance(type_, typing.Pattern): fully_qualified_node_type = self._get_fully_qualified_type(node) if type_.search(fully_qualified_node_type) is None: return False elif isinstance(type_, builtins.type) and not isinstance(node, type_): return False if isinstance(value, typing.Pattern): if is_container(node): # The string representation of a container object tends to # include the child object values, but that's probably not # what searchers want. return False if value.search(str(node)) is None: return False elif value is not NotSet and not self._safe_equals(node, value): return False if filter_ is not None and not filter_(node, identifier): return False return True return AsdfSearchResult( self._identifiers, self._node, filters=[*self._filters, _filter], parent_node=self._parent_node, max_rows=self._max_rows, max_cols=self._max_cols, show_values=self._show_values, ) def replace(self, value): """ Assign a new value in place of all leaf nodes in the search results. Parameters ---------- value : object """ results = [] def _callback(identifiers, parent, node, children): if all(f(node, identifiers[-1]) for f in self._filters): results.append((identifiers[-1], parent)) _walk_tree_breadth_first(self._identifiers, self._node, _callback) for identifier, parent in results: parent[identifier] = value @property def node(self): """ Retrieve the leaf node of a tree with one search result. Returns ------- object the single node of the search result """ results = self.nodes if len(results) == 0: return None if len(results) == 1: return results[0] msg = "More than one result" raise RuntimeError(msg) @property def path(self): """ Retrieve the path to the leaf node of a tree with one search result. Returns ------- str the path to the searched node """ results = self.paths if len(results) == 0: return None if len(results) == 1: return results[0] msg = "More than one result" raise RuntimeError(msg) @property def nodes(self): """ Retrieve all leaf nodes in the search results. Returns ------- list of object every node in the search results (breadth-first order) """ results = [] def _callback(identifiers, parent, node, children): if all(f(node, identifiers[-1]) for f in self._filters): results.append(node) _walk_tree_breadth_first(self._identifiers, self._node, _callback) return results @property def paths(self): """ Retrieve the paths to all leaf nodes in the search results. Returns ------- list of str the path to every node in the search results """ results = [] def _callback(identifiers, parent, node, children): if all(f(node, identifiers[-1]) for f in self._filters): results.append(_build_path(identifiers)) _walk_tree_breadth_first(self._identifiers, self._node, _callback) return results def __repr__(self): lines = render_tree( self._node, max_rows=self._max_rows, max_cols=self._max_cols, show_values=self._show_values, filters=self._filters, identifier=self._identifiers[-1], ) if len(lines) == 0: return format_faint(format_italic("No results found.")) return "\n".join(lines) def schema_info(self, key="description", preserve_list=True, refresh_extension_manager=False): """ Get a nested dictionary of the schema information for a given key, relative to this search result. Parameters ---------- key : str The key to look up. Default: "description" preserve_list : bool If True, then lists are preserved. Otherwise, they are turned into dicts. refresh_extension_manager : bool If `True`, refresh the extension manager before looking up the key. This is useful if you want to make sure that the schema data for a given key is up to date. """ return collect_schema_info( key, None, self._node, filters=self._filters, preserve_list=preserve_list, refresh_extension_manager=refresh_extension_manager, ) def __getitem__(self, key): if isinstance(self._node, (dict, list, tuple)) or NodeSchemaInfo.traversable(self._node): child = self._node.__asdf_traverse__()[key] if NodeSchemaInfo.traversable(self._node) else self._node[key] else: msg = "This node cannot be indexed" raise TypeError(msg) return AsdfSearchResult( [*self._identifiers, key], child, filters=self._filters, parent_node=self._node, max_rows=self._max_rows, max_cols=self._max_cols, show_values=self._show_values, ) def _walk_tree_breadth_first(root_identifiers, root_node, callback): """ Walk the tree in breadth-first order (useful for prioritizing lower-depth nodes). """ current_nodes = [(root_identifiers, None, root_node)] seen = set() while True: next_nodes = [] for identifiers, parent, node in current_nodes: if (isinstance(node, (dict, list, tuple)) or NodeSchemaInfo.traversable(node)) and id(node) in seen: continue tnode = node.__asdf_traverse__() if NodeSchemaInfo.traversable(node) else node children = get_children(tnode) callback(identifiers, parent, node, [c for _, c in children]) next_nodes.extend([([*identifiers, i], node, c) for i, c in children]) seen.add(id(node)) if len(next_nodes) == 0: break current_nodes = next_nodes def _build_path(identifiers): """ Generate the Python code needed to extract the identified node. """ if len(identifiers) == 0: return "" return identifiers[0] + "".join(f"[{i!r}]" for i in identifiers[1:]) def _wrap_filter(filter_): """ Ensure that filter callable accepts the expected number of arguments. """ if filter_ is None: return None arity = len(inspect.signature(filter_).parameters) if arity == 1: return lambda n, i: filter_(n) if arity == 2: return filter_ msg = "filter must accept 1 or 2 arguments" raise ValueError(msg) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/stream.py0000644000175100001770000000034414653725311014632 0ustar00runnerdockerimport warnings from .exceptions import AsdfDeprecationWarning from .tags.core.stream import Stream # noqa: F401 warnings.warn( "asdf.stream is deprecated. Please use asdf.tags.core.stream", AsdfDeprecationWarning, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/tagged.py0000644000175100001770000001054114653725311014572 0ustar00runnerdocker""" This file manages a transient representation of the tree made up of simple Python data types (lists, dicts, scalars) wrapped inside of `Tagged` subclasses, which add a ``tag`` attribute to hold the associated YAML tag. Below "basic data types" refers to the basic built-in data types defined in the core YAML specification. "Custom data types" are specialized tags that are added by ASDF or third-parties that are not in the YAML specification. When YAML is loaded from disk, we want to first validate it using JSON schema, which only understands basic Python data types, not the ``Nodes`` that ``pyyaml`` uses as its intermediate representation. However, basic Python data types do not preserve the tag information from the YAML file that we need later to convert elements to custom data types. Therefore, the approach here is to wrap those basic types inside of `Tagged` objects long enough to run through the asdf._jsonschema validator, and then convert to custom data types and throwing away the tag annotations in the process. Upon writing, the custom data types are first converted to basic Python data types wrapped in `Tagged` objects. The tags assigned to the ``Tagged`` objects are then used to write tags to the YAML file. All of this is an implementation detail of the our custom YAML loader and dumper (``yamlutil.AsdfLoader`` and ``yamlutil.AsdfDumper``) and is not intended to be exposed to the end user. """ from collections import UserDict, UserList, UserString from copy import copy, deepcopy __all__ = ["tag_object", "get_tag", "Tagged", "TaggedDict", "TaggedList", "TaggedString"] class Tagged: """ Base class of classes that wrap a given object and store a tag with it. """ _base_type = None @property def base(self): """Convert to base type""" return self._base_type(self) class TaggedDict(Tagged, UserDict, dict): """ A Python dict with a tag attached. """ _base_type = dict flow_style = None property_order = None def __init__(self, data=None, tag=None): if data is None: data = {} self.data = data self._tag = tag def __eq__(self, other): return isinstance(other, TaggedDict) and self.data == other.data and self._tag == other._tag def __deepcopy__(self, memo): data_copy = deepcopy(self.data, memo) return TaggedDict(data_copy, self._tag) def __copy__(self): data_copy = copy(self.data) return TaggedDict(data_copy, self._tag) class TaggedList(Tagged, UserList, list): """ A Python list with a tag attached. """ _base_type = list flow_style = None def __init__(self, data=None, tag=None): if data is None: data = [] self.data = data self._tag = tag def __eq__(self, other): return isinstance(other, TaggedList) and self.data == other.data and self._tag == other._tag def __deepcopy__(self, memo): data_copy = deepcopy(self.data, memo) return TaggedList(data_copy, self._tag) def __copy__(self): data_copy = copy(self.data) return TaggedList(data_copy, self._tag) class TaggedString(Tagged, UserString, str): """ A Python string with a tag attached. """ _base_type = str style = None def __eq__(self, other): return isinstance(other, TaggedString) and str.__eq__(self, other) and self._tag == other._tag def tag_object(tag, instance, ctx=None): """ Tag an object by wrapping it in a ``Tagged`` instance. """ if isinstance(instance, Tagged): instance._tag = tag elif isinstance(instance, dict): instance = TaggedDict(instance, tag) elif isinstance(instance, list): instance = TaggedList(instance, tag) elif isinstance(instance, str): instance = TaggedString(instance) instance._tag = tag else: from . import AsdfFile, yamlutil if ctx is None: ctx = AsdfFile() try: instance = yamlutil.custom_tree_to_tagged_tree(instance, ctx) except TypeError as err: msg = f"Don't know how to tag a {type(instance)}" raise TypeError(msg) from err instance._tag = tag return instance def get_tag(instance): """ Get the tag associated with the instance, if there is one. """ return getattr(instance, "_tag", None) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1530983 asdf-3.4.0/asdf/tags/0000755000175100001770000000000014653725331013724 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/tags/__init__.py0000644000175100001770000000000014653725311016021 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1530983 asdf-3.4.0/asdf/tags/core/0000755000175100001770000000000014653725331014654 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/tags/core/__init__.py0000644000175100001770000000240514653725311016764 0ustar00runnerdockerimport collections from .constant import Constant from .external_reference import ExternalArrayReference from .integer import IntegerType from .ndarray import NDArrayType from .stream import Stream __all__ = [ "AsdfObject", "Constant", "Software", "HistoryEntry", "ExtensionMetadata", "SubclassMetadata", "NDArrayType", "IntegerType", "ExternalArrayReference", "Stream", ] # AsdfObject inherits both collections.UserDict and dict to allow it # to pass an isinstance(..., dict) check and to allow it to be "lazy" # loaded when "lazy_tree=True". class AsdfObject(collections.UserDict, dict): pass class Software(dict): pass class HistoryEntry(dict): pass class ExtensionMetadata(dict): @property def extension_uri(self): return self.get("extension_uri") @property def extension_class(self): return self["extension_class"] @property def software(self): return self.get("software") class SubclassMetadata(dict): """ The tagged object supported by this class is part of an experimental feature that has since been dropped from this library. This class remains so that ASDF files that used that feature will still deserialize without warnings. """ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/tags/core/constant.py0000644000175100001770000000021214653725311017050 0ustar00runnerdockerclass Constant: def __init__(self, value): self._value = value @property def value(self): return self._value ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/tags/core/external_reference.py0000644000175100001770000000321614653725311021066 0ustar00runnerdockerclass ExternalArrayReference: """ Store a reference to an array in an external File. This class is a simple way of referring to an array in another file. It provides no way to resolve these references, that is left to the user. It also performs no checking to see if any of the arguments are correct. e.g. if the file exits. Parameters ---------- fileuri: `str` The path to the path to be referenced. Can be relative to the file containing the reference. target: `object` Some internal target to the data in the file. Examples may include a HDU index, a HDF path or an asdf fragment. dtype: `str` The (numpy) dtype of the contained array. shape: `tuple` The shape of the array to be loaded. Examples -------- >>> import asdf >>> ref = asdf.ExternalArrayReference("myfitsfile.fits", 1, "float64", (100, 100)) >>> tree = {'reference': ref} >>> with asdf.AsdfFile(tree) as ff: ... ff.write_to("test.asdf") """ def __init__(self, fileuri, target, dtype, shape): self.fileuri = str(fileuri) self.target = target self.dtype = dtype self.shape = tuple(shape) def __repr__(self): return f"" def __str__(self): return repr(self) def __eq__(self, other): uri = self.fileuri == other.fileuri target = self.target == other.target dtype = self.dtype == other.dtype shape = self.shape == other.shape return all((uri, target, dtype, shape)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/tags/core/integer.py0000644000175100001770000000403114653725311016657 0ustar00runnerdockerfrom numbers import Integral class IntegerType: """ Enables the storage of arbitrarily large integer values The ASDF Standard mandates that integer literals in the tree can be no larger than 64 bits. Use of this class enables the storage of arbitrarily large integer values. When reading files that contain arbitrarily large integers, the values that are restored in the tree will be raw Python `int` instances. Parameters ---------- value: `numbers.Integral` A Python integral value (e.g. `int` or `numpy.integer`) storage_type: `str`, optional Optionally overrides the storage type of the array used to represent the integer value. Valid values are "internal" (the default) and "inline" Examples -------- >>> import asdf >>> import random >>> # Create a large integer value >>> largeval = random.getrandbits(100) >>> # Store the large integer value to the tree using asdf.IntegerType >>> tree = dict(largeval=asdf.IntegerType(largeval)) >>> with asdf.AsdfFile(tree) as af: ... af.write_to('largeval.asdf') >>> with asdf.open('largeval.asdf') as aa: ... assert aa['largeval'] == largeval """ def __init__(self, value, storage_type="internal"): if storage_type not in ["internal", "inline"]: msg = f"storage_type '{storage_type}' is not a recognized storage type" raise ValueError(msg) self._value = value self._sign = "-" if value < 0 else "+" self._storage = storage_type def __int__(self): return int(self._value) def __float__(self): return float(self._value) def __eq__(self, other): if isinstance(other, Integral): return self._value == other if isinstance(other, IntegerType): return self._value == other._value msg = f"Can't compare IntegralType to unknown type: {type(other)}" raise ValueError(msg) def __repr__(self): return f"IntegerType({self._value})" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/tags/core/ndarray.py0000644000175100001770000004353114653725311016672 0ustar00runnerdockerimport mmap import sys import numpy as np from numpy import ma from asdf import util from asdf._jsonschema import ValidationError _datatype_names = { "int8": "i1", "int16": "i2", "int32": "i4", "int64": "i8", "uint8": "u1", "uint16": "u2", "uint32": "u4", "uint64": "u8", "float16": "f2", "float32": "f4", "float64": "f8", "complex64": "c8", "complex128": "c16", "bool8": "b1", } _string_datatype_names = {"ascii": "S", "ucs4": "U"} def asdf_byteorder_to_numpy_byteorder(byteorder): if byteorder == "big": return ">" if byteorder == "little": return "<" msg = f"Invalid ASDF byteorder '{byteorder}'" raise ValueError(msg) def asdf_datatype_to_numpy_dtype(datatype, byteorder=None): if byteorder is None: byteorder = sys.byteorder if isinstance(datatype, str) and datatype in _datatype_names: datatype = _datatype_names[datatype] byteorder = asdf_byteorder_to_numpy_byteorder(byteorder) return np.dtype(str(byteorder + datatype)) if ( isinstance(datatype, list) and len(datatype) == 2 and isinstance(datatype[0], str) and isinstance(datatype[1], int) and datatype[0] in _string_datatype_names ): length = datatype[1] byteorder = asdf_byteorder_to_numpy_byteorder(byteorder) datatype = str(byteorder) + str(_string_datatype_names[datatype[0]]) + str(length) return np.dtype(datatype) if isinstance(datatype, dict): if "datatype" not in datatype: msg = f"Field entry has no datatype: '{datatype}'" raise ValueError(msg) name = datatype.get("name", "") byteorder = datatype.get("byteorder", byteorder) shape = datatype.get("shape") datatype = asdf_datatype_to_numpy_dtype(datatype["datatype"], byteorder) if shape is None: return (str(name), datatype) return (str(name), datatype, tuple(shape)) if isinstance(datatype, list): datatype_list = [] for subdatatype in datatype: np_dtype = asdf_datatype_to_numpy_dtype(subdatatype, byteorder) if isinstance(np_dtype, tuple): datatype_list.append(np_dtype) elif isinstance(np_dtype, np.dtype): datatype_list.append(("", np_dtype)) else: msg = "Error parsing asdf datatype" raise RuntimeError(msg) return np.dtype(datatype_list) msg = f"Unknown datatype {datatype}" raise ValueError(msg) def numpy_byteorder_to_asdf_byteorder(byteorder, override=None): if override is not None: return override if byteorder == "=": return sys.byteorder if byteorder == "<": return "little" return "big" def numpy_dtype_to_asdf_datatype(dtype, include_byteorder=True, override_byteorder=None): dtype = np.dtype(dtype) if dtype.names is not None: fields = [] for name in dtype.names: field = dtype.fields[name][0] d = {} d["name"] = name field_dtype, byteorder = numpy_dtype_to_asdf_datatype(field, override_byteorder=override_byteorder) d["datatype"] = field_dtype if include_byteorder: d["byteorder"] = byteorder if field.shape: d["shape"] = list(field.shape) fields.append(d) return fields, numpy_byteorder_to_asdf_byteorder(dtype.byteorder, override=override_byteorder) if dtype.subdtype is not None: return numpy_dtype_to_asdf_datatype(dtype.subdtype[0], override_byteorder=override_byteorder) if dtype.name in _datatype_names: return dtype.name, numpy_byteorder_to_asdf_byteorder(dtype.byteorder, override=override_byteorder) if dtype.name == "bool": return "bool8", numpy_byteorder_to_asdf_byteorder(dtype.byteorder, override=override_byteorder) if dtype.name.startswith("string") or dtype.name.startswith("bytes"): return ["ascii", dtype.itemsize], "big" if dtype.name.startswith("unicode") or dtype.name.startswith("str"): return ( ["ucs4", int(dtype.itemsize / 4)], numpy_byteorder_to_asdf_byteorder(dtype.byteorder, override=override_byteorder), ) msg = f"Unknown dtype {dtype}" raise ValueError(msg) def inline_data_asarray(inline, dtype=None): # np.asarray doesn't handle structured arrays unless the innermost # elements are tuples. To do that, we drill down the first # element of each level until we find a single item that # successfully converts to a scalar of the expected structured # dtype. Then we go through and convert everything at that level # to a tuple. This probably breaks for nested structured dtypes, # but it's probably good enough for now. It also won't work with # object dtypes, but ASDF explicitly excludes those, so we're ok # there. if dtype is not None and dtype.fields is not None: def find_innermost_match(line, depth=0): if not isinstance(line, list) or not len(line): msg = "data can not be converted to structured array" raise ValueError(msg) try: np.asarray(tuple(line), dtype=dtype) except ValueError: return find_innermost_match(line[0], depth + 1) else: return depth depth = find_innermost_match(inline) def convert_to_tuples(line, data_depth, depth=0): if data_depth == depth: return tuple(line) return [convert_to_tuples(x, data_depth, depth + 1) for x in line] inline = convert_to_tuples(inline, depth) return np.asarray(inline, dtype=dtype) def handle_mask(inline): if isinstance(inline, list): if None in inline: inline_array = np.asarray(inline) nones = np.equal(inline_array, None) return np.ma.array(np.where(nones, 0, inline), mask=nones) return [handle_mask(x) for x in inline] return inline inline = handle_mask(inline) inline = np.ma.asarray(inline, dtype=dtype) if not ma.is_masked(inline): return inline.data return inline def numpy_array_to_list(array): def tolist(x): if isinstance(x, (np.ndarray, NDArrayType)): x = x.astype("U").tolist() if x.dtype.char == "S" else x.tolist() if isinstance(x, (list, tuple)): return [tolist(y) for y in x] return x def ascii_to_unicode(x): # Convert byte string arrays to unicode string arrays, since YAML # doesn't handle the former. if isinstance(x, list): return [ascii_to_unicode(y) for y in x] if isinstance(x, bytes): return x.decode("ascii") return x return ascii_to_unicode(tolist(array)) class NDArrayType: def __init__(self, source, shape, dtype, offset, strides, order, mask, data_callback=None): self._source = source self._data_callback = data_callback self._array = None self._mask = mask if isinstance(source, list): self._array = inline_data_asarray(source, dtype) self._array = self._apply_mask(self._array, self._mask) # single element structured arrays can have shape == () # https://github.com/asdf-format/asdf/issues/1540 if shape is not None and ( self._array.shape != tuple(shape) or (len(shape) and shape[0] == "*" and self._array.shape[1:] != tuple(shape[1:])) ): msg = "inline data doesn't match the given shape" raise ValueError(msg) self._shape = shape self._dtype = dtype self._offset = offset self._strides = strides self._order = order def _make_array(self): # If the ASDF file has been updated in-place, then there's # a chance that the block's original data object has been # closed and replaced. We need to check here and re-generate # the array if necessary, otherwise we risk segfaults when # memory mapping. if self._array is not None: base = util.get_array_base(self._array) if isinstance(base, np.memmap) and isinstance(base.base, mmap.mmap): # check if the underlying mmap matches the one generated by generic_io try: fd = self._data_callback(_attr="_fd")() except AttributeError: # external blocks do not have a '_fd' and don't need to be updated fd = None if fd is not None: if getattr(fd, "_mmap", None) is not base.base: self._array = None del fd if self._array is None: if isinstance(self._source, str): # we need to keep _source as a str to allow stdatamodels to # support AsdfInFits data = self._data_callback() else: # cached data is used here so that multiple NDArrayTypes will all use # the same base array data = self._data_callback(_attr="cached_data") if hasattr(data, "base") and isinstance(data.base, mmap.mmap) and data.base.closed: msg = "ASDF file has already been closed. Can not get the data." raise OSError(msg) # compute shape (streaming blocks have '0' data size in the block header) shape = self.get_actual_shape( self._shape, self._strides, self._dtype, data.size, ) self._array = np.ndarray(shape, self._dtype, data, self._offset, self._strides, self._order) self._array = self._apply_mask(self._array, self._mask) return self._array def _apply_mask(self, array, mask): if isinstance(mask, (np.ndarray, NDArrayType)): # Use "mask.view()" here so the underlying possibly # memmapped mask array is freed properly when the masked # array goes away. array = ma.array(array, mask=mask.view()) return array if np.isscalar(mask): if np.isnan(mask): return ma.array(array, mask=np.isnan(array)) return ma.masked_values(array, mask) return array def __array__(self): return self._make_array() def __repr__(self): # repr alone should not force loading of the data if self._array is None: return ( f"<{'array' if self._mask is None else 'masked array'} " f"(unloaded) shape: {self._shape} dtype: {self._dtype}>" ) return repr(self._make_array()) def __str__(self): # str alone should not force loading of the data if self._array is None: return ( f"<{'array' if self._mask is None else 'masked array'} " f"(unloaded) shape: {self._shape} dtype: {self._dtype}>" ) return str(self._make_array()) def get_actual_shape(self, shape, strides, dtype, block_size): """ Get the actual shape of an array, by computing it against the block_size if it contains a ``*``. """ num_stars = shape.count("*") if num_stars == 0: return shape if num_stars == 1: if shape[0] != "*": msg = "'*' may only be in first entry of shape" raise ValueError(msg) stride = strides[0] if strides is not None else np.prod(shape[1:]) * dtype.itemsize missing = int(block_size / stride) return [missing] + shape[1:] msg = f"Invalid shape '{shape}'" raise ValueError(msg) @property def shape(self): if self._shape is None or self._array is not None or "*" in self._shape: # streamed blocks have a '0' data_size in the header so we # need to make the array to get the shape return self.__array__().shape return tuple(self._shape) @property def dtype(self): if self._array is None: return self._dtype return self._make_array().dtype def __len__(self): if self._array is None: return self._shape[0] return len(self._make_array()) def __getattr__(self, attr): # We need to ignore __array_struct__, or unicode arrays end up # getting "double casted" and upsized. This also reduces the # number of array creations in the general case. if attr == "__array_struct__": raise AttributeError # AsdfFile.info will call hasattr(obj, "__asdf_traverse__") which # will trigger this method, making the array, and loading the array # data. Intercept this and raise AttributeError as this class does # not support that method # see: https://github.com/asdf-format/asdf/issues/1553 if attr == "__asdf_traverse__": raise AttributeError return getattr(self._make_array(), attr) def __setitem__(self, *args): # This workaround appears to be necessary in order to avoid a segfault # in the case that array assignment causes an exception. The segfault # originates from the call to __repr__ inside the traceback report. try: self._make_array().__setitem__(*args) except Exception: self._array = None raise def _make_operation(name): def operation(self, *args): return getattr(self._make_array(), name)(*args) return operation for op in [ "__neg__", "__pos__", "__abs__", "__invert__", "__complex__", "__int__", "__long__", "__float__", "__oct__", "__hex__", "__lt__", "__le__", "__eq__", "__ne__", "__gt__", "__ge__", "__cmp__", "__rcmp__", "__add__", "__sub__", "__mul__", "__floordiv__", "__mod__", "__divmod__", "__pow__", "__lshift__", "__rshift__", "__and__", "__xor__", "__or__", "__div__", "__truediv__", "__radd__", "__rsub__", "__rmul__", "__rdiv__", "__rtruediv__", "__rfloordiv__", "__rmod__", "__rdivmod__", "__rpow__", "__rlshift__", "__rrshift__", "__rand__", "__rxor__", "__ror__", "__iadd__", "__isub__", "__imul__", "__idiv__", "__itruediv__", "__ifloordiv__", "__imod__", "__ipow__", "__ilshift__", "__irshift__", "__iand__", "__ixor__", "__ior__", "__getitem__", "__delitem__", "__contains__", ]: setattr(NDArrayType, op, _make_operation(op)) def _get_ndim(instance): if isinstance(instance, list): array = inline_data_asarray(instance) return array.ndim if isinstance(instance, dict): if "shape" in instance: return len(instance["shape"]) if "data" in instance: array = inline_data_asarray(instance["data"]) return array.ndim if isinstance(instance, (np.ndarray, NDArrayType)): return len(instance.shape) return None def validate_ndim(validator, ndim, instance, schema): in_ndim = _get_ndim(instance) if in_ndim != ndim: yield ValidationError(f"Wrong number of dimensions: Expected {ndim}, got {in_ndim}", instance=repr(instance)) def validate_max_ndim(validator, max_ndim, instance, schema): in_ndim = _get_ndim(instance) if in_ndim > max_ndim: yield ValidationError( f"Wrong number of dimensions: Expected max of {max_ndim}, got {in_ndim}", instance=repr(instance), ) def validate_datatype(validator, datatype, instance, schema): if isinstance(instance, list): array = inline_data_asarray(instance) in_datatype, _ = numpy_dtype_to_asdf_datatype(array.dtype) elif isinstance(instance, dict): if "datatype" in instance: in_datatype = instance["datatype"] elif "data" in instance: array = inline_data_asarray(instance["data"]) in_datatype, _ = numpy_dtype_to_asdf_datatype(array.dtype) else: msg = "Not an array" raise ValidationError(msg) elif isinstance(instance, (np.ndarray, NDArrayType)): in_datatype, _ = numpy_dtype_to_asdf_datatype(instance.dtype) else: msg = "Not an array" raise ValidationError(msg) if datatype == in_datatype: return if schema.get("exact_datatype", False): yield ValidationError(f"Expected datatype '{datatype}', got '{in_datatype}'") np_datatype = asdf_datatype_to_numpy_dtype(datatype) np_in_datatype = asdf_datatype_to_numpy_dtype(in_datatype) if not np_datatype.fields: if np_in_datatype.fields: yield ValidationError(f"Expected scalar datatype '{datatype}', got '{in_datatype}'") if not np.can_cast(np_in_datatype, np_datatype, "safe"): yield ValidationError(f"Can not safely cast from '{in_datatype}' to '{datatype}' ") else: if not np_in_datatype.fields: yield ValidationError(f"Expected structured datatype '{datatype}', got '{in_datatype}'") if len(np_in_datatype.fields) != len(np_datatype.fields): yield ValidationError(f"Mismatch in number of columns: Expected {len(datatype)}, got {len(in_datatype)}") for i in range(len(np_datatype.fields)): in_type = np_in_datatype[i] out_type = np_datatype[i] if not np.can_cast(in_type, out_type, "safe"): yield ValidationError( "Can not safely cast to expected datatype: " f"Expected {numpy_dtype_to_asdf_datatype(out_type)[0]}, " f"got {numpy_dtype_to_asdf_datatype(in_type)[0]}", ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/tags/core/stream.py0000644000175100001770000000207414653725311016522 0ustar00runnerdockerfrom .ndarray import numpy_dtype_to_asdf_datatype class Stream: """ Used to put a streamed array into the tree. Examples -------- Save a double-precision array with 1024 columns, one row at a time:: >>> from asdf import AsdfFile, Stream >>> import numpy as np >>> ff = AsdfFile() >>> ff.tree['streamed'] = Stream([1024], np.float64) >>> with open('test.asdf', 'wb') as fd: ... ff.write_to(fd) ... for i in range(200): ... nbytes = fd.write( ... np.array([i] * 1024, np.float64).tobytes()) """ def __init__(self, shape, dtype, strides=None): self._shape = shape self._datatype, self._byteorder = numpy_dtype_to_asdf_datatype(dtype) self._strides = strides self._array = None def _make_array(self): self._array = None def __repr__(self): return f"Stream({self._shape}, {self._datatype}, strides={self._strides})" def __str__(self): return str(self.__repr__()) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1530983 asdf-3.4.0/asdf/testing/0000755000175100001770000000000014653725331014443 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/testing/__init__.py0000644000175100001770000000000014653725311016540 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/testing/helpers.py0000644000175100001770000000375614653725311016470 0ustar00runnerdocker""" Helpers for writing unit tests of ASDF support. """ import warnings from io import BytesIO import asdf from asdf.exceptions import AsdfDeprecationWarning from asdf.versioning import AsdfSpec def format_tag(organization, standard, version, tag_name): """ Format a YAML tag. """ warnings.warn("format_tag is deprecated", AsdfDeprecationWarning) tag = f"tag:{organization}:{standard}/{tag_name}" if version is None: return tag if isinstance(version, AsdfSpec): version = str(version.spec) return f"{tag}-{version}" def roundtrip_object(obj, version=None): """ Add the specified object to an AsdfFile's tree, write the file to a buffer, then read it back in and return the deserialized object. Parameters ---------- obj : object Object to serialize. version : str or None. ASDF Standard version. If None, use the library's default version. Returns ------- object The deserialized object. """ buff = BytesIO() with asdf.AsdfFile(version=version) as af: af["obj"] = obj af.write_to(buff) buff.seek(0) with asdf.open(buff, lazy_load=False, memmap=False) as af: return af["obj"] def yaml_to_asdf(yaml_content, version=None): """ Given a string of YAML content, adds the extra pre- and post-amble to make it an ASDF file. Parameters ---------- yaml_content : string or bytes YAML content. version : str or None. ASDF Standard version. If None, use the library's default version. Returns ------- io.BytesIO A file-like object containing the ASDF file. """ if isinstance(yaml_content, str): yaml_content = yaml_content.encode("utf-8") buff = BytesIO() with asdf.AsdfFile(version=version) as af: af["$REPLACE"] = "ME" af.write_to(buff) buff.seek(0) asdf_content = buff.read().replace(b"$REPLACE: ME", yaml_content) return BytesIO(asdf_content) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/treeutil.py0000644000175100001770000003636114653725311015204 0ustar00runnerdocker""" Utility functions for managing tree-like data structures. """ import types import warnings from contextlib import contextmanager from . import lazy_nodes, tagged from .exceptions import AsdfDeprecationWarning, AsdfWarning from .util import NotSet __all__ = ["walk", "iter_tree", "walk_and_modify", "get_children", "is_container", "PendingValue", "RemoveNode"] def walk(top, callback): """ Walking through a tree of objects, calling a given function at each node. Parameters ---------- top : object The root of the tree. May be a dict, list or other Python object. callback : callable A function to call at each node in the tree. The callback is called on an instance after all of its children have been visited (depth-first order). Returns ------- tree : object The modified tree. """ for x in iter_tree(top): callback(x) def iter_tree(top): """ Iterate over all nodes in a tree, in depth-first order. Parameters ---------- top : object The root of the tree. May be a dict, list or other Python object. callback : callable A function to call at each node in the tree. The callback is called on an instance after all of its children have been visited (depth-first order). Returns ------- tree : object The modified tree. """ seen = set() def recurse(tree): tree_id = id(tree) if tree_id in seen: return if isinstance(tree, (list, tuple, lazy_nodes.AsdfListNode)): seen.add(tree_id) for val in tree: yield from recurse(val) seen.remove(tree_id) elif isinstance(tree, (dict, lazy_nodes.AsdfDictNode)): seen.add(tree_id) for val in tree.values(): yield from recurse(val) seen.remove(tree_id) yield tree return recurse(top) class _TreeModificationContext: """ Context of a call to walk_and_modify, which includes a map of already modified nodes, a list of generators to drain before exiting the call, and a set of node object ids that are currently pending modification. Instances of this class are context managers that track how many times they have been entered, and only drain generators and reset themselves when exiting the outermost context. They are also collections that map unmodified nodes to the corresponding modified result. """ def __init__(self): self._map = {} self._generators = [] self._depth = 0 self._pending = set() def add_generator(self, generator): """ Add a generator that should be drained before exiting the outermost call to walk_and_modify. """ self._generators.append(generator) def is_pending(self, node): """ Return True if the node is already being modified. This will not be the case unless the node contains a reference to itself somewhere among its descendents. """ return id(node) in self._pending @contextmanager def pending(self, node): """ Context manager that marks a node as pending for the duration of the context. """ if id(node) in self._pending: msg = ( "Unhandled cycle in tree. This is possibly a bug " "in extension code, which should be yielding " "nodes that may contain reference cycles." ) raise RuntimeError(msg) self._pending.add(id(node)) try: yield self finally: self._pending.remove(id(node)) def __enter__(self): self._depth += 1 return self def __exit__(self, exc_type, exc_value, traceback): self._depth -= 1 if self._depth == 0: # If we're back to 0 depth, then we're exiting # the outermost context, so it's time to drain # the generators and reset this object for next # time. if exc_type is None: self._drain_generators() self._generators = [] self._map = {} self._pending = set() def _drain_generators(self): """ Drain each generator we've accumulated during this call to walk_and_modify. """ # Generator code may add yet more generators # to the list, so we need to loop until the # list is empty. while len(self._generators) > 0: generators = self._generators self._generators = [] for generator in generators: for _ in generator: # Subsequent yields of the generator should # always return the same value. What we're # really doing here is executing the generator's # remaining code, to further modify that first # yielded object. pass def __contains__(self, node): return id(node) in self._map def __getitem__(self, node): return self._map[id(node)][1] def __setitem__(self, node, result): if id(node) in self._map: # This indicates that an already defined # modified node is being replaced, which is an # error because it breaks references within the # tree. msg = "Node already has an associated result" raise RuntimeError(msg) self._map[id(node)] = (node, result) class _PendingValue: """ Class of the PendingValue singleton instance. The presence of the instance in an asdf tree indicates that extension code is failing to handle reference cycles. """ def __repr__(self): return "PendingValue" PendingValue = _PendingValue() class _RemoveNode: """ Class of the RemoveNode singleton instance. This instance is used as a signal for `asdf.treeutil.walk_and_modify` to remove the node received by the callback. """ def __repr__(self): return "RemoveNode" RemoveNode = _RemoveNode() def walk_and_modify(top, callback, ignore_implicit_conversion=NotSet, postorder=True, _context=None): """Modify a tree by walking it with a callback function. It also has the effect of doing a deep copy. Parameters ---------- top : object The root of the tree. May be a dict, list or other Python object. callback : callable A function to call at each node in the tree. It takes either one or two arguments: - an instance from the tree - a json id (optional) It may return a different instance in order to modify the tree. If the singleton instance `~asdf.treeutil._RemoveNode` is returned, the node will be removed from the tree. The json id is the context under which any relative URLs should be resolved. It may be `None` if no ids are in the file The tree is traversed depth-first, with order specified by the ``postorder`` argument. postorder : bool Determines the order in which the callable is invoked on nodes of the tree. If `True`, the callable will be invoked on children before their parents. If `False`, the callable is invoked on the parents first. Defaults to `True`. ignore_implicit_conversion : bool DEPRECATED Controls whether warnings should be issued when implicitly converting a given type instance in the tree into a serializable object. The primary case for this is currently ``namedtuple``. Defaults to `False`. Returns ------- tree : object The modified tree. """ if ignore_implicit_conversion is NotSet: ignore_implicit_conversion = False else: warnings.warn("ignore_implicit_conversion is deprecated", AsdfDeprecationWarning) callback_arity = callback.__code__.co_argcount if callback_arity < 1 or callback_arity > 2: msg = "Expected callback to accept one or two arguments" raise ValueError(msg) def _handle_generator(result): # If the result is a generator, generate one value to # extract the true result, then register the generator # to be drained later. if isinstance(result, types.GeneratorType): generator = result result = next(generator) _context.add_generator(generator) return result def _handle_callback(node, json_id): result = callback(node) if callback_arity == 1 else callback(node, json_id) return _handle_generator(result) def _handle_mapping(node, json_id): if isinstance(node, lazy_nodes.AsdfDictNode): result = {} else: result = node.__class__() if isinstance(node, tagged.Tagged): result._tag = node._tag pending_items = {} for key, value in node.items(): if _context.is_pending(value): # The child node is pending modification, which means # it must be its own ancestor. Assign the special # PendingValue instance for now, and note that we'll # need to fill in the real value later. pending_items[key] = value result[key] = PendingValue elif (val := _recurse(value, json_id)) is not RemoveNode: result[key] = val yield result if len(pending_items) > 0: # Now that we've yielded, the pending children should # be available. for key, value in pending_items.items(): if (val := _recurse(value, json_id)) is not RemoveNode: result[key] = val else: # The callback may have decided to delete # this node after all. del result[key] def _handle_mutable_sequence(node, json_id): if isinstance(node, lazy_nodes.AsdfListNode): result = [] else: result = node.__class__() if isinstance(node, tagged.Tagged): result._tag = node._tag pending_items = {} for i, value in enumerate(node): if _context.is_pending(value): # The child node is pending modification, which means # it must be its own ancestor. Assign the special # PendingValue instance for now, and note that we'll # need to fill in the real value later. pending_items[i] = value result.append(PendingValue) else: result.append(_recurse(value, json_id)) yield result for i, value in pending_items.items(): # Now that we've yielded, the pending children should # be available. result[i] = _recurse(value, json_id) def _handle_immutable_sequence(node, json_id): # Immutable sequences containing themselves are impossible # to construct (well, maybe possible in a C extension, but # we're not going to worry about that), so we don't need # to yield here. contents = [_recurse(value, json_id) for value in node] try: result = node.__class__(contents) if isinstance(node, tagged.Tagged): result._tag = node._tag except TypeError: # The derived class signature is different, so simply store the # list representing the contents. Currently this is primarily # intended to handle namedtuple and NamedTuple instances. if not ignore_implicit_conversion: warnings.warn(f"Failed to serialize instance of {type(node)}, converting to list instead", AsdfWarning) result = contents warnings.warn("implicit conversion is deprecated. Please instead use a Converter.", AsdfDeprecationWarning) return result def _handle_children(node, json_id): if isinstance(node, (dict, lazy_nodes.AsdfDictNode)): result = _handle_mapping(node, json_id) elif isinstance(node, tuple): result = _handle_immutable_sequence(node, json_id) elif isinstance(node, (list, lazy_nodes.AsdfListNode)): result = _handle_mutable_sequence(node, json_id) else: result = node return _handle_generator(result) def _recurse(node, json_id=None): if node in _context: # The node's modified result has already been # created, all we need to do is return it. This # occurs when the tree contains multiple references # to the same object id. return _context[node] # Inform the context that we're going to start modifying # this node. with _context.pending(node): # Take note of the "id" field, in case we're modifying # a schema and need to know the namespace for resolving # URIs. Ignore an id that is not a string, since it may # be an object defining an id property and not an id # itself (this is common in metaschemas). if isinstance(node, (dict, lazy_nodes.AsdfDictNode)) and "id" in node and isinstance(node["id"], str): json_id = node["id"] if postorder: # If this is a postorder modification, invoke the # callback on this node's children first. result = _handle_children(node, json_id) result = _handle_callback(result, json_id) else: # Otherwise, invoke the callback on the node first, # then its children. result = _handle_callback(node, json_id) result = _handle_children(result, json_id) # Store the result in the context, in case there are # additional references to the same node elsewhere in # the tree. _context[node] = result return result if _context is None: _context = _TreeModificationContext() with _context: return _recurse(top) # Generators will be drained here, if this is the outermost # call to walk_and_modify. def get_children(node): """ Retrieve the children (and their dict keys or list/tuple indices) of an ASDF tree node. Parameters ---------- node : object an ASDF tree node Returns ------- list of (object, object) tuples list of (identifier, child node) tuples, or empty list if the node has no children (either it is an empty container, or is a non-container type) """ if isinstance(node, (dict, lazy_nodes.AsdfDictNode)): return list(node.items()) if isinstance(node, (list, tuple, lazy_nodes.AsdfListNode)): return list(enumerate(node)) return [] def is_container(node): """ Determine if an ASDF tree node is an instance of a "container" type (i.e., value may contain child nodes). Parameters ---------- node : object an ASDF tree node Returns ------- bool True if node is a container, False otherwise """ return isinstance(node, (dict, list, tuple, lazy_nodes.AsdfDictNode, lazy_nodes.AsdfListNode)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/util.py0000644000175100001770000004127714653725311014326 0ustar00runnerdockerimport enum import importlib.util import inspect import math import re import struct import sys import types import warnings from functools import lru_cache from importlib import metadata from urllib.request import pathname2url import numpy as np import yaml from packaging.version import Version from . import constants, exceptions # The standard library importlib.metadata returns duplicate entrypoints # for all python versions up to and including 3.11 # https://github.com/python/importlib_metadata/issues/410#issuecomment-1304258228 # see PR https://github.com/asdf-format/asdf/pull/1260 # see issue https://github.com/asdf-format/asdf/issues/1254 if sys.version_info >= (3, 12): from importlib.metadata import packages_distributions else: from importlib_metadata import packages_distributions # We're importing our own copy of urllib.parse because # we need to patch it to support asdf:// URIs, but it'd # be irresponsible to do this for all users of a # standard library. urllib_parse_spec = importlib.util.find_spec("urllib.parse") _patched_urllib_parse = importlib.util.module_from_spec(urllib_parse_spec) urllib_parse_spec.loader.exec_module(_patched_urllib_parse) del urllib_parse_spec # urllib.parse needs to know that it should treat asdf:// # URIs like http:// URIs for the purposes of joining # a relative path to a base URI. _patched_urllib_parse.uses_relative.append("asdf") _patched_urllib_parse.uses_netloc.append("asdf") __all__ = [ "load_yaml", "human_list", "get_array_base", "get_base_uri", "filepath_to_url", "iter_subclasses", "calculate_padding", "resolve_name", "NotSet", "is_primitive", "uri_match", "get_class_name", "get_file_type", "FileType", ] def load_yaml(init, tagged=False): """ Load just the yaml portion of an ASDF file Parameters ---------- init : filename or file-like If file-like this must be opened in binary mode. tagged: bool, optional Return tree with instances of `asdf.tagged.Tagged` this can be helpful if the yaml tags are of interest. If False, the tree will only contain basic python types (see the pyyaml ``BaseLoader`` documentation). Returns ------- tree : dict Dictionary representing the ASDF tree """ from .generic_io import get_file from .yamlutil import AsdfLoader if tagged: loader = AsdfLoader else: loader = yaml.CBaseLoader if getattr(yaml, "__with_libyaml__", None) else yaml.BaseLoader with get_file(init, "r") as gf: reader = gf.reader_until( constants.YAML_END_MARKER_REGEX, 7, "End of YAML marker", include=True, ) # The following call to yaml.load is safe because we're # using only loaders that don't create custom python objects content = yaml.load(reader, Loader=loader) # noqa: S506 return content def human_list(line, separator="and"): """ Formats a list for human readability. Parameters ---------- l : sequence A sequence of strings separator : string, optional The word to use between the last two entries. Default: ``"and"``. Returns ------- formatted_list : string Examples -------- >>> human_list(["vanilla", "strawberry", "chocolate"], "or") # doctest: +SKIP 'vanilla, strawberry or chocolate' """ warnings.warn("asdf.util.human_list is deprecated", exceptions.AsdfDeprecationWarning) if len(line) == 1: return line[0] return ", ".join(line[:-1]) + " " + separator + " " + line[-1] def get_array_base(arr): """ For a given Numpy array, finds the base array that "owns" the actual data. """ from .tags.core import ndarray base = arr while isinstance(base.base, (np.ndarray, ndarray.NDArrayType)): base = base.base return base def get_base_uri(uri): """ For a given URI, return the part without any fragment. """ parts = _patched_urllib_parse.urlparse(uri) return _patched_urllib_parse.urlunparse([*list(parts[:5]), ""]) def filepath_to_url(path): """ For a given local file path, return a file:// url. """ msg = "asdf.util.filepath_to_url is deprecated. Please use pathlib.Path.as_uri" warnings.warn(msg, exceptions.AsdfDeprecationWarning) return _patched_urllib_parse.urljoin("file:", pathname2url(path)) def _iter_subclasses(cls): """ Returns all subclasses of a class. """ for x in cls.__subclasses__(): yield x yield from _iter_subclasses(x) def iter_subclasses(cls): """ Returns all subclasses of a class. """ warnings.warn("asdf.util.iter_subclasses is deprecated", exceptions.AsdfDeprecationWarning) yield from _iter_subclasses(cls) def calculate_padding(content_size, pad_blocks, block_size): """ Calculates the amount of extra space to add to a block given the user's request for the amount of extra space. Care is given so that the total of size of the block with padding is evenly divisible by block size. Parameters ---------- content_size : int The size of the actual content pad_blocks : float or bool If `False`, add no padding (always return 0). If `True`, add a default amount of padding of 10% If a float, it is a factor to multiple content_size by to get the new total size. block_size : int The filesystem block size to use. Returns ------- nbytes : int The number of extra bytes to add for padding. """ if not pad_blocks: return 0 if pad_blocks is True: pad_blocks = 1.1 new_size = content_size * pad_blocks new_size = int((math.ceil(float(new_size) / block_size) + 1) * block_size) return max(new_size - content_size, 0) class _BinaryStruct: """ A wrapper around the Python stdlib struct module to define a binary struct more like a dictionary than a tuple. """ def __init__(self, descr, endian=">"): """ Parameters ---------- descr : list of tuple Each entry is a pair ``(name, format)``, where ``format`` is one of the format types understood by `struct`. endian : str, optional The endianness of the struct. Must be ``>`` or ``<``. """ self._fmt = [endian] self._offsets = {} self._names = [] i = 0 for name, fmt in descr: self._fmt.append(fmt) self._offsets[name] = (i, (endian + fmt).encode("ascii")) self._names.append(name) i += struct.calcsize(fmt.encode("ascii")) self._fmt = "".join(self._fmt).encode("ascii") self._size = struct.calcsize(self._fmt) @property def size(self): """ Return the size of the struct. """ return self._size def pack(self, **kwargs): """ Pack the given arguments, which are given as kwargs, and return the binary struct. """ fields = [0] * len(self._names) for key, val in kwargs.items(): if key not in self._offsets: msg = f"No header field '{key}'" raise KeyError(msg) i = self._names.index(key) fields[i] = val return struct.pack(self._fmt, *fields) def unpack(self, buff): """ Unpack the given binary buffer into the fields. The result is a dictionary mapping field names to values. """ args = struct.unpack_from(self._fmt, buff[: self._size]) return dict(zip(self._names, args)) def update(self, fd, **kwargs): """ Update part of the struct in-place. Parameters ---------- fd : generic_io.GenericIO instance A writable, seekable file descriptor, currently seeked to the beginning of the struct. **kwargs : values The values to update on the struct. """ updates = [] for key, val in kwargs.items(): if key not in self._offsets: msg = f"No header field '{key}'" raise KeyError(msg) updates.append((self._offsets[key], val)) updates.sort() start = fd.tell() for (offset, datatype), val in updates: fd.seek(start + offset) fd.write(struct.pack(datatype, val)) class HashableDict(dict): """ A simple wrapper around dict to make it hashable. This is sure to be slow, but for small dictionaries it shouldn't matter. """ def __hash__(self): return hash(frozenset(self.items())) def resolve_name(name): """Resolve a name like ``module.object`` to an object and return it. This ends up working like ``from module import object`` but is easier to deal with than the `__import__` builtin and supports digging into submodules. Parameters ---------- name : `str` A dotted path to a Python object--that is, the name of a function, class, or other object in a module with the full path to that module, including parent modules, separated by dots. Also known as the fully qualified name of the object. Examples -------- >>> resolve_name('asdf.util.resolve_name') # doctest: +SKIP Raises ------ `ImportError` If the module or named object is not found. """ warnings.warn( "asdf.util.resolve_name is deprecated, see astropy.utils.resolve_name", exceptions.AsdfDeprecationWarning ) # Note: On python 2 these must be str objects and not unicode parts = [str(part) for part in name.split(".")] if len(parts) == 1: # No dots in the name--just a straight up module import cursor = 1 attr_name = "" # Must not be unicode on Python 2 else: cursor = len(parts) - 1 attr_name = parts[-1] module_name = parts[:cursor] while cursor > 0: try: ret = __import__(str(".".join(module_name)), fromlist=[attr_name]) break except ImportError: if cursor == 0: raise cursor -= 1 module_name = parts[:cursor] attr_name = parts[cursor] ret = "" for part in parts[cursor:]: try: ret = getattr(ret, part) except AttributeError as err: raise ImportError(name) from err return ret def get_class_name(obj, instance=True): """ Given a class or instance of a class, returns a string representing the fully specified path of the class. Parameters ---------- obj : object An instance of any object instance: bool Indicates whether given object is an instance of the class to be named """ typ = type(obj) if instance else obj return f"{typ.__module__}.{typ.__qualname__}" def minversion(module, version, inclusive=True): """ Returns `True` if the specified Python module satisfies a minimum version requirement, and `False` if not. Copied from astropy.utils.misc.minversion to avoid dependency on astropy. Parameters ---------- module : module or `str` An imported module of which to check the version, or the name of that module (in which case an import of that module is attempted-- if this fails `False` is returned). version : `str` The version as a string that this module must have at a minimum (e.g. ``'0.12'``). inclusive : `bool` The specified version meets the requirement inclusively (i.e. ``>=``) as opposed to strictly greater than (default: `True`). """ warnings.warn("asdf.util.minversion is deprecated, see astropy.utils.minversion", exceptions.AsdfDeprecationWarning) if isinstance(module, types.ModuleType): module_name = module.__name__ module_version = getattr(module, "__version__", None) elif isinstance(module, str): module_name = module module_version = None try: with warnings.catch_warnings(): warnings.filterwarnings("ignore", "asdf.util.resolve_name", exceptions.AsdfDeprecationWarning) module = resolve_name(module_name) except ImportError: return False else: msg = f"module argument must be an actual imported module, or the import name of the module; got {module!r}" raise ValueError(msg) if module_version is None: try: module_version = metadata.version(module_name) except metadata.PackageNotFoundError: # Maybe the distribution name is different from package name. # Calling packages_distributions is costly so we do it only # if necessary, as only a few packages don't have the same # distribution name. dist_names = packages_distributions() module_version = metadata.version(dist_names[module_name][0]) if inclusive: return Version(module_version) >= Version(version) return Version(module_version) > Version(version) class _InheritDocstrings(type): """ This metaclass makes methods of a class automatically have their docstrings filled in from the methods they override in the base class. If the class uses multiple inheritance, the docstring will be chosen from the first class in the bases list, in the same way as methods are normally resolved in Python. If this results in selecting the wrong docstring, the docstring will need to be explicitly included on the method. For example:: >>> from asdf.util import _InheritDocstrings >>> class A(metaclass=_InheritDocstrings): ... def wiggle(self): ... "Wiggle the thingamajig" ... pass >>> class B(A): ... def wiggle(self): ... pass >>> B.wiggle.__doc__ 'Wiggle the thingamajig' """ def __init__(cls, name, bases, dct): def is_public_member(key): return (key.startswith("__") and key.endswith("__") and len(key) > 4) or not key.startswith("_") for key, val in dct.items(): if inspect.isfunction(val) and is_public_member(key) and val.__doc__ is None: for base in cls.__mro__[1:]: super_method = getattr(base, key, None) if super_method is not None: val.__doc__ = super_method.__doc__ break super().__init__(name, bases, dct) class _NotSetType: def __repr__(self): return "NotSet" """ Special value indicating that a parameter is not set. Distinct from None, which may for example be a value of interest in a search. """ NotSet = _NotSetType() def is_primitive(value): """ Determine if a value is an instance of a "primitive" type. Parameters ---------- value : object the value to test Returns ------- bool True if the value is primitive, False otherwise """ warnings.warn("asdf.util.is_primitive is deprecated", exceptions.AsdfDeprecationWarning) return isinstance(value, (bool, int, float, complex, str)) or value is None def uri_match(pattern, uri): """ Determine if a URI matches a URI pattern with possible wildcards. The two recognized wildcards: "*": match any character except / "**": match any character Parameters ---------- pattern : str URI pattern. uri : str URI to check against the pattern. Returns ------- bool `True` if URI matches the pattern. """ if not isinstance(uri, str): return False if "*" in pattern: return _compile_uri_match_pattern(pattern).fullmatch(uri) is not None return pattern == uri @lru_cache(1024) def _compile_uri_match_pattern(pattern): # Escape the pattern in case it contains regex special characters # ('.' in particular is common in URIs) and then replace the # escaped asterisks with the appropriate regex matchers. pattern = re.escape(pattern) pattern = pattern.replace(r"\*\*", r".*") pattern = pattern.replace(r"\*", r"[^/]*") return re.compile(pattern) def get_file_type(fd): """ Determine the file type of an open GenericFile instance. Parameters ---------- fd : ``asdf.generic_io.GenericFile`` Returns ------- `asdf.util.FileType` """ if fd.peek(5) == constants.ASDF_MAGIC: return FileType.ASDF if fd.peek(6) == constants.FITS_MAGIC: return FileType.FITS return FileType.UNKNOWN class FileType(enum.Enum): """ Enum representing if a file is ASDF, FITS or UNKNOWN. """ ASDF = 1 FITS = 2 UNKNOWN = 3 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/versioning.py0000644000175100001770000001372314653725311015527 0ustar00runnerdocker""" This module deals with things that change between different versions of the ASDF spec. """ import warnings from functools import total_ordering import yaml from semantic_version import SimpleSpec, Version from .exceptions import AsdfDeprecationWarning _yaml_base_loader = yaml.CSafeLoader if getattr(yaml, "__with_libyaml__", None) else yaml.SafeLoader __all__ = ["AsdfVersion", "AsdfSpec", "AsdfVersionMixin", "split_tag_version", "join_tag_version"] def split_tag_version(tag): """ Split a tag into its base and version. """ name, version = tag.rsplit("-", 1) version = AsdfVersion(version) return name, version def join_tag_version(name, version): """ Join the root and version of a tag back together. """ return f"{name}-{version}" _version_map = {} def _get_version_map(version): version_map = _version_map.get(version) if version_map is None: from .config import get_config uri = f"http://stsci.edu/schemas/asdf/version_map-{version}" # The following call to yaml.load is safe because we're # using a loader that inherits from pyyaml's SafeLoader. version_map = yaml.load(get_config().resource_manager[uri], Loader=_yaml_base_loader) # noqa: S506 # Separate the core tags from the rest of the standard for convenience version_map["core"] = {} version_map["standard"] = {} for tag_name, tag_version in version_map["tags"].items(): if tag_name.startswith("tag:stsci.edu:asdf/core"): version_map["core"][tag_name] = tag_version else: version_map["standard"][tag_name] = tag_version _version_map[version] = version_map return version_map @total_ordering class AsdfVersionMixin: """This mix-in is required in order to impose the total ordering that we want for ``AsdfVersion``, rather than accepting the total ordering that is already provided by ``Version`` from ``semantic_version``. Defining these comparisons directly in ``AsdfVersion`` and applying ``total_ordering`` there will not work since ``total_ordering`` only defines comparison operations if they do not exist already and the base class ``Version`` already defines these operations. """ def __eq__(self, other): # Seems like a bit of a hack... if isinstance(other, SimpleSpec): return other == self if isinstance(other, (str, tuple, list)): other = AsdfVersion(other) return Version.__eq__(self, other) def __ne__(self, other): return not self.__eq__(other) def __lt__(self, other): if isinstance(other, (str, tuple, list)): other = AsdfVersion(other) return Version.__lt__(self, other) def __hash__(self): # To be honest, I'm not sure why I had to make this explicit return Version.__hash__(self) class AsdfVersion(AsdfVersionMixin, Version): """This class adds features to the existing ``Version`` class from the ``semantic_version`` module. Namely, it allows ``Version`` objects to be constructed from tuples and lists as well as strings, and it allows ``Version`` objects to be compared with tuples, lists, and strings, instead of just other ``Version`` objects. If any of these features are added to the ``Version`` class itself (as requested in https://github.com/rbarrois/python-semanticversion/issues/52), then this class will become obsolete. """ def __init__(self, version): # This is a dirty hack and you know it if isinstance(version, AsdfVersion): version = str(version) if isinstance(version, (tuple, list)): version = ".".join([str(x) for x in version]) super().__init__(version) class AsdfSpec(SimpleSpec): """ Deprecated. """ def __init__(self, *args, **kwargs): warnings.warn("AsdfSpec is deprecated.", AsdfDeprecationWarning) super().__init__(*args, **kwargs) def match(self, version): if isinstance(version, (str, tuple, list)): version = AsdfVersion(version) return super().match(version) def __iterate_versions(self, versions): for v in versions: yield AsdfVersion(v) if isinstance(v, (str, tuple, list)) else v def select(self, versions): return super().select(self.__iterate_versions(versions)) def filter(self, versions): return super().filter(self.__iterate_versions(versions)) def __eq__(self, other): """Equality between Spec and Version, string, or tuple, means match""" if isinstance(other, SimpleSpec): return super().__eq__(other) return self.match(other) def __ne__(self, other): return not self.__eq__(other) def __hash__(self): return super().__hash__() supported_versions = [ AsdfVersion("1.0.0"), AsdfVersion("1.1.0"), AsdfVersion("1.2.0"), AsdfVersion("1.3.0"), AsdfVersion("1.4.0"), AsdfVersion("1.5.0"), AsdfVersion("1.6.0"), ] default_version = AsdfVersion("1.5.0") # This is the ASDF Standard version that is currently in development # it is possible that breaking changes will be made to this version. asdf_standard_development_version = AsdfVersion("1.6.0") # This is the ASDF Standard version at which the format of the history # field changed to include extension metadata. NEW_HISTORY_FORMAT_MIN_VERSION = AsdfVersion("1.2.0") # This is the ASDF Standard version at which we begin restricting # mapping keys to string, integer, and boolean only. RESTRICTED_KEYS_MIN_VERSION = AsdfVersion("1.6.0") # This library never removed defaults for ASDF Standard versions # later than 1.5.0, so filling them isn't necessary. FILL_DEFAULTS_MAX_VERSION = AsdfVersion("1.5.0") # ASDF currently only defined a single file format version _FILE_FORMAT_VERSION = AsdfVersion("1.0.0") # ASDF currently only supports a single yaml version # use a tuple as that is what yaml expects _YAML_VERSION = (1, 1) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asdf/yamlutil.py0000644000175100001770000003623014653725311015202 0ustar00runnerdockerimport warnings from collections import OrderedDict from types import GeneratorType import numpy as np import yaml from . import config, schema, tagged, treeutil, util from .constants import STSCI_SCHEMA_TAG_BASE, YAML_TAG_PREFIX from .exceptions import AsdfConversionWarning, AsdfSerializationError from .extension._serialization_context import BlockAccess from .tags.core import AsdfObject from .versioning import _YAML_VERSION, _yaml_base_loader __all__ = ["custom_tree_to_tagged_tree", "tagged_tree_to_custom_tree"] _yaml_base_dumper = yaml.CSafeDumper if getattr(yaml, "__with_libyaml__", None) else yaml.SafeDumper YAML_OMAP_TAG = YAML_TAG_PREFIX + "omap" # ---------------------------------------------------------------------- # Custom loader/dumpers class AsdfDumper(_yaml_base_dumper): """ A specialized YAML dumper that understands "tagged basic Python data types" as implemented in the `tagged` module. """ def __init__(self, *args, **kwargs): kwargs["default_flow_style"] = None super().__init__(*args, **kwargs) def represent_data(self, data): node = super().represent_data(data) tag_name = getattr(data, "_tag", None) if tag_name is not None: node.tag = tag_name return node _flow_style_map = {"flow": True, "block": False} def represent_sequence(dumper, sequence): flow_style = _flow_style_map.get(sequence.flow_style, None) sequence = sequence.data return super(AsdfDumper, dumper).represent_sequence(None, sequence, flow_style) def represent_mapping(dumper, mapping): flow_style = _flow_style_map.get(mapping.flow_style, None) node = super(AsdfDumper, dumper).represent_mapping(None, mapping.data, flow_style) if mapping.property_order: values = node.value new_mapping = {} for key, val in values: new_mapping[key.value] = (key, val) new_values = [] for key in mapping.property_order: if key in mapping: new_values.append(new_mapping[key]) property_order = set(mapping.property_order) for key, val in values: if key.value not in property_order: new_values.append((key, val)) node.value = new_values return node _style_map = {"inline": '"', "folded": ">", "literal": "|"} def represent_scalar(dumper, value): style = _style_map.get(value.style, None) return super(AsdfDumper, dumper).represent_scalar(None, value.data, style) def represent_ordered_mapping(dumper, tag, data): # TODO: Again, adjust for preferred flow style, and other stylistic details # NOTE: For block style this uses the compact omap notation, but for flow style # it does not. # TODO: Need to see if I can figure out a mechanism so that classes that # use this representer can specify which values should use flow style values = [] node = yaml.SequenceNode(tag, values, flow_style=dumper.default_flow_style) if dumper.alias_key is not None: dumper.represented_objects[dumper.alias_key] = node for key, value in data.items(): key_item = dumper.represent_data(key) value_item = dumper.represent_data(value) node_item = yaml.MappingNode(YAML_OMAP_TAG, [(key_item, value_item)], flow_style=False) values.append(node_item) return node def represent_ordereddict(dumper, data): return represent_ordered_mapping(dumper, YAML_OMAP_TAG, data) AsdfDumper.add_representer(tagged.TaggedList, represent_sequence) AsdfDumper.add_representer(tagged.TaggedDict, represent_mapping) AsdfDumper.add_representer(tagged.TaggedString, represent_scalar) AsdfDumper.add_representer(OrderedDict, represent_ordereddict) # ---------------------------------------------------------------------- # Handle numpy scalars for scalar_type in util._iter_subclasses(np.floating): AsdfDumper.add_representer(scalar_type, lambda dumper, data: dumper.represent_float(float(data))) for scalar_type in util._iter_subclasses(np.integer): AsdfDumper.add_representer(scalar_type, lambda dumper, data: dumper.represent_int(int(data))) def represent_numpy_str(dumper, data): # The CSafeDumper implementation will raise an error if it # doesn't recognize data as a string. The Python SafeDumper # has no problem with np.str_. return dumper.represent_str(str(data)) AsdfDumper.add_representer(np.str_, represent_numpy_str) AsdfDumper.add_representer(np.bytes_, AsdfDumper.represent_binary) class AsdfLoader(_yaml_base_loader): """ A specialized YAML loader that can construct "tagged basic Python data types" as implemented in the `tagged` module. """ def construct_undefined(self, node): if isinstance(node, yaml.MappingNode): return self._construct_tagged_mapping(node) if isinstance(node, yaml.SequenceNode): return self._construct_tagged_sequence(node) if isinstance(node, yaml.ScalarNode): return self._construct_tagged_scalar(node) return super().construct_undefined(node) def _construct_tagged_mapping(self, node): data = tagged.tag_object(node.tag, {}) yield data data.update(self.construct_mapping(node)) def _construct_tagged_sequence(self, node): data = tagged.tag_object(node.tag, []) yield data data.extend(self.construct_sequence(node)) def _construct_tagged_scalar(self, node): return tagged.tag_object(node.tag, self.construct_scalar(node)) # Custom omap deserializer that builds an OrderedDict instead # of a list of tuples. Code is mostly identical to pyyaml's SafeConstructor. def construct_yaml_omap(self, node): omap = OrderedDict() yield omap if not isinstance(node, yaml.SequenceNode): msg = "while constructing an ordered map" raise yaml.constructor.ConstructorError( msg, node.start_mark, f"expected a sequence, but found {node.id}", node.start_mark, ) for subnode in node.value: if not isinstance(subnode, yaml.MappingNode): msg = "while constructing an ordered map" raise yaml.constructor.ConstructorError( msg, node.start_mark, f"expected a mapping of length 1, but found {subnode.id}", subnode.start_mark, ) if len(subnode.value) != 1: msg = "while constructing an ordered map" raise yaml.constructor.ConstructorError( msg, node.start_mark, f"expected a single mapping item, but found {len(subnode.value)} items", subnode.start_mark, ) key_node, value_node = subnode.value[0] key = self.construct_object(key_node) value = self.construct_object(value_node) omap[key] = value # pyyaml will invoke the constructor associated with None when a node's # tag is not explicitly handled by another constructor. AsdfLoader.add_constructor(None, AsdfLoader.construct_undefined) AsdfLoader.add_constructor(YAML_TAG_PREFIX + "omap", AsdfLoader.construct_yaml_omap) def custom_tree_to_tagged_tree(tree, ctx, _serialization_context=None): """ Convert a tree, possibly containing custom data types that aren't directly representable in YAML, to a tree of basic data types, annotated with tags. """ if _serialization_context is None: _serialization_context = ctx._create_serialization_context(BlockAccess.WRITE) extension_manager = _serialization_context.extension_manager def _convert_obj(obj, converter): tag = converter.select_tag(obj, _serialization_context) # if select_tag returns None, converter.to_yaml_tree should return a new # object which will be handled by a different converter converters_used = set() while tag is None: converters_used.add(converter) obj = converter.to_yaml_tree(obj, tag, _serialization_context) try: converter = extension_manager.get_converter_for_type(type(obj)) except KeyError: # no converter supports this type, return it as-is yield obj return if converter in converters_used: msg = "Conversion cycle detected" raise TypeError(msg) tag = converter.select_tag(obj, _serialization_context) _serialization_context.assign_object(obj) node = converter.to_yaml_tree(obj, tag, _serialization_context) _serialization_context.assign_blocks() if isinstance(node, GeneratorType): generator = node node = next(generator) else: generator = None if isinstance(node, dict): tagged_node = tagged.TaggedDict(node, tag) elif isinstance(node, list): tagged_node = tagged.TaggedList(node, tag) elif isinstance(node, str): tagged_node = tagged.TaggedString(node) tagged_node._tag = tag else: msg = f"Converter returned illegal node type: {util.get_class_name(node)}" raise TypeError(msg) _serialization_context._mark_extension_used(converter.extension) yield tagged_node if generator is not None: yield from generator cfg = config.get_config() convert_ndarray_subclasses = cfg.convert_unknown_ndarray_subclasses converters_cache = {} def _walker(obj): typ = type(obj) if typ in converters_cache: return converters_cache[typ](obj) if extension_manager.handles_type(typ): converter = extension_manager.get_converter_for_type(typ) converters_cache[typ] = lambda obj, _converter=converter: _convert_obj(obj, _converter) return _convert_obj(obj, converter) if convert_ndarray_subclasses and isinstance(obj, np.ndarray): warnings.warn( f"A ndarray subclass ({type(obj)}) was converted as a ndarray. " "This behavior will be removed from a future version of ASDF. " "See https://asdf.readthedocs.io/en/latest/asdf/config.html#convert-unknown-ndarray-subclasses", AsdfConversionWarning, ) converter = extension_manager.get_converter_for_type(np.ndarray) converters_cache[typ] = lambda obj, _converter=converter: _convert_obj(obj, _converter) return _convert_obj(obj, converter) converters_cache[typ] = lambda obj: obj return obj return treeutil.walk_and_modify( tree, _walker, ignore_implicit_conversion=ctx._ignore_implicit_conversion, # Walk the tree in preorder, so that extensions can return # container nodes with unserialized children. postorder=False, _context=ctx._tree_modification_context, ) def tagged_tree_to_custom_tree(tree, ctx, force_raw_types=False, _serialization_context=None): """ Convert a tree containing only basic data types, annotated with tags, to a tree containing custom data types. """ if _serialization_context is None: _serialization_context = ctx._create_serialization_context(BlockAccess.READ) extension_manager = _serialization_context.extension_manager def _walker(node): if force_raw_types: return node tag = getattr(node, "_tag", None) if tag is None: return node if extension_manager.handles_tag(tag): converter = extension_manager.get_converter_for_tag(tag) obj = converter.from_yaml_tree(node.data, tag, _serialization_context) _serialization_context.assign_object(obj) _serialization_context.assign_blocks() _serialization_context._mark_extension_used(converter.extension) return obj if not ctx._ignore_unrecognized_tag: warnings.warn( f"{tag} is not recognized, converting to raw Python data structure", AsdfConversionWarning, ) return node return treeutil.walk_and_modify( tree, _walker, ignore_implicit_conversion=ctx._ignore_implicit_conversion, # Walk the tree in postorder, so that extensions receive # container nodes with children already deserialized. postorder=True, _context=ctx._tree_modification_context, ) def load_tree(stream): """ Load YAML, returning a tree of objects. Parameters ---------- stream : readable file-like object Stream containing the raw YAML content. """ # The following call to yaml.load is safe because we're # using a loader that inherits from pyyaml's SafeLoader. return yaml.load(stream, Loader=AsdfLoader) # noqa: S506 def dump_tree(tree, fd, ctx, tree_finalizer=None, _serialization_context=None): """ Dump a tree of objects, possibly containing custom types, to YAML. Parameters ---------- tree : object Tree of objects, possibly containing custom data types. fd : asdf.generic_io.GenericFile A file object to dump the serialized YAML to. ctx : Context The writing context. tree_finalizer : callable, optional Callback that receives the tagged tree before it is validated and defaults are removed. `asdf.AsdfFile` uses this to update extension metadata on the tagged tree before it is fully serialized to YAML. """ # The _serialization_context parameter allows AsdfFile to track # what extensions were used when converting the tree's custom # types. In 3.0, it will be passed as the `ctx` instead of the # AsdfFile itself. if type(tree) is not AsdfObject: msg = "Root node of ASDF tree must be of type AsdfObject" raise TypeError(msg) tags = {"!": STSCI_SCHEMA_TAG_BASE + "/"} tree = custom_tree_to_tagged_tree(tree, ctx, _serialization_context=_serialization_context) if tree_finalizer is not None: tree_finalizer(tree) schema.validate(tree, ctx) # add yaml %TAG definitions from extensions if _serialization_context: for ext in _serialization_context._extensions_used: for key, val in ext.yaml_tag_handles.items(): if key not in tags: tags[key] = val try: yaml.dump_all( [tree], stream=fd, Dumper=AsdfDumper, explicit_start=True, explicit_end=True, version=_YAML_VERSION, allow_unicode=True, encoding="utf-8", tags=tags, ) except yaml.representer.RepresenterError as err: if len(err.args) < 2: raise err # inspect the exception arguments to determine what object failed obj = err.args[1] msg = ( f"Object of type[{type(obj)}] is not serializable by asdf. " "Please convert the object to a supported type or implement " "a Converter for this type to allow the tree to be serialized." ) raise AsdfSerializationError(msg, obj) from err ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1610985 asdf-3.4.0/asdf.egg-info/0000755000175100001770000000000014653725331014460 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788568.0 asdf-3.4.0/asdf.egg-info/PKG-INFO0000644000175100001770000003433414653725330015563 0ustar00runnerdockerMetadata-Version: 2.1 Name: asdf Version: 3.4.0 Summary: Python implementation of the ASDF Standard Author-email: The ASDF Developers License: BSD 3-Clause License Copyright (c) 2021 Association of Universities for Research in Astronomy. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Project-URL: documentation, https://asdf.readthedocs.io/en/stable Project-URL: repository, https://github.com/asdf-format/asdf Project-URL: tracker, https://github.com/asdf-format/asdf/issues Classifier: Development Status :: 5 - Production/Stable Classifier: License :: OSI Approved :: BSD License Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Requires-Python: >=3.9 Description-Content-Type: text/x-rst License-File: LICENSE Requires-Dist: asdf-standard>=1.1.0 Requires-Dist: asdf-transform-schemas>=0.3 Requires-Dist: importlib-metadata>=4.11.4; python_version <= "3.11" Requires-Dist: jmespath>=0.6.2 Requires-Dist: numpy>=1.22 Requires-Dist: packaging>=19 Requires-Dist: pyyaml>=5.4.1 Requires-Dist: semantic_version>=2.8 Requires-Dist: attrs>=22.2.0 Provides-Extra: all Requires-Dist: lz4>=0.10; extra == "all" Provides-Extra: docs Requires-Dist: sphinx-asdf>=0.2.2; extra == "docs" Requires-Dist: graphviz; extra == "docs" Requires-Dist: sphinx-inline-tabs; extra == "docs" Requires-Dist: tomli; python_version < "3.11" and extra == "docs" Provides-Extra: tests Requires-Dist: fsspec[http]>=2022.8.2; extra == "tests" Requires-Dist: lz4>=0.10; extra == "tests" Requires-Dist: psutil; extra == "tests" Requires-Dist: pytest>=8; extra == "tests" Requires-Dist: pytest-remotedata; extra == "tests" ASDF - Advanced Scientific Data Format ====================================== .. _begin-badges: .. image:: https://github.com/asdf-format/asdf/workflows/CI/badge.svg :target: https://github.com/asdf-format/asdf/actions :alt: CI Status .. image:: https://github.com/asdf-format/asdf/workflows/s390x/badge.svg :target: https://github.com/asdf-format/asdf/actions :alt: s390x Status .. image:: https://github.com/asdf-format/asdf/workflows/Downstream/badge.svg :target: https://github.com/asdf-format/asdf/actions :alt: Downstream CI Status .. image:: https://readthedocs.org/projects/asdf/badge/?version=latest :target: https://asdf.readthedocs.io/en/latest/ .. image:: https://codecov.io/gh/asdf-format/asdf/branch/main/graphs/badge.svg :target: https://codecov.io/gh/asdf-format/asdf .. _begin-zenodo: .. image:: https://zenodo.org/badge/18112754.svg :target: https://zenodo.org/badge/latestdoi/18112754 .. _end-zenodo: .. image:: https://img.shields.io/pypi/l/asdf.svg :target: https://img.shields.io/pypi/l/asdf.svg .. image:: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white :target: https://github.com/pre-commit/pre-commit :alt: pre-commit .. image:: https://img.shields.io/badge/code%20style-black-000000.svg :target: https://github.com/psf/black .. _end-badges: .. _begin-summary-text: The **A**\ dvanced **S**\ cientific **D**\ ata **F**\ ormat (ASDF) is a next-generation interchange format for scientific data. This package contains the Python implementation of the ASDF Standard. More information on the ASDF Standard itself can be found `here `__. The ASDF format has the following features: * A hierarchical, human-readable metadata format (implemented using `YAML `__) * Numerical arrays are stored as binary data blocks which can be memory mapped. Data blocks can optionally be compressed. * The structure of the data can be automatically validated using schemas (implemented using `JSON Schema `__) * Native Python data types (numerical types, strings, dicts, lists) are serialized automatically * ASDF can be extended to serialize custom data types .. _end-summary-text: ASDF is under active development `on github `__. More information on contributing can be found `below <#contributing>`__. Overview -------- This section outlines basic use cases of the ASDF package for creating and reading ASDF files. Creating a file ~~~~~~~~~~~~~~~ .. _begin-create-file-text: We're going to store several `numpy` arrays and other data to an ASDF file. We do this by creating a "tree", which is simply a `dict`, and we provide it as input to the constructor of `AsdfFile`: .. code:: python import asdf import numpy as np # Create some data sequence = np.arange(100) squares = sequence**2 random = np.random.random(100) # Store the data in an arbitrarily nested dictionary tree = { "foo": 42, "name": "Monty", "sequence": sequence, "powers": {"squares": squares}, "random": random, } # Create the ASDF file object from our data tree af = asdf.AsdfFile(tree) # Write the data to a new file af.write_to("example.asdf") If we open the newly created file's metadata section, we can see some of the key features of ASDF on display: .. _begin-example-asdf-metadata: .. code:: yaml #ASDF 1.0.0 #ASDF_STANDARD 1.2.0 %YAML 1.1 %TAG ! tag:stsci.edu:asdf/ --- !core/asdf-1.1.0 asdf_library: !core/software-1.0.0 {author: The ASDF Developers, homepage: 'http://github.com/asdf-format/asdf', name: asdf, version: 2.0.0} history: extensions: - !core/extension_metadata-1.0.0 extension_class: asdf.extension.BuiltinExtension software: {name: asdf, version: 2.0.0} foo: 42 name: Monty powers: squares: !core/ndarray-1.0.0 source: 1 datatype: int64 byteorder: little shape: [100] random: !core/ndarray-1.0.0 source: 2 datatype: float64 byteorder: little shape: [100] sequence: !core/ndarray-1.0.0 source: 0 datatype: int64 byteorder: little shape: [100] ... .. _end-example-asdf-metadata: The metadata in the file mirrors the structure of the tree that was stored. It is hierarchical and human-readable. Notice that metadata has been added to the tree that was not explicitly given by the user. Notice also that the numerical array data is not stored in the metadata tree itself. Instead, it is stored as binary data blocks below the metadata section (not shown above). .. _end-create-file-text: .. _begin-compress-file: It is possible to compress the array data when writing the file: .. code:: python af.write_to("compressed.asdf", all_array_compression="zlib") The built-in compression algorithms are ``'zlib'``, and ``'bzp2'``. The ``'lz4'`` algorithm becomes available when the `lz4 `__ package is installed. Other compression algorithms may be available via extensions. .. _end-compress-file: Reading a file ~~~~~~~~~~~~~~ .. _begin-read-file-text: To read an existing ASDF file, we simply use the top-level `open` function of the `asdf` package: .. code:: python import asdf af = asdf.open("example.asdf") The `open` function also works as a context handler: .. code:: python with asdf.open("example.asdf") as af: ... To get a quick overview of the data stored in the file, use the top-level `AsdfFile.info()` method: .. code:: pycon >>> import asdf >>> af = asdf.open("example.asdf") >>> af.info() root (AsdfObject) ├─asdf_library (Software) │ ├─author (str): The ASDF Developers │ ├─homepage (str): http://github.com/asdf-format/asdf │ ├─name (str): asdf │ └─version (str): 2.8.0 ├─history (dict) │ └─extensions (list) │ └─[0] (ExtensionMetadata) │ ├─extension_class (str): asdf.extension.BuiltinExtension │ └─software (Software) │ ├─name (str): asdf │ └─version (str): 2.8.0 ├─foo (int): 42 ├─name (str): Monty ├─powers (dict) │ └─squares (NDArrayType): shape=(100,), dtype=int64 ├─random (NDArrayType): shape=(100,), dtype=float64 └─sequence (NDArrayType): shape=(100,), dtype=int64 The `AsdfFile` behaves like a Python `dict`, and nodes are accessed like any other dictionary entry: .. code:: pycon >>> af["name"] 'Monty' >>> af["powers"] {'squares': } Array data remains unloaded until it is explicitly accessed: .. code:: pycon >>> af["powers"]["squares"] array([ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400, 441, 484, 529, 576, 625, 676, 729, 784, 841, 900, 961, 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849, 1936, 2025, 2116, 2209, 2304, 2401, 2500, 2601, 2704, 2809, 2916, 3025, 3136, 3249, 3364, 3481, 3600, 3721, 3844, 3969, 4096, 4225, 4356, 4489, 4624, 4761, 4900, 5041, 5184, 5329, 5476, 5625, 5776, 5929, 6084, 6241, 6400, 6561, 6724, 6889, 7056, 7225, 7396, 7569, 7744, 7921, 8100, 8281, 8464, 8649, 8836, 9025, 9216, 9409, 9604, 9801]) >>> import numpy as np >>> expected = [x**2 for x in range(100)] >>> np.equal(af["powers"]["squares"], expected).all() True By default, uncompressed data blocks are memory mapped for efficient access. Memory mapping can be disabled by using the ``copy_arrays`` option of `open` when reading: .. code:: python af = asdf.open("example.asdf", copy_arrays=True) .. _end-read-file-text: For more information and for advanced usage examples, see the `documentation <#documentation>`__. Extending ASDF ~~~~~~~~~~~~~~ Out of the box, the ``asdf`` package automatically serializes and deserializes native Python types. It is possible to extend ``asdf`` by implementing custom tags that correspond to custom user types. More information on extending ASDF can be found in the `official documentation `__. Installation ------------ .. _begin-pip-install-text: Stable releases of the ASDF Python package are registered `at PyPi `__. The latest stable version can be installed using ``pip``: :: $ pip install asdf .. _begin-source-install-text: The latest development version of ASDF is available from the ``main`` branch `on github `__. To clone the project: :: $ git clone https://github.com/asdf-format/asdf To install: :: $ cd asdf $ pip install . To install in `development mode `__:: $ pip install -e . .. _end-source-install-text: Testing ------- .. _begin-testing-text: To install the test dependencies from a source checkout of the repository: :: $ pip install -e ".[tests]" To run the unit tests from a source checkout of the repository: :: $ pytest It is also possible to run the test suite from an installed version of the package. :: $ pip install "asdf[tests]" $ pytest --pyargs asdf It is also possible to run the tests using `tox `__. :: $ pip install tox To list all available environments: :: $ tox -va To run a specific environment: :: $ tox -e .. _end-testing-text: Documentation ------------- More detailed documentation on this software package can be found `here `__. More information on the ASDF Standard itself can be found `here `__. There are two mailing lists for ASDF: * `asdf-users `_ * `asdf-developers `_ If you are looking for the **A**\ daptable **S**\ eismic **D**\ ata **F**\ ormat, information can be found `here `__. License ------- ASDF is licensed under a BSD 3-clause style license. See `LICENSE.rst `_ for the `licenses folder `_ for licenses for any included software. Contributing ------------ We welcome feedback and contributions to the project. Contributions of code, documentation, or general feedback are all appreciated. Please follow the `contributing guidelines `__ to submit an issue or a pull request. We strive to provide a welcoming community to all of our users by abiding to the `Code of Conduct `__. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788569.0 asdf-3.4.0/asdf.egg-info/SOURCES.txt0000644000175100001770000012470614653725331016356 0ustar00runnerdockerCHANGES.rst CITATION.rst CONTRIBUTING.rst LICENSE MANIFEST.in README.rst asv.conf.json pyproject.toml requirements-dev.txt tox.ini .github/CODEOWNERS .github/codecov.yml .github/dependabot.yml .github/issue_template.md .github/pull_request_template.md .github/workflows/build.yml .github/workflows/changelog.yml .github/workflows/ci.yml .github/workflows/downstream.yml .github/workflows/s390x.yml asdf/__init__.py asdf/_asdf.py asdf/_compression.py asdf/_convenience.py asdf/_display.py asdf/_entry_points.py asdf/_helpers.py asdf/_node_info.py asdf/_version.py asdf/asdf.py asdf/config.py asdf/conftest.py asdf/constants.py asdf/exceptions.py asdf/generic_io.py asdf/lazy_nodes.py asdf/reference.py asdf/resource.py asdf/schema.py asdf/search.py asdf/stream.py asdf/tagged.py asdf/treeutil.py asdf/util.py asdf/versioning.py asdf/yamlutil.py asdf.egg-info/PKG-INFO asdf.egg-info/SOURCES.txt asdf.egg-info/dependency_links.txt asdf.egg-info/entry_points.txt asdf.egg-info/requires.txt asdf.egg-info/top_level.txt asdf/_block/__init__.py asdf/_block/callback.py asdf/_block/exceptions.py asdf/_block/external.py asdf/_block/io.py asdf/_block/key.py asdf/_block/manager.py asdf/_block/options.py asdf/_block/reader.py asdf/_block/store.py asdf/_block/writer.py asdf/_core/__init__.py asdf/_core/_extensions.py asdf/_core/_integration.py asdf/_core/_converters/__init__.py asdf/_core/_converters/complex.py asdf/_core/_converters/constant.py asdf/_core/_converters/external_reference.py asdf/_core/_converters/integer.py asdf/_core/_converters/ndarray.py asdf/_core/_converters/reference.py asdf/_core/_converters/tree.py asdf/_core/_validators/__init__.py asdf/_core/_validators/ndarray.py asdf/_extern/__init__.py asdf/_extern/atomicfile.py asdf/_jsonschema/COPYING asdf/_jsonschema/README.md asdf/_jsonschema/__init__.py asdf/_jsonschema/_format.py asdf/_jsonschema/_legacy_validators.py asdf/_jsonschema/_types.py asdf/_jsonschema/_utils.py asdf/_jsonschema/_validators.py asdf/_jsonschema/conftest.py asdf/_jsonschema/exceptions.py asdf/_jsonschema/protocols.py asdf/_jsonschema/validators.py asdf/_jsonschema/json/.gitignore asdf/_jsonschema/json/CONTRIBUTING.md asdf/_jsonschema/json/LICENSE asdf/_jsonschema/json/README.md asdf/_jsonschema/json/package.json asdf/_jsonschema/json/test-schema.json asdf/_jsonschema/json/tox.ini asdf/_jsonschema/json/bin/jsonschema_suite asdf/_jsonschema/json/remotes/different-id-ref-string.json asdf/_jsonschema/json/remotes/extendible-dynamic-ref.json asdf/_jsonschema/json/remotes/integer.json asdf/_jsonschema/json/remotes/locationIndependentIdentifier.json asdf/_jsonschema/json/remotes/locationIndependentIdentifierDraft4.json asdf/_jsonschema/json/remotes/locationIndependentIdentifierPre2019.json asdf/_jsonschema/json/remotes/name-defs.json asdf/_jsonschema/json/remotes/name.json asdf/_jsonschema/json/remotes/nested-absolute-ref-to-string.json asdf/_jsonschema/json/remotes/ref-and-definitions.json asdf/_jsonschema/json/remotes/ref-and-defs.json asdf/_jsonschema/json/remotes/subSchemas-defs.json asdf/_jsonschema/json/remotes/subSchemas.json asdf/_jsonschema/json/remotes/tree.json asdf/_jsonschema/json/remotes/urn-ref-string.json asdf/_jsonschema/json/remotes/baseUriChange/folderInteger.json asdf/_jsonschema/json/remotes/baseUriChangeFolder/folderInteger.json asdf/_jsonschema/json/remotes/baseUriChangeFolderInSubschema/folderInteger.json asdf/_jsonschema/json/remotes/draft-next/extendible-dynamic-ref.json asdf/_jsonschema/json/remotes/draft-next/format-assertion-false.json asdf/_jsonschema/json/remotes/draft-next/format-assertion-true.json asdf/_jsonschema/json/remotes/draft-next/integer.json asdf/_jsonschema/json/remotes/draft-next/locationIndependentIdentifier.json asdf/_jsonschema/json/remotes/draft-next/metaschema-no-validation.json asdf/_jsonschema/json/remotes/draft-next/name-defs.json asdf/_jsonschema/json/remotes/draft-next/ref-and-defs.json asdf/_jsonschema/json/remotes/draft-next/subSchemas-defs.json asdf/_jsonschema/json/remotes/draft-next/subSchemas.json asdf/_jsonschema/json/remotes/draft-next/tree.json asdf/_jsonschema/json/remotes/draft-next/baseUriChange/folderInteger.json asdf/_jsonschema/json/remotes/draft-next/baseUriChangeFolder/folderInteger.json asdf/_jsonschema/json/remotes/draft-next/baseUriChangeFolderInSubschema/folderInteger.json asdf/_jsonschema/json/remotes/draft-next/nested/foo-ref-string.json asdf/_jsonschema/json/remotes/draft-next/nested/string.json asdf/_jsonschema/json/remotes/draft2019-09/dependentRequired.json asdf/_jsonschema/json/remotes/draft2019-09/extendible-dynamic-ref.json asdf/_jsonschema/json/remotes/draft2019-09/ignore-prefixItems.json asdf/_jsonschema/json/remotes/draft2019-09/integer.json asdf/_jsonschema/json/remotes/draft2019-09/locationIndependentIdentifier.json asdf/_jsonschema/json/remotes/draft2019-09/metaschema-no-validation.json asdf/_jsonschema/json/remotes/draft2019-09/name-defs.json asdf/_jsonschema/json/remotes/draft2019-09/ref-and-defs.json asdf/_jsonschema/json/remotes/draft2019-09/subSchemas-defs.json asdf/_jsonschema/json/remotes/draft2019-09/subSchemas.json asdf/_jsonschema/json/remotes/draft2019-09/tree.json asdf/_jsonschema/json/remotes/draft2019-09/baseUriChange/folderInteger.json asdf/_jsonschema/json/remotes/draft2019-09/baseUriChangeFolder/folderInteger.json asdf/_jsonschema/json/remotes/draft2019-09/baseUriChangeFolderInSubschema/folderInteger.json asdf/_jsonschema/json/remotes/draft2019-09/nested/foo-ref-string.json asdf/_jsonschema/json/remotes/draft2019-09/nested/string.json asdf/_jsonschema/json/remotes/draft2020-12/extendible-dynamic-ref.json asdf/_jsonschema/json/remotes/draft2020-12/format-assertion-false.json asdf/_jsonschema/json/remotes/draft2020-12/format-assertion-true.json asdf/_jsonschema/json/remotes/draft2020-12/integer.json asdf/_jsonschema/json/remotes/draft2020-12/locationIndependentIdentifier.json asdf/_jsonschema/json/remotes/draft2020-12/metaschema-no-validation.json asdf/_jsonschema/json/remotes/draft2020-12/name-defs.json asdf/_jsonschema/json/remotes/draft2020-12/prefixItems.json asdf/_jsonschema/json/remotes/draft2020-12/ref-and-defs.json asdf/_jsonschema/json/remotes/draft2020-12/subSchemas-defs.json asdf/_jsonschema/json/remotes/draft2020-12/subSchemas.json asdf/_jsonschema/json/remotes/draft2020-12/tree.json asdf/_jsonschema/json/remotes/draft2020-12/baseUriChange/folderInteger.json asdf/_jsonschema/json/remotes/draft2020-12/baseUriChangeFolder/folderInteger.json asdf/_jsonschema/json/remotes/draft2020-12/baseUriChangeFolderInSubschema/folderInteger.json asdf/_jsonschema/json/remotes/draft2020-12/nested/foo-ref-string.json asdf/_jsonschema/json/remotes/draft2020-12/nested/string.json asdf/_jsonschema/json/remotes/draft7/ignore-dependentRequired.json asdf/_jsonschema/json/remotes/nested/foo-ref-string.json asdf/_jsonschema/json/remotes/nested/string.json asdf/_jsonschema/json/tests/draft-next/additionalProperties.json asdf/_jsonschema/json/tests/draft-next/allOf.json asdf/_jsonschema/json/tests/draft-next/anchor.json asdf/_jsonschema/json/tests/draft-next/anyOf.json asdf/_jsonschema/json/tests/draft-next/boolean_schema.json asdf/_jsonschema/json/tests/draft-next/const.json asdf/_jsonschema/json/tests/draft-next/contains.json asdf/_jsonschema/json/tests/draft-next/content.json asdf/_jsonschema/json/tests/draft-next/default.json asdf/_jsonschema/json/tests/draft-next/defs.json asdf/_jsonschema/json/tests/draft-next/dependentRequired.json asdf/_jsonschema/json/tests/draft-next/dependentSchemas.json asdf/_jsonschema/json/tests/draft-next/dynamicRef.json asdf/_jsonschema/json/tests/draft-next/enum.json asdf/_jsonschema/json/tests/draft-next/exclusiveMaximum.json asdf/_jsonschema/json/tests/draft-next/exclusiveMinimum.json asdf/_jsonschema/json/tests/draft-next/format.json asdf/_jsonschema/json/tests/draft-next/id.json asdf/_jsonschema/json/tests/draft-next/if-then-else.json asdf/_jsonschema/json/tests/draft-next/infinite-loop-detection.json asdf/_jsonschema/json/tests/draft-next/items.json asdf/_jsonschema/json/tests/draft-next/maxContains.json asdf/_jsonschema/json/tests/draft-next/maxItems.json asdf/_jsonschema/json/tests/draft-next/maxLength.json asdf/_jsonschema/json/tests/draft-next/maxProperties.json asdf/_jsonschema/json/tests/draft-next/maximum.json asdf/_jsonschema/json/tests/draft-next/minContains.json asdf/_jsonschema/json/tests/draft-next/minItems.json asdf/_jsonschema/json/tests/draft-next/minLength.json asdf/_jsonschema/json/tests/draft-next/minProperties.json asdf/_jsonschema/json/tests/draft-next/minimum.json asdf/_jsonschema/json/tests/draft-next/multipleOf.json asdf/_jsonschema/json/tests/draft-next/not.json asdf/_jsonschema/json/tests/draft-next/oneOf.json asdf/_jsonschema/json/tests/draft-next/pattern.json asdf/_jsonschema/json/tests/draft-next/patternProperties.json asdf/_jsonschema/json/tests/draft-next/prefixItems.json asdf/_jsonschema/json/tests/draft-next/properties.json asdf/_jsonschema/json/tests/draft-next/propertyDependencies.json asdf/_jsonschema/json/tests/draft-next/propertyNames.json asdf/_jsonschema/json/tests/draft-next/ref.json asdf/_jsonschema/json/tests/draft-next/refRemote.json asdf/_jsonschema/json/tests/draft-next/required.json asdf/_jsonschema/json/tests/draft-next/type.json asdf/_jsonschema/json/tests/draft-next/unevaluatedItems.json asdf/_jsonschema/json/tests/draft-next/unevaluatedProperties.json asdf/_jsonschema/json/tests/draft-next/uniqueItems.json asdf/_jsonschema/json/tests/draft-next/unknownKeyword.json asdf/_jsonschema/json/tests/draft-next/vocabulary.json asdf/_jsonschema/json/tests/draft-next/optional/bignum.json asdf/_jsonschema/json/tests/draft-next/optional/dependencies-compatibility.json asdf/_jsonschema/json/tests/draft-next/optional/ecmascript-regex.json asdf/_jsonschema/json/tests/draft-next/optional/float-overflow.json asdf/_jsonschema/json/tests/draft-next/optional/format-assertion.json asdf/_jsonschema/json/tests/draft-next/optional/non-bmp-regex.json asdf/_jsonschema/json/tests/draft-next/optional/refOfUnknownKeyword.json asdf/_jsonschema/json/tests/draft-next/optional/format/date-time.json asdf/_jsonschema/json/tests/draft-next/optional/format/date.json asdf/_jsonschema/json/tests/draft-next/optional/format/duration.json asdf/_jsonschema/json/tests/draft-next/optional/format/email.json asdf/_jsonschema/json/tests/draft-next/optional/format/hostname.json asdf/_jsonschema/json/tests/draft-next/optional/format/idn-email.json asdf/_jsonschema/json/tests/draft-next/optional/format/idn-hostname.json asdf/_jsonschema/json/tests/draft-next/optional/format/ipv4.json asdf/_jsonschema/json/tests/draft-next/optional/format/ipv6.json asdf/_jsonschema/json/tests/draft-next/optional/format/iri-reference.json asdf/_jsonschema/json/tests/draft-next/optional/format/iri.json asdf/_jsonschema/json/tests/draft-next/optional/format/json-pointer.json asdf/_jsonschema/json/tests/draft-next/optional/format/regex.json asdf/_jsonschema/json/tests/draft-next/optional/format/relative-json-pointer.json asdf/_jsonschema/json/tests/draft-next/optional/format/time.json asdf/_jsonschema/json/tests/draft-next/optional/format/uri-reference.json asdf/_jsonschema/json/tests/draft-next/optional/format/uri-template.json asdf/_jsonschema/json/tests/draft-next/optional/format/uri.json asdf/_jsonschema/json/tests/draft-next/optional/format/uuid.json asdf/_jsonschema/json/tests/draft2019-09/additionalItems.json asdf/_jsonschema/json/tests/draft2019-09/additionalProperties.json asdf/_jsonschema/json/tests/draft2019-09/allOf.json asdf/_jsonschema/json/tests/draft2019-09/anchor.json asdf/_jsonschema/json/tests/draft2019-09/anyOf.json asdf/_jsonschema/json/tests/draft2019-09/boolean_schema.json asdf/_jsonschema/json/tests/draft2019-09/const.json asdf/_jsonschema/json/tests/draft2019-09/contains.json asdf/_jsonschema/json/tests/draft2019-09/content.json asdf/_jsonschema/json/tests/draft2019-09/default.json asdf/_jsonschema/json/tests/draft2019-09/defs.json asdf/_jsonschema/json/tests/draft2019-09/dependentRequired.json asdf/_jsonschema/json/tests/draft2019-09/dependentSchemas.json asdf/_jsonschema/json/tests/draft2019-09/enum.json asdf/_jsonschema/json/tests/draft2019-09/exclusiveMaximum.json asdf/_jsonschema/json/tests/draft2019-09/exclusiveMinimum.json asdf/_jsonschema/json/tests/draft2019-09/format.json asdf/_jsonschema/json/tests/draft2019-09/id.json asdf/_jsonschema/json/tests/draft2019-09/if-then-else.json asdf/_jsonschema/json/tests/draft2019-09/infinite-loop-detection.json asdf/_jsonschema/json/tests/draft2019-09/items.json asdf/_jsonschema/json/tests/draft2019-09/maxContains.json asdf/_jsonschema/json/tests/draft2019-09/maxItems.json asdf/_jsonschema/json/tests/draft2019-09/maxLength.json asdf/_jsonschema/json/tests/draft2019-09/maxProperties.json asdf/_jsonschema/json/tests/draft2019-09/maximum.json asdf/_jsonschema/json/tests/draft2019-09/minContains.json asdf/_jsonschema/json/tests/draft2019-09/minItems.json asdf/_jsonschema/json/tests/draft2019-09/minLength.json asdf/_jsonschema/json/tests/draft2019-09/minProperties.json asdf/_jsonschema/json/tests/draft2019-09/minimum.json asdf/_jsonschema/json/tests/draft2019-09/multipleOf.json asdf/_jsonschema/json/tests/draft2019-09/not.json asdf/_jsonschema/json/tests/draft2019-09/oneOf.json asdf/_jsonschema/json/tests/draft2019-09/pattern.json asdf/_jsonschema/json/tests/draft2019-09/patternProperties.json asdf/_jsonschema/json/tests/draft2019-09/properties.json asdf/_jsonschema/json/tests/draft2019-09/propertyNames.json asdf/_jsonschema/json/tests/draft2019-09/recursiveRef.json asdf/_jsonschema/json/tests/draft2019-09/ref.json asdf/_jsonschema/json/tests/draft2019-09/refRemote.json asdf/_jsonschema/json/tests/draft2019-09/required.json asdf/_jsonschema/json/tests/draft2019-09/type.json asdf/_jsonschema/json/tests/draft2019-09/unevaluatedItems.json asdf/_jsonschema/json/tests/draft2019-09/unevaluatedProperties.json asdf/_jsonschema/json/tests/draft2019-09/uniqueItems.json asdf/_jsonschema/json/tests/draft2019-09/unknownKeyword.json asdf/_jsonschema/json/tests/draft2019-09/vocabulary.json asdf/_jsonschema/json/tests/draft2019-09/optional/bignum.json asdf/_jsonschema/json/tests/draft2019-09/optional/cross-draft.json asdf/_jsonschema/json/tests/draft2019-09/optional/dependencies-compatibility.json asdf/_jsonschema/json/tests/draft2019-09/optional/ecmascript-regex.json asdf/_jsonschema/json/tests/draft2019-09/optional/float-overflow.json asdf/_jsonschema/json/tests/draft2019-09/optional/no-schema.json asdf/_jsonschema/json/tests/draft2019-09/optional/non-bmp-regex.json asdf/_jsonschema/json/tests/draft2019-09/optional/refOfUnknownKeyword.json asdf/_jsonschema/json/tests/draft2019-09/optional/format/date-time.json asdf/_jsonschema/json/tests/draft2019-09/optional/format/date.json asdf/_jsonschema/json/tests/draft2019-09/optional/format/duration.json asdf/_jsonschema/json/tests/draft2019-09/optional/format/email.json asdf/_jsonschema/json/tests/draft2019-09/optional/format/hostname.json asdf/_jsonschema/json/tests/draft2019-09/optional/format/idn-email.json asdf/_jsonschema/json/tests/draft2019-09/optional/format/idn-hostname.json asdf/_jsonschema/json/tests/draft2019-09/optional/format/ipv4.json asdf/_jsonschema/json/tests/draft2019-09/optional/format/ipv6.json asdf/_jsonschema/json/tests/draft2019-09/optional/format/iri-reference.json asdf/_jsonschema/json/tests/draft2019-09/optional/format/iri.json asdf/_jsonschema/json/tests/draft2019-09/optional/format/json-pointer.json asdf/_jsonschema/json/tests/draft2019-09/optional/format/regex.json asdf/_jsonschema/json/tests/draft2019-09/optional/format/relative-json-pointer.json asdf/_jsonschema/json/tests/draft2019-09/optional/format/time.json asdf/_jsonschema/json/tests/draft2019-09/optional/format/unknown.json asdf/_jsonschema/json/tests/draft2019-09/optional/format/uri-reference.json asdf/_jsonschema/json/tests/draft2019-09/optional/format/uri-template.json asdf/_jsonschema/json/tests/draft2019-09/optional/format/uri.json asdf/_jsonschema/json/tests/draft2019-09/optional/format/uuid.json asdf/_jsonschema/json/tests/draft2020-12/additionalProperties.json asdf/_jsonschema/json/tests/draft2020-12/allOf.json asdf/_jsonschema/json/tests/draft2020-12/anchor.json asdf/_jsonschema/json/tests/draft2020-12/anyOf.json asdf/_jsonschema/json/tests/draft2020-12/boolean_schema.json asdf/_jsonschema/json/tests/draft2020-12/const.json asdf/_jsonschema/json/tests/draft2020-12/contains.json asdf/_jsonschema/json/tests/draft2020-12/content.json asdf/_jsonschema/json/tests/draft2020-12/default.json asdf/_jsonschema/json/tests/draft2020-12/defs.json asdf/_jsonschema/json/tests/draft2020-12/dependentRequired.json asdf/_jsonschema/json/tests/draft2020-12/dependentSchemas.json asdf/_jsonschema/json/tests/draft2020-12/dynamicRef.json asdf/_jsonschema/json/tests/draft2020-12/enum.json asdf/_jsonschema/json/tests/draft2020-12/exclusiveMaximum.json asdf/_jsonschema/json/tests/draft2020-12/exclusiveMinimum.json asdf/_jsonschema/json/tests/draft2020-12/format.json asdf/_jsonschema/json/tests/draft2020-12/id.json asdf/_jsonschema/json/tests/draft2020-12/if-then-else.json asdf/_jsonschema/json/tests/draft2020-12/infinite-loop-detection.json asdf/_jsonschema/json/tests/draft2020-12/items.json asdf/_jsonschema/json/tests/draft2020-12/maxContains.json asdf/_jsonschema/json/tests/draft2020-12/maxItems.json asdf/_jsonschema/json/tests/draft2020-12/maxLength.json asdf/_jsonschema/json/tests/draft2020-12/maxProperties.json asdf/_jsonschema/json/tests/draft2020-12/maximum.json asdf/_jsonschema/json/tests/draft2020-12/minContains.json asdf/_jsonschema/json/tests/draft2020-12/minItems.json asdf/_jsonschema/json/tests/draft2020-12/minLength.json asdf/_jsonschema/json/tests/draft2020-12/minProperties.json asdf/_jsonschema/json/tests/draft2020-12/minimum.json asdf/_jsonschema/json/tests/draft2020-12/multipleOf.json asdf/_jsonschema/json/tests/draft2020-12/not.json asdf/_jsonschema/json/tests/draft2020-12/oneOf.json asdf/_jsonschema/json/tests/draft2020-12/pattern.json asdf/_jsonschema/json/tests/draft2020-12/patternProperties.json asdf/_jsonschema/json/tests/draft2020-12/prefixItems.json asdf/_jsonschema/json/tests/draft2020-12/properties.json asdf/_jsonschema/json/tests/draft2020-12/propertyNames.json asdf/_jsonschema/json/tests/draft2020-12/ref.json asdf/_jsonschema/json/tests/draft2020-12/refRemote.json asdf/_jsonschema/json/tests/draft2020-12/required.json asdf/_jsonschema/json/tests/draft2020-12/type.json asdf/_jsonschema/json/tests/draft2020-12/unevaluatedItems.json asdf/_jsonschema/json/tests/draft2020-12/unevaluatedProperties.json asdf/_jsonschema/json/tests/draft2020-12/uniqueItems.json asdf/_jsonschema/json/tests/draft2020-12/unknownKeyword.json asdf/_jsonschema/json/tests/draft2020-12/vocabulary.json asdf/_jsonschema/json/tests/draft2020-12/optional/bignum.json asdf/_jsonschema/json/tests/draft2020-12/optional/cross-draft.json asdf/_jsonschema/json/tests/draft2020-12/optional/dependencies-compatibility.json asdf/_jsonschema/json/tests/draft2020-12/optional/ecmascript-regex.json asdf/_jsonschema/json/tests/draft2020-12/optional/float-overflow.json asdf/_jsonschema/json/tests/draft2020-12/optional/format-assertion.json asdf/_jsonschema/json/tests/draft2020-12/optional/no-schema.json asdf/_jsonschema/json/tests/draft2020-12/optional/non-bmp-regex.json asdf/_jsonschema/json/tests/draft2020-12/optional/refOfUnknownKeyword.json asdf/_jsonschema/json/tests/draft2020-12/optional/format/date-time.json asdf/_jsonschema/json/tests/draft2020-12/optional/format/date.json asdf/_jsonschema/json/tests/draft2020-12/optional/format/duration.json asdf/_jsonschema/json/tests/draft2020-12/optional/format/email.json asdf/_jsonschema/json/tests/draft2020-12/optional/format/hostname.json asdf/_jsonschema/json/tests/draft2020-12/optional/format/idn-email.json asdf/_jsonschema/json/tests/draft2020-12/optional/format/idn-hostname.json asdf/_jsonschema/json/tests/draft2020-12/optional/format/ipv4.json asdf/_jsonschema/json/tests/draft2020-12/optional/format/ipv6.json asdf/_jsonschema/json/tests/draft2020-12/optional/format/iri-reference.json asdf/_jsonschema/json/tests/draft2020-12/optional/format/iri.json asdf/_jsonschema/json/tests/draft2020-12/optional/format/json-pointer.json asdf/_jsonschema/json/tests/draft2020-12/optional/format/regex.json asdf/_jsonschema/json/tests/draft2020-12/optional/format/relative-json-pointer.json asdf/_jsonschema/json/tests/draft2020-12/optional/format/time.json asdf/_jsonschema/json/tests/draft2020-12/optional/format/unknown.json asdf/_jsonschema/json/tests/draft2020-12/optional/format/uri-reference.json asdf/_jsonschema/json/tests/draft2020-12/optional/format/uri-template.json asdf/_jsonschema/json/tests/draft2020-12/optional/format/uri.json asdf/_jsonschema/json/tests/draft2020-12/optional/format/uuid.json asdf/_jsonschema/json/tests/draft3/additionalItems.json asdf/_jsonschema/json/tests/draft3/additionalProperties.json asdf/_jsonschema/json/tests/draft3/default.json asdf/_jsonschema/json/tests/draft3/dependencies.json asdf/_jsonschema/json/tests/draft3/disallow.json asdf/_jsonschema/json/tests/draft3/divisibleBy.json asdf/_jsonschema/json/tests/draft3/enum.json asdf/_jsonschema/json/tests/draft3/extends.json asdf/_jsonschema/json/tests/draft3/format.json asdf/_jsonschema/json/tests/draft3/infinite-loop-detection.json asdf/_jsonschema/json/tests/draft3/items.json asdf/_jsonschema/json/tests/draft3/maxItems.json asdf/_jsonschema/json/tests/draft3/maxLength.json asdf/_jsonschema/json/tests/draft3/maximum.json asdf/_jsonschema/json/tests/draft3/minItems.json asdf/_jsonschema/json/tests/draft3/minLength.json asdf/_jsonschema/json/tests/draft3/minimum.json asdf/_jsonschema/json/tests/draft3/pattern.json asdf/_jsonschema/json/tests/draft3/patternProperties.json asdf/_jsonschema/json/tests/draft3/properties.json asdf/_jsonschema/json/tests/draft3/ref.json asdf/_jsonschema/json/tests/draft3/refRemote.json asdf/_jsonschema/json/tests/draft3/required.json asdf/_jsonschema/json/tests/draft3/type.json asdf/_jsonschema/json/tests/draft3/uniqueItems.json asdf/_jsonschema/json/tests/draft3/optional/bignum.json asdf/_jsonschema/json/tests/draft3/optional/ecmascript-regex.json asdf/_jsonschema/json/tests/draft3/optional/non-bmp-regex.json asdf/_jsonschema/json/tests/draft3/optional/zeroTerminatedFloats.json asdf/_jsonschema/json/tests/draft3/optional/format/color.json asdf/_jsonschema/json/tests/draft3/optional/format/date-time.json asdf/_jsonschema/json/tests/draft3/optional/format/date.json asdf/_jsonschema/json/tests/draft3/optional/format/email.json asdf/_jsonschema/json/tests/draft3/optional/format/host-name.json asdf/_jsonschema/json/tests/draft3/optional/format/ip-address.json asdf/_jsonschema/json/tests/draft3/optional/format/ipv6.json asdf/_jsonschema/json/tests/draft3/optional/format/regex.json asdf/_jsonschema/json/tests/draft3/optional/format/time.json asdf/_jsonschema/json/tests/draft3/optional/format/uri.json asdf/_jsonschema/json/tests/draft4/additionalItems.json asdf/_jsonschema/json/tests/draft4/additionalProperties.json asdf/_jsonschema/json/tests/draft4/allOf.json asdf/_jsonschema/json/tests/draft4/anyOf.json asdf/_jsonschema/json/tests/draft4/default.json asdf/_jsonschema/json/tests/draft4/definitions.json asdf/_jsonschema/json/tests/draft4/dependencies.json asdf/_jsonschema/json/tests/draft4/enum.json asdf/_jsonschema/json/tests/draft4/format.json asdf/_jsonschema/json/tests/draft4/id.json asdf/_jsonschema/json/tests/draft4/infinite-loop-detection.json asdf/_jsonschema/json/tests/draft4/items.json asdf/_jsonschema/json/tests/draft4/maxItems.json asdf/_jsonschema/json/tests/draft4/maxLength.json asdf/_jsonschema/json/tests/draft4/maxProperties.json asdf/_jsonschema/json/tests/draft4/maximum.json asdf/_jsonschema/json/tests/draft4/minItems.json asdf/_jsonschema/json/tests/draft4/minLength.json asdf/_jsonschema/json/tests/draft4/minProperties.json asdf/_jsonschema/json/tests/draft4/minimum.json asdf/_jsonschema/json/tests/draft4/multipleOf.json asdf/_jsonschema/json/tests/draft4/not.json asdf/_jsonschema/json/tests/draft4/oneOf.json asdf/_jsonschema/json/tests/draft4/pattern.json asdf/_jsonschema/json/tests/draft4/patternProperties.json asdf/_jsonschema/json/tests/draft4/properties.json asdf/_jsonschema/json/tests/draft4/ref.json asdf/_jsonschema/json/tests/draft4/refRemote.json asdf/_jsonschema/json/tests/draft4/required.json asdf/_jsonschema/json/tests/draft4/type.json asdf/_jsonschema/json/tests/draft4/uniqueItems.json asdf/_jsonschema/json/tests/draft4/optional/bignum.json asdf/_jsonschema/json/tests/draft4/optional/ecmascript-regex.json asdf/_jsonschema/json/tests/draft4/optional/float-overflow.json asdf/_jsonschema/json/tests/draft4/optional/non-bmp-regex.json asdf/_jsonschema/json/tests/draft4/optional/zeroTerminatedFloats.json asdf/_jsonschema/json/tests/draft4/optional/format/date-time.json asdf/_jsonschema/json/tests/draft4/optional/format/email.json asdf/_jsonschema/json/tests/draft4/optional/format/hostname.json asdf/_jsonschema/json/tests/draft4/optional/format/ipv4.json asdf/_jsonschema/json/tests/draft4/optional/format/ipv6.json asdf/_jsonschema/json/tests/draft4/optional/format/unknown.json asdf/_jsonschema/json/tests/draft4/optional/format/uri.json asdf/_jsonschema/json/tests/draft6/additionalItems.json asdf/_jsonschema/json/tests/draft6/additionalProperties.json asdf/_jsonschema/json/tests/draft6/allOf.json asdf/_jsonschema/json/tests/draft6/anyOf.json asdf/_jsonschema/json/tests/draft6/boolean_schema.json asdf/_jsonschema/json/tests/draft6/const.json asdf/_jsonschema/json/tests/draft6/contains.json asdf/_jsonschema/json/tests/draft6/default.json asdf/_jsonschema/json/tests/draft6/definitions.json asdf/_jsonschema/json/tests/draft6/dependencies.json asdf/_jsonschema/json/tests/draft6/enum.json asdf/_jsonschema/json/tests/draft6/exclusiveMaximum.json asdf/_jsonschema/json/tests/draft6/exclusiveMinimum.json asdf/_jsonschema/json/tests/draft6/format.json asdf/_jsonschema/json/tests/draft6/id.json asdf/_jsonschema/json/tests/draft6/infinite-loop-detection.json asdf/_jsonschema/json/tests/draft6/items.json asdf/_jsonschema/json/tests/draft6/maxItems.json asdf/_jsonschema/json/tests/draft6/maxLength.json asdf/_jsonschema/json/tests/draft6/maxProperties.json asdf/_jsonschema/json/tests/draft6/maximum.json asdf/_jsonschema/json/tests/draft6/minItems.json asdf/_jsonschema/json/tests/draft6/minLength.json asdf/_jsonschema/json/tests/draft6/minProperties.json asdf/_jsonschema/json/tests/draft6/minimum.json asdf/_jsonschema/json/tests/draft6/multipleOf.json asdf/_jsonschema/json/tests/draft6/not.json asdf/_jsonschema/json/tests/draft6/oneOf.json asdf/_jsonschema/json/tests/draft6/pattern.json asdf/_jsonschema/json/tests/draft6/patternProperties.json asdf/_jsonschema/json/tests/draft6/properties.json asdf/_jsonschema/json/tests/draft6/propertyNames.json asdf/_jsonschema/json/tests/draft6/ref.json asdf/_jsonschema/json/tests/draft6/refRemote.json asdf/_jsonschema/json/tests/draft6/required.json asdf/_jsonschema/json/tests/draft6/type.json asdf/_jsonschema/json/tests/draft6/uniqueItems.json asdf/_jsonschema/json/tests/draft6/unknownKeyword.json asdf/_jsonschema/json/tests/draft6/optional/bignum.json asdf/_jsonschema/json/tests/draft6/optional/ecmascript-regex.json asdf/_jsonschema/json/tests/draft6/optional/float-overflow.json asdf/_jsonschema/json/tests/draft6/optional/non-bmp-regex.json asdf/_jsonschema/json/tests/draft6/optional/format/date-time.json asdf/_jsonschema/json/tests/draft6/optional/format/email.json asdf/_jsonschema/json/tests/draft6/optional/format/hostname.json asdf/_jsonschema/json/tests/draft6/optional/format/ipv4.json asdf/_jsonschema/json/tests/draft6/optional/format/ipv6.json asdf/_jsonschema/json/tests/draft6/optional/format/json-pointer.json asdf/_jsonschema/json/tests/draft6/optional/format/unknown.json asdf/_jsonschema/json/tests/draft6/optional/format/uri-reference.json asdf/_jsonschema/json/tests/draft6/optional/format/uri-template.json asdf/_jsonschema/json/tests/draft6/optional/format/uri.json asdf/_jsonschema/json/tests/draft7/additionalItems.json asdf/_jsonschema/json/tests/draft7/additionalProperties.json asdf/_jsonschema/json/tests/draft7/allOf.json asdf/_jsonschema/json/tests/draft7/anyOf.json asdf/_jsonschema/json/tests/draft7/boolean_schema.json asdf/_jsonschema/json/tests/draft7/const.json asdf/_jsonschema/json/tests/draft7/contains.json asdf/_jsonschema/json/tests/draft7/default.json asdf/_jsonschema/json/tests/draft7/definitions.json asdf/_jsonschema/json/tests/draft7/dependencies.json asdf/_jsonschema/json/tests/draft7/enum.json asdf/_jsonschema/json/tests/draft7/exclusiveMaximum.json asdf/_jsonschema/json/tests/draft7/exclusiveMinimum.json asdf/_jsonschema/json/tests/draft7/format.json asdf/_jsonschema/json/tests/draft7/id.json asdf/_jsonschema/json/tests/draft7/if-then-else.json asdf/_jsonschema/json/tests/draft7/infinite-loop-detection.json asdf/_jsonschema/json/tests/draft7/items.json asdf/_jsonschema/json/tests/draft7/maxItems.json asdf/_jsonschema/json/tests/draft7/maxLength.json asdf/_jsonschema/json/tests/draft7/maxProperties.json asdf/_jsonschema/json/tests/draft7/maximum.json asdf/_jsonschema/json/tests/draft7/minItems.json asdf/_jsonschema/json/tests/draft7/minLength.json asdf/_jsonschema/json/tests/draft7/minProperties.json asdf/_jsonschema/json/tests/draft7/minimum.json asdf/_jsonschema/json/tests/draft7/multipleOf.json asdf/_jsonschema/json/tests/draft7/not.json asdf/_jsonschema/json/tests/draft7/oneOf.json asdf/_jsonschema/json/tests/draft7/pattern.json asdf/_jsonschema/json/tests/draft7/patternProperties.json asdf/_jsonschema/json/tests/draft7/properties.json asdf/_jsonschema/json/tests/draft7/propertyNames.json asdf/_jsonschema/json/tests/draft7/ref.json asdf/_jsonschema/json/tests/draft7/refRemote.json asdf/_jsonschema/json/tests/draft7/required.json asdf/_jsonschema/json/tests/draft7/type.json asdf/_jsonschema/json/tests/draft7/uniqueItems.json asdf/_jsonschema/json/tests/draft7/unknownKeyword.json asdf/_jsonschema/json/tests/draft7/optional/bignum.json asdf/_jsonschema/json/tests/draft7/optional/content.json asdf/_jsonschema/json/tests/draft7/optional/cross-draft.json asdf/_jsonschema/json/tests/draft7/optional/ecmascript-regex.json asdf/_jsonschema/json/tests/draft7/optional/float-overflow.json asdf/_jsonschema/json/tests/draft7/optional/non-bmp-regex.json asdf/_jsonschema/json/tests/draft7/optional/format/date-time.json asdf/_jsonschema/json/tests/draft7/optional/format/date.json asdf/_jsonschema/json/tests/draft7/optional/format/email.json asdf/_jsonschema/json/tests/draft7/optional/format/hostname.json asdf/_jsonschema/json/tests/draft7/optional/format/idn-email.json asdf/_jsonschema/json/tests/draft7/optional/format/idn-hostname.json asdf/_jsonschema/json/tests/draft7/optional/format/ipv4.json asdf/_jsonschema/json/tests/draft7/optional/format/ipv6.json asdf/_jsonschema/json/tests/draft7/optional/format/iri-reference.json asdf/_jsonschema/json/tests/draft7/optional/format/iri.json asdf/_jsonschema/json/tests/draft7/optional/format/json-pointer.json asdf/_jsonschema/json/tests/draft7/optional/format/regex.json asdf/_jsonschema/json/tests/draft7/optional/format/relative-json-pointer.json asdf/_jsonschema/json/tests/draft7/optional/format/time.json asdf/_jsonschema/json/tests/draft7/optional/format/unknown.json asdf/_jsonschema/json/tests/draft7/optional/format/uri-reference.json asdf/_jsonschema/json/tests/draft7/optional/format/uri-template.json asdf/_jsonschema/json/tests/draft7/optional/format/uri.json asdf/_jsonschema/json/tests/latest/additionalProperties.json asdf/_jsonschema/json/tests/latest/allOf.json asdf/_jsonschema/json/tests/latest/anchor.json asdf/_jsonschema/json/tests/latest/anyOf.json asdf/_jsonschema/json/tests/latest/boolean_schema.json asdf/_jsonschema/json/tests/latest/const.json asdf/_jsonschema/json/tests/latest/contains.json asdf/_jsonschema/json/tests/latest/content.json asdf/_jsonschema/json/tests/latest/default.json asdf/_jsonschema/json/tests/latest/defs.json asdf/_jsonschema/json/tests/latest/dependentRequired.json asdf/_jsonschema/json/tests/latest/dependentSchemas.json asdf/_jsonschema/json/tests/latest/dynamicRef.json asdf/_jsonschema/json/tests/latest/enum.json asdf/_jsonschema/json/tests/latest/exclusiveMaximum.json asdf/_jsonschema/json/tests/latest/exclusiveMinimum.json asdf/_jsonschema/json/tests/latest/format.json asdf/_jsonschema/json/tests/latest/id.json asdf/_jsonschema/json/tests/latest/if-then-else.json asdf/_jsonschema/json/tests/latest/infinite-loop-detection.json asdf/_jsonschema/json/tests/latest/items.json asdf/_jsonschema/json/tests/latest/maxContains.json asdf/_jsonschema/json/tests/latest/maxItems.json asdf/_jsonschema/json/tests/latest/maxLength.json asdf/_jsonschema/json/tests/latest/maxProperties.json asdf/_jsonschema/json/tests/latest/maximum.json asdf/_jsonschema/json/tests/latest/minContains.json asdf/_jsonschema/json/tests/latest/minItems.json asdf/_jsonschema/json/tests/latest/minLength.json asdf/_jsonschema/json/tests/latest/minProperties.json asdf/_jsonschema/json/tests/latest/minimum.json asdf/_jsonschema/json/tests/latest/multipleOf.json asdf/_jsonschema/json/tests/latest/not.json asdf/_jsonschema/json/tests/latest/oneOf.json asdf/_jsonschema/json/tests/latest/pattern.json asdf/_jsonschema/json/tests/latest/patternProperties.json asdf/_jsonschema/json/tests/latest/prefixItems.json asdf/_jsonschema/json/tests/latest/properties.json asdf/_jsonschema/json/tests/latest/propertyNames.json asdf/_jsonschema/json/tests/latest/ref.json asdf/_jsonschema/json/tests/latest/refRemote.json asdf/_jsonschema/json/tests/latest/required.json asdf/_jsonschema/json/tests/latest/type.json asdf/_jsonschema/json/tests/latest/unevaluatedItems.json asdf/_jsonschema/json/tests/latest/unevaluatedProperties.json asdf/_jsonschema/json/tests/latest/uniqueItems.json asdf/_jsonschema/json/tests/latest/unknownKeyword.json asdf/_jsonschema/json/tests/latest/vocabulary.json asdf/_jsonschema/json/tests/latest/optional/bignum.json asdf/_jsonschema/json/tests/latest/optional/cross-draft.json asdf/_jsonschema/json/tests/latest/optional/dependencies-compatibility.json asdf/_jsonschema/json/tests/latest/optional/ecmascript-regex.json asdf/_jsonschema/json/tests/latest/optional/float-overflow.json asdf/_jsonschema/json/tests/latest/optional/format-assertion.json asdf/_jsonschema/json/tests/latest/optional/no-schema.json asdf/_jsonschema/json/tests/latest/optional/non-bmp-regex.json asdf/_jsonschema/json/tests/latest/optional/refOfUnknownKeyword.json asdf/_jsonschema/json/tests/latest/optional/format/date-time.json asdf/_jsonschema/json/tests/latest/optional/format/date.json asdf/_jsonschema/json/tests/latest/optional/format/duration.json asdf/_jsonschema/json/tests/latest/optional/format/email.json asdf/_jsonschema/json/tests/latest/optional/format/hostname.json asdf/_jsonschema/json/tests/latest/optional/format/idn-email.json asdf/_jsonschema/json/tests/latest/optional/format/idn-hostname.json asdf/_jsonschema/json/tests/latest/optional/format/ipv4.json asdf/_jsonschema/json/tests/latest/optional/format/ipv6.json asdf/_jsonschema/json/tests/latest/optional/format/iri-reference.json asdf/_jsonschema/json/tests/latest/optional/format/iri.json asdf/_jsonschema/json/tests/latest/optional/format/json-pointer.json asdf/_jsonschema/json/tests/latest/optional/format/regex.json asdf/_jsonschema/json/tests/latest/optional/format/relative-json-pointer.json asdf/_jsonschema/json/tests/latest/optional/format/time.json asdf/_jsonschema/json/tests/latest/optional/format/unknown.json asdf/_jsonschema/json/tests/latest/optional/format/uri-reference.json asdf/_jsonschema/json/tests/latest/optional/format/uri-template.json asdf/_jsonschema/json/tests/latest/optional/format/uri.json asdf/_jsonschema/json/tests/latest/optional/format/uuid.json asdf/_jsonschema/schemas/draft2019-09.json asdf/_jsonschema/schemas/draft2020-12.json asdf/_jsonschema/schemas/draft3.json asdf/_jsonschema/schemas/draft4.json asdf/_jsonschema/schemas/draft6.json asdf/_jsonschema/schemas/draft7.json asdf/_jsonschema/schemas/vocabularies/draft2019-09/applicator asdf/_jsonschema/schemas/vocabularies/draft2019-09/content asdf/_jsonschema/schemas/vocabularies/draft2019-09/core asdf/_jsonschema/schemas/vocabularies/draft2019-09/meta-data asdf/_jsonschema/schemas/vocabularies/draft2019-09/validation asdf/_jsonschema/schemas/vocabularies/draft2020-12/applicator asdf/_jsonschema/schemas/vocabularies/draft2020-12/content asdf/_jsonschema/schemas/vocabularies/draft2020-12/core asdf/_jsonschema/schemas/vocabularies/draft2020-12/format asdf/_jsonschema/schemas/vocabularies/draft2020-12/format-annotation asdf/_jsonschema/schemas/vocabularies/draft2020-12/format-assertion asdf/_jsonschema/schemas/vocabularies/draft2020-12/meta-data asdf/_jsonschema/schemas/vocabularies/draft2020-12/unevaluated asdf/_jsonschema/schemas/vocabularies/draft2020-12/validation asdf/_jsonschema/tests/__init__.py asdf/_jsonschema/tests/_helpers.py asdf/_jsonschema/tests/_suite.py asdf/_jsonschema/tests/test_deprecations.py asdf/_jsonschema/tests/test_exceptions.py asdf/_jsonschema/tests/test_format.py asdf/_jsonschema/tests/test_jsonschema_test_suite.py asdf/_jsonschema/tests/test_types.py asdf/_jsonschema/tests/test_utils.py asdf/_jsonschema/tests/test_validators.py asdf/_tests/__init__.py asdf/_tests/_helpers.py asdf/_tests/conftest.py asdf/_tests/httpserver.py asdf/_tests/test_api.py asdf/_tests/test_array_blocks.py asdf/_tests/test_asdf.py asdf/_tests/test_block_converter.py asdf/_tests/test_compression.py asdf/_tests/test_config.py asdf/_tests/test_deprecated.py asdf/_tests/test_entry_points.py asdf/_tests/test_extension.py asdf/_tests/test_file_format.py asdf/_tests/test_generic_io.py asdf/_tests/test_history.py asdf/_tests/test_info.py asdf/_tests/test_integration.py asdf/_tests/test_lazy_nodes.py asdf/_tests/test_reference.py asdf/_tests/test_reference_files.py asdf/_tests/test_resource.py asdf/_tests/test_schema.py asdf/_tests/test_search.py asdf/_tests/test_serialization_context.py asdf/_tests/test_stream.py asdf/_tests/test_tagged.py asdf/_tests/test_testing_helpers.py asdf/_tests/test_treeutil.py asdf/_tests/test_types.py asdf/_tests/test_util.py asdf/_tests/test_versioning.py asdf/_tests/test_yaml.py asdf/_tests/_block/__init__.py asdf/_tests/_block/test_callback.py asdf/_tests/_block/test_external.py asdf/_tests/_block/test_io.py asdf/_tests/_block/test_key.py asdf/_tests/_block/test_manager.py asdf/_tests/_block/test_options.py asdf/_tests/_block/test_reader.py asdf/_tests/_block/test_store.py asdf/_tests/_block/test_writer.py asdf/_tests/_regtests/test_1013.py asdf/_tests/_regtests/test_1334.py asdf/_tests/_regtests/test_1505.py asdf/_tests/_regtests/test_1523.py asdf/_tests/_regtests/test_1525.py asdf/_tests/_regtests/test_1526.py asdf/_tests/_regtests/test_1530.py asdf/_tests/_regtests/test_1538.py asdf/_tests/_regtests/test_1539.py asdf/_tests/_regtests/test_1540.py asdf/_tests/_regtests/test_1541.py asdf/_tests/_regtests/test_1542.py asdf/_tests/_regtests/test_1553.py asdf/_tests/_regtests/test_1558.py asdf/_tests/_regtests/test_1715.py asdf/_tests/_regtests/test_1738.py asdf/_tests/commands/__init__.py asdf/_tests/commands/test_defragment.py asdf/_tests/commands/test_diff.py asdf/_tests/commands/test_edit.py asdf/_tests/commands/test_exploded.py asdf/_tests/commands/test_extension.py asdf/_tests/commands/test_info.py asdf/_tests/commands/test_main.py asdf/_tests/commands/test_tags.py asdf/_tests/commands/test_to_yaml.py asdf/_tests/core/__init__.py asdf/_tests/core/_converters/__init__.py asdf/_tests/core/_converters/test_complex.py asdf/_tests/core/_converters/test_constant.py asdf/_tests/core/_converters/test_external_reference.py asdf/_tests/core/_converters/test_tree.py asdf/_tests/core/tests/__init__.py asdf/_tests/core/tests/test_integration.py asdf/_tests/data/__init__.py asdf/_tests/data/block0.asdf asdf/_tests/data/block1.asdf asdf/_tests/data/blocks.diff asdf/_tests/data/complex-42.0.0.yaml asdf/_tests/data/custom-1.0.0.yaml asdf/_tests/data/custom_schema.yaml asdf/_tests/data/custom_schema_definitions.yaml asdf/_tests/data/custom_schema_external_ref.yaml asdf/_tests/data/example_schema.json asdf/_tests/data/fraction-1.0.0.yaml asdf/_tests/data/fraction_with_inverse-1.0.0.yaml asdf/_tests/data/fractional_2d_coord-1.0.0.yaml asdf/_tests/data/frames.diff asdf/_tests/data/frames0.asdf asdf/_tests/data/frames1.asdf asdf/_tests/data/frames_ignore_asdf_library.diff asdf/_tests/data/frames_ignore_both.diff asdf/_tests/data/frames_ignore_reference_frame.diff asdf/_tests/data/frames_minimal.diff asdf/_tests/data/missing-1.1.0.yaml asdf/_tests/data/ndarray0.asdf asdf/_tests/data/ndarray1.asdf asdf/_tests/data/ndarray_in_list.diff asdf/_tests/data/ndarray_in_list0.asdf asdf/_tests/data/ndarray_in_list1.asdf asdf/_tests/data/ndarrays.diff asdf/_tests/data/self_referencing-1.0.0.yaml asdf/_tests/data/simple_inline_array.diff asdf/_tests/data/simple_inline_array0.asdf asdf/_tests/data/simple_inline_array1.asdf asdf/_tests/tags/__init__.py asdf/_tests/tags/core/__init__.py asdf/_tests/tags/core/tests/__init__.py asdf/_tests/tags/core/tests/test_integer.py asdf/_tests/tags/core/tests/test_ndarray.py asdf/commands/__init__.py asdf/commands/defragment.py asdf/commands/diff.py asdf/commands/edit.py asdf/commands/exploded.py asdf/commands/extension.py asdf/commands/info.py asdf/commands/main.py asdf/commands/tags.py asdf/commands/to_yaml.py asdf/extension/__init__.py asdf/extension/_compressor.py asdf/extension/_converter.py asdf/extension/_extension.py asdf/extension/_manager.py asdf/extension/_manifest.py asdf/extension/_serialization_context.py asdf/extension/_tag.py asdf/extension/_validator.py asdf/tags/__init__.py asdf/tags/core/__init__.py asdf/tags/core/constant.py asdf/tags/core/external_reference.py asdf/tags/core/integer.py asdf/tags/core/ndarray.py asdf/tags/core/stream.py asdf/testing/__init__.py asdf/testing/helpers.py benchmarks/__init__.py benchmarks/_utils.py benchmarks/asdf.py benchmarks/schema.py benchmarks/treeutil.py benchmarks/yamlutil.py compatibility_tests/README.md compatibility_tests/assert_file_correct.py compatibility_tests/common.py compatibility_tests/generate_file.py compatibility_tests/test_file_compatibility.py docs/Makefile docs/conf.py docs/conftest.py docs/index.rst docs/make.bat docs/rtd_environment.yaml docs/_static/logo.ico docs/_static/logo.pdf docs/_static/logo.png docs/asdf/CODE_OF_CONDUCT.rst docs/asdf/arrays.rst docs/asdf/asdf_tool.rst docs/asdf/changes.rst docs/asdf/citation.rst docs/asdf/config.rst docs/asdf/contributing.rst docs/asdf/deprecations.rst docs/asdf/developer_api.rst docs/asdf/developer_overview.rst docs/asdf/features.rst docs/asdf/install.rst docs/asdf/overview.rst docs/asdf/release_and_support.rst docs/asdf/user_api.rst docs/asdf/using_extensions.rst docs/asdf/whats_new.rst docs/asdf/extending/compressors.rst docs/asdf/extending/converters.rst docs/asdf/extending/extensions.rst docs/asdf/extending/manifests.rst docs/asdf/extending/resources.rst docs/asdf/extending/schemas.rst docs/asdf/extending/uris.rst docs/asdf/extending/use_cases.rst docs/asdf/extending/validators.rst licenses/JSONSCHEMA_LICENSE licenses/JSON_LICENSE pytest_asdf/__init__.py pytest_asdf/plugin.py././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788568.0 asdf-3.4.0/asdf.egg-info/dependency_links.txt0000644000175100001770000000000114653725330020525 0ustar00runnerdocker ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788568.0 asdf-3.4.0/asdf.egg-info/entry_points.txt0000644000175100001770000000051214653725330017753 0ustar00runnerdocker[asdf.extensions] asdf = asdf._core._integration:get_extensions [asdf.resource_mappings] asdf = asdf._core._integration:get_json_schema_resource_mappings [asdf_extensions] builtin = asdf.extension._legacy:BuiltinExtension [console_scripts] asdftool = asdf.commands.main:main [pytest11] asdf_schema_tester = pytest_asdf.plugin ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788568.0 asdf-3.4.0/asdf.egg-info/requires.txt0000644000175100001770000000060014653725330017053 0ustar00runnerdockerasdf-standard>=1.1.0 asdf-transform-schemas>=0.3 jmespath>=0.6.2 numpy>=1.22 packaging>=19 pyyaml>=5.4.1 semantic_version>=2.8 attrs>=22.2.0 [:python_version <= "3.11"] importlib-metadata>=4.11.4 [all] lz4>=0.10 [docs] sphinx-asdf>=0.2.2 graphviz sphinx-inline-tabs [docs:python_version < "3.11"] tomli [tests] fsspec[http]>=2022.8.2 lz4>=0.10 psutil pytest>=8 pytest-remotedata ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788568.0 asdf-3.4.0/asdf.egg-info/top_level.txt0000644000175100001770000000002114653725330017202 0ustar00runnerdockerasdf pytest_asdf ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/asv.conf.json0000644000175100001770000000072414653725311014462 0ustar00runnerdocker{ "version": 1, "project": "asdf", "project_url": "https://github.com/asdf-format/asdf", "repo": ".", "branches": [ "main" ], "show_commit_url": "http://github.com/asdf-format/asdf/commit/", "environment_type": "virtualenv", "install_command": [ "pip install ." ], "build_command": [ "pip install ." ], "env_dir": ".asv/env", "results_dir": ".asv/results", "html_dir": ".asv/html" } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1530983 asdf-3.4.0/benchmarks/0000755000175100001770000000000014653725331014166 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/benchmarks/__init__.py0000644000175100001770000000000014653725311016263 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/benchmarks/_utils.py0000644000175100001770000000253714653725311016044 0ustar00runnerdockerimport io import string import numpy as np import asdf tree_sizes = ["small", "flat", "deep", "large"] data_sizes = ["0", "3x3", "128x128"] def data_function(size): if not size: return ord dims = [int(d) for d in size.split("x")] return lambda k: np.zeros(dims) * ord(k) def build_tree(size, value_function=None): if value_function is None: value_function = str if isinstance(value_function, str): value_function = data_function(value_function) if size == "small": return {k: value_function(k) for k in string.ascii_lowercase[:3]} if size == "flat": return {k: value_function(k) for k in string.ascii_lowercase[:26]} if size == "deep": tree = {} for k in string.ascii_lowercase[:26]: tree[k] = {"value": value_function(k)} tree = tree[k] return tree if size == "large": tree = {} for k in string.ascii_lowercase[:26]: tree[k] = {k2: value_function(k2) for k2 in string.ascii_lowercase[:26]} return tree msg = f"Unknown tree size: {size}" raise ValueError(msg) def write_to_bytes(af): bs = io.BytesIO() with asdf.generic_io.get_file(bs, "w") as f: af.write_to(f) bs.seek(0) return bs def build_tree_keys(): return {f"{k}_{dk}" for k in tree_sizes for dk in data_sizes} ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/benchmarks/asdf.py0000644000175100001770000000536114653725311015460 0ustar00runnerdockerimport io import asdf from . import _utils def build_tree_keys(): return [f"{tree_size}_{data_size}" for tree_size in _utils.tree_sizes for data_size in _utils.data_sizes] class AsdfFileInitSuite: params = build_tree_keys() def setup(self, key): self.tree = _utils.build_tree(*key.split("_")) def _init(self, key): return asdf.AsdfFile(self.tree) def time_init(self, key): self._init(key) def mem_init(self, key): return self._init(key) class AsdfFileValidateSuite: params = build_tree_keys() def setup(self, key): self.asdf_file = asdf.AsdfFile(_utils.build_tree(*key.split("_"))) def _validate(self, key): self.asdf_file.validate() def time_validate(self, key): self._validate(key) def peakmem_pass(self, key): # peakmem includes setup, this is for comparison pass def peakmem_validate(self, key): # peakmem includes setup self._validate(key) class AsdfFileWriteToSuite: params = build_tree_keys() def setup(self, key): self.asdf_file = asdf.AsdfFile(_utils.build_tree(*key.split("_"))) def _write_to(self, key): with asdf.generic_io.get_file(io.BytesIO(), "w") as f: self.asdf_file.write_to(f) def time_write_to(self, key): self._write_to(key) def peakmem_pass(self, key): # peakmem includes setup, this is for comparison pass def peakmem_write_to(self, key): self._write_to(key) class AsdfFileOpenSuite: params = build_tree_keys() def setup(self, key): self.byte_file = _utils.write_to_bytes(asdf.AsdfFile(_utils.build_tree(*key.split("_")))) def _open(self, key): self.byte_file.seek(0) with asdf.open(self.byte_file): pass def time_open(self, key): self._open(key) def peakmem_pass(self, key): # peakmem includes setup, this is for comparison pass def peakmem_open(self, key): self._open(key) class AsdfFileUpdateSuite: params = build_tree_keys() def setup(self, key): self.byte_file = _utils.write_to_bytes(asdf.AsdfFile(_utils.build_tree(*key.split("_")))) def _update(self, key): self.byte_file.seek(0) with asdf.open(self.byte_file, mode="rw") as af: af.update() def time_update(self, key): self._update(key) def peakmem_pass(self, key): # peakmem includes setup, this is for comparison pass def peakmem_update(self, key): self._update(key) def timeraw_first_asdf_file(): # Time creation of first AsdfFile which will trigger extension loading # and other one time operations return """ import asdf af = asdf.AsdfFile() """ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/benchmarks/schema.py0000644000175100001770000000211614653725311015776 0ustar00runnerdockerimport numpy import asdf class SoftwareValidateSuite: def setup(self): # software is a pretty simple tag, so validation should be fast s = asdf.tags.core.Software(name="foo", version="0.0.0") self.af = asdf.AsdfFile() self.af["i"] = s self.obj = dict(asdf.yamlutil.custom_tree_to_tagged_tree(self.af.tree, self.af)["i"]) self.schema = asdf.schema.load_schema( "http://stsci.edu/schemas/asdf/core/software-1.0.0", resolve_references=True, ) def time_validate(self): self.af.validate() class NDArrayValidateSuite: def setup(self): # ndarray is more complicated and validation will be slower n = numpy.ndarray([1]) self.af = asdf.AsdfFile() self.af["i"] = n self.obj = dict(asdf.yamlutil.custom_tree_to_tagged_tree(self.af.tree, self.af)["i"]) self.schema = asdf.schema.load_schema( "http://stsci.edu/schemas/asdf/core/ndarray-1.0.0", resolve_references=True, ) def time_validate(self): self.af.validate() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/benchmarks/treeutil.py0000644000175100001770000000060114653725311016370 0ustar00runnerdockerimport asdf from . import _utils def build_tree_keys(): return [f"{tree_size}_{data_size}" for tree_size in _utils.tree_sizes for data_size in _utils.data_sizes] class WalkTree: params = build_tree_keys() def setup(self, key): self.tree = _utils.build_tree(*key.split("_")) def time_walk(self, key): asdf.treeutil.walk(self.tree, lambda x: None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/benchmarks/yamlutil.py0000644000175100001770000000216414653725311016401 0ustar00runnerdockerimport asdf from . import _utils def build_tree_keys(): return [f"{tree_size}_{data_size}" for tree_size in _utils.tree_sizes for data_size in _utils.data_sizes] class YamlUtilSuite: params = build_tree_keys() def setup(self, key): self.af = asdf.AsdfFile() self.custom_tree = _utils.build_tree(*key.split("_")) self.tagged_tree = asdf.yamlutil.custom_tree_to_tagged_tree(self.custom_tree, self.af) def _custom_tree_to_tagged_tree(self, key): asdf.yamlutil.custom_tree_to_tagged_tree(self.custom_tree, self.af) def _tagged_tree_to_custom_tree(self, key): asdf.yamlutil.tagged_tree_to_custom_tree(self.tagged_tree, self.af) def time_custom_tree_to_tagged_tree(self, key): self._custom_tree_to_tagged_tree(key) def time_tagged_tree_to_custom_tree(self, key): self._tagged_tree_to_custom_tree(key) def peakmem_pass(self, key): pass def peakmem_custom_tree_to_tagged_tree(self, key): self._custom_tree_to_tagged_tree(key) def peakmem_tagged_tree_to_custom_tree(self, key): self._tagged_tree_to_custom_tree(key) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1570983 asdf-3.4.0/compatibility_tests/0000755000175100001770000000000014653725331016144 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/compatibility_tests/README.md0000644000175100001770000000100714653725311017417 0ustar00runnerdockerASDF file compatibility tests ============================= These tests confirm that files produced by the latest library code can be read by earlier releases of the library, and vice versa. The tests obtain a list of released versions from pypi.org and install each tested version into a virtualenv, so an internet connection is required to run them. The tests in this directory are excluded from the normal test suite, but can be run (from the repo root directory) with `pytest compatibility_tests/ --remote-data`. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/compatibility_tests/assert_file_correct.py0000644000175100001770000000071214653725311022535 0ustar00runnerdockerimport argparse from pathlib import Path from common import assert_file_correct def parse_args(): parser = argparse.ArgumentParser(description="Confirm that an ASDF file generated by generate_file.py can be read") parser.add_argument("filename", help="the filename to test") return parser.parse_args() def main(): args = parse_args() path = Path(args.filename) assert_file_correct(path) if __name__ == "__main__": main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/compatibility_tests/common.py0000644000175100001770000000110314653725311017777 0ustar00runnerdockerimport numpy as np import asdf from asdf.versioning import supported_versions def generate_file(path, version): if version not in supported_versions: msg = f"ASDF Standard version {version} is not supported by version {asdf.__version__} of the asdf library" raise ValueError(msg) af = asdf.AsdfFile({"array": np.ones((8, 16))}, version=version) af.write_to(path) def assert_file_correct(path): __tracebackhide__ = True with asdf.open(str(path)) as af: assert af["array"].shape == (8, 16) assert np.all(af["array"] == 1) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/compatibility_tests/generate_file.py0000644000175100001770000000114114653725311021302 0ustar00runnerdockerimport argparse from pathlib import Path from common import generate_file from asdf.versioning import AsdfVersion def parse_args(): parser = argparse.ArgumentParser(description="Generate an ASDF file for library version compatibility testing") parser.add_argument("filename", help="the output filename") parser.add_argument("version", help="the ASDF Standard version to write") return parser.parse_args() def main(): args = parse_args() path = Path(args.filename) version = AsdfVersion(args.version) generate_file(path, version) if __name__ == "__main__": main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/compatibility_tests/test_file_compatibility.py0000644000175100001770000002005214653725311023422 0ustar00runnerdockerimport json import os import subprocess import urllib.request from contextlib import contextmanager from itertools import groupby from pathlib import Path import pytest import pytest_remotedata from common import assert_file_correct, generate_file from packaging.version import Version import asdf from asdf.versioning import AsdfVersion # Strange version present on pypi that doesn't parse as a Version BAD_VERSIONS = {"0"} # Minimum library version to read files produced by the current # version of the code. We're not maintaining < 2.7.x and bugs in older # versions prevent valid files from being read. MIN_VERSION_NEW_FILES = Version("2.7.0") # Minimum library version to produce files read by the current # version of the code. Earlier versions aren't able to generate # files for all the ASDF Standard versions that they claim to support. MIN_VERSION_OLD_FILES = Version("2.5.0") # Minimum library version that is capable of correctly writing # files that follow ASDF Standard 1.0.0. # ASDF library versions older than this version would sometimes write newer # tags that were not listed in the supported standard MIN_VERSION_1_0_0_STANDARD = Version("2.7.0") GENERATE_SCRIPT_PATH = Path(__file__).parent / "generate_file.py" ASSERT_SCRIPT_PATH = Path(__file__).parent / "assert_file_correct.py" # Starting at this version ndarray tag version 1.1.0 is supported # this is required for asdf standard 1.6.0 or later NDARRAY_1_1_0_ASDF_VERSION = Version("2.14.0") NDARRAY_1_1_0_STANDARD_VERSION = AsdfVersion("1.6.0") @contextmanager def internet_temporarily_enabled(verbose=False): """ Context manager that temporarily enables pytest_remotedata internet. """ initially_disabled = pytest_remotedata.disable_internet.INTERNET_OFF pytest_remotedata.disable_internet.turn_on_internet(verbose=verbose) try: yield finally: if initially_disabled: pytest_remotedata.disable_internet.turn_off_internet(verbose=verbose) def fetch_package_versions(package_name): """ Request a package's available versions from pypi.org metadata. """ content = urllib.request.urlopen(f"https://pypi.org/pypi/{package_name}/json").read() version_strings = json.loads(content)["releases"].keys() return [ Version(v) for v in version_strings if v not in BAD_VERSIONS and (Version(v) >= MIN_VERSION_NEW_FILES or Version(v) >= MIN_VERSION_OLD_FILES) ] def fetch_latest_patch_versions(package_name): """ Return the latest patch version within each of the package's minor versions. """ def key_fn(v): return v.release[0:2] versions = sorted(fetch_package_versions(package_name), key=key_fn) return [max(group) for _, group in groupby(versions, key=key_fn)] # Enable internet here, otherwise pytest_remotedata will complain # (and @pytest.mark.remote_data doesn't work on non-test methods). with internet_temporarily_enabled(): PATCH_VERSIONS = sorted(fetch_latest_patch_versions("asdf")) def env_run(env_path, command, *args, **kwargs): """ Run a command on the context of the virtual environment at the specified path. """ return subprocess.run([env_path / "bin" / command, *list(args)], **kwargs).returncode == 0 # noqa: S603 def env_check_output(env_path, command, *args): """ Run a command on the context of the virtual environment at the specified path, and return the output. """ return subprocess.check_output([env_path / "bin" / command, *list(args)]).decode("utf-8").strip() # noqa: S603 def get_supported_versions(env_path): """ Get ASDF Standard versions that are supported by the asdf library installed in the specified virtual environment. """ script = r"""import asdf; print("\n".join(str(v) for v in asdf.versioning.supported_versions))""" output = env_check_output(env_path, "python3", "-c", script) return [asdf.versioning.AsdfVersion(v) for v in output.split("\n")] def get_installed_version(env_path): """ Get the version of the asdf library installed in the specified virtual environment. """ script = r"""import asdf; print(asdf.__version__)""" return Version(env_check_output(env_path, "python3", "-c", script)) @pytest.fixture(scope="module", params=PATCH_VERSIONS, ids=[f"asdf=={v}" for v in PATCH_VERSIONS]) def asdf_version(request): """ The (old) version of the asdf library under test. """ return request.param @pytest.fixture(scope="module") def env_path(asdf_version, tmp_path_factory): """ Path to the virtualenv where the (old) asdf library is installed. """ path = tmp_path_factory.mktemp(f"asdf-{asdf_version}-env", numbered=False) assert subprocess.run(["virtualenv", str(path)]).returncode == 0 # noqa: S603,S607 assert env_run( path, "pip", "install", f"asdf=={asdf_version}", capture_output=True, ), f"Failed to install asdf version {asdf_version}" return path @pytest.fixture(autouse=True) def _pushd_tmp_path(tmp_path): """ Change the working directory, in case the user is running these tests from the repo root. Python will import a module from the current working directory by preference, so this prevents us from accidentally comparing the current library code to itself. """ original_cwd = os.getcwd() os.chdir(str(tmp_path)) yield os.chdir(original_cwd) @pytest.mark.remote_data() def test_file_compatibility(asdf_version, env_path, tmp_path): # Sanity check to ensure we're not accidentally comparing # the current code to itself. installed_version = get_installed_version(env_path) assert installed_version == asdf_version, ( f"The version of asdf in the virtualenv ({installed_version}) does " f"not match the version being tested ({asdf_version})" ) # We can only test ASDF Standard versions that both library # versions support. current_supported_versions = set(asdf.versioning.supported_versions) old_supported_versions = set(get_supported_versions(env_path)) standard_versions = list(current_supported_versions.intersection(old_supported_versions)) if asdf_version < MIN_VERSION_1_0_0_STANDARD: standard_versions.remove(AsdfVersion("1.0.0")) # Confirm that this test isn't giving us a false sense of security. assert len(standard_versions) > 0 for standard_version in sorted(standard_versions): # older versions of asdf reported support for 1.6.0 (the development # version of the standard) yet did not support the tags in that # version. if standard_version >= NDARRAY_1_1_0_STANDARD_VERSION: if asdf_version < NDARRAY_1_1_0_ASDF_VERSION: continue # Confirm that a file generated by the current version of the code # can be read by the older version of the library. if asdf_version >= MIN_VERSION_NEW_FILES: current_file_path = Path(str(tmp_path)) / "test-current.asdf" generate_file(current_file_path, standard_version) assert env_run(env_path, "python3", ASSERT_SCRIPT_PATH, current_file_path, capture_output=True), ( f"asdf library version {asdf_version} failed to read an ASDF Standard {standard_version} " "file produced by this code" ) # Confirm that a file generated by the older version of the library # can be read by the current version of the code. if asdf_version >= MIN_VERSION_OLD_FILES: old_file_path = Path(str(tmp_path)) / "test-old.asdf" assert env_run( env_path, "python3", GENERATE_SCRIPT_PATH, old_file_path, str(standard_version), capture_output=True, ), f"asdf library version {asdf_version} failed to generate an ASDF Standard {standard_version} file" assert_file_correct(old_file_path), ( f"asdf library version {asdf_version} produced an ASDF Standard {standard_version}" "that this code failed to read" ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1570983 asdf-3.4.0/docs/0000755000175100001770000000000014653725331013001 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/Makefile0000644000175100001770000001116414653725311014442 0ustar00runnerdocker# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest #This is needed with git because git doesn't create a dir if it's empty $(shell [ -d "_static" ] || mkdir -p _static) help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR) -rm -rf api html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Astropy.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Astropy.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/Astropy" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Astropy" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." make -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1570983 asdf-3.4.0/docs/_static/0000755000175100001770000000000014653725331014427 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/_static/logo.ico0000644000175100001770000001307614653725311016070 0ustar00runnerdocker@@((@€  !!!"""###$$$%%%&&&((()))***,,,---...///000111222444555666777888999:::;;;<<<===>>>???@@@BBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~€€€‚‚‚ƒƒƒ„„„………†††‡‡‡ˆˆˆ‰‰‰ŠŠŠ‹‹‹ŒŒŒŽŽŽ‘‘‘’’’“““”””•••–––———˜˜˜™™™ššš›››œœœžžžŸŸŸ   ¡¡¡¢¢¢£££¤¤¤¥¥¥¦¦¦§§§¨¨¨ªªª«««¬¬¬­­­®®®¯¯¯°°°±±±²²²³³³´´´µµµ¶¶¶···¸¸¸¹¹¹ººº»»»¼¼¼½½½¾¾¾¿¿¿ÀÀÀÁÁÁÂÂÂÃÃÃÄÄÄÅÅÅÆÆÆÇÇÇÈÈÈÉÉÉÊÊÊËËËÌÌÌÍÍÍÎÎÎÏÏÏÐÐÐÑÑÑÒÒÒÓÓÓÔÔÔÕÕÕÖÖÖ×××ØØØÙÙÙÚÚÚÛÛÛÜÜÜÝÝÝÞÞÞßßßàààáááâââãããäääåååæææçççèèèéééêêêëëëìììíííîîîïïïðððñññòòòóóóôôôõõõööö÷÷÷øøøùùùúúúûûûüüüýýýþþþÿÿÿöööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööóÓglZ™ööööÎp7®ööööööööööööööööööööööööööööööööööööööööööööööööööÈ–öö‘îöŠ2›«íÞöööööööööööööööööööööööööööööööööööööööööööööööööööööööÛºöAröööööööööööööööööööööööööööööööööööööööööööööööööööööööööööö¦ö<§öööööööööööööööööööööööööööööööööööööööööööööööööööööööööööö§´$·öööööööööööööööööööööööööööööööööööööööööööööööööööööööööööô¬ë¶öööööööööööööööööööööööööööööööööööööööööööööööööööööööööööäÁö §ööööööööööööööööööööööööööööööööööööööööööööööööööööööööööö«ïö7hööööööööööööööööööööööööööööööööööööööæ¸ööööööööööööööööööÝröèÖöööööööööööööööööööööööööööööööööööööö°h€°éööööööööööööò•PÚß¼'ÎöööööööööööööööööÐ~©ööööööööööööööõ›îöõÅYnåööööööööé’}ÌöàS¢N=Ÿ¼ÌÜåâÔõ¨š‹‡Y&ßöööß¶ÅööööööÖ§ÁèöyööööÐH*G^^lo`\#¡ÅH3™3á/4m* !0%U!bR«ºßöööööööööÙ¯“XlU<4W‰¡¡vN¬ôöÊ+YR~aööñ͸–1~b“ööööÇ[ßÔšU žõöööööööööööï¬ZT©íaðööö×;Uœöööö¨ âx…¬€i’öööööá7‹‰“õöööìoñööá@:ÉöööööÇ{r‰”Hvåöö½öööõ–0JáööööÇfwö“RÍô]Íööööö}ï³aMêööööööööñU¿ewïöööî‰jÒöËÚööö”×öç“.(|õöööööRäö¦Ðöá4õöööößf»ÛZ&ÐööööööööípîÁQÐöö§çöööööööäãööööÆ!\öööööö¾=kööºÂöö±«ööööö‰iµâ«c¿õööööööí¼öñ‡ööööööööööööööï­P%îööööÜ{,DØööÎ;µöööQ1ôööööõ9®ööåUe¶óöööööööööööööô©ˆ‡bLJ ŒâˆÎ“ˆo>cºKöööâl¤öööÒEŠööööö’¯»öööƒ4I¸òööööööööööööööÙHžó(±ö«ãöà)xåöÏZžöööè|zöööö2XÀöööö¯ôòööööR·öÓ`2Þöööööööööööööóö±möö±öãiÕööîg3ÝöööènJööööIs=ÜööööööööööØXöööÁ-±ööööööë²Ãéöª€ëööòIíööÐö±ôööélw!öööö{=òöööS¯~"¾ööööööööööUéöööÆ UÑööööööå©=töööö‹³ööööööööêleV9ööö”y&¦öööOôu FÈöööööööö©œöööö„Ï‹·ööööööÓnõöööÛjööööööööòA:ãvHööª´öY‹Cööö4àç›ÈV:‚—ööööçMööööó†ö¼‰öööÖr ãöööðRäööö¹Öööö[ ÍönXöÅ¥ööOŽöö©öºCÊöÐq¤ëööööö+–ööööÛõöíööñÉé³öööçVÎöööô§,.]BœöögZówöööXSÒ Æé€{ööŸ$Üööß—Àööööƒ‚¶ööööööööööööööõ©dÛöööööéåóåYööö_V¤·öööu{öÑ+Çà“ööö~+åööööööööcæËööööööööööÄ•%mõööööööööðAëöööWCXìöööfSöö´+èÛõööò++ãöööööööe”ö±æöööööööööööóMõööööööööÞ9šööööK ÚöööZôöör8íööööš#ÓööööööpfööõöööööööööööÛ…öööööööö©-æöööö?0P—ööötPíöå Fóöööæ8š¹ööööö”£ÖöööööööööööööòÞöö¿œ†ƒŒA¿´!ööööö43Tƒööög“­k±öa‰sööööMö»ˆôööö•ó–ööööööööööööööööööööÐ(·ölBööööö)¸BŒööàV´öö¢5#æ\ÅöööfÛöÁ U®öö˜öõööööööööööööööööö±„yRböãXöööööæ’·öö|>Îööö| qÞTööö™•öö­zÝíöôöÃÁöööööööööööööööí‚ÏööEÇö‘ejööööö&öçsöÇÞöööÕõöoäöö¾CöööeôöööööÒööööööööööööööÍ?Ýööyõöãz~ööööí)ööfèGâ·öööö`öö½¬ööÜËöö•¡ööööööööööööööööööö¨7³öö”žpöööi“ööööº6ööš;ÓñAÖöööoööð€ööìCÀööº,Çöööööööööööööööööäá‹ööÒȳºöööG§öööÐ'CööXöÌ*écìööröööööïöööʨ×ööööööööööööööööööåöööötôööؼööœ»^ö§_ö¢Höå‚ööuööö‡õöêÕööéÃöíööööööööööööööööööööööTöööaŸÑï…{˜ötÜIvàwWöö×ìö|ööö«ÓöÖlööööööööööööööööööööööööööö­}öözyëâïÑöö}®áÕ» JÍööööÐöööÓ®öÁ¹öööööööööööööööööööööööööööèÞÙö€'çGöööööölæööæ{j}a…àöööööíö°ÑŽööööööööööööööööööööööööööööööïÀ‹ï0ööööööw³ööòËöö–›Ðöööônöðö”ëöööööööööööööööööööööööööööööö¢èÉHöööööö€kööÕ¶fööõñëöööÝPöööÐØööööööööööööööööööööööööööööööÜö²kööööööH<îöo·ôiîöãÕöööö–;öööööööööööööööööööööööööööööööööööööïàöööööЇÑö’öölµpÇöööööööÕôöööööööööööööööööööööööööööööööööööööööööööŸëö~öíööx~ô9·öööööööööööööööööööööööööööööööööööööööööööööööööööæöö‘áööö…ñ¥ëðöööööööööööööööööööööööööööööööööööööööööööööööööööööðñöööÒöòðööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööö././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/_static/logo.pdf0000644000175100001770000002465414653725311016073 0ustar00runnerdocker%PDF-1.4 %µí®û 3 0 obj << /Length 4 0 R /Filter /FlateDecode >> stream xœmœ[ŽäH³œß¹ŠÜÀ_bÜ#–q– $ 3Ý’öÈ?3gVÕ@`º‚dãâssþïë~ñßÿùï×ÿøŸ÷ë¿ÿïUêú*s¿Ê×hçõ÷UjûÚs½ê×¼k´î¯±ë«}õµ^¥Ý‹ÖÚeÔ×N<\æ×Œý«—hô¯¶Æk|ÚôlùZ¥¼æ×.j¼:ë`¦zl÷ÚùjlØ[ý‡¢… Ž«c£æì´f=a¢¤ß´BQGüZG!«>•Ïð§-TÌ#$$ðµ§Þ¹%»Ñ8±çº¾òyÞ“X»É ²yÅ&÷(Ü-¶(”»°”L|¨Ó7{4êMı¡_wtCkL)›.lÌÁŠ¡ÅþÌØ´Ð8~ÃEC°{«‹èôØßМhÕ}b4±\1çég¹¹‹ÑµýÑfCû–:†`ö~vT5úEËb³»W2. [?ÔÐd4Ö7$qv†W­™µÙ¡߯»b(aĘDk)š5ÜÅlˆ*û9­•шnŸVýj¥úQ«t³É -¬“—!<üÃŽFCÍX®椤+Þn9¾dXXµ˜,>#u²ÇOò,hù–Nf+ž ûÉC–ÙkغFsïözZUöäý£lu‹L¼ž=ÔqÓ/¯7¯G c¡«ÔzéoœiLõÐ ÙiŒ7èfV±à·€´t qx¤Ðe­±ÜZ´m«xìÂYv™½1À4Ëw¸žø¹ß¾o‰ç° 1:ûùØ<+Zʦ ÛÂxM´î#ŽSˆ9U s n©aº¤Ùuc)%œaÞ–D ¹E¶Li·]x è•8Ç*­’×Ð XÌx]otkƒá¶WGöd™C<÷G¼ºPÃÒ[G‘õ*EމJ³šŒå¹þsKØqiaªþSù«o™¦Éo‘˜¿Ø·ðO<ŒiŠ?c…ãOBt´47t´ÁcHq4®‘°#$)‡ýŽw³¹ÃhéÖ®aëýŽ6ø$š#^Y$jÑ@Ãc(1á±…Þ ¶åĈ³´bAóU ±u(ä`2äÛrPµÅípL©¼Ã ]1^újzˆ_òpt'ñ )ì·–pÊ»ãšú||*øâê¶‹o¶r!mÕ»¤:ôh`V·”c$Ð a"ŒàÈj â,UWëÄC,G•uh_Lô„a–ªáèGú½¡0TÑM—1Ãð}°X…%,Ö§€+›åÉ 2ƒ3N7ÞB¿µŒçæÎ›CàÓlÏûû‚£®X¬ÇK€’†Ñn×\[fˆX,WbgÇN$Q-æöÂoÙ'Âôåh;,¨öpËŒà‰Â5ÊpLã=|HÀaXQÀs=f‰od[¢‰I{c”a`Â^åòðÐþcMÂW®Ð¯¤!û>Œ¢¯óÃZc` áÚ´é,T%Ú ÝÖOÂ/UÈ–yØï¶`lñO«@Ñpð÷˜sl%þB •BYöÓ¦˜é 0s¦`è°»»1Ì¿\˜Q ÀÛ‘Ë–ÁFu™dk²»Ä`¼‘¬ß,¤R–݃õ’Á2 ,í<&½ífÌ.w`N«%Ãz‡¾ÂñˆñퟫÔ/Q ÑäQgR·iÂý0 [ÊÊçø±Þeø¡9Ü×Ôæ¶æÛöÍÁ±øbB#Wz¹³m÷Œ‹‡NëÑHª|ˆVMˆDëb25 Ú ñ RºØ À©À‡[µ7‹…€Ô,‰Kšy6wB›jÔtÁƛȩJ .Þx˜Û ¸ŒQª¦òbcļÑ@R½\çJ,M.ºEÕåQ¦•.Lw:Ô:.%LoŠ>ˆ‰l‰†.8B F3ÞV Kí²Œ b\ˆÎÛ7¥û ‰ ToćQ`ð¨]sÎZ ψPlߥµêN@ͱ–ɺxkª´üÓì¹6Ÿ ¦™ÅdƒcXâ©f6û#Á-§3M=SøGÔ‰_¾Üò³ZGÝÒC~({ÉìÑñR2"ž»*‹Ãc`äD“¸Uàßߺ˜‚À‹Úb¸2áPöWKüœÆá›·‚üïÛЊ†F.L|5Z¸ÕƳ+àW n‚ª´ÕùDoñ|Üû#dņ§^)G3‘F›È²s¸Ò ¿Í*V ŒŠ˜o•Ó$ÓPrGô¼Ç~ÓS»Ä ]C_QÁš› nB"ñ.â6¿õ%[!×M8­{I‘Ñ!E¶ +%1d×/Œ A>zÙF „YÚ6C@•þÈ›qÚ#[h ¨•M½—\ámh5ÏNÀKløÌB˜êŸŒÑ‘%– Ã{älšrÒOá\ß@HUÛ*߇†£)µŒÂ 3…fv£‘i(¬á»AWöTØpµ± W‚<Úé×d5ãǼY.©M‡‰ù£ÆnÞöPâBƒ—¸tªŒ"[MGà;¡y hJ.`×Åjé}„`îlkâ+Á¯ä…¬B¿D ˆŒ~;mFu1Ÿ±!àø’cˆÎn½j(ý…åÞÓøW_…+dˆÙªßTÙèÏó†þEÕµ§j6Y2xÉqç —ˆˆŠKb‚wÉÛÔ¨gÂ)Mճє¶b{Á·2¾ªygbjYôI2É©Ý"\Æ™x£)£!RÇt¤àw öåtB b©%¼¬ ”,gu7~Ô’´Žvø- G?Ëäá.G®D^xLJ­¿ A•Ó -Æ5ú` õIA}À—ËQ1A“º_oÁ²“.z"¦$Vƒv Ébße^áue™eкѵáô.ñ ¥94—ìJi#ùÆ+EYéfy5;ìx={Ll9õn|Ù›ÑA§ñ{刎ôXƒÁ„®[©6^N*KÏ»w£ëÖhb³™«Äú‰Ïø‰E Ö©…NdËǃ‰à3PØá¼*k+Ù”Çn"ÈXø‘lˆ°HØæ£ÛPzjA¾yǤž¢żK~–=ZOs òn?½d‹åeÈœS¥Ü‡h=Nâñk“"ç¸^&'x'nÄAcS²}i!¦«6žGÌ$S–¤KELÍ>ý ¦p°NÏH6ÖŽÅ…-5ÛUÑƒÖø -u;…äW;±•¤iö¯§j§Éwž”úéXör‡OAK±¯°‰{¡"*#6; vºDHOµ7™ÊðKTÿ3\Q¢*o³”Ša†ÁÇþTyñM™1Ì=¿¨]ªŠªéô»Ës мÿQœžd­`…:Yf ÛñL†Xf¢º.Ò zbP—\ŒiûÆó ÚA¢¾¹ôf gË"Nׯ¸ê •/É‘P?VpOûâ'{8»ò–aN‹r$·‰µíD›l`,ñµªƒÂÛz9Œ¦m5Ýj‰:ª¸’è{ ¼þ÷HšSC¶5ËIª~›‡`;×O1×*ýT(Q³²s'~¤Ô¢8o›ÏWPr›€v’ð‚pVÕê}~:ÓxZÑy-"Š6¾›Y«œM´’d7 ¹½,ØlÉ0Ò¯©èЗ'±…gÂêfao§Ù]îú¶3å9¨ -ÄQ #K‡éœn÷ÃŒ oø RMö»ìØ[Ö»í|5 *n¶-Zæ Ù¥^å¨ÑLΘ’—´.®2LOtÉJN£CÙ"0ÑÄRž­}ÀÌ(&7é‡T…žQs bwáS-\jÑ]lÕkŽ*l9$0ãNÈ–‘‚ðWýÜ}"“âú‡Ï…¼ß­žv+Y­¦0q¤1h5»6*»žÛ3û®fô?í)ÏÿþqÅÕ@][3(ØܲòRŒ +€”lîmÐ{‹ ÖçæÒeTÕ=ɵåäœUȹ0ϰ¤+Oˆ;–ËxBð”Uã[?¹”ÍJîï:…¹”É_¸œ¿d>KÛܳ ?£“#´xÌ,‘·vÆÊV/B…iô Š Ž ¥ÀÅ4™Å0]¢Ï8ªÖýæúäOd¥çJÿäax·„|’¡ùP£DB´\ûÓ20š® znŸ‘êvµ­›Z#rã;1­CŸŒÑ0Ûjv½u=H|L9g=WÊ Ö@Òú\¨ç±g?®P@\ ê²SÀ•‰EëNØMˆåˉ¼ªAú¶³á?ÛÈÝûû ejE æü’g„¨0þ¹•)!¨äRöU6Ñ3¨šûQƒu½3¾ŸT¨ö¹dî£üA}¦P2‡&,×-_¥$æX._Q*ÔcU{Vô£.ìã\‘Í Zˆ«Øm)Ij#Ž•{¿m8ùfu‘¹54ÓÆàÎäé0FDàS‡‹z(Ž2ìï.Æ8݆,‡Å–ù“eøYRf°ÍòI³ˆïb2»™œè>•³»jÚ½íÒ7BÂ3*çoò7ºOÆN Õ®´dD‹L¼’6Jt”l Å„ü}&¥¶8˜$6h÷çDØpf‘ ’½Y\ãr5Þ&Sàimëð‰òP`™"ÄŒ³®]õ[/vw·Cmsßdö·/Y¨)ÿ!îû˜Jw)çšöýRÀ´?®}fµw6)¤v.õ¹ÂRI²Æ'×”ÁáQ…ý§±%5W@]˜@”­­ÌÞù€R¿³`Ro«š}în¹6g¢\⣠Ú)€ê™WuI 4+Yä)ÇØ\¾Œ©£29¬êH’1 ã:ïÌ™"µàò™øV®K5?+ÙV½Ž‹uá¨FMº€«¡¾É#PV¸îÏæÄ>ä-W˜Ì[Á€QÆtÐb€~΄qÃDä]5y†?ÅÜÆ”®“ÇüïoÏ<]ßõi®‡9ú¾  &(­zPŠ«ò I(âtÁNÉÚ›áJäÍ–÷¹² Þºùýmñ²e»BZ£±i;Au\:u¡qÆ:óäx<9>çÓS“wfÈ;qÂŒXMhyÌ´).qí7‚¡ºöúÅÞžâ9¹ä±éì„â2BÈî⚌¥¦‹ï—´‡ô­h:”¬¤…–ª)ÊFOëyžEpEj.ùçY°á¬¸k¾ËRÉ*Ùä&}nÙñ´ì»X¦)C¬*wR:deÀV‚ç’î@<­nÿ1ôëñ4(#-_÷÷½âS+x7Q`ûvX óbýٷݤ´}šâloÙvyÆ9I“F-)ðLmýx¯,žAfîl'ƒ#æQWÀQ«2ž§“uRm‘ï>ÇÓ}·yNKæ”Cá—©ß½rîå¿ý`u©çpG`ñ:–—yLWzŠQ|Ü]8¦`–J\Jn3­iw®²ÕÊMe‘DV­óÔ +©ø”úçïï ¹ÐYŽx­,@HÅtVIþ!‚2™æÀWÆ¡Ã) [7Û°{9oHâ›ÝX¦Ü†}WMfþXò…­°9&ª)Õ¥~¤—n«Ü¡Æ²C¶rä0,`½}@p»x‰&i êTÍÅüÂv…žæ i,.½i³êã[Ž™WN p6ëv´ÅªàëmK¸+žÊÅ©HPÀ!µ UUÁ[u¹Á@J·›nò‹m·ó‚†úub!tCuy·ék™~zÚkgÔÿãJ¥æøØ§oë)v»˜–N7ª•9£”ª I€m¥Ô˜qâ oÖo”ÞçøÊP¸1>ýM#66WÞcfºl]χ_ß“T ‡Y´&«i¬Zä‹ —Ó93‹ˆV¦Ûæý$Ffíp’p^±OP˜å¬óp.ü-Å,F}ò™SòÒmqMCYÂnnÜN^€z3{3|ô‚’÷4ÌY2Û]R­¬û#ÉÂåü.ÁY Uu£»ìÄj´» ¦i`™žÃàkþ¾§Ø+Àû™>ürh‡üõÌPs¢“¬pùô¡÷§`qçÎéD,Yz¬ƒ“=Ø"xUœÓr=¤+“§izû:MˆòãS‹ÄÍráè[2ù§)øÍ|èñáCÀ‘©¡ãÜÝ5¤h‰Yê@QhOUÉ}ÖrÂqä+‘QAžQ½póΙ†bNC¶<¾wûöpá}9á¡qÚ#½àHPZ¨êÃ'Jô5I Ç\!–ݹ-†±P‘wW)jŒ¥=°ùB‘Á"Í%H4q†ª#ó²ú¤{ÒT,;ªA5lKE¦H‹îÕ®^Ö;KnåÌ(¶-2še››êùi‚¥Ö}2¹<¾¶[xµËtºÊ¹–sÓö“^À‡„õmÛ%hXɰ-KÖ¶©É–Ç29žÄ9f–tdTõ_ÍöˆL^i†8P˜áIš!6Jÿ[žòT}Чxªª$…Écn36m½Jjä‹›¾ùÓ"°-l­LÍŸÎN_ô>‚Ç‹1fQ‡Jª—k¿Ñìr»ê¡f„O›ªYçpý¼€O’:¥jŲ\+ÏÙà¿Mƒ¬åY¦’@VæT㠆ȣ…öw[¬ä…Œ®§9²Jø»­ý€×Æ'|,W¯«Ì‚M™eY>mÿäú´÷‡RõWQŸ‰n·’’U4Ö³‡«ÂjýúÏmη99ö…;VæÿIj¦%ËtŠÀ¿¿&ó~ýs‰³™> ÎçeV}ûˆ°\EŒ`Ƕ>§ån¸qÉ¢×ïŸå™‘~?y«êW|‰^G“?}¶“ÇÆ(¦õ¹éÔÿçwõg¯ÿ(v+Ï€þº Ê:jÝ…†]Ñ€¾ˆ°ÜP´å?UúëGã»ËŒÊn½R#€>¶QÉú 7.{gÚõÍõû‡ëg·ÿˆ”ÝþC,Å_GÍÍŸ-PåUUj‰Uß6ûåA1„òr‰N â±GÒW·ÖC?Q:ØŸ?Þ£ßßüð÷P<¸þ¯Áõ_ƒíçàFý×àFý5¸Ñ~®ÿkpã÷àÆ¿×ÿ=8èu8¼ä¯3p¡IÝ4šÓËJp9ûºŸ¦A¹¨v|¨RCÕ»V2ÿKNæÙýêèÌ÷(vðHd<Œ«?5Jÿ29k¼À_EÀ}ûäJLÃôCÏéž/9…i =k@®<‹ŠàƒùˆQ|r©¾áOîO$@’J0»2-*”À§ávQÇÇpûˆNÞËéÖ4²?#|É?úRqüûÐæÀ&ŠyÎàö/¦ŸOsæ©÷ç%׃tìñq‘m¿¤âWÈwçQm‡÷OëäÑŠ+/ÀÝ@?Á7Yóm¦þœÄ³ÛÛ:[Ô|Mõ‰è,Ç.l È}9:k›YþäÏvýÜOù8yiÅ Èý„ÔŠ#ë\½£pȉÚd»TÜgRH°\UäpÖG>°_Yj˜‡}VaäIË£?Õ<ä HÃ_ô,ŒÔp1=Aœºõ Âéc¹Ã¹ObxŸ§ï殃´CU†:ÿü«ˆvŽEˆ.T…úÙìúHFÂøÛpÿJöîbf‘•Vø¼ã˜ù#}.¯i¬ï¯§ÝúØÆ%ûk0 o›d›^Ö¿J…1¥ ;(¼Íf«¡:ö[8„/LI.×,jªÞ·“ôËZº›*cWyŽ4ãèÈÆ)Ÿd‡ C-¸“>fh¨K(þ'ž\f¹}^€cÆýá°ÄTQ˜ 4ØÐ¹Û@¤5¼Ôô—‡v;i¢A·+ñ¦ ^|òZçˆMmìÄÐËG¶ÑaÚnïw–Ok+Ÿ–«zå²Z¥+âùëȦSJßÓåHW·u ÿ)oFÌ ážÓ³:.˜w»¸|>ŸÈs @Þ>ííi9†kfºûE·¨*ÿ¯Ã©DµÄ„œ ÷§4@2¬ç<$³}Èqž,$1éºnUM}·}.”OËð§0æ“UŸúpBHÍ_˜\>‰)?f<*¤›CàÌ4†pP};Ó©($Üõ6ÌSÎñ²,4#„jÃo\é3ô #²úèÖu@©*6˸‘ÕPJ¨z¾—ÑûÝ ³>ûí¢NçîeºÁ‘óÉÚedíq~4C%ȩ̈8S6yd1AÍñEA’äTVN‡Ÿ;ËÆü¹‰K§3\ß•ŒØþZ€>¢¨Ožì·½I~`ñužZí¬ÑɶÓ!úÞßsÁéT\´'r²Œ/Ó#×Shå›5 L»£“…ôOñÓY °ÇI/%w¡oŒl¥Ç³Â‰¯?–ñpÀ¬/{±ž#Þ?·ÃxÒÇDvÕúüu½®«©ú¥xŸvK;}”»Ú˜tg‘Àö§¾TýßU'BQßÀÍþù¨(NÛXúsŸ*Çš*½½U—%K”:Œm%‡Õв¥Ã¯­Ë B'mÿ1HY¬ï¬ÓH¹jÐ Ö̰oéWS_¶P¢‚¥ú”V³×çs–y™¬pÓœ¿›ùÁ¤ç£¿[æg”ì_ƒñž$`I(Y½ãg}Nƒ—çÛ/Y8“>±>…ë]§¥‹øpA•B%yØ’¹,Ñ•ÍÔsˆÜq éeiwÉ¢[ÞiÏ®l¥wh»ýÙ´íϹ çüLªÖ0 ÞþbˆDëÇ,m+¦„ótù¿Y¯Or>ôÛëàï ¹Úüž§ÅE¢OÍoøcû|¾¥Þç!~ü1YÎIYp!òN~[ã_ƒ1ÂïÏ€q_?. —Ò©¦Ï_d,ùqÄó e--g;]ž[>Ÿ©PY^yj&3×þ}Asõ¯!;•‚}ú~¨‘|sÍ~†••$¿‡ý¬ôڊܧ>®Oº}°È1ÙH×êâ¢ññÃÊÌ=·3 ’©-¡³üêBM£äÃÌÅGÕ{–å秈ýy!oòVú› O¹¤Îè –ÓÆ¿‡/—…ó""¾úùî?>€ô¶Ë¯#ÅÊÊ&å3¿~øiòäÓèþîéóÃö³ÓŒw>oÔÍþû‡ýG§ÿ¨˜Ö$éP<šß•>.löñf"½ §¼kÖsäz«"×¹gm_3ÇêïÒ>‡jšÓÔܸئ:½W”‚Ì“vQÝEÿ×ãÍ]ÊWÁ:Šó†‘&£ÚëUÔNl¿žRAÅ%Ï–hÇïÿÿ5û_×]ÿž§N endstream endobj 4 0 obj 9795 endobj 2 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> >> endobj 5 0 obj << /Type /Page /Parent 1 0 R /MediaBox [ 0 0 214 167 ] /Contents 3 0 R /Group << /Type /Group /S /Transparency /CS /DeviceRGB >> /Resources 2 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 5 0 R ] /Count 1 >> endobj 6 0 obj << /Creator (cairo 1.8.10 (http://cairographics.org)) /Producer (cairo 1.8.10 (http://cairographics.org)) >> endobj 7 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 8 0000000000 65535 f 0000010181 00000 n 0000009909 00000 n 0000000015 00000 n 0000009886 00000 n 0000009981 00000 n 0000010246 00000 n 0000010373 00000 n trailer << /Size 8 /Root 7 0 R /Info 6 0 R >> startxref 10425 %%EOF ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/_static/logo.png0000644000175100001770000004057214653725311016103 0ustar00runnerdocker‰PNG  IHDR½[A3PÛ/iCCPICC Profile(c``2ptqre``ÈÍ+) rwRˆˆŒR`¿ÀÀÁÀÍ Ì`Ì`˜\\ààÃyùy© |»ÆÀ¹¬ 2 UŽ +¹ ¨¨ê¥¤'300ÙÙå%@qÆ9@¶HR6˜½Ä. rвùÒ!ì+ v„ýÄ.z¨æ H}:˜ÍÄb'AØ2 vIjÈ^çü‚Ê¢ÌôŒ#Ç”ü¤T…àÊâ’ÔÜbϼäü¢‚ü¢Ä’Ô Zˆû@º! A!¦ahii¡ ¥"ŠˆqŸÁáË(v!†°(¹´¨ Êcd2f` ÄG˜1G‚Á)Ë„˜I/Ãþ©15C}†}sïPoì%¬´ pHYsgŸÒR?ñIDATxí]‹²%7ŠoÌÿÿò¬±›«’Šq¶ª$™ %öÜîiÿñ¿?þS?¥@)°D?þøã¯¸õš-‘·‚–nþÏíQ¥@)P ”¥À¥ Ôл´pû.ðß]¨ m)ðž5ôÞ«i1*JR ¨¡'SËï(ß²nú¦åÅz¿w:«˜Ü¨@ ½«V˜Í xˆ9°Ñþ ‹1u™•¥£@ =F”ZzCÛÈÞŸ7ª[,J1jèéV^¥@¨5¼Bå¬`¥€¨@ =QšÚ¸Y¬C„ÃÕ®Ñ_‰j5hý4ÛÚ+J¿¨¡WpT¯Ü_ç´ù*ù'¨¡÷ɲç"ýÕƒÿ«¼su_¡ùšÿýáâ[ œV@vÖ_mz8Ð|+â{°”m)pZú¦wº•ÿ/èÁ\’ô°è6»~¶²(ÞQ †Þ;µ,&Š'¿áXs[í8š­/7ìZ.N­•¯+PCïõ _Ä;¨GàGÅÉÁ‡ã_/Ce Cjèe¨Baø¼ž¡Ä 5ÛóÄÆ8u-^U þ"Ë«•-^ÿ*ð…CŸv À¸ÿ[èº) Ô7=ƒHe²NöP–o+‚ÿ+‹]«æcÅ 1=qµœµW ¼¤@ ½—ªY\~SÀzð[‡Éo .X9'„^Jå ÔÐ[.q%ð*0:€Fý¼ø"í=ÊÂÏ/’GÅ*nQ †Þ-•*œË° •å „=l0ìjà âÕr)@¨¡GĨÛ3 p‡uïo‘rö\ÜÖïä³Çâ¶Æ¡>u_ |UúÛ›_­|ñÞ¦@ohi@4ßvšrµW ð Ô7=^—ZM €vàSxœÝè@àbÑ\»î‡†e”ß.ü•§Ȫ@ ½¬•ÄÕ;,Ã.wûÚ!®ñÕ†Bó]^¨JP \®@ýzóò¾€vÈsB³·èÕËi‰1bÃq¡qfyÑX7Ý·º|U‡›j–k ½ÌÕ1`áƒXL°>Zj‹ÍWëkÑFÓ¶öJVz­"—>¿p8ÀÁÎñ€5îÐçl9»l%EŒþ+Ú¶ë/=£_àúRÝnåR¦wkå:¸ñ é˜]³½’wخ̱-ñ9\×Ì”ê@ïÁ½}†µ/h<ëgõMo¶bdx™ëååå]¸Ã®µæl²iÊalypÏÙxpW­j¶ OÅ}Oú¦w¨¦õrËÂK‡>j†W9BÌN›žÛµ˜L¿¢HÜYÔ])P Ì(PCoF½IßÕè$¼”î’f³ÃBò—òõÄñúA~ C/—eðàÇb¿ËÆÃÙc» å¹OzjF_^ïáxîçS®®í‡h±3ºhޝð(PCÏ£Ö"ÛÕ‡ê"ØKîp-'­½çbõö©–“ÚÜ{pŒÄ/ŸRàFjèÝXµÂüCÈÁëHæae.ià­ÌÉP4-eÄd^FW*PCïPÙÚ]:¤Á«´ƒ XëØÖ0ëfÅÀ:Z\©Ç!J•6©5ô’&Ö‡åm9-64¦å~ELÌ ±WÆÇ<ÜõT^‹wívx‡n¼Z¿n_C/Q…ëåÊSŒS‡ì¬RÝÀ'FIËÙ•ÿYjèÔŸ{ÉëE;XGê‘:qõv¤ìšJ˜Vçí»Ð@ÒòB*¹Q †^#Èm_>вq×ÊSXOå½í=*¼ßQ †ÞáZs‡’vx†[é‰Ö:q5&aBn9,#y!+d)(PC/A BN,C#뀰`GÕqÐeå‚8ëZ D(PC/BÅÉÜUФ¨IܹÚFCívÑx¢ãíÐ0sÅË«@ýWòÖ¦) d:G‡ŽBojË¢†Ùâ?°œKƒ Ô7½ƒâÓÔÜA£LÔ·î¿«@Û#\QuÀ¾õ¡û=j»âþtþœ*f.jèåªÇí Ð¸¡då”FOm-ÃNë£4¤)]ˆ¾0eýzs¡¸mèöj_&xnm๵kã~í¹ôàÿ«â\´ýÔÚ”–­"vm÷¬•¨¡w°Jx ÕÁs°©¡^X»÷i-·¶Ggí9+~Ê¥îKõëMZ“¶ÒA/:¾ìœ îM¦/÷¸ú„5… }br`ŒÿI ¤¥K¨Y½CKe¾*x ½DåÒ^Lm/…§ hšï–žè8èvcîáÚ½?£án¬•o5ô´yyzÏhì^ÜšÇ]Fµ8<ðÇÏHHv#¾åó·/¾W_¯m ½Á˜9G_¤™œƒ4Ó¹jwŠÈHÍ"Ým:ªO›w¤^mŒzέ@ýE–‰úÀ 2z¸€_½`â'pªálŒö` B)°]z“’ï|3ù&©–û ³CKû•A÷ž\kmŸzô@:ñ‚ANŠa¦ÌR¬”3ªæð=Ñ›9˜ŠR VÏÿ™=L`8Œ  ZFŠ®×ý·€¾ÀÏ·•ØÃ¾}ë½Ü£ûî,Ÿzœàmós6Ñkžì¾h¾#ñ<ÄÏàƒCî \3è]¾§@ ½?kÎ0' x3mÈq™‰W¾ëÀºWíÖk]JzJxŸÇVIù×–åð‹Ì×ÓqøÓO4FN_®.Üš øÎø[ó”]_®Þ}¯²¸QzÿTM:|¸—A²l€:}jru°‡\;}ÝÑC#Q'MÏ‘¸·ùd­Ïm:fÄ[CTEjô“€„ `K¸4BW¼ÅƒO4`6ÐGÂĸ„/Ìí!3[O®›lo©ßMšÖߨ¡×h"Hx¨7æ[%L«“[9g>¬Zlíój Ûø§jÙâ°<¿¨lj[³èS6w*PC©›v0e{A¬x¬vŒâ7JÎÖfraÌ^ ©F=?Œ_×o( õÉ7ØKNzœ*®i/ˉƒUÃÃQðÚs1èpöðöØÒ<î9ìzFÄÈ Oa(nV †žR½l‡”„‡;¤ZÝ-)8r¹${ζ›\0àrpkF6Ä•pМuŸS®ªž9k…ª†^Gɯ¾oî èÈXÛ¥@)P ¤P †ž¡ Ú î;†„eEn)pnóI¶­Õ+â^Ë»:wþ¨Àõf¾7cªaÅÙ£@ =£ÎÒájt5Û‰EËÕ´’íêMÊ;":‡52þ¦žÅLï{~íþŒoköy‡æ™øÎêUþvjèÙµJÿg7íKup@-Í+ÙQ‡äËL³á%ú QþÑ~RÿFç©x稡çÔ¾7œá†Í¥—så!(åweîžP¶žoÄþéüÈ! Ä“ñzºW3jò%L5ô«-.'þ•loÌ­åÐöЮV;ê÷=l­}ûÌåÙæˆ|æðFƯX¥À‹ Ôл¸ªÒ¼ú0„¼Rîžœ«±õò¿²Ïé8Z“Óšp\Ncªüï*PCo¢¶™8HV&£üWâò`¢8è=¶„'úhW.‡f/íqq¢±J¹_^/ _®î/n5ô~iqåÝéò`àà‰Ê½:ÎJÝVc·Æ®_t<+ÉjH?’]­¯Qડ‡²Fб¨Ü õ…ƒ©U‹Ó¡µiŸWêdÅ“±§ZðYÒËÊãÔµø²W =,”ôòãþ×®Y=ÀáŲ²–^,´oF|G|hNí^ÒieN OÔžÄ+*~Å)Z®z-‰ÓÏ·<Ñúyõ ½ÀåÅ‘3:F´&Ñø^ˆwSŸ@?ÐÏ úïäpíÐË~ìÆ—í¥<L»õÚù’ÍäÒtñè;ƒa§ï‹œ¨~Z=©tßú¿®—¤ÃÌúµCo†tùîSÀóR¶/tJ†¨œ«ã¼Èiµf·Ç_õ~Ü®‹ÿUC¯}Ñ£›âÑGÌ›Ç7Ê6ŽK\ [ŽoÔšÔßYðÍò”øÍÆ}ÑŸÓê•>Ø]¯«†Þnq¸Fó`˜õ÷äÊn /èé—tGþ¨RïDÅÏÞ/;ñe×”ë…ì˜wÖÏ›+ÅЃ¢âÇK€ko ´çɃ‹óÇØY®‘zp:­‘%ÿJ,±-6#Ú÷|,ÚôbÌìŸÎ?ƒ}•/× ¥ÓœÚ)†¥À™î¯¾—jרß(O ÿh¼~§1žÎ¯iªõKfÜ'nOãÉÙq­4ZSõtChB±¥‚s/¾d;*—qÆ,¿Ÿ Hÿ´Z÷t:?ÇLëãŒx9µæS€««÷üóe,ëC+<”F+þêÒi˜´Ü’ŸæóÕ½ÌZihE½´|™uZ¡ÅΘٴ­>X_ýChBóI ¨5Jd±A[ëuͱó½¤ñÍœ¼ØµþøŠ>_á©õFõ¦NÜ^𡇔¤æ‡†À¦l0FäUÊ…X"s}5–¤ñJ=,õ³Øp=|´ž8ެk笘Wá-ð#åxµ$¾«×Ó = ¬Y{a´½!%<ž|Û¬å«Àʺ­Œ«Âw¢AM2ÕE:{¾S‘x¦)‡ÐÔŠ}¢)%<ÜK"ÙÆ—¯"Þ¨×3-ê¡V‘µÏ–š¬Eð{ôêß5‰XI;ô€ÜHÑWD Ïʼ…ÎCÓ6»·V^ûY¼;µ˜ÅáŠ/æÝ]_‹fˆÍb[6>R= Å÷6ÀÊ&Ö°ôòöö}¥+ëHz}¶«vZEòåbíâÈ宵_ œì_(Þ½K?ôPúL aƒ£¬Ú}×^mW2Òr¯Ì»3ö‰wCËÉí¬ÃÉÜ;ûàd®k†ˆ am ®™#…¶âˆÌY±æ˜í‹Y‰Aõ“¤ÌºõUµE\=0ªœÏ瑱‡Ô¬Í±º©­87\Wc¢¹êÞ¦@[Çö¹b©a/é±¥~/܉»Ö7_Òátß^9ô@4hK£h!¾CDž/ÄȤe&,_¨}ŽU÷,•X‡ãÚ¡‡’Xš´ªuï5¢†ÞZoycIÊk9$Ÿ[×£4[ÅÿT-Nå]¥cö¸×=š¦×8«_¸^þˆF<"bDðÉc¦n³:ÎäΠ]a˜W z`^Co„'†’¾¥fËYÔ«®}z=5Z‹^Ü>²²ˆT ê©fîXO =šWjàÑÊZB)¯Õ¿gGã¯æÒÃrÛþŒ^TwŽ7›[ã|kí T?ä©ósC¥•ªÕÍ'åE\‘×Õ\"±fŒå©UÏjqs=N`ïiº«gNá8•w—®Yó<;ô@p©©V¿àRÞM°šË Ì/Ç„zTM~¯piò»&µrF§‡H ˆB·N—3ísGÖ¨—Ó~T(L£ù©_&,WÄ}[dM%¼= ’_­¯Qàù¡‡²Iͽª!¥|ˆ'úºŠG4Î,ñFë3ê—…w‹£ú¦UdÏóm}}òJ¯|fèA+K¶ª˜R>À2“SŠ;0eø‘¸eÀ†nÀˆXµ«¥_,6ZØ‹ˆÑË‘uÿî/p ýñ©¡Ä¥ëµÂÒ"¿r?R£‹^RY|3جÒ%7+†S5<•תËëvŸzPP©éà ˆ> ¤\³%ÅÆ?‹3£¿¤]F¬·c’úñ 5¸ßTÓ8´zrèÚK…ÞQì9Ú‚×sœZÅe‰ÑwøŽà5åÝ%oí™»«ñýg‡È ¨5aÔ ­åøYßÓª¸>y­¥ƒ'±¥›HLZ,N“>|è•æü¹\à'ÙÓ˜«ï3`Xͱâó |zè¡$½@zÙÑæ* Ö˜=ìÖ8_±[¡×Š˜»êØñêÍ;êçÍ3b?ûnä)of­8®Îö¦µÿÞv%VlÈ^¡¹}ô]‰¯b—³ p½‹1µ=´¡×^Ï{ãÑØ7߿̻Wó[êVC¯©ÖÓ¼Û&Ý_ày¹ýÞøÎbèå¸m·½ôöOè‹=çÕ ýF0ÏøŽäã|N`8‘“ã^kÿùO =¡ °I½‚®» y0g×øÃ3:}Yߨ>¶h•ë¶6ŸåÍù[ô^¡‡eEž1ëÏô:ªCÓj¼´Û^Œ/7µ…ØXì~ˆÜyj§ô X½HühB«ÅŸÆºé^ã­ñÀŒú[bk6Ö½—jWCÏXu(:~Œ.n³ïñª3½•:Ç‘[{•ÿj^=-¹>šßìYCcÓûÕZÜ¿~½9P¥¶‰#› bµñ­Á/‹5oÙ½¯€¥'µÞ³øGª(a‰Æ!呸Xì£1JX¾º^C/ ò´I-M²B HúÓ ®!ËGà í…$g‚ìÎÇ@xvÉ£­ÅvWö ÒbÍ‚«‡Ûº_¿Þ´*e´ƒ¡£Û³¶é~lv^kPŽîŒ>3¾–™µLX4–žÒ¸Xüµü÷4¾-Þž-ž­_=¯Q †Þ]§£ö^”é(Í~u—ZžL/ ‹Æ÷gô§ŒÃ.Š›Îüìn ½EúCóÌ6ШÔ˽HšíawëÁå­å¨X–|xèâ•ËÅqáì2­Y¸âˆ­é=Šk•ßõïiQ¦×SȹñR8S>g/šWG¯=ŠöâKÝÓ"’³–+2ÖëäUãjÁõšÎmjèTeöeÐ @ìzY~W¨tá5ù}õçJd/­ìûŸ¨Ï?ÍrÔ}•³W኎û™¡'t¦¥˜ÑE‚<^œ`ßÃ77šÛL<įñôê6ƒç„¯Æâ‰Ö¡—7:å²û¾ÇUÓA‡Q £~šö>3ô$±iC÷ŠLm¥x«Ö!wߪܙ㞬‰¦ Ôj%6k왞‘|{¹%?M¯Õ{£˜z\%Ü£ù¤xµ§Àg†4a¯{ûq²E|õ2i^êkéC¡•ÃWûΦ1îÆºQû–ë°n½ëg†…l Üɲ±{¶³¹Áßš«‡åõýWtòöÌokŽžÝHîŒ}ØãÉa~…;Çí¥µTC6ÚÊ¢±iNoai«/õÍ ~4Ž”lFsH1_Z·hÉ—«·†9½µ‹æÓbëá‰Î:ì¾öxrxnæ>—Óà–µTCŠÖ¾pt/ò¾mVK´>£x0Ž%g›}0F»ÿò3rF ,\=¶–x+m¼XQU˜,xVcXÅ­káJ}^áý:'Ê/ÍÐó6%y¢‰1çˆàƒþ#:ÌúäŒòÞ#šEåŒ3Êc¦öü£¸,±£m$¬V$ §5®ä_ëg¨‘åŒîlVx‰F^$xY¹–[c?¸ØÓ±·!‰5ÇH ¶5~-FÆÞž·/pM¼¼{:Þ°_C/a•F_(h`lb¼&¤ÉÊÑjlq Ñþ`ÍèE¸j¸{ùßÎYÓòenÈ»†*‘ì:Ó|Þ—8õ.?m7ña艙¾ˆ†Ÿ Ë·‘Þ¸3Õi„?õ¿õ¾†^âÊí:änlþÌ7\Ù0gÃãí¯=Ù8G]¯óC½j衉¯_iÆèŒlÑ"â­¬ÿˆF+ñDè¥Å¾^ÎÀ÷vέ&^ Zÿ›ŸS½/¦mªÛ_¼–Ïê笽ãÅ•í°Í†ÇÓG^í!öÍ|=Ú|É6ÍЫ沵]édÓI²ºI¿ÕX½C`5©f½õØïÙp9²òå°Î®}‰kš¡7[´/ù¯hБCáKšï溢Æ3²á™ábñ}™ï×ßõôCïë’^Px)_~1%Þ_XßQWÏ{µO¦ºßLՈǒ~èÅS~+â×^Йê•V«÷ÒÀóp±ôΫ=‚:áբū6©†žÔpU(½ý@7I;ÝóçnéüSOuŒÂ K')NÔ;$Åϰ^ï÷ßUH5ô24ÆÍ¾tHquÊÈ?&ëÁ— 7W卑/qm5û"÷k†žõem‹úµçÙ&¾UçYÞúd5kmWãˆÒÚÊGËw WCíùH7ô´&ŒhrŸZÛÊ «½Æö^;ýxýOÙKšgÒv…6á¿Þ\r&&P*0Ć=´›ÉåËaÑðGå“M¿–èÙê—sËž[œ ¬qý#ÙöÖ­9{q´}oŽH~.iÏ‹WгkÓKâÀÙî¹+ûMÁH+š$®7î¬}‹«—g‹ Ÿ?~p-Ó5»~™´ÁbÕ·×çmn¯}ë?ûlå…yNàŒôƒXn½JšŸÐö„†ÝozT QQ ƨo¤(€òicgÁÙâÂg ;Úh×^ fãgÖ«}f¼´ŽÖºôêKcJ÷T.oDÌÍÅÇ=î™›‹O×¼ØÀw'>ŠÕs?ÂËÿ[vèAñ8qèÚ æ qãl³¬QÝ­˜Fêƒ>#ù¬¸NÚqµ®Èû$6ÈÍa9U‹Sy¥ì¨Ñ(çØ$]<ë¿[8xøJ¶ìÐcA©Ýë‰ö= dôºÆ-ÎVãžQúbo~À—I¿ž^Ù÷=úcÍ"8yòŽækshïd$7o‹…³i×VcjóÍ>koã2­ÅŸ„ÿ× ¢ Öó¥û†TÔ|ù½Æë4V f5N+Š î#pYräáâŽÄi9sÏ\.ÎׇÇ}0†÷jÍ5›qµù n»†¶pÊKcjù¨½_ƒÆº÷p»…S”6‡ý‹,m&BO1Z +ž5N'±ZrGÕ¤§«¦‘æká ù¯Üã8eÂëÁÂqY©Ýlì–[oß‹ò·´?š]–=/·,¸wâ0 =„ÅŸiDOQ0ïÊ«Æ%Vª½†y…V»ó­àÐÆä8e¨·Ç¡åiyŽŠÓË%q“Ö#qA)O‹òâ§Ý{å9RÛÛ4ÿL¯G„Šfm¦^ÌÚÿ[ªmM“·Î`Ÿ‘KM¿ŽC멨¾±ölT¾jš™+Ök%F×7=© Ð‰Iñv¯kسaÝ­ ͧéDíè}fý8>™ñR]9ìt?ú~6§+·¸gsA ˆ-Ň}ü\ù0^]ǰÔk<ú¯žzÄÓ@« "&ëUkülX­œ²ØeÖ«û¼\^k½f|­9"í#úŽæòøq:ŽbåbQ,4îÒ_oÒ¤p‰{àZŸSÏ7a½M#èÚ„§ðsy¥ºŸÆœU/NÃUkg‡EGKžÓý°Jããjõâê½í›ŠÉ€= 8úf¹Þ„uµfR={y3k(qÚYÊÝÓ3Ó¾G' _ˆç‰Ùj9ðÓîqÏhkÁÆùŸX“ôÉÊÃëÅÚë )Þö¡ !á„8Ñ@˜S ûÙ°"æWM' Of %N˜i šîéjGmp-ë•Ã/aÕxAüHþ½uˆ¯åèùÃ~D Kž/Ùp=â­5ìÕlë¯7\Ö¼иÑ÷Îè<·ÇÕ)[½i$N˜i ìwX»ùgÿ¬?h‡ZFë¸*n4NïFÌ¿t¯õ‰…ó‘ozHF¨‘Bß ×[pîÒJª'¬K{€-³ŽîÌ4½§õ’òS›[ï3ýÌðèõØLìòS€ësOsþ€ÎSÿ£CO“R"§ù¬ÚÓŠ’ ç*þ³qQ£[u”p/ä6ªQDŒÑÜ‘~³:Œbñv£9²ûÒ>BéÝâbK<=1 gyÙ%’œ «×¼Â®Æ“5¾¤ÖRÚ>h“‘Û ÜZÎL¨hs‹>™juËLŸH¾#=°uèpüXÅ—ÈZýwØÝ€q‡˜CjDÔIÚÚšæÊr¥¸òÅçºÎ)ý€Ÿ¹Hå½[î]°¼ßÜ{…Ø-þhK¯Ë‡‚æHS ÚýŒ¯×»§‰œ£—Ó*{I+ÔIÚGš 1go1»¹hq¯éÀÃñ‘°p¶í¥}°Ñ~Ð_³©½¿Ð4΢£†Ñ[Ç(NËþL¶ IôÑl#…ÔòŒìíÀæÍö^ŸîšÖ°ˆÍR{-Çî=S‹ÅcÛúÞò<Ãñ¶Úg®ÉL"yá{3’ûëMLÐv¤Ú[Ë{+ó·xÚg ßil-V|F=OéÖÓ p‚f‡\²\oÂ¥ö:à·{í•úµ{õ|¯žX®ê vè!ˆUI1~ï ù5ñpï4ΨýžÖ<'uÃZ!†3¬ƒ ÚÁ¾dÛúžzŽª à§¼OñÑòFÖ";WM‡Ó{‘uˆæ2‹mu_,ûõf” @O„Y‘G±j¸VcòÄ—pzbŒj$ùI˜Àþ$. oo]ãÓó½}Ÿr·Ôì©Ïíü3á¿Y×]}‘~èaCõŠiyÙ0Ö¯’~'u“0A}(.Í.S-%œÒz&ì,´&hO¹qûh‡Wjkuõ)`ÑÙ1ÎzôÄξ¸fèAYzâ€à#¢Ï”\+Ön,=Öº!V ìSý4»ÖcŸ¸öpžÀ”%gi³¶§õ¥ï«…)à=ùª¡‡BöÄÚ}ˆk…ó6r´\GbŸÂªñɈIûjOÓaUNk\®×(^nŸÆ¦¶t½î} ôtöE‹³öâ:ÙW=,§‰ç-ÆÍ|ÕøZqk1NifÁ¤ÙX¹—_^Oôö«n~ÍoòèÕŸr^8ÝW=S â) Æô^{¼ñVÛgÄ«aZ­GÅ÷)€µê½[hç‹^Ö^NéÜ«?åq #Å÷O = ‚j¢î~€eç§éZ\õ’0!Oi¸¡M˳žÇà4Åp{4ÚѵºW §÷xä1O+èƒL½ðÌÐòõ†BY‹…1­W­°‘9µš{×=ÇqWnoIû›8x9Íj,ÕYÒâ¦úrèaá,…iŒûÕ¢rô¾$èg¹zp@¼•X,x_³ýo|nïƒÝøGj ½á}?O¿Ÿz ¾µ`Þ†°ÄmjKŽ æÕh[6þ³|2úƒÆ½>­:ì¯\¤æ£ïm$† ~~èØžâ6ˆTÔÞ"ùq둱0¾Gô‰Öâ¶8VpEüuý¥@Oç¶.¿<ënFžî3±Ñwæ=½¹î5ô°œ×™†iSíhð6çŽçH¼x_ÕÔ«ƒÅ^Òªw°õö-¹WÙHœzù°gGý{ñ-û½Ü3ºGð›Éoá¿ÚFý/§¯Nž!~¯ÁzÑŸkXÃ}K.FϯÍùFâpy¬Ø9_ºFãÌ`k¹Bnæ®ûR°ôíÓ—T‹æågÑ~§ÞÏ =oA¢Ä¦yG‹ 1F}WðˆŠIã N<3èE¹½tß«Ooÿ&-°')æSü8,£¸z±hÜ/Ý_5ôn)â NôÝùÒaÎ9½<Á}{xÁο3zÿ4>«–”÷iÌËìýÿÙœ’–ˆ>ëzöþH9ô2ÎZàUv µyÀŽjfñ¥ö«8XâRV¾mÜ–»_Ï>°´6÷ðùæ+Çøœà(a±è;ãk‰¯ÙœÐJÃcÙ;:ôNË"ÎiÔ'²±0¦•›'·7v‹ú[ó‚Õ¶Í÷õgªw«…¶×Úf{n±sýÑÚ Î÷V]%,m>ŠÍêÓÆ}¦¹GcdñÛ>ôvkU‘vá§ 9½|8 voгõµä£þôžú¶q©]ïžÓ¡çóõ}ª=Õb¦4Îéû,ü$’>^{)Noý•:K<·½È¢*Œ–7’_[0Œ­åo},ÏÑñhNñÓ}ë½ÅrYì¬9Ëî§´–?wîz’zd7? Ç 5ws?Á‘æÜ:ô¼ÓmÅhñ®hlŒÙæâ´[jGïi츧¹‘ÃŽ¼£ÕaWÞÌyv×à¤=®´7wàìáYa7ßÕ|¼ñ·=÷%Á[®‘ÍŽ±ÚÞ8aO1#ƒÆœ‰U¾¿+ð²¶;¹EôúïÕ±­ìäiCtÎjûÐ;Gõ|fÚxQ/Æ¡±)ÓìâF.¿çbÍÆðä»ÕÖ£­Ï­|%Ü;¹y4—ðެïä8‚ï„O ½ªÿ™“6cÄ ãÿ¦ÖäßÀÞ€>4>ÝÛqŸ¥>YpìÐ\ʱ»Nh¾›£¤uÆõz ªÂ5h䋱¸ ¨‹o¤b²Ú`À°›I{ý²“SK´„;¹Ec߯þÁéj;rAWÿýØ¢0š-Ú8ʰÔTú"q6þ+8j1wê½Kkà„{íýR ¾éýÒ"徨³/øc¬”D; û¬4K¶oÄŒz/dQPMç]|4 Q´wq‰Â›-N}ÓËV4úl³ïx!øaË¥Á˜”žÚÏj<†pÎKã·ƒä×0̱ûõ\f±f÷¯ozÙ+Ôàƒ¦_ùr5éR>J€.°'í§$³Ôëý¢ñƒ^Xý£åɽó®›}hjè]XI|)h!­4Àý­>í€ÃàòŠë²“Ö«û\ËíÕa5V/žöTÇhhläô°H?¸ñÕ+jqÿÑáá¾-FŽÿ+ÜZ®£Ï^=8MGs¯öÓ¸­æ¡å¶òŒø±ú¼f¡£¤‰û·ozh¸ºi$ YÖoÑë„x³è· ðo¹Ã3·¾ S–<­.Yp­ÆïÄŠ<³š®Ä¶‚ïʘ­–QÚ´q[ü¹ þÒ; D›4ûs+Ú-:´¸{:ß«Çö½ÜÁgŽùþx° ÏjL˜göªqÓ8h~-¦6ŽÇ·«ÝÿÚ3§e«÷ˆ&\\rüqƸ†6ÔùK÷ Ã F¬™¥>·ð²p)›Ÿ xú=oèqÀÚãÖÛG¾ÖëL¼[4µjaÇé¡—âÅÿþOpá=ëDÛ®œ·ðç°k5¹…—Æö¼¼ÁçîÀ…þ¼Ê‹r\u}„È1ª%± ëq9=GÞÝ–;—ÚÐ?þL7¤tmià—îå Üð9wÄ5ª?øgã4Êåë~£½pKýGùq}¡qÍ£Åä0|iÓtV/.&Õ”‹ÿcè¡1jqmÑ÷¥+pCž”¬EóæòМ«ïWpZ¹/Õ«µ£Ï/ð¦|êþw¼ïêè»èÍó;ÒwWF5ÕéÅ”êÁ=Ld9D0±”cÝz•4ÞQœQÃÓEr:Íå‹ùGû(ªWkÞã7Ë£_â7›WŠûʺ¤ë¨nR<ª—û?7Å¿½IƒX¡½1$š³×6_DL6‘q±Åƒn¸¤Ø˜#ú ˜µœœ¢1{âiܤ8Qœ=¹£r'O^ªA$wŽÄ1‚ƒ»Ç#"w/ÇÍû’®#ºI±Z}z±ÿý‹,­cû zÁÐÀY¢O{msEÄlsxž[<è;Ëâ ¶RÌuÌZ®NQX+N) p=‰ïͬB\lKLí²ø¿n#é:¢›‹jhíó7=Ü€ÚÃ}4Ñ‘x-¦‘g‰û)<”ƒ„ÚÐ{Ĭù¡ õË~ÏñÜ:åÁµ—#:Äóä\‘ŸÆ\uÏqœ­ÓŠ6·5Ï­v’¶^ݤ8­.ž¸CCZÁÌ€³äñm±Œ>KÜO`Ñ8H8©bÖlцúe¿×øHØ#xzòîÎGyGä¦ñVÞsšÎâçbZ8Ìæµä¸ÝFÒÖ££ÕÆ}Í¿ÞDc„>ôŠþÖ=RÖ8Ã콄é à”°¢bÖìÐ}n½jÓ,ÏY¯®»óyñ­²ïÕQË šê6“WÃôÒÞ¨¶TkŒÑz˜‡ÞL³PBôÞ³G·枽—0Y 6›ßãX%¼Ç¢ŸÅƃiµ­ÄWZ_…gw> Œ˜$Ü‘ïÓL¬›4“´\½®ékÑÏsÆXâI|Õ¡‡ 42R`Ϻ%ìÅ8žÜ3¶žÕzb–ðzâeåfá`Án±±äZms ÎÕ:XâƒV3zE¼7œ7ÛhúöôóÔbõâõtümè!D/èÌ~/¿…0ƘÁaõ•ðœÒ¯‡;¢i²rk¹Kµ‘Ö[ÿ¬Ï3úßÄãéÅÏÅÀºöbÁ~Ïc}ù:ª1øi¾­¦Qµøë/²xS # ¢ryâŒà¤<-÷žù-[ sk+=gå†x[Žˆ·]G{¼¢>[®mL£Ýƒxtßl¸8Vß‘|ÖØ+ì8®Vœ/Åq4kó‹÷#j>œ†ÑµPÿÓB :)ÆÅ먣~˜7úªáY­á  ·%nfn€ŸòC¬tãˆvÜž´ÖƤ1Ú=ˆA÷¥˜t‹A÷µ{o.-ÖŽ=Ž«•狘1†Å}êÊ+ i¨5z÷ìÑŽ^Ûtoôþßoz+‚ƒúókïêŸU|µÂ®Ê¡•†Û?37Àü(N\“øQ[Ɇ®·ñ¨»~tŸÆ‘î¹’m»îÍÕúï~æ¸ö8p>7úkvhCý²Ü#î ‹¤ ÅØ³åbPnfí¯{se‚p-žÑzy1f›«ç×Û‡x»µ…õè|mŽÑg ·%&rÎÌÏÂcÔùú÷üfâg­I³g_Ó‡ò—ì¨'ïÛ3<ŸÄÛâ‘4°Úµþ«¹ýöYZžAüDãÂà'*¶V´è\Q˜!N„Æ£É#*V.­ÏP‹ Úf¹J|9|`«ÙSþ’µárœ\“0ŸÂdÅcµ£< ;j¡þW( ,÷T”a54Í£ùH{àOãµv°7›£õÜÃÞ˃¼³òüˆ±Çet?Š»„s¶F£¼NùqzJÚÆÖ^²míNñãòfÃ,áá°{Öv×àŠoz’€ ~$›Ñu(0~FcôŠ9—ů‡bôl2ó³h6ÀaÕO/¶´ºK{k¯>Ô6˽…Øhv”·fKí²ðG?´Ùy]…çD ®z´è Þ*ñÅ)¼ÓH\Ê}Õ};àîÙ¶¬üVéWÒÌ¢7ä·ÚE`Ý4‘tAΔwÏvnožL¸{š{¹¡=Ô‰Ö ×w\‡ÿÁéàfshÍ3ü=E³bñÄŒà`¡áGÌš æA[|>uµ`¥Ø4Ü\¬Öž³ø­¬Yl%ð‡.îß;yÿo“†¼å+Åjí´˜'ö$Ü€e7v ˨6»9p8Ÿz”ðŠÒøp¯Ô›_‹ÕæÝõ¬q@¼š ʼnötmç½'Å$aæbµ¶œ ÆF[‹ øhv°ñàþ–Ÿ'‰GËU‹ÓÚJ1O­gÁ®á˜Ñ&‹þ×ýE–QÑAðUÅDL\üÑBc¬QÄyÕ4¼°x¿”í¥ý/­÷´BMAíËRM§¦ g~®°kf4ʦ}}Ó›©æfß,Í£½£fG¥£>t}å½[‹ÃÊÅjí8›66÷LãôbP[.VƵ's˳£µçbž\Óð¯Æ®åžÕd5öQ|O~Ó[YÈQ¡#üZ^§š ò¶X®ƒ âÃ5´i¯¸öíþŠgÊ|#1©¨ÑHœ¬>^NTäÔ‹Áù o†«†v-g„&«pG`ƒW½ÕÅ‹yUŽ–†Cl€>ø¬i6Y8pX#Ň˜9Û™5oj?“wµïˆ^·^Îg57OüÝø{ù<Ø%Ûìš#îôCïT±väÅ"D^­¸= jÉñ@_̇Ϝ-®¡ úàz–+àÛ… µÐ¸ï¢aàö,Ø9?\ãxYbr~3õÇ!/G¤x#ñôb¥ø3½j)ØI¼-þ›žQk¯~è·‚k‹rµk\^Ä$Ùâ>úJv¸O¯èkñA[ê¿úÞ‚kCËÉ“¯õÁíká1Šß;šÏ(ÖhÞx[¿é(ŒW‹½¥Ø¯pµèaµM@;ÔϪµC_kÎ;ÈAsr1zûœeÍ’ã¬Ðb/ÄÜ»Îrü³1z=û==¸=q=x­¶¬Ö˜»ì– ½ÕE‘D÷ä•bDˆo‰íÁ)C ä úÀŸ­ØÐÞ¢¯5&Úј#Ø0ÎÌùÍİúîÌeÅaçåEë>“ß›—æêa˜‰MóÌÞ÷pÎÆßáöëÍÈ¢DÛÑcEz¸Wä<ê0Ëy¦–47‡î[uŠŠ£åãrhö¸7Â}é•ËÏÅF;nÆÃ{´‡g«úÞz¥œ3ónqÞª÷ô7½ÑÆ|EÀè·ºŒêkU¼~£ÕnæÓq½%tË·‡³µ—ž³ð‘ðyÖ£4ñäD[«ŽŒ\,‹bi¯\<´™‰‹1êzV®¾ÑuårŒ²ŽÆFqDâ¤qé}È7=ðäýÊbDñšÁ¸£!¢xŽÄiùÍhåÉßæõø®¶•°íÒf5¿Šÿ÷7;Zç¨ÚÒ˜‘:kqg±sþZ¾^Ï|ÓãÄj‰¯ß{¶`¤1Nã¥XNÞ{tÛ¡Y‡¡çÃ釋eãÈaÑ‹ó•5«®;õ˜­a§'†žEÌ(ÁFšÄ‚Æ=‰•âÈxoÕrµ†.·fÏéLcx}¹x;Ö(æùFsÜ¢ç¿[j@¹yêÁï©_oR!é}„P4žõÞSLˆy §•O;Ô¨§-ÝGŸ ø­(~«Ï*»õÓ´ØÉ'S5MNîIõX¥ÝßôNŒËí-–Tt.v­ýTÀ£u´ÎRn)dÿ“ѹ' ÷9DßÌÑ'UK¹wjèÉÚ¸wFšµšÓ-3ëàÑ>Js.§›³gÉlZÔ°n‚Piœ ŒöPÕú—Пøõæ/ºñwÕ„ñšŽD¤/u¯&¸O}FrÞèóEÎ7ÖIÂLë‡},ÙÒõÖ–Æ¡v_¸¯¡g¬rÛ4F·ß̾Ül¿‰±h5îÕ ÷Ñ~œãa_çw\àC°®ØÇ­Æòĸն†S¹¶!×Ò—Ê%ÌbcÔ½WOº>‹¡m ÿ—-‚]š„Ö™ö²‡çGãzbe·­?Óû§B\ÑG‹÷j³Œê‘ÅÏ[cKiÌž=µ]©IÇÊÜ;ÑýöJ_}~èÍ6Æ+çU]Ä[ó¨{óŽ(…u$wùäW ªoî³O½™Âß\ìü¯ä>„Þˆ¨»7§WŒÞœe¿£}yk¿}êÏôFŠ{kaï×2ÀºŽôÄZdþèÈÅïY¥ÿbXÞ °¹±÷>3ô,EÄàÆB"öºúÀZ÷ú#ë Žø}¬ËºÐhûª÷~èÑrí>?ô¬Åj‹œ«L…fµPÿ^¯d|«µ©ø¥ÀKçãÿ½\ÎÞ!Ü¡˜/ôåz®æ¶º¢ãGÇ[­oÅ/2(ðü7=Iä:0$e¾½Ž}!ý?L+¿ían¨€”«Cmq­®¥@)ÐWàsC¯‹~S”Åß¿è ž(Úžìåmí£pTœRà <ý?Y ‡G_hçxŽ´‡hôUý$åÃÜ«òbüº–¯+ðô7½: ^oßõü ‡zƒ( Å®Sê"©@} ‹T³b•û¨¡·OëÊT ”¥@)pXz‡ PéKR (ö)PCoŸÖ•©p+P¿FuKV¥€ª@ =UžÚ,ú Ô¿©Ùר,J, ÔÐËR‰Âq»¿}íÎwM! h)0 @ ½ÑÊ¥(JRàNjèÝY·Bý1êÛÞÇ ^t—)Pÿ=½eÒVà] pá†?gŒö]ºUžRà‹ Ô7½/Vý!ÎÒÐÖg©·qw×6÷,—ò/¾¨@ ½/V½8_« ¾~×–¯€'P ~½™ áV ›Ñ_qz°ìü6zG% å—¨¡÷åêw³܉&ÜàãÖÌ`CŠ]ÃLí0„f6u-nR ~½ySµ «KîwøÇ8*Ž–›¼‡+~4_ÏÇÖ¸uˆ+­{r–m)Iú¦—©…%•Úƒ)°“îi¸,xПÆÔüÀÞj«Å©½R ƒ5ô2T¡0,SÀ{Àô‘@˜¿‡SÂë³þ§®¥ÀM Ôл©Z…õ‡žCmq`Ð@¸G×n¸G.·â¿AãÂøž5ôÞ«é'ô£~(*|Îp¥˜fùeàSJ• üñç ó¿• *v)©ÀÉCý¦We…N7ñ칊õ–5ôÞªçslVÞ^‘^9죴|Eo”ý ÔÐ{£ŽW²ˆ:„W’ù€ŸÕÿemVöTÅ>«@ ½³ú6ûì« 7rS<#þž[ö¨^Ì_ÕÌ«SÙŸW †Þù|ÁÌ ‚Õ!»¶mfêSµY[›Š>§@ ½9ýÊ{RëáZé¤ÐîÖµ)ªf­"õœAzªPJK€5ü.)îG`ÖÐûH¡‹f)°BϬᷢӫÀÿåb ²Õ"$#IEND®B`‚././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1610985 asdf-3.4.0/docs/asdf/0000755000175100001770000000000014653725331013716 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/CODE_OF_CONDUCT.rst0000644000175100001770000000674514653725311016737 0ustar00runnerdocker.. _code-of-conduct: .. NOTE TO EDITORS This file is a copy of the ASDF-format organization wide code of conduct: https://github.com/asdf-format/.github/blob/main/CODE_OF_CONDUCT.md This file should be kept in sync ASDF-format Open Source Code of Conduct ======================================= We expect all “ASDF-format†organization projects to adopt a code of conduct that ensures a productive, respectful environment for all open source contributors and participants. We are committed to providing a strong and enforced code of conduct and expect everyone in our community to follow these guidelines when interacting with others in all forums. Our goal is to keep ours a positive, inclusive, successful, and growing community. The community of participants in open source Astronomy projects is made up of members from around the globe with a diverse set of skills, personalities, and experiences. It is through these differences that our community experiences success and continued growth. As members of the community, - We pledge to treat all people with respect and provide a harassment- and bullying-free environment, regardless of sex, sexual orientation and/or gender identity, disability, physical appearance, body size, race, nationality, ethnicity, and religion. In particular, sexual language and imagery, sexist, racist, or otherwise exclusionary jokes are not appropriate. - We pledge to respect the work of others by recognizing acknowledgment/citation requests of original authors. As authors, we pledge to be explicit about how we want our own work to be cited or acknowledged. - We pledge to welcome those interested in joining the community, and realize that including people with a variety of opinions and backgrounds will only serve to enrich our community. In particular, discussions relating to pros/cons of various technologies, programming languages, and so on are welcome, but these should be done with respect, taking proactive measure to ensure that all participants are heard and feel confident that they can freely express their opinions. - We pledge to welcome questions and answer them respectfully, paying particular attention to those new to the community. We pledge to provide respectful criticisms and feedback in forums, especially in discussion threads resulting from code contributions. - We pledge to be conscientious of the perceptions of the wider community and to respond to criticism respectfully. We will strive to model behaviors that encourage productive debate and disagreement, both within our community and where we are criticized. We will treat those outside our community with the same respect as people within our community. - We pledge to help the entire community follow the code of conduct, and to not remain silent when we see violations of the code of conduct. We will take action when members of our community violate this code such as such as contacting conduct@stsci.edu (all emails sent to this address will be treated with the strictest confidence) or talking privately with the person. This code of conduct applies to all community situations online and offline, including mailing lists, forums, social media, conferences, meetings, associated social events, and one-to-one interactions. Parts of this code of conduct have been adapted from the Astropy: http://www.astropy.org/code_of_conduct.html and Numfocus: https://www.numfocus.org/about/code-of-conduct codes of conduct. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/arrays.rst0000644000175100001770000002252214653725311015752 0ustar00runnerdocker.. currentmodule:: asdf Saving arrays ------------- Beyond the basic data types of dictionaries, lists, strings and numbers, the most important thing ASDF can save is arrays. It's as simple as putting a :mod:`numpy` array somewhere in the tree. Here, we save an 8x8 array of random floating-point numbers (using `numpy.random.rand`). Note that the resulting YAML output contains information about the structure (size and data type) of the array, but the actual array content is in a binary block. .. runcode:: from asdf import AsdfFile import numpy as np tree = {'my_array': np.random.rand(8, 8)} ff = AsdfFile(tree) ff.write_to("test.asdf") .. note:: In the file examples below, the first YAML part appears as it appears in the file. The ``BLOCK`` sections are stored as binary data in the file, but are presented in human-readable form on this page. .. asdf:: test.asdf Sharing of data --------------- Arrays that are views on the same data automatically share the same data in the file. In this example an array and a subview on that same array are saved to the same file, resulting in only a single block of data being saved. .. runcode:: from asdf import AsdfFile import numpy as np my_array = np.random.rand(8, 8) subset = my_array[2:4,3:6] tree = { 'my_array': my_array, 'subset': subset } ff = AsdfFile(tree) ff.write_to("test.asdf") For circumstances where this is undesirable (such as saving a small view of a large array) this can be disabled by setting `asdf.config.AsdfConfig.default_array_save_base` (to set the default behavior) or `asdf.AsdfFile.set_array_save_base` to control the behavior for a specific array. .. asdf:: test.asdf Saving inline arrays -------------------- For small arrays, you may not care about the efficiency of a binary representation and just want to save the array contents directly in the YAML tree. The `~asdf.AsdfFile.set_array_storage` method can be used to set the storage type of the associated data. The allowed values are ``internal``, ``external``, and ``inline``. - ``internal``: The default. The array data will be stored in a binary block in the same ASDF file. - ``external``: Store the data in a binary block in a separate ASDF file (also known as "exploded" format, which discussed below in :ref:`exploded`). - ``inline``: Store the data as YAML inline in the tree. .. runcode:: from asdf import AsdfFile import numpy as np my_array = np.random.rand(8, 8) tree = {'my_array': my_array} ff = AsdfFile(tree) ff.set_array_storage(my_array, 'inline') ff.write_to("test.asdf") .. asdf:: test.asdf Alternatively, it is possible to use the ``all_array_storage`` parameter of `AsdfFile.write_to` and `AsdfFile.update` to control the storage format of all arrays in the file. .. code:: # This controls the output format of all arrays in the file ff.write_to("test.asdf", all_array_storage='inline') For automatic management of the array storage type based on number of elements, see :ref:`config_options_array_inline_threshold`. .. _exploded: Saving external arrays ---------------------- ASDF files may also be saved in "exploded form", which creates multiple files corresponding to the following data items: - One ASDF file containing only the header and tree. - *n* ASDF files, each containing a single array data block. Exploded form is useful in the following scenarios: - Over a network protocol, such as HTTP, a client may only need to access some of the blocks. While reading a subset of the file can be done using HTTP ``Range`` headers, it still requires one (small) request per block to "jump" through the file to determine the start location of each block. This can become time-consuming over a high-latency network if there are many blocks. Exploded form allows each block to be requested directly by a specific URI. - An ASDF writer may stream a table to disk, when the size of the table is not known at the outset. Using exploded form simplifies this, since a standalone file containing a single table can be iteratively appended to without worrying about any blocks that may follow it. To save a block in an external file, set its block type to ``'external'``. .. runcode:: from asdf import AsdfFile import numpy as np my_array = np.random.rand(8, 8) tree = {'my_array': my_array} ff = AsdfFile(tree) # On an individual block basis: ff.set_array_storage(my_array, 'external') ff.write_to("test.asdf") # Or for every block: ff.write_to("test.asdf", all_array_storage='external') .. asdf:: test.asdf .. asdf:: test0000.asdf Streaming array data -------------------- In certain scenarios, you may want to stream data to disk, rather than writing an entire array of data at once. For example, it may not be possible to fit the entire array in memory, or you may want to save data from a device as it comes in to prevent data loss. The ASDF Standard allows exactly one streaming block per file where the size of the block isn't included in the block header, but instead is implicitly determined to include all of the remaining contents of the file. By definition, it must be the last block in the file. To use streaming, rather than including a Numpy array object in the tree, you include a `asdf.tags.core.Stream` object which sets up the structure of the streamed data, but will not write out the actual content. The file handle's ``write`` method is then used to manually write out the binary data. .. runcode:: from asdf import AsdfFile from asdf.tags.core import Stream import numpy as np tree = { # Each "row" of data will have 128 entries. 'my_stream': Stream([128], np.float64) } ff = AsdfFile(tree) with open('test.asdf', 'wb') as fd: ff.write_to(fd) # Write 100 rows of data, one row at a time. ``write`` # expects the raw binary bytes, not an array, so we use # ``tobytes()``. for i in range(100): fd.write(np.array([i] * 128, np.float64).tobytes()) .. asdf:: test.asdf A case where streaming may be useful is when converting large data sets from a different format into ASDF. In these cases it would be impractical to hold all of the data in memory as an intermediate step. Consider the following example that streams a large CSV file containing rows of integer data and converts it to numpy arrays stored in ASDF: .. doctest-skip:: import csv import numpy as np from asdf import AsdfFile from asdf.tags.core import Stream tree = { # We happen to know in advance that each row in the CSV has 100 ints 'data': Stream([100], np.int64) } ff = AsdfFile(tree) # open the output file handle with open('new_file.asdf', 'wb') as fd: ff.write_to(fd) # open the CSV file to be converted with open('large_file.csv', 'r') as cfd: # read each line of the CSV file reader = csv.reader(cfd) for row in reader: # convert each row to a numpy array array = np.array([int(x) for x in row], np.int64) # write the array to the output file handle fd.write(array.tobytes()) Compression ----------- Individual blocks in an ASDF file may be compressed. You can easily `zlib `__ or `bzip2 `__ compress all blocks: .. runcode:: from asdf import AsdfFile import numpy as np tree = { 'a': np.random.rand(32, 32), 'b': np.random.rand(64, 64) } target = AsdfFile(tree) target.write_to('target.asdf', all_array_compression='zlib') target.write_to('target.asdf', all_array_compression='bzp2') .. asdf:: target.asdf The `lz4 `__ compression algorithm is also supported, but requires the optional `lz4 `__ package in order to work. When reading a file with compressed blocks, the blocks will be automatically decompressed when accessed. If a file with compressed blocks is read and then written out again, by default the new file will use the same compression as the original file. This behavior can be overridden by explicitly providing a different compression algorithm when writing the file out again. .. code:: import asdf # Open a file with some compression af = asdf.open('compressed.asdf') # Use the same compression when writing out a new file af.write_to('same.asdf') # Or specify the (possibly different) algorithm to use when writing out af.write_to('different.asdf', all_array_compression='lz4') Memory mapping -------------- By default, all internal array data is memory mapped using `numpy.memmap`. This allows for the efficient use of memory even when reading files with very large arrays. The use of memory mapping means that the following usage pattern is not permitted: .. code:: import asdf with asdf.open('my_data.asdf') as af: ... af.tree Specifically, if an ASDF file has been opened using a ``with`` context, it is not possible to access the file contents outside of the scope of that context, because any memory mapped arrays will no longer be available. It may sometimes be useful to copy array data into memory instead of using memory maps. This can be controlled by passing the ``copy_arrays`` parameter to either the `AsdfFile` constructor or `asdf.open`. By default, ``copy_arrays=False``. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/asdf_tool.rst0000644000175100001770000000150114653725311016415 0ustar00runnerdocker.. _asdf_tool: Command line tool ----------------- `asdf` includes a command-line tool, ``asdftool`` that performs a number of useful operations: - ``explode``: Convert a self-contained ASDF file into exploded form (see :ref:`exploded`). - ``implode``: Convert an ASDF file in exploded form into a self-contained file. - ``defragment``: Remove unused blocks and extra space. - ``diff``: Report differences between two ASDF files. - ``edit``: Edit the YAML portion of an ASDF file. - ``info``: Print a rendering of an ASDF tree. - ``extensions``: Show information about installed extensions (see :ref:`other_packages`). - ``tags``: List currently available tags. - ``to_yaml``: Inline all of the data in an ASDF file so that it is pure YAML. Run ``asdftool --help`` for more information. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/changes.rst0000644000175100001770000000013514653725311016055 0ustar00runnerdocker.. currentmodule:: asdf *********** Change Log *********** .. include:: ../../CHANGES.rst ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/citation.rst0000644000175100001770000000014414653725311016257 0ustar00runnerdocker.. currentmodule:: asdf .. _citation: ******** Citation ******** .. include:: ../../CITATION.rst ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/config.rst0000644000175100001770000002024614653725311015717 0ustar00runnerdocker.. currentmodule:: asdf.config ============= Configuration ============= Version 2.8 of this library introduced a new mechanism, `AsdfConfig`, for setting global configuration options. Currently available options are limited, but we expect to eventually move many of the ``AsdfFile.__init__`` and ``AsdfFile.write_to`` keyword arguments to `AsdfConfig`. AsdfConfig and you ================== The `AsdfConfig` class provides properties that can be adjusted to change the behavior of the `asdf` library for all files. For example, to disable schema validation on read: .. code-block:: pycon >>> import asdf >>> asdf.get_config().validate_on_read = False # doctest: +SKIP This will prevent validation on any subsequent call to `~asdf.open`. Obtaining an AsdfConfig instance -------------------------------- There are two methods available that give access to an `AsdfConfig` instance: `~asdf.get_config` and `~asdf.config_context`. The former simply returns the currently active config: .. code-block:: pycon >>> import asdf >>> asdf.get_config() The latter method, `~asdf.config_context`, returns a context manager that yields a copy of the currently active config. The copy is also returned by subsequent calls to `~asdf.get_config`, but only until the context manager exits. This allows for short-lived configuration changes that do not impact other code: .. code-block:: pycon >>> import asdf >>> with asdf.config_context() as config: ... config.validate_on_read = False ... asdf.get_config() ... >>> asdf.get_config() Special note to library maintainers ----------------------------------- Libraries that use `asdf` are encouraged to only modify `AsdfConfig` within a surrounding call to `~asdf.config_context`. The downstream library will then be able to customize `asdf`'s behavior without impacting other libraries or clobbering changes made by the user. Config options ============== .. _config_options_array_inline_threshold: array_inline_threshold ---------------------- The threshold number of array elements under which arrays are automatically stored inline in the ASDF tree instead of in binary blocks. If ``None``, array storage type is not managed automatically. Defaults to ``None``. all_array_storage ----------------- Use this storage type for all arrays within an ASDF file. Must be one of - ``"internal"`` - ``"external"`` - ``"inline"`` - ``None`` If ``None`` a different storage type can be used for each array. See ``AsdfFile.set_array_storage`` for more details. Defaults to ``None``. all_array_compression --------------------- Use this compression type for all arrays within an ASDF file. If ``"input"`` a different compression type can be used for each array. See ``AsdfFile.set_array_compression`` for more details. Defaults to ``"input"``. all_array_compression_kwargs ---------------------------- Use these additional compression keyword arguments for all arrays within an ASDF file. If ``None`` diffeerent keyword arguments can be set for each array. See ``AsdfFile.set_array_compression`` for more details. Defaults to ``None``. .. _default_array_save_base: default_array_save_base ----------------------- Controls the default behavior asdf will follow when saving an array view. If ``True`` (the default) the base array for the view will be saved in an ASDF binary block. If ``False`` the data corresponding to the view will be saved in an ASDF binary block. .. _convert_unknown_ndarray_subclasses: convert_unknown_ndarray_subclasses ---------------------------------- Convert otherwise unhandled instances of subclasses of ndarray into ndarrays prior to serialization. Previous extension code allowed AsdfTypes to convert instances of subclasses of supported types. Internally, the handling of ndarrays has been moved from an AsdfType to a Converter which does not support converting instances of subclasses unless they are explicitly listed. This means that code that previously relied on asdf converting instances of subclasses of ndarray into an ndarray will need to be updated to define a Converter for the ndarray subclass or to request that support be added directly in asdf (for subclasses in existing asdf dependencies). With this setting enabled, asdf will continue to convert instances of subclasses of ndarray but will issue a warning when an instance is converted. In a future version of asdf this default will change to ``False``, a deprecation warning will be issued and finally the conversion of instances of subclasses will be removed. Defaults to ``True``. default_version --------------- The default ASDF Standard version used for new files. This can be overridden on an individual file basis (using the version argument to ``AsdfFile.__init__``) or set here to change the default for all new files created in the current session. Defaults to the latest stable ASDF Standard version. io_block_size ------------- The buffer size used when reading and writing to the filesystem. Users may wish to adjust this value to improve I/O performance. Set to -1 to use the preferred block size for each file, as reported by st_blksize. Defaults to -1. legacy_fill_schema_defaults --------------------------- Flag that controls filling default values from schemas for older versions of the ASDF Standard. This library used to remove nodes from the tree whose values matched the default property in the schema. That behavior was changed in `asdf` 2.8, but in order to read files produced by older versions of the library, default values must still be filled from the schema for ASDF Standard <= 1.5.0. Set to False to disable filling default values from the schema for these older ASDF Standard versions. The flag has no effect for ASDF Standard >= 1.6.0. Defaults to True. validate_on_read ---------------- Flag that controls schema validation of the ASDF tree when opening files. Users who trust the source of their files may wish to disable validation on read to improve performance. Defaults to True. Additional AsdfConfig features ============================== `AsdfConfig` also provides methods for adding and removing plugins at runtime. For example, the `AsdfConfig.add_resource_mapping` method can be used to register a schema, which can then be used to validate a file: .. code-block:: pycon >>> import asdf >>> content = b""" ... %YAML 1.1 ... --- ... $schema: http://stsci.edu/schemas/yaml-schema/draft-01 ... id: http://example.com/example-project/schemas/foo-1.0.0 ... type: object ... properties: ... foo: ... type: string ... required: [foo] ... ... ... """ >>> asdf.get_config().add_resource_mapping( ... {"http://example.com/example-project/schemas/foo-1.0.0": content} ... ) >>> af = asdf.AsdfFile(custom_schema="http://example.com/example-project/schemas/foo-1.0.0") >>> af.validate() Traceback (most recent call last): ... asdf._jsonschema.exceptions.ValidationError: 'foo' is a required property ... >>> af["foo"] = "bar" >>> af.validate() See the `AsdfConfig` API documentation for more detail. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/contributing.rst0000644000175100001770000000015314653725311017154 0ustar00runnerdocker.. currentmodule:: asdf .. _contributing: Contributing ============ .. include:: ../../CONTRIBUTING.rst ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/deprecations.rst0000644000175100001770000001147314653725311017134 0ustar00runnerdocker.. currentmodule:: asdf .. _deprecations: ************ Deprecations ************ Version 3.3 =========== ``asdf.util.filepath_to_url`` is deprecated. Please use ``pathlib.Path.to_uri``. The ``ignore_implicit_conversion`` argument for ``AsdfFile`` and ``treeutil.walk_and_modify`` is deprecated. "implicit conversion" is also deprecated. This referred to the behavior where certain types (namedtuple) were silently (or with a warning depending on the ``ignore_implicit_conversion`` setting) converted to a list when added to an asdf tree. As these types (namedtuple) can be supported by a ``Converter`` this "implicit conversion" will be removed. Version 3.1 =========== ``asdf.asdf`` is deprecated. Please use the top-level ``asdf`` module for ``AsdfFile`` and ``open`` (same as ``asdf.asdf.open_asdf``). ``AsdfFile.resolve_and_inline`` is deprecated. Please use ``AsdfFile.resolve_references`` and provide ``all_array_storage='inline'`` to ``AdsfFile.write_to`` (or ``AsdfFile.update``). Automatic calling of ``AsdfFile.find_references`` during calls to ``AsdfFile.__init__`` and ``asdf.open``. Call ``AsdfFile.find_references`` to find references. Several deprecations were added to ``AsdfFile`` methods that validate the tree. In a future version of asdf these methods will not perform any tree validation (please call ``AsdfFile.validate`` to validate the tree). As this behavior is difficult to deprecate (without triggering warnings for every call of the method) an ``AsdfDeprecationWarning`` will only be issued on a failed validation during the following methods: * ``AsdfFile.tree`` assignment * ``AsdfFile.resolve_references`` * ``AsdfFile.__init__`` (when the ``tree`` argument is provided) Providing ``kwargs`` to ``AsdfFile.resolve_references`` does nothing and is deprecated. Version 3.0 =========== The following functions in ``asdf.util`` are deprecated: * ``human_list`` this is no longer part of the public API * ``resolve_name`` see ``astropy.utils.resolve_name`` * ``minversion`` see ``astropy.utils.minversion`` * ``iter_subclasses`` this is no longer part of the public API Version 3.0 =========== SerializationContext was previously importable from ``asdf.asdf.SerializationContext``. Although not part of the public API, this import path has been deprecated and users should instead import ``SerializationContext`` from `asdf.extension`. Version 2.15 ============ ASDF 2.15 introduced many new `asdf.exceptions.AsdfDeprecationWarning` messages. These warnings are subclasses of the built-in python `DeprecationWarning` and will by default be ignored except in `__main__` and with testing tools such as :ref:`pytest `. These are intended to highlight use of features that we will likely remove in the next major version of ASDF (see our :ref:`release_and_support` for more details about our versioning, compatibility and support policy). .. _legacy_extension_api_deprecation: Legacy Extension API Deprecation -------------------------------- A large number of `asdf.exceptions.AsdfDeprecationWarning` messages appear related to use of the ``legacy extension api``. Some examples include: * ``asdf.types`` * ``asdf.types.CustomType`` * ``asdf.type_index`` * ``asdf.resolver`` * the ``asdf_extensions`` entry point * portions of asdf.extension including: * ``asdf.extension.AsdfExtension`` * ``asdf.extension.AsdfExtensionList`` * ``asdf.extension.BuiltinExtension`` * ``asdf.extension.default_extensions`` * ``asdf.extension.get_cached_asdf_extensions`` * ``asdf.extension.get_default_resolver`` * attributes to asdf.AsdfFile including: * ``asdf.AsdfFile.run_hook`` * ``asdf.AsdfFile.run_modifying_hook`` * ``asdf.AsdfFile.url_mapping`` * ``asdf.AsdfFile.tag_mapping`` * ``asdf.AsdfFile.type_index`` * ``asdf.AsdfFile.resolver`` * ``asdf.AsdfFile.extension_list`` This deprecated api is replaced by new-style :ref:`converters `, :ref:`extensions ` and :ref:`validators `. `asdf-astropy `_ is a useful example package that uses these new-style extension api. .. _asdf_in_fits_deprecation: ASDF-in-FITS Deprecation ------------------------ Support for ``AsdfInFits`` (including the ``asdf.fits_embed`` module) is deprecated. Code using this format can migrate to using `stdatamodels` which contains functions to read and write AsdfInFits files (see :external+stdatamodels:doc:`asdf_in_fits` for migration information). Without support for ``fits_embed.AsdfInFits`` the ``extract`` and ``remove-hdu`` commands for :ref:`asdftool ` are no longer usable and are deprecated. .. _tests_helpers_deprecation: asdf.tests.helpers Deprecation ------------------------------ Use of ``asdf.tests.helpers`` is deprecated. Please see `asdf.testing.helpers` for alternative functions to aid in testing. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/developer_api.rst0000644000175100001770000000130314653725311017261 0ustar00runnerdocker.. _developer_api: ************* Developer API ************* The classes and functions documented here will be of use to developers who wish to create their own custom ASDF types and extensions. .. automodapi:: asdf.tagged .. automodapi:: asdf.exceptions :allowed-package-names: jsonschema, asdf .. automodapi:: asdf.extension .. automodapi:: asdf.resource .. automodapi:: asdf.yamlutil .. automodapi:: asdf.treeutil .. automodapi:: asdf.util .. automodapi:: asdf.versioning .. automodapi:: asdf.schema .. automodapi:: asdf.tags.core :skip: ExternalArrayReference :skip: IntegerType :no-inheritance-diagram: .. automodapi:: asdf.testing.helpers .. automodapi:: asdf.lazy_nodes ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/developer_overview.rst0000644000175100001770000011306114653725311020363 0ustar00runnerdockerHigh level overview of the basic ASDF library ============================================= This document is an attempt to make it easier to understand the design and workings of the python asdf library for those unfamiliar with it. This is expected to grow organically so at the moment it should not be considered complete or comprehensive. Understanding the design is complicated by the fact that the library effectively inserts custom methods or classes into the objects that the pyyaml and jsonschema libraries use. Understanding what is going on thus means having some understanding of the relevant parts of the internals of both of those libraries. This overview will try to provide a small amount of context for these packages to illuminate how the code in asdf interacts with them. There are at least two ways of outlining the design. One is to give high level overviews of the various modules and how they interact with other modules. The other is to illustrate how code is actually invoked in common operations, this often being much more informative on a practical level (at least some find that to be the case). This document will attempt to do both. We will start with a high-level review of concepts and terms and point to where these are handled in the asdf modules. Because of the complexity, this initial design overview will focus on issues of validation and tree construction when reading. Construction in progress ------------------------ Before we get into further details, a word on the transition to new plugin APIs. Starting in asdf 2.8 we've introduced new interfaces for extending the asdf library to support additional tags and schemas. The interfaces were redesigned with the following goals in mind: - Simplify the connection between tags and their schema content. The old "resolver" system involves sending the tag URI through a lengthy series of transformations to get the filesystem path to the schema document. This has been error-prone and difficult to troubleshoot, so the new "resource mapping" system explicitly maps schema URIs to their content, and tag URIs directly to schema URIs. - Make it easier to separate schemas from extension code. Until now the schemas have always been provided by the same Python package that implements support for their tags, but we would like to move the schemas to language-agnostic repositories that non-Python implementations can use. To better support this, the new interface splits the old extension plugin into two new plugins, one of which is dedicated to schemas. - Allow tag serialization support to handle arbitrary sets of URIs. Previously tag code was restricted to working with tag URIs that were identical except for version. This presented a problem for the transition of URIs from stsci.edu to asdf-format.org, so the new interface allows for supporting diverse URIs with the same code. - Improve the terminology used in the tag serialization support classes. The old ``ExtensionType`` has been renamed ``Converter`` to indicate its purpose, and to eliminate the ambiguity betwenen YAML types and Python types. The ``to_tree`` and ``from_tree`` methods have been renamed ``to_yaml_tree`` and ``from_yaml_tree`` to better indicate which tree they're expected to convert. - Simplify the code and behavior of tag classes. Converters are used as instances instead of classes with a custom metaclass, Python sub-types are no longer automatically handled, URIs are treated as single values instead of broken down into various components, etc. You can witness the gory details of this effort by clicking through the PR links on the asdf 2.8.0 `roadmap `_. Support for ASDF core tags has not yet been moved to the new system. Doing so would be a breaking change for users who subclass that code, so we'll need to wait until asdf 3.0 to do that. Some features working toward this goal are available for testing but will raise a ``AsdfProvisionalAPIWarning`` when used. This warning indicates that a feature may experience breaking API changes (even for minor ASDF releases) and should not be trusted in a production environment. It is likely that features that raise this warning will become stable and be added to a future ASDF version. Some terminology and definitions -------------------------------- **URI vs URL (Universal Resource Identifier)**. This is distinguished from URL (Universal Resource Locator) primarily in that URI is a mechanism for a unique name that follows a particular syntax, but itself may not indicate where the resource is. Generally URLs are expected to be used on the web for the HTTP protocol, though for asdf, this isn't necessarily the case as mentioned next. Recent changes to the library permit use of URIs with the asdf:// scheme, which is intended to reduce confusion over the distinction between identifiers and locations. **Resolver:** Tools to map URIs and tags into actual locations of schema files, which may be local directories (the usual approach) or an actual URL for retrieval over the network. This is more complicated that it may seem for reasons explained later. The resolver system has been deprecated in favor of resource mappings; new code should use the latter instead. **Global config:** A global library configuration feature that was added in asdf 2.8. Allows plugins to be added or removed at runtime and ``AsdfFile`` defaults to be modified by the user. Accessed via the ``get_config`` method on the top-level ``asdf`` module. For example, the default ASDF Standard version for new files can be set like this:: asdf.get_config().default_version = "1.3.0" Or a resource mapping plugin added at runtime like this:: asdf.get_config().add_resource_mapping({"http://somewhere.org/resources/foo", b"foo resource content"}) **Entry point:** A Python packaging feature that allows asdf to use plugins provided by other packages. Entry points are registered when a package is installed and become available to asdf without any additional effort on the part of the user. See :ref:`pypa-packaging:entry-points` for more information. **Resource mapping:** An asdf plugin that provides access to "resources" which are binary blobs associated with a URI. These resources are mostly schemas, but any resource may provided by a mapping. Resource mappings are provided via entry points or added at runtime using a method on the global config object. This feature is intended to replace the deprecated "resolver" mechanism. **Extension:** An extension to the ASDF Standard that defines additional YAML tags. In the future an extension may include other additional features such as binary block compressors or filters, but currently only tags are supported. **Extension implementation:** An asdf plugin that implements an extension to the ASDF Standard. This is the asdf library's support for an extended set of YAML tags. The library currently provides two interfaces for implementing extensions: the ``AsdfExtension`` class and the new, still-experimental ``Extension`` class. Extension implementations are provided via entry points or added at runtime using a method on the global config object. The ``AsdfFile`` also permits adding additional extensions on a per-instance basis, but use of that feature is discouraged and may be removed in asdf 3.0. **Tag code/tag class:** A class responsible for converting a family of tags into Python objects and vice versa. Each extension implementation includes a list of such classes. For the original ``AsdfExtension`` API, the tag classes all implement the ``ExtensionType`` interface. For the new API, tag classes implement ``Converter``. **Validator:** Tool to confirm that the YAML conforms to the schemas that apply. A lot goes on in this area and it is pretty complex in the implementation. **Tree building:** The YAML content is built into a tree in two stages. The YAML parser converts the raw YAML into a custom Python structure. It is that structure that is validated. Then if no errors are found, the tree is converted into a tree where tagged nodes get converted into corresponding Python objects (usually, an option exists to prevent this from happening, which is useful for some applications), e.g., WCS object or numpy arrays (well, not quite that simply for numpy arrays). The above is a simplified view of what happens when an ASDF file is read. Most of resolver tools and code is in ``resolver.py`` (but not all). Most of the validation code is in ``schema.py``. The code that builds the trees is spread in many places: ``tagged.py``, ``treeutil.py``, ``types.py`` as well as all the extension code that supplies code to handle the tags within (and often the the associated schemas). A note on the location of schemas and tag code; there is a bit of schizophrenic aspect to this since schema should be language agnostic and in that view, not bundled with specific language library code. But currently nearly all of the implementation is in Python so while the long-term goal is to keep them separate, it is more convenient to keep them together for now. You will see cases where they are separate and some where they are bundled. The introduction of a separate plugin for providing access to schemas (the "resource mapping") is intended to allow extension authors to keep the schema documents in a separate language-neutral repository. Actions that happen when an AsdfFile is instantiated ---------------------------------------------------- The asdf plugins (new and old-style extensions as well as resource mappings) registered as entry points can be obtained by calling methods in ``entry_points.py``. These methods are invoked by ``config.AsdfConfig`` the first time library needs to use the plugins, and thereafter are cached within that config object. Both extensions and resource mappings are stored wrapped in proxy objects (``ExtensionProxy`` and ``ResourceMappingProxy``, respectively) that carry additional metadata like the package name and version of the entry point, and add some convenience methods on top of what the extension developer provides. Additionally, ``ExtensionProxy`` allows the library to treat both new-style ``Extension`` instances and old-style ``AsdfExtension`` instances similarly. To see the list of extensions loaded by the library, call ``asdf.get_config().extensions``. To see the list of resource mappings, call ``asdf.get_config().resource_mappings``. Both of these properties are lazy-loaded and then cached, so the first call will take a moment to complete but subsequent calls will return immediately. When an ``AsdfFile`` class is instantiated, one thing that happens on the ``__init__`` is that ``self._process_plugin_extensions()`` is called. This method retrieves the extensions from the global config and selects those that are compatible with the ``AsdfFile``'s ASDF Standard version. It returns the resulting list, which is assigned to the ``_plugin_extensions`` variable. The term "plugin extensions" contrasts with "user extensions" which are additional extensions provided by the user as an argument to ``AsdfFile.__init__``. The extension lists are used by ``AsdfFile`` to create the file's ``ExtensionList`` and ``ExtensionManager`` instances, which manage extensions for the old and new extension APIs, respectively. These instances are created lazily when the ``extension_list`` and ``extension_manager`` properties are first accessed, to help speed up the initial construction of the ``AsdfFile``. The ``extension_manager`` is responsible for mapping tag URIs to schema URIs for validation and retrieving type converters (instances of the ``Converter`` interface) by Python type or by YAML tag URI. ``extension_list`` handles the same duties, but for old-style extensions. ``extension_manager`` takes precedence over ``extension_list`` throughout the asdf library, so ``extension_list`` will only be consulted if ``extension_manager`` can't handle a particular tag or Python type. On the subject of resolvers and tag/url mapping ----------------------------------------------- The ``AsdfFile`` class has ``tag_mapping`` and ``url_mapping`` properties that each return the ``extension_list`` properties of the same name. These objects implement the original support for mapping tag URIs to schema content that in the new API is provided by resource mappings. ``tag_mapping`` and ``url_mapping`` are each ``resolver.Resolver`` instances that are generated from the mapping lists in the old-style extensions. These lists consist of 2-tuples. In the first case it is a mechanism to map the tag string to a url string, typically with an expected prefix or suffix to the tag (suffix is typical) so that given a full tag, it generates a url that includes the suffix. This permits one mapping to cover many tag variants (The details of mapping machinery with examples are given in a later section since understanding this is essential to defining new tags and corresponding schemas). The URL mapping works in a similar way, except that it consists of 2-tuples where the first element is the common elements of the url, and the second part maps it to an actual location (url or file path). Again the second part may include a place holder for the suffix or prefix, and code to generate the path to the schema file. The use of the resolver object turns these lists into functions so that supplied the appropriate input that matches something in the list, it gives the corresponding output. Outline of how an ASDF file is opened and read into the corresponding Python object. ------------------------------------------------------------------------------------ The starting point can be found in ``asdf.py`` essentially through the following chain (many calls and steps left out to keep it simpler to follow) When ``asdf.open("myasdffile.asdf")`` is called, it is aliased to ``asdf.open_asdf`` which first creates an instance of ``asdf.AsdfFile`` (let's call the instance ``af``), then calls ``af._open_impl()`` and then ``af._open_asdf``. That invokes a call to ``generic_io.get_file()``. ``generic.py`` basically contains code to handle all the variants of I/O possible (files, streaming, http access, etc). In this case it returns a ``RealFile`` instance that wraps a local file system file. Next the file is examined to see if it is an ASDF file (first by examining the first few lines in the header). If it passes those checks, the header (yaml) section of the file is extracted through a proxy mechanism that signals an end of file when the end of the yaml is reached, but otherwise looks like a file object. The yaml parsing phase described below normally returns a "tagged_tree". That is (somewhat simplified), it returns the data structure that yaml would normally return without any object conversion (i.e., all nodes are either dicts, lists, or scalar values), except that they are objects that now support a tag attribute that indicates if a tag was associated with that node and what the tag was. This reader object is passed to the yaml parser by calling ``yamlutil.load_tree``. A simple explanation for what goes on here is necessary to understand how this all works. Yaml supports various kinds of loaders. For security reasons, the "safe" loader is used (note that both C and python versions are supported through an indirection of the ``_yaml_base_loader`` defined at the beginning of that module that determines whether the C version is available). The loaders are recursive mechanisms that build the tree structure. Note that ``yamlutil.load_tree`` creates a temporary subclass of ``AsdfLoader`` and attaches a reference to the AsdfFile instance as the ``.ctx`` attribute of that temporary subclass. One of the hooks that pyyaml supplies is the ability to overload the method ``construct_object``. That's what the class ``yamlutil.AsdfLoader`` does. pyyaml calls this method at each node in the tree to see if anything special should be done. One could perform conversion to predefined objects here, but instead it does the following: it sees if the node.tag attribute is handled by yaml itself (examples?) it calls that constructor which returns the type yaml converts it to. Otherwise: - it converts the node to the type indicated (dict, list, or scalar type) by yaml for that node. - it obtains the appropriate tag class (an AsdfType subclass) from the AsdfFile instance (using ``ctx.type_index.fix_yaml_tag`` to deal with version issues to match the most appropriate tag class). The new extension API does not support this "fix YAML tag" feature so file's ExtensionManager is not used here. - it wraps all the node alternatives in a special asdf ``Tagged`` class instance variant where that object contains a ._tag attribute that is a reference to the corresponding Tag class. The loading process returns a tree of these Tagged object instances. This tagged_tree is then returned to the ``af`` instance (still running the ``_open_asdf()`` method) this tree is passed to to the ``_validate()`` method (This is the major reason that the tree isn't directly converted to an object tree since jsonschema would not be able to use the final object tree for validation, besides issues relate to the fact that things that don't validate may not be convertible to the designated object.) The validate machinery is a bit confusing since there are essentially two basic approaches to how validation is done. One type of validation is for validation of schema files themselves, and the other for schemas for tags. The schema.py file is fairly involved and the details are covered elsewhere. When the validator machinery is constructed, it uses the fundamental validation files (schemas). But this doesn't handle the fact that the file being validated is yaml, not json and that there are items in yaml not part of json so special handling is needed. And the way it is handled is through a internal mechanism of the jsonschema library. There is a method that jsonschema calls recursively for a validator and it is called iter_errors. The subclass of the jsonschema validator class is defined as schema.ASDFValidator and this method is overloaded in this class. Despite its name, it's primary purpose is to validate the special features that yaml has, namely applying schemas associated with tags (this is not part of the normal jsonschema scheme [ahem]). It is in this method that it looks for a tag for a node and if it exists and in the tag_index, loads the appropriate schema and applies it to the node. (jsonschemas are normally only associated with a whole json entity rather than specific nodes). While the purpose of this method is to iteratively handle errors that jsonschema detects, it has essentially been repurposed as the means of interjecting handling tag schemas. In order to prevent repeated loading of the same schema, the lru caching scheme is used (from functools in the standard library) where the last n cached schemas are saved (details of how this works were recently changed to prevent a serious memory leak) In any event, a lot is going on behind the scenes in validation and it deserves its own description elsewhere. After validation, the tagged tree is then passed to yamlutil.tagged_tree_to_custom_tree() where the nodes in the tree that have special tag code convert the nodes into the appropriate Python objects that the base asdf and extensions are aware of. This is accomplished by that function defining a walker "callback" function (defined within that function as to pick up the af object intrinsically). The function then passes the callback walker to treeutil.walk_and_modify() where the tree will be traversed recursively applying the tag code associated with the tag to the more primitive tree representation replacing such nodes with Python objects. The tree traversal starts from the top, but the objects are created from the bottom up due to recursion (well, not quite that simple). Understanding how this works is described more fully later on. The result is what af.tree is set to, after doing another tree traversal looking for special type hooks for each node. It isn't clear if there is yet any use of that feature. Not quite that simple --------------------- Outline of schema.py -------------------- This module is somewhat confusing due to the many functions and methods with some variant of validate in their name. This will try to make clear what they do (a renaming of these may be in order). Here is a list of the functions/classes in ``schema.py`` and their purpose and where they sit in the order of things default_ext_resolver **_type_to_tag:** Handles mapping python types to yaml_tags, with the addition of support for OrderedDicts. The next 5 functions are put in the ``YAML_VALIDATORS`` dictionary to ultimately be used by ``_create_validator`` to create the json validator object ------ **validate_tag:** Obtain the relevant tag for the supplied instance (either built ins or custom objects) and check that it matches the tag supplied to the function. **validate_propertyOrder:** Not really a validator but rather as a trick to indicate that properties should retain their order. **validate_flowStyle:** Not really a validator but rather as a trick to store what style to use to write the elements (for yaml objects and arrays) **validate_style:** Not really a validator but rather as a trick to store info on what style to use to write the string. **validate_type:** Used to deal with date strings (It may make sense to rename the above to be more descriptive of the action than where they are stuck in the validation machinery; e.g., ``set_propertyOrder``) **validate_fill_default:** Set the default values for all properties that have a subschema that defines a default. Called indirectly in ``fill_defaults`` **validate_remove_default:** does the opposite; remove all properties where value equals subschema default. Called indirectly in ``remove_defaults`` (For this and the above, validate in the name mostly confuses although it is used by the json validator.) [these could be renamed as well since they do more than validate] **_create_validator:** Creates an ``ASDFValidator`` class on the fly that uses the ``jsonchema.validators`` class created. This ``ASDFValidator`` class overrides the ``iter_errors`` method that is used to handle yaml tag cases (using the ``._tag`` attribute of the node to obtain the corresponding schema for that tag; e.g., it calls ``load_schema`` to obtain the right schema when called for each node in the jsonschema machinery). What isn't clear to me is why this is done on the fly and at least cached since it really only handles two variants of calls (basically which JSONSCHEMA version is to be used). Otherwise it doesn't appear to vary except for that. Admittedly, this is only created at the top level. This is called by ``get_validator``. **class OrderedLoader:** Inherits from the ``_yaml_base_loader``, but otherwise does nothing new in the definition. But the following code defines ``construct_mapping``, and then adds it as a method. **construct_mapping:** Defined outside the ``OrderedLoader`` class but to be added to the ``OrderedLoader`` class by use of the base class add_constructor method. This function flattens the mapping and returns an ``OrderedDict`` of the property attributes (This needs some deep understanding of how the yaml parser actually works, which is not covered here. Apparently mappings can be represented as nested trees as the yaml is originally parsed. Or something like that.) **_load_schema:** Loads json or yaml schemas (using the ``OrderedLoader``). **_make_schema_loader:** Defines the function load_schema using the provided resolver and _load_schema. **_make_jsonschema_refresolver:** Sets the schema loader for http, https, file, tag using a dictionary where these access methods are the keys and the schema loader returning only the schema (and not the uri). These all appear to use the same schema loader. **_load_draft4_metaschema:** **load_schema:** Loads a schema from the specified location (this is cached). Called for every tag encountered (uses resolver machinery). Most of the complexity is in resolving json references. Calls ``_make_schema_loader, resolver, reference.resolve_fragment, load_schema`` **get_validator:** Calls ``_create_validator``. Is called by validate to return the created validator. **validate_large_literals:** Ensures tree has no large literals (raises error if it does) **validate:** Uses ``get_validator`` to get a validator object and then calls its validate method, and validates any large literals using ``validate_large_literals``. **fill_defaults:** Inserts attributes missing with the default value **remove_defaults:** Where the tree has attributes with value equal to the default, strip the attribute. **check_schema:** Checks schema against the metaschema. --------------- **Illustration of the where these are called:** ``af._open_asdf`` calls ``af.validate`` which calls ``af._validate`` which then calls ``schema.validate`` with the tagged tree as the first argument (it can be called again if there is a custom schema). **in schema.py** ``validate -> get_validator -> _create_validator`` (returns ``ASDFValidator``). There are two levels of validation, those passed to the json_validation machinery for the schemas themselves, and those that the tag machinery triggers when the jsonschema validator calls through ``iter_errors``. The first level handles all the tricks at the top. the ``ASDFValidator`` uses ``load_schema`` which in turn calls ``_make_schema_loader``, then ``_load_schema``. ``_load_schema`` uses the ``OrderedLoader`` to load the schemas. Got that? How the ASDF library works with pyyaml -------------------------------------- A Tree Identifier ................. There are three flavors of trees in the process of reading ASDF files, one will see many references to each in the code and description below. **pyyaml native tree.** This consists of standard Python containers like dict and list, and primitive values like string, integer, float, etc. **Tagged tree.** These are similar to pyyaml native trees, but with the basic types wrapped in a class that has has an attribute that identifies the tag associated with that node so that later processing can apply the appropriate conversion code to convert to the final Python object. **Custom tree**. This is a tree where all nodes are converted to the destination Python objects. For example, a numpy array or GWCS object. Brief overview of how pyyaml constructs a Python tree ..................................................... Understanding the process of creating Python objects from yaml requires some understanding of how pyyaml works. We will not go into all the details of pyyaml, but instead concentrate on one phase of its loading process. First an outline of the phases of processing that pyyaml goes through in loading a yaml file: 1. **scanning:** Converting the text into lexical tokens. Done in scanner.py #. **parsing:** Converting the lexical tokens into parsing events. Done in parser.py. #. **composing:** Converting the parsing events into a tree structure of pyyaml objects. Done in composer.py #. **loading:** Converting the pyyaml tree into a Python object tree. Done in constructor.py We will focus on the last step since that is where asdf integrates with how pyyaml works. The key object in that module is ``BaseConstructor`` and its subclasses (asdf uses ``SafeConstructor`` for security purposes). Note that the pyyaml code is severely deficient in docstrings and comments. The key method that kicks off the conversion is ``construct_document()``. Its responsibilities are to call the ``construct_object()`` method on the top node, "drain" any generators produced by construction (more on this later), and finally reset internal data structures once construction is complete. The actual process seems somewhat mysterious because what is going on is that it is using generators in place of vanilla code to construct the children for mutable items. The general scheme is that each constructor for mutable elements (see as an example the ``SafeConstructor.construct_yaml_seq()`` method) is written as a generator that is expected to be asked a value twice. The first value returned is an empty object of the expected type (e.g., empty dict or list) and when asked a second time, it populates the previous object returned (and returns None, which is not used). (In rare exceptions, when called with ``deep=True``, it does immediately populate the child nodes.) Normally the generator is appended to the loader's state_generators attribute (a list) for later use. Any generators not handled in the recursive chain are handled when contruct_object returns to ``construct_document``, where it iteratively asks each generator to complete populating its referenced object. Since that step of populating the object may in turn create new generators on the ``state_generator`` list, it only stops when no more generators appear on the list. Why is this done? One reason is to handle references (anchors and aliases) that may be circular. Suppose one had the following yaml source:: A: &a x: 1 B: item1: 42 item2: life, the universe, and everything circular: *a Without generators, it would not be possible to handle this case since the node identified by anchor ``a`` has not been fully constructed when pyyaml encounters a reference to that anchor among the same node's descendants. The use of the generator allows creation of the container object to reference to before it is populated so that the above construction will work when constructing the tree. To follow the above example in more detail, the construction creates a dictionary for ``a`` and then returns to the ``construct_document()`` method, which then starts handling the generators put on the list (there is only one in this case). The generator then populates the contents of ``a``. For the attribute ``B`` it encounters a new mutable container, and puts its generator on the list to handle, and then makes a reference to ``a`` which now is defined. One last time it handles the generator for ``B`` and since each item in that is not a container, the construction completes. Pyyaml tracks pending objects in a recursive objects dict and throws an exception if generators fail to handle reference cycles. (The conversion of the tagged tree to the custom tree, performed later does not use the same technique; explained later) How ASDF hooks into pyyaml construction ....................................... ASDF makes use of this by adding generators to this process by defining a new construct method ``construct_undefined()`` that handles all ASDF tag cases. This is added to the pyyaml dict of construct methods under the key of ``None``. When pyyaml doesn't find a tag, that is what it uses as a key to handle unknown tags. Thus the construction is redirected to ASDF code. That code returns a generator in the case of mutable ASDF objects in line with how yaml works with mutable objects. Historical note: Versions older than 2.6.0 did not work this way. Instead, those versions completely replaced the pyyaml method ``construct_object()`` with their own version that did not use generators as pyyaml did. How conversion to ASDF objects is done ...................................... The current means of conversion is simpler to use by tag code, but also more subtle to understand how it actually works (for many, that means harder ;-) The YAML loading process produces a tagged tree of basic Python types. The conversion of these into ASDF types is kicked off when the ``AsdfFile`` method ``_open_asdf()`` calls ``yamlutil.tagged_tree_to_custom_tree()``. This function defines a walker function that is to be used with ``treeutil.walk_and_modify()``. Most of what the walker function does is handle tag issues (e.g., can the tag be appropriately mapped to the tag creation code) and then returns the appropriate ASDF type by calling ``tag_type.from_tree_tagged()``. A note on tree traversal. One can traverse a tree in three ways: inorder, preorder, and postorder (``asdf.info()`` uses a breadth-first traversal, yet another exciting option, which we won't describe here). These respectively mean whether nodes are visited in the horizontal ordering of the nodes displayed on a graphs (inorder), descending the tree from the root, doing the left node first, before the right node (preorder), or from the bottom up, doing both leaf nodes before the parent node (postorder). In generating the pyyaml tree, preorder works since it builds the tree from the root as one would expect in constructing the tree. But in converting the tagged tree into the custom tree, postorder is the natural course, where the children are generated first so that the parent node can refer to the final objects. An important part of this conversion process is handled by an instance of the class ``treeutil._TreeModificationContext``. This class does much the same trick that pyyaml does with generators. Although pyyaml creates references between basic python objects, these references must be converted to references between ASDF objects, and doing so requires a similar mechanism for building the ASDF objects. The ``_TreeModificationContext`` object (hereafter context object) holds the incomplete generators in a way similar to the pyyaml ``construct_document`` function. There are differences though. The class ``TreeModificationContext`` provides methods to indicate if nodes are pending (i.e., incomplete), and there is a special value ``PendingValue`` that is a signal that the node hasn't been handled yet (e.g., it may be referencing something yet to be done). If ``PendingValue`` persists to the end, it indicates a failure to handle circular references in the tag code. This approach was taken because one of the earlier prototype implementations did something like this, passing dict and list subclasses that would throw an exception if a ``PendingValue`` element was accessed. That would have been more friendly to extension developers, but it was discarded because it wasn't thought it was worth turning all those high performance containers into slower asdf subclasses. We may want to revisit this if we decide to implement a tree that tracks "dirty" nodes and only writes to disk those that have changed, since in that case we'll need custom container subclasses anyway. We could also consider writing our own dict/list subclass in C so we could have our cake and eat it too. The ``walk_and_modify`` code handles the case where the tag code returns a generator instead of a value. This generator is expected to be a similar kind of generator to what pyyaml uses, but differing in that instead of returning an empty container object it will populate whatever elements it can complete (e.g, all non-mutable ones), and complete the population of all the mutable members on the second iteration (which may, in turn, generate new generators for mutable elements contained within). When it detects a generator, the ``walk_and_modify`` code retrieves the first yielded value, then saves the generator in the context. When the top level of the context is reached (it handles nesting by indicating how many times it has been entered as a context), it starts "draining" the saved generators by doing the second iteration on them. Like pyyaml, this second iteration may produce yet more generators that get saved, and thus keeps iterating on the saved generators until none are left. It is not possible to construct reference cycles in immutable objects within pure Python code, and thus the generators are only needed for mutable constructs (e.g., dicts and lists). Historical note: versions of the ASDF library prior to 2.6.0 required tag code when converting from a tagged object to a custom object to call ``tagged_tree_to_custom_tree`` on any values of attributes that may be arbitrarily nested objects. That no longer is needed with the latest code since any attribute that contains a mapping or sequence object automatically uses a generator, so population of that attribute is automatically deferred until the context is exited. Thus there is no need to explicitly call a function to populate it. More explicitly, the ``_recurse`` function defined within ``walk_and_modify`` (in this postorder case) calls ``_handle_children()`` on the node in question first. If the node contains children, they are each fed back into ``_recurse`` and transformed into their final objects. A new node is populated with these transformed children, and that is the node that gets handed to ``tag.from_tree_tagged()``. The effect is that the tag class receives a structure containing only transformed children, so it has no need to call ``tagged_tree_to_custom_tree`` on its own. Future plans for SerializationContext ------------------------------------- Currently, the ``AsdfFile`` itself is used as a container for serialization parameters and is passed to various methods in block.py, reference.py, schema.py, yamlutil.py, in ``ExtensionType`` subclasses, and others. This doesn't work very well for a couple of reasons. For one, the intention of ``AsdfFile.write_to`` is to "export" a copy of the file to disk without changing the in-memory ``AsdfFile``, but since serialization parameters are read from the ``AsdfFile``, the code currently modifies the open file as part of the write (and doesn't change it back). The second issue is that requiring an ``AsdfFile`` instance in so many method signatures forces the code (or users themselves) to create an empty dummy ``AsdfFile`` just to use the method. The new ``Converter`` interface also accepts a ``ctx`` variable, but instead of an ``AsdfFile`` it's an instance of `asdf.extension.SerializationContext`. This new object will serve the purpose of configuring serialization parameters and keeping necessary state, which means that the ``AsdfFile`` can go unmodified. The `asdf.extension.SerializationContext` will be relatively lightweight and creating it will not incur as much of a performance penalty as creating an ``AsdfFile``. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1610985 asdf-3.4.0/docs/asdf/extending/0000755000175100001770000000000014653725331015703 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/extending/compressors.rst0000644000175100001770000000550414653725311021016 0ustar00runnerdocker.. currentmodule:: asdf.extension .. _extending_compressors: ======================== Binary block compressors ======================== The `Compressor` interface provides an implementation of a compression algorithm that can be used to transform binary blocks in an `~asdf.AsdfFile`. Each Compressor must provide a 4-byte compression code that identifies the algorithm. Once the Compressor is installed as part of an Extension plugin, this code will be available to users as an argument to `~asdf.AsdfFile.set_array_compression` and the ``all_array_compression`` argument to `~asdf.AsdfFile.write_to` and `~asdf.AsdfFile.update`. See :ref:`extending_extensions_compressors` for details on including a Compressor in an extension. The Compressor interface ======================== Every Compressor implementation must provide one required property and two required methods: `Compressor.label` - A 4-byte compression code. This code is used by users to select a compression algorithm and also stored in the binary block header to identify the algorithm that was applied to the block's data. `Compressor.compress` - The method that transforms the block's bytes before they are written to an ASDF file. The positional argument is a `memoryview` object which is guaranteed to be 1D and contiguous. Compressors must be prepared to handle `memoryview.itemsize` > 1. Any keyword arguments are passed through from the user and may be used to tune the compression algorithm. ``compress`` methods have no return value and instead are expected to yield bytes-like values until the input data has been fully compressed. `Compressor.decompress` - The method that transforms the block's bytes after they are read from an ASDF file. The first positional argument is an `~collections.abc.Iterable` of bytes-like objects that each contain a chunk of the compressed input data. The second positional argument is a pre-allocated output array where the decompressed bytes should be written. The method is expected to return the number of bytes written to the output array. Entry point performance considerations ====================================== For the good of `asdf` users everywhere, it's important that entry point methods load as quickly as possible. All extensions must be loaded before reading an ASDF file, and therefore all compressors are created as well. Any compressor module or ``__init__`` method that lingers will introduce a delay to the initial call to `asdf.open`. For that reason, we recommend that compressor authors minimize the number of imports that occur in the module containing the Compressor implementation, and defer imports of compression libraries to inside the `Compressor.compress` and `Compressor.decompress` methods. This will prevent the library from ever being imported when reading ASDF files that do not utilize the Compressor's algorithm. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/extending/converters.rst0000644000175100001770000004726314653725311020641 0ustar00runnerdocker.. currentmodule:: asdf.extension .. _extending_converters: ========== Converters ========== The `~asdf.extension.Converter` interface defines a mapping between tagged objects in the ASDF tree and their corresponding Python object(s). Typically a Converter will map one YAML tag to one Python type, but the interface also supports many-to-one and many-to-many mappings. A Converter provides the software support for a tag and is responsible for both converting from parsed YAML to more complex Python objects and vice versa. The Converter interface ======================= Every Converter implementation must provide two required properties and two required methods: `Converter.tags` - a list of tag URIs or URI patterns handled by the converter. Patterns may include the wildcard character ``*``, which matches any sequence of characters up to a ``/``, or ``**``, which matches any sequence of characters. The `~asdf.util.uri_match` method can be used to test URI patterns. `Converter.types` - a list of Python types or fully-qualified Python type names handled by the converter. For strings, the private or public path can be used. For example, if class ``Foo`` is implemented in ``example_package.foo.Foo`` but imported as ``example_package.Foo`` for convenience either ``example_package.foo.Foo`` or ``example_package.Foo`` can be used. As most libraries do not consider moving where a class is implemented it is preferred to use the "public" location where the class is imported (in this example ``example_package.Foo``). The string type name is recommended over a type object for performance reasons, see :ref:`extending_converters_performance`. `Converter.to_yaml_tree` - a method that accepts a complex Python object and returns a simple node object (typically a `dict`) suitable for serialization to YAML. The node is permitted to contain nested complex objects; these will in turn be passed to other ``to_yaml_tree`` methods in other Converters. `Converter.from_yaml_tree` - a method that accepts a simple node object from parsed YAML and returns the appropriate complex Python object. For a non-lazy-tree, nested nodes in the received node will have already been converted to complex objects by other calls to ``from_yaml_tree`` methods, except where reference cycles are present -- see :ref:`extending_converters_reference_cycles` for information on how to handle that situation. For a ``lazy_tree`` (see `asdf.open`) the node will contain `asdf.lazy_nodes` instances which act like dicts and lists but convert child objects only when they are accessed. Additionally, the Converter interface includes a method that must be implemented when some logic is required to select the tag to assign to a ``to_yaml_tree`` result: `Converter.select_tag` - an optional method that accepts a complex Python object and a list candidate tags and returns the tag that should be used to serialize the object. `Converter.lazy` - a boolean attribute indicating if this converter accepts "lazy" objects (those defined in `asdf.lazy_nodes`). This is mostly useful for container-like classes (where the "lazy" objects can defer conversion of contained objects until they are accessed). If a converter produces a generator lazy should be set to ``False`` as asdf will need to generate nodes further out the branch to fully resolve the object returned from the generator. A simple example ================ Say we have a Python class, ``Rectangle``, that we wish to serialize to an ASDF file. A ``Rectangle`` instance has two attributes, width and height, and a convenient method that computes its area: .. code-block:: python # in module example_package.shapes class Rectangle: def __init__(self, width, height): self.width = width self.height = height def get_area(self): return self.width * self.height We'll need to designate a tag URI to represent this object's type in the ASDF tree -- let's use ``asdf://example.com/example-project/tags/rectangle-1.0.0``. Here is a simple Converter implementation for this type and tag: .. code-block:: python from asdf.extension import Converter class RectangleConverter(Converter): tags = ["asdf://example.com/shapes/tags/rectangle-1.0.0"] types = ["example_package.shapes.Rectangle"] def to_yaml_tree(self, obj, tag, ctx): return { "width": obj.width, "height": obj.height, } def from_yaml_tree(self, node, tag, ctx): from example_package.shapes import Rectangle return Rectangle(node["width"], node["height"]) Note that import of the ``Rectangle`` class has been deferred to inside the ``from_yaml_tree`` method. This is a performance consideration that is discussed in :ref:`extending_converters_performance`. In order to use this Converter, we'll need to create a simple extension around it and install that extension: .. code-block:: python import asdf from asdf.extension import Extension class ShapesExtension(Extension): extension_uri = "asdf://example.com/shapes/extensions/shapes-1.0.0" converters = [RectangleConverter()] tags = ["asdf://example.com/shapes/tags/rectangle-1.0.0"] asdf.get_config().add_extension(ShapesExtension()) Now we can include a Rectangle object in an `~asdf.AsdfFile` tree and write out a file: .. code-block:: python with asdf.AsdfFile() as af: af["rect"] = Rectangle(5, 4) af.write_to("test.asdf") The portion of the ASDF file that represents the rectangle looks like this: .. code-block:: yaml rect: ! {height: 4, width: 5} Multiple tags ============= Now say we want to map our one Rectangle class to one of two tags, either rectangle-1.0.0 or square-1.0.0. We'll need to add square-1.0.0 to the converter's list of tags and implement a `select_tag` method: .. code-block:: python RETANGLE_TAG = "asdf://example.com/shapes/tags/rectangle-1.0.0" SQUARE_TAG = "asdf://example.com/shapes/tags/square-1.0.0" class RectangleConverter(Converter): tags = [RECTANGLE_TAG, SQUARE_TAG] types = ["example_package.shapes.Rectangle"] def select_tag(self, obj, tags, ctx): if obj.width == obj.height: return SQUARE_TAG else: return RECTANGLE_TAG def to_yaml_tree(self, obj, tag, ctx): if tag == SQUARE_TAG: return { "side_length": obj.width, } else: return { "width": obj.width, "height": obj.height, } def from_yaml_tree(self, node, tag, ctx): from example_package.shapes import Rectangle if tag == SQUARE_TAG: return Rectangle(node["side_length"], node["side_length"]) else: return Rectangle(node["width"], node["height"]) .. _extending_converters_deferral: Deferring to another converter ============================== Converters only support the exact types listed in `Converter.types`. When a supported type is subclassed the extension will need to be updated to support the new subclass. There are a few options for supporting subclasses. If serialization of the subclass needs to differ from the superclass a new Converter, tag and schema should be defined. If the subclass can be treated the same as the superclass (specifically if subclass instances can be serialized as the superclass) then the subclass can be added to the existing `Converter.types`. Note that adding the subclass to the supported types (without making other changes to the Converter) will result in subclass instances using the same tag as the superclass. This means that any instances created during deserialization will always be of the superclass (subclass instances will never be read from an ASDF file). Another option (useful when modifying the existing Converter is not convenient) is to define a Converter that does not tag the subclass instance being serialized and instead defers to the existing Converter. Deferral is triggered by returning ``None`` from `Converter.select_tag` and implementing `Converter.to_yaml_tree` to convert the subclass instance into an instance of the (supported) superclass. For example, using the example ``Rectangle`` class above, let's say we have another class, ``AspectRectangle``, that represents a rectangle as a height and aspect ratio. We know we never need to deserialize this class for our uses and are ok with always reading ``Rectangle`` instances after saving ``AspectRectangle`` instances. In this case we can define a Converter for ``AspectRectangle`` that converts instances to ``Rectangle`` and defers to the ``RectangleConverter``. .. code-block:: python class AspectRectangle(Rectangle): def __init__(self, height, ratio): self.height = height self.ratio = ratio def get_area(self): width = self.height * self.ratio return width * self.height class AspectRectangleConverter(Converter): tags = [] types = [AspectRectangle] def select_tag(self, obj, tags, ctx): return None # defer to a different Converter def to_yaml_tree(self, obj, tag, ctx): # convert the instance of AspectRectangle (obj) to # a supported type (Rectangle) return Rectangle(obj.height * obj.ratio, obj.height) def from_yaml_tree(self, node, tag, ctx): raise NotImplementedError() Just like a non-deferring Converter this Converter will need to be added to an Extension and registered with asdf. .. _extending_converters_reference_cycles: Reference cycles ================ Special considerations must be made when deserializing a tagged object that contains a reference to itself among its descendants. Consider a `fractions.Fraction` subclass that maintains a reference to its multiplicative inverse: .. code-block:: python # in the example_project.fractions module class FractionWithInverse(fractions.Fraction): def __init__(self, *args, **kwargs): self._inverse = None @property def inverse(self): return self._inverse @inverse.setter def inverse(self, value): self._inverse = value The inverse of the inverse of a fraction is the fraction itself, we might wish to construct the objects in the following way: .. code-block:: python f1 = FractionWithInverse(3, 5) f2 = FractionWithInverse(5, 3) f1.inverse = f2 f2.inverse = f1 Which creates an "infinite loop" between the two fractions. An ordinary Converter wouldn't be able to deserialize this, since each fraction requires that the other be deserialized first! Let's see what happens when we define our ``from_yaml_tree`` method in a naive way: .. code-block:: python class FractionWithInverseConverter(Converter): tags = ["asdf://example.com/fractions/tags/fraction-1.0.0"] types = ["example_project.fractions.FractionWithInverse"] def to_yaml_tree(self, obj, tag, ctx): return { "numerator": obj.width, "denominator": obj.height, "inverse": obj.inverse, } def from_yaml_tree(self, node, tag, ctx): from example_project.fractions import FractionWithInverse obj = FractionWithInverse(tree["numerator"], tree["denominator"]) obj.inverse = tree["inverse"] return obj After adding this Converter to an Extension and installing it, the fraction will serialize correctly: .. code-block:: python with asdf.AsdfFile({"fraction": f1}) as af: af.write_to("with_inverse.asdf") But upon deserialization, we notice a problem: .. code-block:: python with asdf.open("with_inverse.asdf") as af: reconstituted_f1 = af["fraction"] assert reconstituted_f1.inverse.inverse is asdf.treeutil.PendingValue The presence of `~asdf.treeutil._PendingValue` is asdf's way of telling us that the value corresponding to the key ``inverse`` was not fully deserialized at the time that we retrieved it. We can handle this situation by making our ``from_yaml_tree`` a generator function: .. code-block:: python def from_yaml_tree(self, node, tag, ctx): from example_project.fractions import FractionWithInverse obj = FractionWithInverse(tree["numerator"], tree["denominator"]) yield obj obj.inverse = tree["inverse"] The generator version of ``from_yaml_tree`` yields the partially constructed ``FractionWithInverse`` object before setting its inverse property. This allows `asdf` to proceed to constructing the inverse ``FractionWithInverse`` object, and resume the original ``from_yaml_tree`` execution only when the inverse is actually available. With this modification we can successfully deserialize our ASDF file: .. code-block:: python with asdf.open("with_inverse.asdf") as af: reconstituted_f1 = ff["fraction"] assert reconstituted_f1.inverse.inverse is reconstituted_f1 .. _extending_converter_block_storage: Block storage ============= As described above :ref:`extending_converters` can return complex objects that will be passed to other Converters. If a Converter returns a ndarray, asdf will recognize this array and store it in an ASDF block. This is the easiest and preferred means of storing data in ASDF blocks. For applications that require more flexibility, Converters can control block storage through use of the `asdf.extension.SerializationContext` provided as an argument to `Converter.to_yaml_tree` `Converter.from_yaml_tree` and ``Converter.select_tag``. It is helpful to first review some details of how asdf :ref:`stores block `. Blocks are stored sequentially within a ASDF file following the YAML tree. During reads and writes, asdf will need to know the index of the block a Converter would like to use to read or write the correct block. However, the index used for reading might not be the same index for writing if the tree was modified or the file is being written to a new location. During serialization and deserialization, asdf will associate each object with the accessed block during `Converter.from_yaml_tree` and `Converter.to_yaml_tree`. .. note:: Converters using multiple blocks are slightly more complicated. See: :ref:`extending_converter_multiple_block_storage` A simple example of a Converter using block storage to store the ``payload`` for ``BlockData`` object instances is as follows: .. runcode:: import asdf import numpy as np from asdf.extension import Converter, Extension class BlockData: def __init__(self, payload): self.payload = payload class BlockConverter(Converter): tags = ["asdf://somewhere.org/tags/block_data-1.0.0"] types = [BlockData] def to_yaml_tree(self, obj, tag, ctx): block_index = ctx.find_available_block_index( lambda: np.ndarray(len(obj.payload), dtype="uint8", buffer=obj.payload), ) return {"block_index": block_index} def from_yaml_tree(self, node, tag, ctx): block_index = node["block_index"] data_callback = ctx.get_block_data_callback(block_index) obj = BlockData(data_callback()) return obj class BlockExtension(Extension): tags = ["asdf://somewhere.org/tags/block_data-1.0.0"] converters = [BlockConverter()] extension_uri = "asdf://somewhere.org/extensions/block_data-1.0.0" with asdf.config_context() as cfg: cfg.add_extension(BlockExtension()) ff = asdf.AsdfFile({"example": BlockData(b"abcdefg")}) ff.write_to("block_converter_example.asdf") .. asdf:: block_converter_example.asdf During read, `Converter.from_yaml_tree` will be called. Within this method the Converter can prepare to access a block by calling ``SerializationContext.get_block_data_callback``. This will return a function that when called will return the contents of the block (to support lazy loading without keeping a reference to the ``SerializationContext`` (which is meant to be a short lived and lightweight object). During write, `Converter.to_yaml_tree` will be called. The Converter can use ``SerializationContext.find_available_block_index`` to find the location of an available block for writing. The data to be written to the block can be provided as an ``ndarray`` or a callable function that will return a ``ndarray`` (note that it is possible this callable function will be called multiple times and the developer should cache results from any non-repeatable sources). .. _extending_converter_multiple_block_storage: Converters using multiple blocks -------------------------------- As discussed above, while serializing and deserializing objects that use one block, asdf will watch which block is accessed by ``find_available_block_index`` and ``get_block_data_callback`` and associate the block with the converted object. This association allows asdf to map read and write blocks during updates of ASDF files. An object that uses multiple blocks must provide a unique key for each block it uses. These keys are generated using ``SerializationContext.generate_block_key`` and must be stored by the extension code. These keys must be resupplied to the converter when writing an object that was read from an ASDF file. .. runcode:: import asdf import numpy as np from asdf.extension import Converter, Extension class MultiBlockData: def __init__(self, data): self.data = data self.keys = [] class MultiBlockConverter(Converter): tags = ["asdf://somewhere.org/tags/multi_block_data-1.0.0"] types = [MultiBlockData] def to_yaml_tree(self, obj, tag, ctx): if not len(obj.keys): obj.keys = [ctx.generate_block_key() for _ in obj.data] indices = [ctx.find_available_block_index(d, k) for d, k in zip(obj.data, obj.keys)] return { "indices": indices, } def from_yaml_tree(self, node, tag, ctx): indices = node["indices"] keys = [ctx.generate_block_key() for _ in indices] cbs = [ctx.get_block_data_callback(i, k) for i, k in zip(indices, keys)] obj = MultiBlockData([cb() for cb in cbs]) obj.keys = keys return obj class MultiBlockExtension(Extension): tags = ["asdf://somewhere.org/tags/multi_block_data-1.0.0"] converters = [MultiBlockConverter()] extension_uri = "asdf://somewhere.org/extensions/multi_block_data-1.0.0" with asdf.config_context() as cfg: cfg.add_extension(MultiBlockExtension()) obj = MultiBlockData([np.arange(3, dtype="uint8") + i for i in range(3)]) ff = asdf.AsdfFile({"example": obj}) ff.write_to("multi_block_converter_example.asdf") .. asdf:: multi_block_converter_example.asdf .. _extending_converters_performance: Entry point performance considerations ====================================== For the good of `asdf` users everywhere, it's important that entry point methods load as quickly as possible. All extensions must be loaded before reading an ASDF file, and therefore all converters are created as well. Any converter module or ``__init__`` method that lingers will introduce a delay to the initial call to `asdf.open`. For that reason, we recommend that converter authors minimize the number of imports that occur in the module containing the Converter implementation, and defer imports of serializable types to within the ``from_yaml_tree`` method. This will prevent the type from ever being imported when reading ASDF files that do not contain the associated tag. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/extending/extensions.rst0000644000175100001770000003657214653725311020647 0ustar00runnerdocker.. currentmodule:: asdf.extension .. _extending_extensions: ========== Extensions ========== An ASDF "extension" is a supplement to the core ASDF specification that describes additional YAML tags, binary block compressors, or schema validators which may be used when reading and writing files. In this library, extensions implement the `Extension` interface and can be installed manually by the user or automatically by a package using Python's entry points mechanism. Extension features ================== Basics ------ Every extension to ASDF must be uniquely identified by a URI; this URI is written to the file's metadata when the extension is used and allows software to determine if the necessary extensions are installed when the file is read. An ASDF extension implementation intended for use with this library must, at a minimum, implement the `Extension` interface and provide its URI as a property: .. code-block:: python from asdf.extension import Extension class FooExtension(Extension): extension_uri = "asdf://example.com/example-project/extensions/foo-1.0.0" Note that this is an "empty" extension that does not extend the library in any meaningful way; other attributes must be implemented to actually support additional tags, compressors and/or validators. Read on for a description of the rest of the Extension interface. Additional tags --------------- In order to implement support for additional YAML tags, an Extension subclass must provide both a list of relevant tags and a list of `Converter` instances that translate objects with those tags to and from YAML. These lists are provided in the ``tags`` and ``converters`` properties, respectively: .. code-block:: python from asdf.extension import Extension, Converter class FooConverter(Converter): # ... pass class FooExtension(Extension): extension_uri = "asdf://example.com/example-project/extensions/foo-1.0.0" tags = ["asdf://example.com/example-project/tags/foo-1.0.0"] converters = [FooConverter()] The implementation of a Converter is a topic unto itself and is discussed in detail in :ref:`extending_converters`. The Extension implemented above will happily convert between ``foo-1.0.0`` tagged YAML objects and the appropriate Python representation, but it will not perform any schema validation. In order to associate the tag with a schema, we'll need to provide a `TagDefinition` object instead of just a string: .. code-block:: python from asdf.extension import Extension, Converter, TagDefinition class FooConverter(Converter): # ... pass class FooExtension(Extension): extension_uri = "asdf://example.com/example-project/extensions/foo-1.0.0" tags = [ TagDefinition( "asdf://example.com/example-project/tags/foo-1.0.0", schema_uris=["asdf://example.com/example-project/schemas/foo-1.0.0"], ) ] converters = [FooConverter()] .. _extending_extensions_compressors: Additional block compressors ---------------------------- Binary block compressors implement the `Compressor` interface and are included in an extension via the ``compressors`` property: .. code-block:: python from asdf.extension import Extension, Compressor class FooCompressor(Compressor): # ... pass class FooExtension(Extension): extension_uri = "asdf://example.com/example-project/extensions/foo-1.0.0" compressors = [FooCompressor()] See :ref:`extending_compressors` for details on implementing the Compressor interface. Additional YAML tag handles --------------------------- The YAML format permits use of "tag handles" as shorthand prefixes in tags. For example, these two YAML files are equivalent: .. code-block:: yaml %YAML 1.1 --- value: ! # etc ... .. code-block:: yaml %YAML 1.1 %TAG !example! asdf://example.com/example-project/tags/ --- value: !example!foo-1.0.0 # etc ... In both cases the ``value`` object has tag asdf://example.com/example-project/tags/foo-1.0.0, but in the second example the tag is abbreviated as ``!example!foo-1.0.0`` through use of a handle. This has no impact on the interpretation of the file but can make the raw ASDF tree easier to read for humans. Tag handles can be defined in the ``yaml_tag_handles`` property of an extension: .. code-block:: python from asdf.extension import Extension class FooExtension(Extension): extension_uri = "asdf://example.com/example-project/extensions/foo-1.0.0" yaml_tag_handles = {"!example!": "asdf://example.com/example-project/tags/"} Additional schema validators ---------------------------- Schema validators implement the `Validator` interface and are included in an extension via the ``validators`` property: .. code-block:: python from asdf.extension import Extension, Validator class FooValidator(Validator): # ... pass class FooExtension(Extension): extension_uri = "asdf://example.com/example-project/extensions/foo-1.0.0" validators = [FooValidator()] See :ref:`extending_validators` for details on implementing the Validator interface. ASDF Standard version requirement --------------------------------- Some extensions may only work with specific version(s) of the ASDF Standard -- for example, the schema associated with one of an extension's tags may reference specific versions of ASDF core tags. This requirement can be expressed as a PEP 440 version specifier in an Extension's ``asdf_standard_requirement`` property: .. code-block:: python from asdf.extension import Extension class FooExtension(Extension): extension_uri = "asdf://example.com/example-project/extensions/foo-1.0.0" asdf_standard_requirement = ">= 1.2.0, < 1.5.0" Now the extension will only be used with ASDF Standard 1.3.0 and 1.4.0 files. Legacy class names ------------------ Previous versions of this library referred to extensions by their Python class names instead of by URI. These class names were written to ASDF file metadata and allowed the library to warn users when an extension used to write the file was not available on read. Now the extension URI is written to the metadata, but to prevent warnings when reading older files, extension authors can provide an additional list of class names that previously identified the extension: .. code-block:: python from asdf.extension import Extension class FooExtension(Extension): extension_uri = "asdf://example.com/example-project/extensions/foo-1.0.0" legacy_class_names = [ "foo_package.extensions.FooExtension", ] .. _exposing_extension_object_internals: Making converted object's contents visible to ``info`` and ``search`` --------------------------------------------------------------------- When an object is converted to YAML, the resulting YAML tree is stored in the If the object produced by the extension supports a class method ``.__asdf_traverse__`` then it can be used by those tools to expose the contents of the object. That method should accept no arguments and return either a dict of attributes and their values, or a list if the object itself is list-like. .. _extending_extensions_installing: Installing an extension ======================= Once an extension is implemented, it must be installed so that the `asdf` library knows to use it. There are two options for installing an extension: manually per session using `~asdf.config.AsdfConfig`, or automatically for every session using the ``asdf.extensions`` entry point .. _extending_extensions_installing_asdf_config: Installing extensions via AsdfConfig ------------------------------------ The simplest way to install an extension is to add it at runtime using the `AsdfConfig.add_extension ` method. For example, the following code defines and installs a minimal extension: .. code-block:: python import asdf from asdf.extension import Extension class FooExtension(Extension): extension_uri = "asdf://example.com/example-project/extensions/foo-1.0.0" asdf.get_config().add_extension(FooExtension()) Now the extension will be available when working with ASDF files, but only for the duration of the current Python session. .. _extending_extensions_installing_entry_points: Installing extensions via entry points -------------------------------------- The `asdf` package also offers an entry point for installing extensions This registers a package's extensions automatically on package install without requiring calls to the AsdfConfig method. The entry point is called ``asdf.extensions`` and expects to receive a method that returns a list of ``Extension`` instances. For example, let's say we're creating a package named ``asdf-foo-extension`` that provides the not-particularly-useful ``FooExtension`` from the previous section. We'll need to define an entry point method that returns a list containing an instance of ``FooExtension``: .. code-block:: python def get_extensions(): return [FooExtension()] We'll assume that method is located in the module ``asdf_foo_extension.integration``. Next, in the package's ``pyproject.toml``, define a ``[project.entry-points]`` section (or ``[options.entry_points]`` in ``setup.cfg``) that identifies the method as an ``asdf.extensions`` entry point: .. tab:: pyproject.toml .. code-block:: toml [project.entry-points] 'asdf.extensions' = { asdf_foo_extension = 'asdf_foo_extension.integration:get_extensions' } .. tab:: setup.cfg .. code-block:: ini [options.entry_points] asdf.extensions = asdf_foo_extension = asdf_foo_extension.integration:get_extensions After installing the package, the extension should be automatically available in any new Python session. Entry point performance considerations -------------------------------------- For the good of `asdf` users everywhere, it's important that entry point methods load as quickly as possible. All extensions must be loaded before reading an ASDF file, so any entry point method that lingers will introduce a delay to the initial call to `asdf.open`. For that reason, we recommend that extension authors minimize the number of imports that occur in the module containing the entry point method, particularly imports of modules outside of the Python standard library or `asdf` itself. .. _extending_extensions_manifest: Populating an extension from a manifest ======================================= An "extension manifest" is a language-independent description of an ASDF extension (little 'e') that includes information such as the extension URI, list of tags, ASDF Standard requirement, etc. Instructions on writing a manifest can be found in :ref:`extending_manifests`, but once written, we'll still need a Python Extension (big 'E') whose content mirrors the manifest. Rather than duplicate that information in Python code, we recommend use of the `ManifestExtension` class, which reads a manifest and maps its content to the appropriate Extension interface properties. Assuming the manifest is installed as a resource (see :ref:`extending_resources`), an extension instance can be created using the ``from_uri`` factory method: .. code-block:: python from asdf.extension import ManifestExtension extension = ManifestExtension.from_uri( "asdf://example.com/example-project/manifests/foo-1.0.0" ) Compressors and converters can be included in the extension by adding them as keyword arguments: .. code-block:: python from asdf.extension import ManifestExtension extension = ManifestExtension.from_uri( "asdf://example.com/example-project/manifests/foo-1.0.0", converters=[FooConverter()], compressors=[FooCompressor()], ) The extension may then be installed by one of the two methods described above. Warning on ManifestExtension and entry points --------------------------------------------- When implementing a package that automatically installs a ManifestExtension, we'll need to utilize both the ``asdf.resource_mappings`` entry point (to install the manifest) and the ``asdf.extensions`` entry point (to install the extension). Because the manifest must be installed before the extension can be instantiated, it's easy to end up trapped in an import loop. For example, this seemingly innocuous set of entry point methods cannot be successfully loaded: .. code-block:: python from asdf.extension import ManifestExtension RESOURCES = { "asdf://example.com/example-project/manifests/foo-1.0.0": open( "foo-1.0.0.yaml" ).read() } def get_resource_mappings(): return [RESOURCES] EXTENSION = ManifestExtension.from_uri( "asdf://example.com/example-project/manifests/foo-1.0.0" ) def get_extensions(): return [EXTENSION] When the module is imported, ``ManifestExtension.from_uri`` asks the `asdf` library to load all available resources so that it can retrieve the manifest content. But loading the resources requires importing this module to get at the ``get_resource_mappings`` method, so now we're stuck! The solution is to instantiate the ManifestExtension inside of its entry point method: .. code-block:: python def get_extensions(): return [ ManifestExtension.from_uri( "asdf://example.com/example-project/manifests/foo-1.0.0" ) ] This is not as inefficient as it might seem, since the `asdf` library only calls the method once and reuses a cached result thereafter. .. _extending_versioning_extensions: Versioning extensions ===================== As asdf relies on extensions to provide support for serializing and deserializing many custom objects it is important that extension authors consider backwards compatibility when making changes to schemas, converters and extensions. Breaking backwards compatibility without providing support for previous versions can result in unreadable files. Extension authors should strive to use conventions described by `semantic versioning `_ for versioning tags, schemas and extensions. Versions for tags and schemas need not move in lock-step with other tags and schemas in the same extension. The patch version should be increased for bug fixes and other minor, backwards-compatible changes. New features can be indicated with increments to the minor version, as long as they remain backwards compatible with older versions of the schema. Any changes that break backwards compatibility must be indicated by a new major version. Since ASDF is intended to be an archival file format, authors of tags and schemas should work to ensure that ASDF files created with older extensions can continue to be processed. This means that every time a schema version is increased (with the possible exception of patch updates), a **new** schema file should be created. For example, if we currently have a schema for ``xyz-1.0.0``, and we wish to make changes and bump the version to ``xyz-1.1.0``, we should leave the original schema intact. A **new** schema file should be created for ``xyz-1.1.0``, which can exist in parallel with the old file. The version of the corresponding tag type should be bumped to ``1.1.0``. For more details on the behavior of schema and tag versioning from a user perspective, see :ref:`version_and_compat`, and also :ref:`custom_type_versions`. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/extending/manifests.rst0000644000175100001770000000704614653725311020433 0ustar00runnerdocker.. _extending_manifests: =================== Extension manifests =================== An extension "manifest" is a YAML document that defines an extension in a language-independent way. Use of a manifest is recommended for ASDF extensions that are intended to be implemented by ASDF libraries in multiple languages, so that other implementers do not need to go spelunking through Python code to discover the tags and schemas that are included in the extension. This library provides support for automatically populating a `~asdf.extension.Extension` object from a manifest; see :ref:`extending_extensions_manifest` for more information. Anatomy of a manifest ===================== Here is an example of a simple manifest that describes an extension with one tag and schema: .. code-block:: yaml :linenos: %YAML 1.1 --- id: asdf://example.com/example-project/manifests/example-1.0.0 extension_uri: asdf://example.com/example-project/extensions/example-1.0.0 title: Example extension 1.0.0 description: Tags for example objects. asdf_standard_requirement: gte: 1.3.0 lt: 1.5.0 tags: - tag_uri: asdf://example.com/example-project/tags/foo-1.0.0 schema_uri: asdf://example.com/example-project/schemas/foo-1.0.0 ... .. code-block:: yaml :lineno-start: 3 id: asdf://example.com/example-project/manifests/example-1.0.0 The ``id`` property contains the URI that uniquely identifies our manifest. This URI is how we'll refer to the manifest document's content when using the `asdf` library. .. code-block:: yaml :lineno-start: 4 extension_uri: asdf://example.com/example-project/extensions/example-1.0.0 The ``extension_uri`` property contains the URI of the extension that the manifest describes. This is the URI written to ASDF file metadata to document that an extension was used when writing the file. .. code-block:: yaml :lineno-start: 5 title: Example extension 1.0.0 description: Tags for example objects. ``title`` and ``description`` are optional documentation properties. .. code-block:: yaml :lineno-start: 7 asdf_standard_requirement: gte: 1.3.0 lt: 1.5.0 The optional ``asdf_standard_requirement`` property describes the ASDF Standard versions that are compatible with this extension. The ``gte`` and ``lt`` properties are used here to restrict ASDF Standard versions to greater-than-or-equal 1.3.0 and less-than 1.5.0, respectively. ``gt`` and ``lte`` properties are also available. .. code-block:: yaml :lineno-start: 10 tags: - tag_uri: asdf://example.com/example-project/tags/foo-1.0.0 schema_uri: asdf://example.com/example-project/schemas/foo-1.0.0 The ``tags`` property contains a list of objects, each representing a new tag that the extension brings to ASDF. The ``tag_uri`` property contains the tag itself, while the (optional, but recommended) ``schema_uri`` property contains the URI of a schema that can be used to validate objects with that tag. Tag objects may also include ``title`` and ``description`` documentation properties. Validating a manifest ===================== This library includes a schema, ``asdf://asdf-format.org/core/schemas/extension_manifest-1.0.0``, that can be used to validate a manifest document: .. code-block:: python import asdf import yaml schema = asdf.schema.load_schema( "asdf://asdf-format.org/core/schemas/extension_manifest-1.0.0" ) manifest = yaml.safe_load(open("path/to/manifests/example-1.0.0.yaml").read()) asdf.schema.validate(manifest, schema=schema) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/extending/resources.rst0000644000175100001770000002173714653725311020457 0ustar00runnerdocker.. currentmodule:: asdf.resource .. _extending_resources: =============================== Resources and resource mappings =============================== In the terminology of this library, a "resource" is a sequence of bytes associated with a URI. Currently the two types of resources recognized by `asdf` are schemas and extension manifests. Both of these are YAML documents whose associated URI is expected to match the ``id`` property of the document. A "resource mapping" is an `asdf` plugin that provides access to the content for a URI. These plugins must implement the `~collections.abc.Mapping` interface (a simple `dict` qualifies) and map `str` URI keys to `bytes` values. Resource mappings are installed into the `asdf` library via one of two routes: the `AsdfConfig.add_resource_mapping ` method or the ``asdf.resource_mappings`` entry point. Installing resources via AsdfConfig =================================== The simplest way to install a resource into `asdf` is to add it at runtime using the `AsdfConfig.add_resource_mapping ` method. For example, the following code installs a schema for use with the `asdf.AsdfFile` custom_schema argument: .. code-block:: python import asdf content = b""" %YAML 1.1 --- $schema: http://stsci.edu/schemas/yaml-schema/draft-01 id: asdf://example.com/example-project/schemas/foo-1.0.0 type: object properties: foo: type: string required: [foo] ... """ asdf.get_config().add_resource_mapping( {"asdf://example.com/example-project/schemas/foo-1.0.0": content} ) The schema will now be available for validating files: .. code-block:: python af = asdf.AsdfFile(custom_schema="asdf://example.com/example-project/schemas/foo-1.0.0") af.validate() # Error, "foo" is missing The DirectoryResourceMapping class ================================== But what if we don't want to store our schemas in variables in the code? Storing resources in a directory tree is a common use case, so `asdf` provides a `~collections.abc.Mapping` implementation that reads schema content from a filesystem. This is the `DirectoryResourceMapping` class. Consider these three schemas: .. code-block:: yaml # foo-1.0.0.yaml id: asdf://example.com/example-project/schemas/foo-1.0.0 # ... # bar-2.3.4.yaml id: asdf://example.com/example-project/nested/bar-2.3.4 # ... # baz-8.1.1.yaml id: asdf://example.com/example-project/nested/baz-8.1.1 # ... which are arranged in the following directory structure:: schemas ├─ foo-1.0.0.yaml ├─ README └─ nested ├─ bar-2.3.4.yaml └─ baz-8.1.1.yaml Our goal is to install all schemas in the directory tree so that they are available for use with `asdf`. The `DirectoryResourceMapping` class can do that for us, but we need to show it how to construct the schema URIs from the file paths *without reading the id property from the files*. This requirement is a performance consideration; not all resources are used in every session, and if `asdf` were to read and parse all available files when plugins are loaded, the first call to `asdf.open` would be intolerably slow. We should configure `DirectoryResourceMapping` like this: .. code-block:: python import asdf from asdf.resource import DirectoryResourceMapping mapping = DirectoryResourceMapping( "/path/to/schemas", "asdf://example.com/example-project/schemas/", recursive=True, filename_pattern="*.yaml", stem_filename=True, ) asdf.get_config().add_resource_mapping(mapping) The first argument is the path to the schemas directory on the filesystem. The second argument is the prefix that should be prepended to file paths relative to that root when constructing the schema URIs. The ``recursive`` argument tells the class to descend into the ``nested`` directory when searching for schemas, ``filename_pattern`` is a glob pattern chosen to exclude our README file, and ``stem_filename`` causes the class to drop the ``.yaml`` suffix when constructing URIs. We can test that our configuration is correct by asking `asdf` to read and parse one of the schemas: .. code-block:: python from asdf.schema import load_schema uri = "asdf://example.com/example-project/schemas/nested/bar-2.3.4.yaml" schema = load_schema(uri) assert schema["id"] == uri .. _extending_resources_entry_points: Installing resources via entry points ===================================== The `asdf` package also offers an entry point for installing resource mapping plugins. This installs a package's resources automatically without requiring calls to the AsdfConfig method. The entry point is called ``asdf.resource_mappings`` and expects to receive a method that returns a list of `~collections.abc.Mapping` instances. For example, let's say we're creating a package named ``asdf-foo-schemas`` that provides the same schemas described in the previous section. Our directory structure might look something like this:: asdf-foo-schemas ├─ pyproject.toml └─ src └─ asdf_foo_schemas ├─ __init__.py ├─ integration.py └─ schemas ├─ __init__.py ├─ foo-1.0.0.yaml ├─ README └─ nested ├─ __init__.py ├─ bar-2.3.4.yaml └─ baz-8.1.1.yaml ``pyproject.toml`` is the preferred central configuration file for Python build and development systems. However, it is also possible to write configuration to a ``setup.cfg`` file (used by `setuptools `_) placed in the root directory of the project. This documentation will cover both options. In ``integration.py``, we'll define the entry point method and have it return a list with a single element, our `DirectoryResourceMapping` instance: .. code-block:: python # integration.py from pathlib import Path from asdf.resource import DirectoryResourceMapping def get_resource_mappings(): # Get path to schemas directory relative to this file schemas_path = Path(__file__).parent / "schemas" mapping = DirectoryResourceMapping( schemas_path, "asdf://example.com/example-project/schemas/", recursive=True, filename_pattern="*.yaml", stem_filename=True, ) return [mapping] Then in ``pyproject.toml``, define an ``[project.entry-points]`` section (or ``[options.entry_points]`` in ``setup.cfg``) that identifies the method as an ``asdf.resource_mappings`` entry point: .. tab:: pyproject.toml .. code-block:: toml [project.entry-points] 'asdf.resource_mappings' = { asdf_foo_schemas = 'asdf_foo_schemas.integration:get_resource_mappings' } .. tab:: setup.cfg .. code-block:: ini [options.entry_points] asdf.resource_mappings = asdf_foo_schemas = asdf_foo_schemas.integration:get_resource_mappings After installing the package, it should be possible to load one of our schemas in a new session without any additional setup: .. code-block:: python from asdf.schema import load_schema uri = "asdf://example.com/example-project/schemas/nested/bar-2.3.4.yaml" schema = load_schema(uri) assert schema["id"] == uri Note that the package will need to be configured to include the YAML files. There are multiple ways to accomplish this, but one easy option is to add ``[tool.setuptools.package-data]`` and ``[tool.setuptools.package-dir]`` sections to ``pyproject.toml`` (or ``[options.package_data]`` in ``setup.cfg``) requesting that all files with a ``.yaml`` extension be installed: .. tab:: pyproject.toml .. code-block:: toml [tool.setuptools] packages = ["asdf_foo_schemas", "asdf_foo_schemas.resources"] [tool.setuptools.package-data] "asdf_foo_schemas.resources" = ["resources/**/*.yaml"] [tool.setuptools.package-dir] "" = "src" "asdf_foo_schemas.resources" = "resources" .. tab:: setup.cfg .. code-block:: ini [options.package_data] * = *.yaml Entry point performance considerations -------------------------------------- For the good of `asdf` users everywhere, it's important that entry point methods load as quickly as possible. All resource URIs must be loaded before reading an ASDF file, so any entry point method that lingers will introduce a delay to the initial call to `asdf.open`. For that reason, we recommend to minimize the number of imports that occur in the module containing the entry point method, particularly imports of modules outside of the Python standard library or `asdf` itself. When resources are stored in a filesystem, it's also helpful to delay reading a file until its URI is actually requested, which may not occur in a given session. The DirectoryResourceMapping class is implemented with this behavior. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/extending/schemas.rst0000644000175100001770000002467014653725311020067 0ustar00runnerdocker.. _extending_schemas: ============ ASDF schemas ============ ASDF schemas are YAML documents that describe validations to be performed on tagged objects nested within the ASDF tree or on the tree itself. Schemas can validate the presence, datatype, and value of objects and their properties, and can be combined in different ways to facilitate reuse. These schemas, though expressed in YAML, are structured according to the `JSON Schema Draft 4`_ specification. The excellent `Understanding JSON Schema`_ book is a great place to start for users not already familiar with JSON Schema. Just keep in mind that the book includes coverage of later drafts of the JSON Schema spec, so certain features (constant values, conditional subschemas, etc) will not be available when writing schemas for ASDF. The book makes clear which features were introduced after Draft 4. Anatomy of a schema =================== Here is an example of an ASDF schema that validates an object with a numeric value and corresponding unit: .. code-block:: yaml :linenos: %YAML 1.1 --- $schema: http://stsci.edu/schemas/yaml-schema/draft-01 id: asdf://asdf-format.org/core/schemas/quantity-2.0.0 title: Quantity object containing numeric value and unit description: >- An object with a numeric value, which may be a scalar or an array, and associated unit. type: object properties: value: description: A vector of one or more values anyOf: - type: number - tag: tag:stsci.edu:asdf/core/ndarray-1.0.0 unit: description: The unit corresponding to the values tag: tag:stsci.edu:asdf/unit/unit-1.0.0 required: [value, unit] ... This is similar to the quantity schema, found :ref:`here `, of the ASDF Standard, but has been updated to reflect current recommendations regarding schemas. Let's walk through this schema line by line. .. code-block:: yaml :linenos: %YAML 1.1 --- These first two lines form the header of the file. The ``%YAML 1.1`` indicates that we're following version 1.1 of the YAML spec. The ``---`` marks the start of a new YAML document. .. code-block:: yaml :lineno-start: 3 $schema: http://stsci.edu/schemas/yaml-schema/draft-01 The ``$schema`` property contains the URI of the schema that validates this document. Since our document is itself a schema, the URI refers to a *metaschema*. ASDF comes with three built-in metaschemas: - ``http://json-schema.org/draft-04/schema`` - The JSON Schema Draft 4 metaschema. Includes basic validators and combiners. - ``http://stsci.edu/schemas/yaml-schema/draft-01`` - The YAML Schema metaschema. Includes everything in JSON Schema Draft 4, plus additional YAML-specific validators including ``tag`` and ``propertyOrder``. - ``http://stsci.edu/schemas/asdf/asdf-schema-1.0.0`` - The ASDF Schema metaschema. Includes everything in YAML Schema, plus additional ASDF-specific validators that check ndarray properties. Our schema makes use of the ``tag`` validator, so we're specifying the YAML Schema URI here. .. code-block:: yaml :lineno-start: 4 id: asdf://asdf-format.org/core/schemas/quantity-2.0.0 The ``id`` property contains the URI that uniquely identifies our schema. This URI is how we'll refer to the schema when using the asdf library. .. code-block:: yaml :lineno-start: 6 title: Quantity object containing numeric value and unit description: >- An object with a numeric value, which may be a scalar or an array, and associated unit. Title and description are optional (but recommended) documentation properties. These properties can be placed multiple times at any level of the schema and do not have an impact on the validation process. .. code-block:: yaml :lineno-start: 11 type: object This line invokes the ``type`` validator to check the data type of the top-level value. We're asserting that the type must be a YAML mapping, which in Python is represented as a `dict`. .. code-block:: yaml :lineno-start: 12 properties: The ``properties`` validator announces that we'd like to validate certain named properties of mapping. If a property is listed here and is present in the ASDF, it will be validated accordingly. .. code-block:: yaml :lineno-start: 13 value: description: A vector of one or more values Here we're identifying a property named ``value`` that we'd like to validate. The ``description`` is used to add some additional documentation. .. code-block:: yaml :lineno-start: 15 anyOf: The ``anyOf`` validator is one of JSON Schema's combiners. The ``value`` property will be validated against each of the following subschemas, and if any validates successfully, the entire ``anyOf`` will be considered valid. Other available combiners are ``allOf``, which requires that all subschemas validate successfully, ``oneOf``, which requires that one and only one of the subschemas validates, and ``not``, which requires that a single subschema does *not* validate. .. code-block:: yaml :lineno-start: 16 - type: number The first subschema in the list contains a ``type`` validator that succeeds if the entity assigned to ``value`` is a numeric literal. .. code-block:: yaml :lineno-start: 17 - tag: tag:stsci.edu:asdf/core/ndarray-1.0.0 The second subschema contains a ``tag`` validator, which makes an assertion regarding the YAML tag URI of the object assigned to ``value``. In this subschema we're requiring the tag of an ndarray-1.0.0 object, which is how n-dimensional arrays are represented in an ASDF tree. The net effect of the ``anyOf`` combiner and its two subschemas is: validate successfully if the ``value`` object is either a numeric literal or an n-dimensional array. .. code-block:: yaml :lineno-start: 18 unit: description: The unit corresponding to the values tag: tag:stsci.edu:asdf/unit/unit-1.0.0 The ``unit`` property has another bit of documentation and a ``tag`` validator that requires it to be a unit-1.0.0 object. .. code-block:: yaml :lineno-start: 21 required: [value, unit] Since the ``properties`` validator does not require the presence of its listed properties, we need another validator to do that. The ``required`` validator defines a list of properties that need to be present if validation is to succeed. .. code-block:: yaml :lineno-start: 21 ... Finally, the YAML document end indicator indicates the end of the schema. Checking schema syntax ====================== The `~asdf.schema.check_schema` function performs basic syntax checks on a schema and will raise an error if it discovers a problem. It does not currently accept URIs and requires that the schema already be loaded into Python objects. If the schema is already registered with the asdf library as a resource (see :ref:`extending_resources`), it can be loaded and checked like this: .. code-block:: python from asdf.schema import load_schema, check_schema schema = load_schema("asdf://example.com/example-project/schemas/foo-1.0.0") check_schema(schema) Otherwise, the schema can be loaded using pyyaml directly: .. code-block:: python from asdf.schema import check_schema import yaml schema = yaml.safe_load(open("/path/to/foo-1.0.0.yaml").read()) check_schema(schema) Testing validation ================== Getting a schema to validate as intended can be a tricky business, so it's helpful to test validation against some example objects as you go along. The `~asdf.schema.validate` function will validate a Python object against a schema: .. code-block:: python from asdf.schema import validate import yaml schema = yaml.safe_load(open("/path/to/foo-1.0.0.yaml").read()) obj = {"foo": "bar"} validate(obj, schema=schema) The validate function will return successfully if the object is valid, or raise an error if not. .. _testing_custom_schemas: Testing custom schemas ---------------------- Packages that provide their own schemas can test them using `asdf`'s :ref:`pytest ` plugin for schema testing. Schemas are tested for overall validity, and any examples given within the schemas are also tested. The schema tester plugin is automatically registered when the `asdf` package is installed. In order to enable testing, it is necessary to add the directory containing your schema files to the pytest section of your project's build configuration (``pyproject.toml`` or ``setup.cfg``). If you do not already have such a file, creating one with the following should be sufficient: .. tab:: pyproject.toml .. code-block:: toml [tool.pytest.ini_options] asdf_schema_root = 'path/to/schemas another/path/to/schemas' .. tab:: setup.cfg .. code-block:: ini [tool:pytest] asdf_schema_root = path/to/schemas another/path/to/schemas The schema directory paths should be paths that are relative to the top of the package directory **when it is installed**. If this is different from the path in the source directory, then both paths can be used to facilitate in-place testing (see `asdf`'s own ``pyproject.toml`` for an example of this). .. note:: Older versions of `asdf` (prior to 2.4.0) required the plugin to be registered in your project's ``conftest.py`` file. As of 2.4.0, the plugin is now registered automatically and so this line should be removed from your ``conftest.py`` file, unless you need to retain compatibility with older versions of `asdf`. The ``asdf_schema_skip_names`` configuration variable can be used to skip schema files that live within one of the ``asdf_schema_root`` directories but should not be tested. The names should be given as simple base file names (without directory paths or extensions). Again, see `asdf`'s own ``pyproject.toml`` file for an example. The schema tests do **not** run by default. In order to enable the tests by default for your package, add ``asdf_schema_tests_enabled = 'true'`` to the ``[tool.pytest.ini_options]`` section of your ``pyproject.toml`` file (or ``[tool:pytest]`` in ``setup.cfg``). If you do not wish to enable the schema tests by default, you can add the ``--asdf-tests`` option to the ``pytest`` command line to enable tests on a per-run basis. See also: ========= - `JSON Schema Draft 4 `_ - `Understanding JSON Schema `_ - :ref:`Unit Schemas ` ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/extending/uris.rst0000644000175100001770000001125714653725311017423 0ustar00runnerdocker.. _extending_uris: ============ URIs in ASDF ============ The ASDF format uses `Uniform Resource Identifiers `__ to refer to various entities such as schemas or tags. These are string identifiers used to uniquely identify the associated entity. Here are some examples of URIs that might be encountered in an ASDF file: - ``asdf://example.com/schemas/foo-1.0.0`` (URI of the foo-1.0.0 schema) - ``tag:stsci.edu:asdf/core/asdf-1.1.0`` (URI of the asdf-1.0.0 YAML tag) - ``http://stsci.edu/schemas/asdf/core/ndarray-1.0.0`` (URI of the ndarray-1.0.0 schema) Each of these uses a different URI *scheme*, and each is a valid URI format in ASDF. URI vs URL ========== One common point of confusion is the distinction between a URI and a URL. The two are easily conflated -- for example, consider the URI of the ndarray-1.0.0 schema above. ``http://stsci.edu/schemas/asdf/core/ndarray-1.0.0`` This string looks just like the URL of a web page, but if we were to attempt to visit that location in a browser, we'd get a 404 Not Found from stsci.edu. And yet it is still a valid URI! The similarity arises from the need for URIs to be globally unique. Since web domains are already controlled by a single organization or individual, they offer a convenient way to define URIs -- just reserve some path prefix off a domain you control and dole out strings with that prefix where unique identifiers are needed. But using ``http://`` as a URI scheme has the downside that users expect to be able to retrieve the document contents from that address. The asdf:// URI scheme ====================== To counter the problem of URIs vs URLs, `asdf` 2.8 introduced support for the ``asdf://`` URI scheme. These URIs are constructed just like ``http://`` or ``https://`` URIs, but the ASDF-specific scheme makes clear that the content cannot be fetched from a webserver. Entities identified by URI ========================== The following is a complete list of entity types that are identified by URI in ASDF: .. _extending_uris_entities_schemas: Schemas ------- Schemas are expected to include an ``id`` property that contains the URI that identifies them. That URI is used when referring to the schema in calls to `asdf` library functions. We recommend the following pattern for schema URIs: ``asdf:////schemas/-`` Where ```` is some domain that you control, ```` collects all entities for a particular ASDF project, ```` is the name of the schema, and ```` is the schema's version number. For example: ``asdf://example.com/example-project/schemas/foo-1.2.3`` .. _extending_uris_entities_tags: Tags ---- Tags, which annotate typed objects in an ASDF file's YAML tree, are represented as URIs. Unlike schemas, there is no resource associated with the tag; no blob of bytes exists that corresponds to the URI. Instead, the URI alone communicates the type of a YAML object. We recommend the following pattern for tag URIs: ``asdf:////tags/-`` Where ```` is some domain that you control, ```` collects all entities for a particular ASDF project, ```` is the name of the tag, and ```` is the tag's version number. For example: ``asdf://example.com/example-project/tags/foo-1.2.3`` Manifests --------- Manifest documents are language-independent definitions of extensions to ASDF and include an ``id`` property that contains the URI that identifies them. That URI is used when referring to the manifest in calls to `asdf` library functions. We recommend the following pattern for manifest URIs: ``asdf:////manifests/-`` Where ```` is some domain that you control, ```` collects all entities for a particular ASDF project, ```` is the name of the manifest, and ```` is the manifest's version number. For example: ``asdf://example.com/example-project/manifests/foo-1.2.3`` Extensions ---------- Finally, extensions URIs identify extensions to the ASDF format. These URIs are included in an ASDF file's metadata to advertise the fact that additional software support (beyond a core ASDF library) is needed to properly interpret the file. Like tags, these URIs are not associated with a particular resource. We recommend the following pattern for extension URIs: ``asdf:////extensions/-`` Where ```` is some domain that you control, ```` collects all entities for a particular ASDF project, ```` is the name of the extension, and ```` is the extension's version number. For example: ``asdf://example.com/example-project/extensions/foo-1.2.3`` ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/extending/use_cases.rst0000644000175100001770000002235114653725311020410 0ustar00runnerdocker.. _extending_use_cases: ================ Common use cases ================ This section is intended as a kind of index to the rest of the "Extending ASDF" documentation. Here we list common use cases and link to the relevant documentation sections that are needed to get the job done. Validate an ASDF tree against a schema ====================================== The `asdf` library already validates individual tagged objects within the tree, but what if we want to validate the structure of the tree itself? Such "document schemas" can be associated with an `~asdf.AsdfFile` using the ``custom_schema`` argument, but this argument accepts a URI and the asdf library needs to know how to access the schema content associated with that URI. 1. Designate a URI for the schema. See :ref:`extending_uris_entities_schemas` for recommendations on schema URI structure. 2. Write the schema. See :ref:`extending_schemas` if you're new to authoring schemas. 3. Install the schema as an `asdf` library resource. See :ref:`extending_resources` for an overview of resources in `asdf` and options for installing them. Serialize a new type ==================== This section summarizes the steps needed to serialize a new type to an ASDF file. We'll describe three options, starting with the most expedient and growing progressively more formal. Quick and dirty, for personal use --------------------------------- In this scenario, we want to serialize a new Python type to an ASDF file, but we're not planning on widely sharing the file, so we want to cut as many corners as possible. Here are the minimal steps needed to get instances of that type into the file and back again: 1. Identify the Python type to serialize. We'll need to know the fully-qualified name of the type (module path + class name). 2. Select a tag URI that will signify the type in YAML. See :ref:`extending_uris_entities_tags` for recommendations on tag URI structure. 3. Implement a `~asdf.extension.Converter` class that converts the type to YAML-serializable objects and back again. See :ref:`extending_converters` for a discussion of the Converter interface. 4. Implement an `~asdf.extension.Extension` class which is the vehicle for plugging our converter into the asdf library. See :ref:`extending_extensions` for a discussion of the Extension interface. 5. Install the extension. There are multiple ways to do this, but the path of least resistance is to install the extension at runtime using `~asdf.config.AsdfConfig`. See :ref:`extending_extensions_installing_asdf_config`. Now instances of our type can be added to an `~asdf.AsdfFile`'s tree and serialized to an ASDF file. For sharing with other Python users ----------------------------------- Now say our files are getting out into the world and into the hands of other Python users. We'll want to build an installable package around our code and use the `asdf` library's entry points to make our extension more convenient to use. We should also think about adding a schema that validates our tagged objects, so if someone manually edits a file and makes a mistake, we get a clear error when `asdf` opens the file. 1. Identify the Python type to serialize. We'll need to know the fully-qualified name of the type (module path + class name). 2. Select a tag URI that will signify the type in YAML. See :ref:`extending_uris_entities_tags` for recommendations on tag URI structure. 3. Designate a URI for the schema. See :ref:`extending_uris_entities_schemas` for recommendations on schema URI structure. 4. Write the schema that will validate the tagged object. See :ref:`extending_schemas` if you're new to authoring schemas. 5. Make the schema installable as an `asdf` library resource. See :ref:`extending_resources` for an overview of resources in `asdf` and :ref:`extending_resources_entry_points` for information on installing resources via an entry point. 6. Implement a `~asdf.extension.Converter` class that converts the type to YAML-serializable objects and back again. See :ref:`extending_converters` for a discussion of the Converter interface. Refer to the schema to ensure that the Converter is writing YAML objects correctly. 7. Implement an `~asdf.extension.Extension` class which is the vehicle for plugging our converter into the `asdf` library. See :ref:`extending_extensions` for a discussion of the Extension interface. We'll need to associate the schema URI with the tag URI in our tag's `~asdf.extension.TagDefinition` object. 8. Install the extension via an entry point. See :ref:`extending_extensions_installing_entry_points`. Now anyone who installs the package containing the entry points will be able to read, write, and validate ASDF files containing our new tag! For sharing with users of other languages ----------------------------------------- Finally, let's consider the case where we want to serialize instances of our type to an ASDF file that will be read using ASDF libraries written in other languages. The problem with our previous efforts is that the extension definition exists only as Python code, so here we'll want to create an additional YAML document called an extension manifest that defines the extension in a language-independent way. 1. Identify the Python type to serialize. We'll need to know the fully-qualified name of the type (module path + class name). 2. Select a tag URI that will signify the type in YAML. See :ref:`extending_uris_entities_tags` for recommendations on tag URI structure. 3. Designate a URI for the schema. See :ref:`extending_uris_entities_schemas` for recommendations on schema URI structure. 4. Write the schema that will validate the tagged object. See :ref:`extending_schemas` if you're new to authoring schemas. 5. Write an extension manifest document that describes the tag and schema that we're including in our extension. See :ref:`extending_manifests` for information on the manifest format. 5. Make the schema and manifest installable as `asdf` library resources. See :ref:`extending_resources` for an overview of resources in `asdf` and :ref:`extending_resources_entry_points` for information on installing resources via an entry point. 6. Implement a `~asdf.extension.Converter` class that converts the type to YAML-serializable objects and back again. See :ref:`extending_converters` for a discussion of the Converter interface. Refer to the schema to ensure that the Converter is writing YAML objects correctly. 7. Use `asdf.extension.ManifestExtension.from_uri` to populate an extension with the Converter and information from the manifest document. See :ref:`extending_extensions_manifest` for instructions on using ManifestExtension. 8. Install the extension via an entry point. See :ref:`extending_extensions_installing_entry_points`. That's it! Python users should experience the same convenience, but now the manifest document is available as a reference for developers who wish to implement support for reading our tagged objects in their language of choice. Support a new block compressor ============================== In order to support a new compression algorithm for ASDF binary blocks, we need to implement the `~asdf.extension.Compressor` interface and install that in an extension. 1. Select a 4-byte compression code that will signify the compression algorithm. 1. Implement a `~asdf.extension.Compressor` class that associates the 4-byte code with compression and decompression methods. See :ref:`extending_compressors` for a discussion of the Compressor interface. 2. Implement an `~asdf.extension.Extension` class which is the vehicle for plugging our compressor into the `asdf` library. See :ref:`extending_extensions` for a discussion of the Extension interface. 3. Install the extension via one of the two available methods. See :ref:`extending_extensions_installing` for instructions. Now the compression algorithm will be available for both reading and writing ASDF files. Users writing files will simply need to specify the new 4-byte compression code when making calls to `asdf.AsdfFile.set_array_compression`. Support a new schema property ============================= In order to support custom validation behavior that is triggered by a new schema property, we need to implement the `~asdf.extension.Validator` interface and install that in an extension. 1. Determine the tag or tags that this property will apply to. 2. Select a schema property for the validator. The property need not be globally unique, but it should be unique among the validators that apply to the tag(s), and must not collide with any of the built-in JSON schema properties (type, additionalProperties, etc). 3. Implement a `~asdf.extension.Validator` class that associates the schema property and tag(s) with a ``validate`` method that does the work of checking an ADSF node against the schema. 4. Implement an `~asdf.extension.Extension` class which is the vehicle for plugging our validator into the `asdf` library. See :ref:`extending_extensions` for a discussion of the Extension interface. 5. Install the extension via one of the two available methods. See :ref:`extending_extensions_installing` for instructions. Now the new schema property will have an effect when validating ASDF files. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/extending/validators.rst0000644000175100001770000000563314653725311020612 0ustar00runnerdocker.. currentmodule:: asdf.extension .. _extending_validators: ========== Validators ========== The `~asdf.extension.Validator` interface provides support for a custom ASDF schema property. The Validator identifies the schema property and tag(s) that it works on and provides a method for doing the work of validation. The Validator interface ======================= Every Validator implementation must provide two required properties and one required method: `Validator.schema_property` - The schema property that triggers this validator. The property need not be globally unique, but it should be unique among the validators that apply to the tag(s), and must not collide with any of the built-in JSON schema properties (type, additionalProperties, etc). `Validator.tags` - a list of tag URIs or URI patterns handled by the validator. Patterns may include the wildcard character ``*``, which matches any sequence of characters up to a ``/``, or ``**``, which matches any sequence of characters. The `~asdf.util.uri_match` method can be used to test URI patterns. `Validator.validate` - a method that accepts the schema property value, a tagged ASDF node, and the surrounding schema dict, and performs validation on the node. For every error present, the method should yield an instance of ``asdf.exceptions.ValidationError``. A simple example ================ Say we have a custom tagged object, ``asdf://example.com/example-project/tags/rectangle-1.0.0``, which describes a rectangle with ``width`` and ``height`` properties. Let's implement a validator that checks that the area of the rectangle is less than some maximum value. The schema property will be called ``max_area``, so our validator will look like this: .. code-block:: python from asdf.extension import Validator from asdf.exceptions import ValidationError class MaxAreaValidator(Validator): schema_property = "max_area" tags = ["asdf://example.com/example-project/tags/rectangle-1.0.0"] def validate(self, max_area, node, schema): area = node["width"] * node["height"] if area > max_area: yield ValidationError( f"Rectangle with area {area} exceeds max area of {max_area}" ) Note that the validator operates on raw ASDF tagged nodes, and not the custom Python object that they'll be converted to. In order to use this Validator, we'll need to create a simple extension around it and install that extension: .. code-block:: python import asdf from asdf.extension import Extension class ShapesExtension(Extension): extension_uri = "asdf://example.com/shapes/extensions/shapes-1.0.0" validators = [MaxAreaValidator()] tags = ["asdf://example.com/shapes/tags/rectangle-1.0.0"] asdf.get_config().add_extension(ShapesExtension()) Now we can include a ``max_area`` property in a schema and have it restrict the area of a rectangle. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/features.rst0000644000175100001770000006173714653725311016302 0ustar00runnerdocker.. currentmodule:: asdf ************* Core Features ************* This section discusses the core features of the ASDF data format, and provides examples and use cases that are specific to the Python implementation. .. _data-model: Data Model ========== The fundamental data object in ASDF is the ``tree``, which is a nested combination of basic data structures: dictionaries, lists, strings and numbers. In Python, these types correspond to :class:`dict`, :class:`list`, :class:`str`, and :class:`int`, :class:`float`, and :class:`complex`, respectively. The top-level tree object behaves like a Python dictionary and supports arbitrary nesting of data structures. For simple examples of creating and reading trees, see :ref:`overview`. .. note:: The ASDF Standard imposes a maximum size of 64-bit signed integers literals in the tree (see :ref:`asdf-standard:literal_integers` for details and justification). Attempting to store a larger value as a YAML literal will result in a validation error. For arbitrary precision integer support, see `IntegerType`. Integers and floats of up to 64 bits can be stored inside of :mod:`numpy` arrays (see below). .. note:: The ASDF standard does not have an immutable sequence type that maps directly to Python's :class:`tuple`. Following the behavior of pyyaml, asdf writes tuples as YAML sequences, which when loaded are converted to lists. If round-tripping of tuples is important to your application see the :ref:`extending` to write a custom extension to save and load tuples. One of the key features of `asdf` is its ability to serialize :mod:`numpy` arrays. This is discussed in detail in :ref:`array-data`. While the core `asdf` package supports serialization of basic data types and Numpy arrays, its true power comes from its ability to be extended to support serialization of a wide range of custom data types. Details on using ASDF extensions can be found in :ref:`using_extensions`. Details on creating custom ASDF extensions to support custom data types can be found in :ref:`extending`. .. _array-data: Array Data ========== Much of ASDF's power and convenience comes from its ability to represent multidimensional array data. The :mod:`asdf` Python package provides native support for :mod:`numpy` arrays. .. toctree:: :maxdepth: 2 arrays .. _using_extensions: Using extensions ================ According to Wikipedia, serialization "is the process of translating data structures or object state into a format that can be stored...and reconstructed later" [#wiki]_. The power of ASDF is that it provides the ability to store, or serialize, the state of Python objects into a *human-readable* data format. The state of those objects can later be restored by another program in a process called deserialization. While ASDF is capable of serializing basic Python types and Numpy arrays out of the box, it can also be extended to serialize arbitrary custom data types. This section discusses the extension mechanism from a user's perspective. For documentation on creating extensions, see :ref:`extending_extensions`. Even though this particular implementation of ASDF necessarily serializes Python data types, in theory an ASDF implementation in another language could read the resulting file and reconstruct an analogous type in that language. Conversely, this implementation can read ASDF files that were written by other implementations of ASDF as long as the proper extensions are available. .. toctree:: :maxdepth: 2 using_extensions .. _schema_validation: Schema validation ================= Schema validation is used to determine whether an ASDF file is well formed. All ASDF files must conform to the schemas defined by the :ref:`ASDF Standard `. Schema validation can be run using `AsdfFile.validate` and occurs when reading ASDF files (using `asdf.open`) and writing them out (using `AsdfFile.write_to` or `AsdfFile.update`). Schema validation also plays a role when using custom extensions (see :ref:`using_extensions` and :ref:`extending_extensions`). Extensions must provide schemas for the types that they serialize. When writing a file with custom types, the output is validated against the schemas corresponding to those types. If the appropriate extension is installed when reading a file with custom types, then the types will be validated against the schemas provided by the corresponding extension. .. _custom-schemas: Custom schemas -------------- Every ASDF file is validated against the ASDF Standard, and also against any schemas provided by custom extensions. However, it is sometimes useful for particular applications to impose additional restrictions when deciding whether a given file is valid or not. For example, consider an application that processes digital image data. The application expects the file to contain an image, and also some metadata about how the image was created. The following example schema reflects these expectations: .. code:: yaml %YAML 1.1 --- id: "http://example.com/schemas/your-custom-schema" $schema: "http://stsci.edu/schemas/yaml-schema/draft-01" type: object properties: image: description: An ndarray containing image data. $ref: "ndarray-1.0.0" metadata: type: object description: Metadata about the image properties: time: description: | A timestamp for when the image was created, in UTC. type: string format: date-time resolution: description: | A 2D array representing the resolution of the image (N x M). type: array items: type: integer number: 2 required: [image, metadata] additionalProperties: true This schema restricts the kinds of files that will be accepted as valid to those that contain a top-level ``image`` property that is an ``ndarray``, and a top-level ``metadata`` property that contains information about the time the image was taken and the resolution of the image. In order to use this schema for a secondary validation pass, we pass the ``custom_schema`` argument to either `asdf.open` or the `AsdfFile` constructor. Assume that the schema file lives in ``image_schema.yaml``, and we wish to open a file called ``image.asdf``. We would open the file with the following code: .. code:: import asdf af = asdf.open('image.asdf', custom_schema='image_schema.yaml') Similarly, if we wished to use this schema when creating new files: .. code:: new_af = asdf.AsdfFile(custom_schema='image_schema.yaml') ... If your custom schema is registered with ASDF in an extension, you may pass the schema URI (``http://example.com/schemas/your-custom-schema``, in this case) instead of a file path. .. _top-level core schema: .. note:: The top-level core schemas can be found :ref:`here `. .. _version_and_compat: Versioning and Compatibility ============================ There are several different versions to keep in mind when discussing ASDF: * The software package version * The ASDF Standard version * The ASDF file format version * Individual tag, schema, and extension versions Each ASDF file contains information about the various versions that were used to create the file. The most important of these are the ASDF Standard version and the ASDF file format version. A particular version of the ASDF software package will explicitly provide support for specific combinations of these versions. Tag, schema, and extension versions are also important for serializing and deserializing data types that are stored in ASDF files. A detailed discussion of these versions from a user perspective can be found in :ref:`custom_type_versions`. Since ASDF is designed to serve as an archival format, this library is careful to maintain backwards compatibility with older versions of the ASDF Standard, ASDF file format, and core tags. However, since deserializing custom tags requires other software packages, backwards compatibility is often contingent on the available versions of such software packages. In general, forward compatibility with newer versions of the ASDF Standard and ASDF file format is not supported by the software. When creating new ASDF files, it is possible to control the version of the ASDF standard that is used. This can be specified by passing the ``version`` argument to either the `AsdfFile` constructor when the file object is created, or to the `AsdfFile.write_to` method when it is written. By default, the latest stable version of the ASDF standard will be used. .. warning:: Take care when providing ``version`` to `AsdfFile.write_to` to select a version that is stable. Writing files with a ``development`` (unstable) version may produce files that will become unreadable as that version evolves. The default version will always be stable and is often the best choice unless you are trying to write out a file that is readable by older software (where you will want to use an older, stable version). External References =================== Tree References --------------- ASDF files may reference items in the tree in other ASDF files. The syntax used in the file for this is called "JSON Pointer", but users of `asdf` can largely ignore that. First, we'll create a ASDF file with a couple of arrays in it: .. runcode:: import asdf from asdf import AsdfFile import numpy as np tree = { 'a': np.arange(0, 10), 'b': np.arange(10, 20) } target = AsdfFile(tree) target.write_to('target.asdf') .. asdf:: target.asdf Then we will reference those arrays in a couple of different ways. First, we'll load the source file in Python and use the ``make_reference`` method to generate a reference to array ``a``. Second, we'll work at the lower level by manually writing a JSON Pointer to array ``b``, which doesn't require loading or having access to the target file. .. runcode:: ff = AsdfFile() with asdf.open('target.asdf') as target: ff.tree['my_ref_a'] = target.make_reference(['a']) ff.tree['my_ref_b'] = {'$ref': 'target.asdf#b'} ff.write_to('source.asdf') .. asdf:: source.asdf Calling `~asdf.AsdfFile.find_references` will look up all of the references so they can be used as if they were local to the tree. It doesn't actually move any of the data, and keeps the references as references. .. runcode:: with asdf.open('source.asdf') as ff: ff.find_references() assert ff.tree['my_ref_b'].shape == (10,) On the other hand, calling `~asdf.AsdfFile.resolve_references` places all of the referenced content directly in the tree, so when we write it out again, all of the external references are gone, with the literal content in its place. .. runcode:: with asdf.open('source.asdf') as ff: ff.resolve_references() ff.write_to('resolved.asdf') .. asdf:: resolved.asdf A similar feature provided by YAML, anchors and aliases, also provides a way to support references within the same file. These are supported by `asdf`, however the JSON Pointer approach is generally favored because: - It is possible to reference elements in another file - Elements are referenced by location in the tree, not an identifier, therefore, everything can be referenced. Anchors and aliases are handled automatically by `asdf` when the data structure is recursive. For example here is a dictionary that is included twice in the same tree: .. runcode:: d = {'foo': 'bar'} d['baz'] = d tree = {'d': d} ff = AsdfFile(tree) ff.write_to('anchors.asdf') .. asdf:: anchors.asdf .. _array-references: Array References ---------------- ASDF files can refer to array data that is stored in other files using the `ExternalArrayReference` type. External files need not be ASDF files: ASDF is completely agnostic as to the format of the external file. The ASDF external array reference does not define how the external data file will be resolved; in fact it does not even check for the existence of the external file. It simply provides a way for ASDF files to refer to arrays that exist in external files. Creating an external array reference is simple. Only four pieces of information are required: * The name of the external file. Since ASDF does not itself resolve the file or check for its existence, the format of the name is not important. In most cases the name will be a path relative to the ASDF file itself, or a URI for a network resource. * The data type of the array data. This is a string representing any valid `numpy.dtype`. * The shape of the data array. This is a tuple representing the dimensions of the array data. * The array data ``target``. This is either an integer or a string that indicates to the user something about how the data array should be accessed in the external file. For example, if there are multiple data arrays in the external file, the ``target`` might be an integer index. Or if the external file is an ASDF file, the ``target`` might be a string indicating the key to use in the external file's tree. The value and format of the ``target`` field is completely arbitrary since ASDF will not use it itself. As an example, we will create a reference to an external CSV file. We will assume that one of the rows of the CSV file contains the array data we care about: .. runcode:: import asdf csv_data_row = 10 # The row of the CSV file containing the data we want csv_row_size = 100 # The size of the array extref = asdf.ExternalArrayReference('data.csv', csv_data_row, "int64", (csv_row_size,)) tree = {'csv_data': extref} af = asdf.AsdfFile(tree) af.write_to('external_array.asdf') .. asdf:: external_array.asdf When reading a file containing external references, the user is responsible for using the information in the `ExternalArrayReference` type to open the external file and retrieve the associated array data. Saving history entries ====================== `asdf` has a convenience method for notating the history of transformations that have been performed on a file. Given a `~asdf.AsdfFile` object, call `~asdf.AsdfFile.add_history_entry`, given a description of the change and optionally a description of the software (i.e. your software, not `asdf`) that performed the operation. .. runcode:: from asdf import AsdfFile import numpy as np tree = { 'a': np.random.rand(32, 32) } ff = AsdfFile(tree) ff.add_history_entry( "Initial random numbers", {'name': 'asdf examples', 'author': 'John Q. Public', 'homepage': 'http://github.com/asdf-format/asdf', 'version': '0.1'}) ff.write_to('example.asdf') .. asdf:: example.asdf `asdf` automatically saves history metadata about the extensions that were used to create the file. This information is used when opening files to determine if the proper extensions are installed (see :ref:`extension_checking` for more details). .. rubric:: Footnotes .. [#wiki] https://en.wikipedia.org/wiki/Serialization Rendering ASDF trees ==================== The `asdf.info` function prints a representation of an ASDF tree to stdout. For example: .. code:: pycon >>> asdf.info("path/to/some/file.asdf") # doctest: +SKIP root (AsdfObject) ├─asdf_library (Software) │ ├─author (str): The ASDF Developers │ ├─homepage (str): http://github.com/asdf-format/asdf │ ├─name (str): asdf │ └─version (str): 2.5.1 ├─history (dict) │ └─extensions (list) ... └─data (dict) └─example_key (str): example value The first argument may be a ``str`` or ``pathlib.Path`` filesystem path, or an `AsdfFile` or sub-node of an ASDF tree. By default, `asdf.info` limits the number of lines, and line length, of the displayed tree. The ``max_rows`` parameter controls the number of lines, and ``max_cols`` controls the line length. Set either to ``None`` to disable that limit. An integer ``max_rows`` will be interpreted as an overall limit on the number of displayed lines. If ``max_rows`` is a tuple, then each member limits lines per node at the depth corresponding to its tuple index. For example, to show all top-level nodes and 5 of each's children: If the attribute is described in a schema, the info functionality will see if it has an associated title and if it does, display it as a comment on the same line. This provides a way for users to see more information about the the attribute in a similar way that FITS header comments are used. .. code:: pycon >>> asdf.info("file.asdf", max_rows=(None, 5)) # doctest: +SKIP The `AsdfFile.info` method behaves similarly to `asdf.info`, rendering the tree of the associated `AsdfFile`. Normally `asdf.info` will not show the contents of asdf nodes turned into Python custom objects, but if that object supports a special method, you may see the contents of such objects. See :ref:`exposing_extension_object_internals` for how to implement such support for `asdf.info` and `asdf.search`. Searching the ASDF tree ======================= The `AsdfFile` search interface provides a way to interactively discover the locations and values of nodes within the ASDF tree. We can search for nodes by key/index, type, or value. Basic usage ----------- Initiate a search by calling `AsdfFile.search` on an open file: .. code:: pycon >>> af.search() # doctest: +SKIP root (AsdfObject) ├─asdf_library (Software) │ ├─author (str): The ASDF Developers │ ├─homepage (str): http://github.com/asdf-format/asdf │ ├─name (str): asdf │ └─version (str): 2.5.1 ├─history (dict) │ └─extensions (list) ... └─data (dict) └─example_key (str): example value >>> af.search("example") # doctest: +SKIP root (AsdfObject) └─data (dict) └─example_key (str): example value .. currentmodule:: asdf.search The search returns an `AsdfSearchResult` object that displays in the Python console as a rendered tree. For single-node search results, the `AsdfSearchResult.path` property contains the Python code required to reference that node directly: .. code:: pycon >>> af.search("example").path # doctest: +SKIP "root['data']['example_key']" While the `AsdfSearchResult.node` property contains the actual value of the node: .. code:: pycon >>> af.search("example").node # doctest: +SKIP 'example value' For searches with multiple matching nodes, use the `AsdfSearchResult.paths` and `AsdfSearchResult.nodes` properties instead: .. code:: pycon >>> af.search("duplicate_key").paths # doctest: +SKIP ["root['data']['duplicate_key']", "root['other_data']['duplicate_key']"] >>> af.search("duplicate_key").nodes # doctest: +SKIP ["value 1", "value 2"] To replace matching nodes with a new value, use the `AsdfSearchResult.replace` method: .. code:: pycon >>> af.search("example").replace("replacement value") # doctest: +SKIP >>> af.search("example").node # doctest: +SKIP 'replacement value' .. currentmodule:: asdf The first argument to `AsdfFile.search` searches by dict key or list/tuple index. We can also search by type, value, or any combination thereof: .. code:: pycon >>> af.search("foo") # Find nodes with key containing the string 'foo' # doctest: +SKIP >>> af.search(type=int) # Find nodes that are instances of int # doctest: +SKIP >>> af.search(value=10) # Find nodes whose value is equal to 10 # doctest: +SKIP >>> af.search( ... "foo", type=int, value=10 ... ) # Find the intersection of the above # doctest: +SKIP Chaining searches ----------------- The return value of `AsdfFile.search`, `asdf.search.AsdfSearchResult`, has its own search method, so it's possible to chain searches together. This is useful when you need to see intermediate results before deciding how to further narrow the search. .. code:: pycon >>> af.search() # See an overview of the entire ASDF tree # doctest: +SKIP >>> af.search().search(type="NDArrayType") # Find only ndarrays # doctest: +SKIP >>> af.search().search(type="NDArrayType").search( ... "err" ... ) # Only ndarrays with 'err' in the key # doctest: +SKIP Descending into child nodes --------------------------- Another way to narrow the search is to use the index operator to descend into a child node of the current tree root: .. code:: pycon >>> af.search()["data"] # Restrict search to the 'data' child # doctest: +SKIP >>> af.search()["data"].search( ... type=int ... ) # Find integer descendants of 'data' # doctest: +SKIP Regular expression searches --------------------------- Any string argument to search is interpreted as a regular expression. For example, we can search for nodes whose keys start with a particular string: .. code:: pycon >>> af.search("foo") # Find nodes with 'foo' anywhere in the key # doctest: +SKIP >>> af.search("^foo") # Find only nodes whose keys start with 'foo' # doctest: +SKIP Note that all node keys (even list indices) will be converted to string before the regular expression is matched: .. code:: pycon >>> af.search("^7$") # Returns all nodes with key '7' or index 7 # doctest: +SKIP When the ``type`` argument is a string, the search compares against the fully-qualified class name of each node: .. code:: pycon >>> af.search( ... type="asdf.tags.core.Software" ... ) # Find instances of ASDF's Software type # doctest: +SKIP >>> af.search(type="^asdf\.") # Find all ASDF objects # doctest: +SKIP When the ``value`` argument is a string, the search compares against the string representation of each node's value. .. code:: pycon >>> af.search( ... value="^[0-9]{4}-[0-9]{2}-[0-9]{2}$" ... ) # Find values that look like dates # doctest: +SKIP Arbitrary search criteria ------------------------- If ``key``, ``type``, and ``value`` aren't sufficient, we can also provide a callback function to search by arbitrary criteria. The ``filter`` parameter accepts a callable that receives the node under consideration, and returns ``True`` to keep it or ``False`` to reject it from the search results. For example, to search for NDArrayType with a particular shape: .. code:: pycon >>> af.search(type="NDArrayType", filter=lambda n: n.shape[0] == 1024) # doctest: +SKIP Formatting search results ------------------------- .. currentmodule:: asdf.search The `AsdfSearchResult` object displays its content as a rendered tree with reasonable defaults for maximum number of lines and columns displayed. To change those values, we call `AsdfSearchResult.format`: .. code:: pycon >>> af.search(type=float) # Displays limited rows # doctest: +SKIP >>> af.search(type=float).format(max_rows=None) # Show all matching rows # doctest: +SKIP Like `AsdfSearchResult.search`, calls to format may be chained: .. code:: pycon >>> af.search("time").format(max_rows=10).search(type=str).format( ... max_rows=None ... ) # doctest: +SKIP Searching Schema information ============================ In some cases, one may wish to include information and/or documentation about an object defined by a tagged schema within the schema itself. It can be useful to directly access this information relative to a given ASDF file. For example one may wish to examine: * The ``title`` of a value to get a short description of it. * The ``description`` of a value to get the longer description of it. In other cases, it maybe useful to store general descriptive information such as specific archival information about a given value in the file so that an archive can easily ingest the file into the archive, such as what is done with the ``archive_catalog`` information in the `rad schemas `_ for the Nancy Grace Roman Space Telescope. .. currentmodule:: asdf The `AsdfFile.schema_info` method provides a way to access this information. This method returns a nested tree of dictionaries which contains tuples consisting of the information from the schema requested together with the value stored in the ASDF file itself. One needs to provide a ``key``, which corresponds the to the keyword the information is stored under inside the schema, by default this is ``description``. One can also provide a ``path`` in the form of a dot-separated string of the keys in the ASDF file that lead to the value(s) of interest. For example: .. code:: pycon >>> af.schema_info("archive_catalog", "foo.bar") # doctest: +SKIP {'thing1': {'archive_catalog': 'Thing 1 Archive catalog information'}, 'thing2': {'archive_catalog': 'Thing 2 Archive catalog information'}} Or one can provide a ``path`` as an `asdf.search.AsdfSearchResult` object: .. code:: pycon >>> af.schema_info("archive_catalog", af.search("bar")) # doctest: +SKIP {'thing1': {'archive_catalog': 'Thing 1 Archive catalog information'}, 'thing2': {'archive_catalog': 'Thing 2 Archive catalog information'}} .. note:: The there is also the `asdf.search.AsdfSearchResult.schema_info` method, which can be directly called on an `asdf.search.AsdfSearchResult` object. instead of having to pass the search through `AsdfFile.schema_info`. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/install.rst0000644000175100001770000000330314653725311016113 0ustar00runnerdocker.. _installation: ************ Installation ************ There are several different ways to install the `asdf` package. Each is described in detail below. Requirements ============ The `asdf` package has several dependencies which are listed in the project's build configuration ``pyproject.toml``. All dependencies are available on pypi and will be automatically installed along with `asdf`. Support for units, time, and transform tags requires an implementation of these types. One recommended option is the `asdf-astropy `__ package. Optional support for `lz4 `__ compression is provided by the `lz4 `__ package. Installing with pip =================== .. include:: ../../README.rst :start-after: begin-pip-install-text: :end-before: begin-source-install-text: Installing with conda ===================== `asdf` is also distributed as a `conda `__ package via the `conda-forge `__ channel. It is also available through the `astroconda `__ channel. To install `asdf` within an existing conda environment:: $ conda install -c conda-forge asdf To create a new conda environment and install `asdf`:: $ conda create -n new-env-name -c conda-forge python asdf Building from source ==================== .. include:: ../../README.rst :start-after: begin-source-install-text: :end-before: end-source-install-text: Running the tests ================= .. include:: ../../README.rst :start-after: begin-testing-text: :end-before: end-testing-text: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/overview.rst0000644000175100001770000000433114653725311016315 0ustar00runnerdocker.. currentmodule:: asdf .. _overview: ******** Overview ******** Let's start by taking a look at a few basic ASDF use cases. This will introduce you to some of the core features of ASDF and will show you how to get started with using ASDF in your own projects. To follow along with this tutorial, you will need to install the :mod:`asdf` package. See :ref:`installation` for details. Hello World =========== At its core, ASDF is a way of saving nested data structures to YAML. Here we save a :class:`dict` with the key/value pair ``'hello': 'world'``. .. runcode:: from asdf import AsdfFile # Make the tree structure, and create a AsdfFile from it. tree = {'hello': 'world'} ff = AsdfFile(tree) ff.write_to("test.asdf") # You can also make the AsdfFile first, and modify its tree directly: ff = AsdfFile() ff.tree['hello'] = 'world' ff.write_to("test.asdf") .. asdf:: test.asdf Creating Files ============== .. runcode:: hidden import asdf import numpy as np # Create some data sequence = np.arange(100) squares = sequence**2 random = np.random.random(100) # Store the data in an arbitrarily nested dictionary tree = { 'foo': 42, 'name': 'Monty', 'sequence': sequence, 'powers': { 'squares' : squares }, 'random': random } # Create the ASDF file object from our data tree af = asdf.AsdfFile(tree) # Write the data to a new file af.write_to('example.asdf') .. include:: ../../README.rst :start-after: begin-create-file-text: :end-before: begin-example-asdf-metadata: .. asdf:: example.asdf no_blocks .. include:: ../../README.rst :start-after: end-example-asdf-metadata: :end-before: end-create-file-text: A rendering of the binary data contained in the file can be found below. Observe that the value of ``source`` in the metadata corresponds to the block number (e.g. ``BLOCK 0``) of the block which contains the binary data. .. asdf:: example.asdf no_header .. include:: ../../README.rst :start-after: _begin-compress-file: :end-before: _end-compress-file: Reading Files ============= .. include:: ../../README.rst :start-after: begin-read-file-text: :end-before: end-read-file-text: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/release_and_support.rst0000644000175100001770000000752114653725311020511 0ustar00runnerdocker.. currentmodule:: asdf .. _release_and_support: ************************************************* Release Cycle and Major Dependency Support Policy ************************************************* This document describes a general plan for releasing the ASDF library, along with how long we intend to support each release. Moreover, it also describes our policy for how long we plan to support versions of CPython and NumPy. Note that this is a living document, and may be updated at any time. .. _backwards_compatibility: Backwards Compatibility and Semantic Versioning =============================================== ASDF will maintain a backwards compatible API for all minor and patch versions. Any breaking API changes will only be included in major releases (where the major version number will be increased). We follow `Semantic Versioning `_. .. note:: We are planning to clean up the public API following the 2.15 release. We will attempt to do so with the smallest number of major version changes. If there are portions of the ASDF API that you are using that are not documented in the :ref:`user_api` or :ref:`developer_api` please `open an issue `_. .. _release_cycle: Release Cycle ============= As ASDF is still under active development, it will continue to be developed on a rolling release cycle. This means that ASDF will not have a fixed release schedule, but rather will be released as needed. .. _dependency_support_policy: Dependency Support Policy ========================= ASDF primarily depends on CPython and NumPy. As a scientific Python library, we have chosen to abide by the policy laid out in `NEP 29 `_. The following table summarizes this policy: ============ ====== ===== Date Python NumPy ------------ ------ ----- Jan 31, 2023 3.8+ 1.21+ Apr 14, 2023 3.9+ 1.21+ Jun 23, 2023 3.9+ 1.22+ Jan 01, 2024 3.9+ 1.23+ Apr 05, 2024 3.10+ 1.23+ Jun 22, 2024 3.10+ 1.24+ Dec 18, 2024 3.10+ 1.25+ Apr 04, 2025 3.11+ 1.25+ Apr 24, 2026 3.12+ 1.25+ ============ ====== ===== .. _drop_schedule: CPython and NumPy Drop Schedule ------------------------------- :: On Jan 31, 2023 drop support for NumPy 1.20 (initially released on Jan 31, 2021) On Apr 14, 2023 drop support for Python 3.8 (initially released on Oct 14, 2019) On Jun 23, 2023 drop support for NumPy 1.21 (initially released on Jun 22, 2021) On Jan 01, 2024 drop support for NumPy 1.22 (initially released on Dec 31, 2021) On Apr 05, 2024 drop support for Python 3.9 (initially released on Oct 05, 2020) On Jun 22, 2024 drop support for NumPy 1.23 (initially released on Jun 22, 2022) On Dec 18, 2024 drop support for NumPy 1.24 (initially released on Dec 18, 2022) On Apr 04, 2025 drop support for Python 3.10 (initially released on Oct 04, 2021) On Apr 24, 2026 drop support for Python 3.11 (initially released on Oct 24, 2022) .. _support_for_other_dependencies: Support for Other Dependencies ------------------------------ ASDF also depends on several other Python packages. We currently do not have a formal policy for how long we intend to support these dependencies. However, we will try to support as many versions of these dependencies as possible. In general, we will pin each of these dependencies from below with the oldest version that we guarantee will work with ASDF. We will also try to test against the latest version of each of these dependencies and release bugfixes to supported versions of ASDF on an as-needed basis. We will try our best to announce when we need to bump the support of these dependencies, and will always record doing so (and why) in the changelog. If you find any issues with ASDF dependencies which affect a currently-supported version of ASDF, please open an issue in the ASDF repository. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/user_api.rst0000644000175100001770000000036614653725311016262 0ustar00runnerdocker.. _user_api: ******** User API ******** .. automodapi:: asdf :include-all-objects: :inherited-members: :no-inheritance-diagram: :skip: ValidationError :skip: Stream .. automodapi:: asdf.search .. automodapi:: asdf.config ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/using_extensions.rst0000644000175100001770000002171514653725311020060 0ustar00runnerdocker.. currentmodule:: asdf The built-in extension ---------------------- The ability to serialize the following types is provided by `asdf`'s built-in extension: * `dict` * `list` * `str` * `int` * `float` * `complex` * `numpy.ndarray` The built-in extension is packaged with `asdf` and is automatically used when reading and writing files. Users can not control the use of the built-in extension and in general they need not concern themselves with the details of its implementation. However, it is useful to be aware that the built-in extension is always in effect when reading and writing ASDF files. Custom types ------------ For the purposes of this documentation, a "custom type" is any data type that can not be serialized by the built-in extension. In order for a particular custom type to be serialized, a special class called a "converter" must be implemented. Each converter defines how the corresponding custom type will be serialized and deserialized. More details on how converters are implemented can be found in :ref:`extending_converters`. Users should never have to refer to converter implementations directly; they simply enable `asdf` to recognize and process custom types. In addition to converters, each custom type may have a corresponding schema, which is used for validation. The definition of the schema if present is closely tied to the definition of the converter. More details on schema validation can be found in :ref:`schema_validation`. Schemas are generally versioned and change in sync with their associated converters. The version number will increase whenever a schema (and therefore the converter implementation) changes. Extensions ---------- In order for the converters and schemas to be used by `asdf`, they must be packaged into an **extension** class. In general, the details of extensions are irrelevant to users of `asdf`. However, users need to be aware of extensions in the following two scenarios: * when storing custom data types to files to be written * when reading files that contain custom data types These scenarios require the use of custom extensions (the built-in extension is always used). There are two ways to use custom extensions, which are detailed below in :ref:`other_packages` and :ref:`explicit_extensions`. Writing custom types to files ***************************** `asdf` is not capable of serializing any custom type unless an extension is provided that defines how to serialize that type. Attempting to do so will cause an error when trying to write the file. For details on developing support for custom types and extensions, see :ref:`extending_extensions`. .. _reading_custom_types: Reading files with custom types ******************************* The `asdf` software is capable of reading files that contain custom data types even if the extension that was used to create the file is not present. However, the extension is required in order to properly deserialize the original type. If the necessary extension is **not** present, the custom data types will simply appear in the tree as a nested combination of basic data types. The structure of this data will mirror the structure of the YAML objects in the ASDF file. In this case, a warning will occur by default to indicate to the user that the custom type in the file was not recognized and can not be deserialized. To suppress these warnings, users should pass ``ignore_unrecognized_tag=True`` to `asdf.open`. Even if an extension for the custom type is present, it does not guarantee that the type can be deserialized successfully. Instantiating the custom type may involve additional software dependencies, which, if not present, will cause an error when the type is deserialized. Users should be aware of the dependencies that are required for instantiating custom types when reading ASDF files. .. _custom_type_versions: Custom types, extensions, and versioning ---------------------------------------- Tags and schemas that follow best practices are versioned. This allows changes to tags and schemas to be recorded, and it allows `asdf` to define behavior with respect to version compatibility. Tag and schema versions may change for several reasons. One common reason is to reflect a change to the API of the custom type that a tag represents. This typically corresponds to an update to the version of the software that defines that custom type. Since ASDF is designed to be an archival file format, extension authors are encouraged to maintain backwards compatibility with all older tag versions. Reading files ************* When `asdf` encounters a tagged object in a file, it will compare the URI of the tag in the file with the list of tags handled by available converters. The first matching converter will be selected to deserialize the object. If no such converters exist, the library will emit a warning and the object will be presented to the user in its primitive form. If multiple converters are present that both handle the same tag, the first found by the library will be used. Users may disable a converter by removing its extension with the `~asdf.config.AsdfConfig.remove_extension` method. Writing files ************* When writing a object to a file, `asdf` compares the object's type to the list of types handled by available converters. The first matching converter will be selected to serialize the object. If no such converters exist, the library will raise an error. If multiple converters are present that both handle the same type, the first found by the library will be used. Users may disable a converter by removing its extension with the `~asdf.config.AsdfConfig.remove_extension` method. .. _other_packages: Extensions from other packages ------------------------------ Some external packages may define extensions that allow `asdf` to recognize some or all of the types that are defined by that package. Such packages may install the extension class as part of the package itself (details for developers can be found in :ref:`extending_extensions_installing_entry_points`). If the package installs its extension, then `asdf` will automatically detect the extension and use it when processing any files. No specific action is required by the user in order to successfully read and write custom types defined by the extension for that particular package. Users can use the ``extensions`` command of the ``asdftool`` command line tool in order to determine which packages in the current Python environment have installed ASDF extensions: .. code-block:: none $ asdftool extensions -s Extension Name: 'bizbaz' (from bizbaz 1.2.3) Class: bizbaz.io.asdf.extension.BizbazExtension Extension Name: 'builtin' (from asdf 2.0.0) Class: asdf.extension.BuiltinExtension The output will always include the built-in extension, but may also display other extensions from other packages, depending on what is installed. .. _explicit_extensions: Explicit use of extensions -------------------------- Sometimes no packaged extensions are provided for the types you wish to serialize. In this case, it is necessary to explicitly install any necessary extension classes when reading and writing files that contain custom types. The config object returned from `asdf.get_config` offers an `~asdf.config.AsdfConfig.add_extension` method that can be used to install an extension for the remainder of the current Python session. Consider the following example where there exists a custom type ``MyCustomType`` that needs to be written to a file. An extension is defined ``MyCustomExtension`` that contains a converter that can serialize and deserialize ``MyCustomType``. Since ``MyCustomExtension`` is not installed by any package, we will need to manually install it: .. code-block:: python import asdf ... asdf.get_config().add_extension(MyCustomExtension()) af = asdf.AsdfFile() af.tree = {"thing": MyCustomType("foo")} # This call would cause an error if the proper extension was not # provided to the constructor af.write_to("custom.asdf") Note that the extension class must actually be instantiated when it is passed to `~asdf.config.AsdfConfig.add_extension`. To read the file (in a new session) we again need to install the extension first: .. code-block:: python import asdf asdf.get_config().add_extension(MyCustomExtension()) af = asdf.open("custom.asdf") .. _extension_checking: Extension checking ------------------ When writing ASDF files using this software, metadata about the extensions that were used to create the file will be added to the file itself. This includes the extension's URI, which uniquely identifies a particular version of the extension. When reading files with extension metadata, `asdf` can check whether the required extensions are present before processing the file. If a required extension is not present, `asdf` will issue a warning. It is possible to turn these warnings into errors by using the ``strict_extension_check`` parameter of `asdf.open`. If this parameter is set to `True`, then opening the file will fail if any of the required extensions are missing. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/asdf/whats_new.rst0000644000175100001770000001174314653725311016453 0ustar00runnerdocker.. currentmodule:: asdf .. _whats_new: ********** What's New ********** .. _whats_new_3.0.0: 3.0.0 ===== Asdf 3.0.0 is the first major asdf release since 2018. Thank you to all the `contributors `_! .. _whats_new_3.0.0_removed: Removed features ---------------- The following deprecated features are removed in asdf 3.0.0: * :ref:`AsdfInFits ` * :ref:`Legacy Extensions ` Please see the links above or the :ref:`deprecations` for more details. .. _whats_new_3.0.0__ew_features: New features ------------ As asdf now only supports new-style :ref:`extensions ` several new features were added to allow these extensions to retain all the functionality of the now removed type system. Converters can now :ref:`defer ` conversion allowing a different converter to handle serailizing an object. This is useful if a subclass instance can be safely converted to a superclass during serialization. See :ref:`extending_converters_deferral` for an example and more information. Converters can now access :ref:`ASDF block storage `. during serialization and deserialization. See :ref:`extending_converter_block_storage` for examples and more information. Converters have always been "strict" about tag version mismatches (returning 'raw' objects if a specific tag version is not supported). This "strictness" now extends to all objects handled by asdf. As all known asdf extensions have already migrated to converters this should pose no issue for users. Please `open an issue `_ if you run into any difficulty. .. whats_new_3.0.0_internal: Internal changes ---------------- 2.15.1 included internally a version of jsonschema. See the :ref:`jsonschema ` sub-section of the :ref:`2.15.1 ` section for more details. Asdf 3.0.0 drops jsonschema as a dependency. If your software requires jsonschema be sure to add it to your dependencies. To accomplish the above improvements to asdf extensions, a major rewrite of the ASDF block management code was required. During this rewrite ``AsdfBlockIndexWarning`` was added which users will see if they open an ASDF file with an invalid block index. Re-saving the file (or removing the optional block index) is often sufficient to fix the file so it no longer issues the warning when opened. .. whats_new_3.0.0_upcoming: Upcoming changes ---------------- With the release of asdf 3.0.0 the developers are beginning work on 3.1.0 and 4.0.0. One major change being considered for asdf 4.0.0 is the disabling of memory mapping as the default option when as ASDF file is opened. Memory mapping can offer significant performance gains but also increases the chance for gnarly errors like segfaults and corrupt data. Please let us know if this change would impact your use of asdf in the newly opened `asdf discussions `_ In an attempt to construct a coherent api, asdf 3.1 (and additional minor versions) will likely contain new deprecations in an effort to reorganize and clean up the api. If you are using features that are not currently listed in the :ref:`user_api` or :ref:`developer_api` documentation please open an issue. This will help us to know what functions should be preserved, what requires a deprecation prior to removal and which of our un-documented (non-public) features can be removed without a deprecation. .. _whats_new_2.15.1: 2.15.1 ====== .. _whats_new_2.15.1_jsonschema: jsonschema ---------- Asdf 2.15.1 includes internally a version of jsonschema 4.17.3. This inclusion was done to deal with incompatible changes in jsonschema 4.18. Many libraries that use asdf import jsonschema to allow catching of ``ValidationError`` instances that might be raised during schema validation. Prior to asdf 2.15 this error type was not part of the public asdf API. For 2.15 and later users are expected to import ``ValidationError`` from `asdf.exceptions` (instead of jsonschema directly). To further ease the transition, asdf will, when possible, use exceptions imported from any installed version of jsonschema. This means that when the asdf internal jsonschema raises a ``ValidationError`` on a system where jsonschema was separately installed, the internal jsonschema will attempt to use ``ValidationError`` from the installed version. This should allow code that catches exceptions imported from jsonschema to continue to work with no changes. However, asdf cannot guarantee compatibility with future installed jsonschema versions and users are encouraged to update their code to import ``ValidationError`` from `asdf.exceptions`. Finally, asdf is temporarily keeping jsonschema as a dependency as many libraries expected this to be installed by asdf. We expect to drop this requirement soon (likely in 3.0.0) and this change might occur in a minor or even patch version. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/conf.py0000644000175100001770000000476414653725311014311 0ustar00runnerdockerimport sys from pathlib import Path if sys.version_info < (3, 11): import tomli as tomllib else: import tomllib from sphinx_asdf.conf import * # noqa: F403 # The standard library importlib.metadata returns duplicate entrypoints # for all python versions up to and including 3.11 # https://github.com/python/importlib_metadata/issues/410#issuecomment-1304258228 # see PR https://github.com/asdf-format/asdf/pull/1260 # see issue https://github.com/asdf-format/asdf/issues/1254 if sys.version_info >= (3, 12): from importlib.metadata import distribution else: from importlib_metadata import distribution # Get configuration information from `pyproject.toml` with open(Path(__file__).parent.parent / "pyproject.toml", "rb") as configuration_file: conf = tomllib.load(configuration_file) configuration = conf["project"] # -- Project information ------------------------------------------------------ project = configuration["name"] author = f"{configuration['authors'][0]['name']} <{configuration['authors'][0]['email']}>" copyright = f"{datetime.datetime.now().year}, {configuration['authors'][0]['name']}" release = distribution(configuration["name"]).version # for example take major/minor version = ".".join(release.split(".")[:2]) # -- Options for HTML output --------------------------------------------------- html_title = f"{project} v{release}" # Output file base name for HTML help builder. htmlhelp_basename = project + "doc" # -- Options for LaTeX output -------------------------------------------------- latex_documents = [("index", project + ".tex", project + " Documentation", author, "manual")] # -- Options for manual page output -------------------------------------------- man_pages = [("index", project.lower(), project + " Documentation", [author], 1)] # Enable nitpicky mode - which ensures that all references in the docs # resolve. nitpicky = True # ignore a few pyyaml docs links since they don't appear to support intersphinx nitpick_ignore = [ ("py:class", "yaml.representer.RepresenterError"), ("py:class", "yaml.error.YAMLError"), ] # Add intersphinx mappings intersphinx_mapping["semantic_version"] = ("https://python-semanticversion.readthedocs.io/en/latest/", None) intersphinx_mapping["jsonschema"] = ("https://python-jsonschema.readthedocs.io/en/stable/", None) intersphinx_mapping["stdatamodels"] = ("https://stdatamodels.readthedocs.io/en/latest/", None) intersphinx_mapping["pytest"] = ("https://docs.pytest.org/en/latest/", None) extensions += ["sphinx_inline_tabs"] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/conftest.py0000644000175100001770000000003514653725311015174 0ustar00runnerdockercollect_ignore = ["conf.py"] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/index.rst0000644000175100001770000000414114653725311014640 0ustar00runnerdocker.. _asdf: ************************************** ASDF - Advanced Scientific Data Format ************************************** .. only:: html .. include:: ../README.rst :start-after: begin-badges: :end-before: end-badges: `asdf` is a tool for reading and writing Advanced Scientific Data Format (ASDF) files. .. include:: ../README.rst :start-after: begin-summary-text: :end-before: end-summary-text: .. note:: This is the **A**\ dvanced **S**\ cientific **D**\ ata **F**\ ormat - if you are looking for the **A**\ daptable **S**\ eismic **D**\ ata **F**\ ormat, go here: http://seismic-data.org/ .. note:: ASDF 2.15 introduced a number of deprecation warnings in preparation for changes planned for ASDF 3.0. Please see the :ref:`deprecations` page for more information. Also see :ref:`whats_new` for a description of other major changes. Getting Started =============== .. toctree:: :maxdepth: 2 asdf/install asdf/overview asdf/features asdf/config asdf/asdf_tool .. _extending: Extending ASDF ============== .. toctree:: :maxdepth: 2 asdf/extending/use_cases asdf/extending/uris asdf/extending/schemas asdf/extending/resources asdf/extending/converters asdf/extending/extensions asdf/extending/manifests asdf/extending/compressors asdf/extending/validators API Documentation ================= .. toctree:: :maxdepth: 1 asdf/user_api asdf/developer_api Developer Overview ================== Currently a work in progress. Intended to give an overview of how the various parts of ASDF interact and which modules do what and how. .. toctree:: :maxdepth: 1 asdf/developer_overview Resources ========= .. toctree:: :maxdepth: 1 asdf/contributing asdf/CODE_OF_CONDUCT asdf/release_and_support asdf/whats_new asdf/deprecations asdf/changes asdf/citation See also ======== - The :ref:`Advanced Scientific Data Format (ASDF) standard `. - `asdf` Python package distribution on `pypi `_ Index ===== * :ref:`genindex` * :ref:`modindex` * :ref:`search` ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/make.bat0000644000175100001770000001064114653725311014406 0ustar00runnerdocker@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. changes to make an overview over all changed/added/deprecated items echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Astropy.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Astropy.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) :end ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/docs/rtd_environment.yaml0000644000175100001770000000020214653725311017072 0ustar00runnerdockername: rtd311 channels: - conda-forge - defaults dependencies: - python=3.11 - pip - graphviz - sphinx_rtd_theme>1.2.0 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1610985 asdf-3.4.0/licenses/0000755000175100001770000000000014653725331013656 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/licenses/JSONSCHEMA_LICENSE0000644000175100001770000000204114653725311016370 0ustar00runnerdockerCopyright (c) 2013 Julian Berman Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/licenses/JSON_LICENSE0000644000175100001770000000204114653725311015507 0ustar00runnerdockerCopyright (c) 2012 Julian Berman Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/pyproject.toml0000644000175100001770000001142514653725311014766 0ustar00runnerdocker[project] name = "asdf" description = "Python implementation of the ASDF Standard" readme = 'README.rst' license = { file = 'LICENSE' } authors = [{ name = 'The ASDF Developers', email = 'help@stsci.edu' }] requires-python = '>=3.9' classifiers = [ 'Development Status :: 5 - Production/Stable', "License :: OSI Approved :: BSD License", 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', ] dynamic = [ 'version', ] dependencies = [ "asdf-standard>=1.1.0", "asdf-transform-schemas>=0.3", # required for asdf-1.0.0 schema "importlib-metadata>=4.11.4 ; python_version<='3.11'", "jmespath>=0.6.2", "numpy>=1.22", "packaging>=19", "pyyaml>=5.4.1", "semantic_version>=2.8", # for vendorized jsonschema "attrs>=22.2.0", # end of vendorized jsonschema deps ] [project.optional-dependencies] all = [ "lz4>=0.10", ] docs = [ "sphinx-asdf>=0.2.2", "graphviz", "sphinx-inline-tabs", 'tomli; python_version < "3.11"', ] tests = [ "fsspec[http]>=2022.8.2", "lz4>=0.10", "psutil", "pytest>=8", "pytest-remotedata", ] [project.urls] 'documentation' = 'https://asdf.readthedocs.io/en/stable' 'repository' = 'https://github.com/asdf-format/asdf' 'tracker' = 'https://github.com/asdf-format/asdf/issues' [project.entry-points] 'asdf.extensions' = {asdf = 'asdf._core._integration:get_extensions'} 'asdf.resource_mappings' = {asdf = 'asdf._core._integration:get_json_schema_resource_mappings'} asdf_extensions = {builtin = 'asdf.extension._legacy:BuiltinExtension'} console_scripts = {asdftool = 'asdf.commands.main:main'} pytest11 = {asdf_schema_tester = 'pytest_asdf.plugin'} [build-system] build-backend = 'setuptools.build_meta' requires = [ "setuptools>=60", "setuptools_scm[toml]>=3.4", "wheel", ] [tool.setuptools.packages.find] include = ['asdf*', 'pytest_asdf*'] exclude = ['asdf/_jsonschema/json/*'] [tool.setuptools.package-data] 'asdf.commands.tests.data' = ["*"] 'asdf.tags.core.tests.data' = ["*"] 'asdf.tests.data' = ["*"] [tool.setuptools_scm] version_file = "asdf/_version.py" [tool.black] line-length = 120 force-exclude = ''' ^/( ( \.eggs | \.git | \.pytest_cache | \.tox | asdf/_extern | asdf/_jsonschema | build | dist )/ ) ''' [tool.pytest.ini_options] testpaths = ['asdf', 'docs'] minversion = 4.6 remote_data_strict = true filterwarnings = [ 'error', # also set in _tests/conftest to work with pyargs 'ignore:numpy.ndarray size changed:RuntimeWarning', ] addopts = [ '--doctest-modules', '--doctest-glob=*.rst', '--color=yes', '-rsxfE', '-p no:legacypath', ] [tool.coverage.run] omit = [ 'asdf/_astropy_init*', 'asdf/conftest*', 'asdf/cython_version*', 'asdf/setup_package*', 'asdf/*/setup_package*', 'asdf/*/*/setup_package*', 'asdf/testing/*', 'asdf/tests/*', 'asdf/*/tests/*', 'asdf/*/*/tests/*', 'asdf/version.*', 'asdf/compat*', 'asdf/_extern*', 'asdf/_jsonschema/**', # And again for running against installed version '*/asdf/_astropy_init*', '*/asdf/conftest*', '*/asdf/cython_version*', '*/asdf/setup_package*', '*/asdf/*/setup_package*', '*/asdf/*/*/setup_package*', '*/asdf/testing/*', '*/asdf/tests/*', '*/asdf/*/tests/*', '*/asdf/*/*/tests/*', '*/asdf/version.*', '*/asdf/compat*', '*/asdf/_extern*', '*/asdf/_jsonschema/**', ] [tool.coverage.report] exclude_lines = [ # Have to re-enable the standard pragma 'pragma: no cover', # Don't complain about packages we have installed 'except ImportError', # Don't complain if tests don't hit assertions 'raise AssertionError', 'raise NotImplementedError', # Don't complain about script hooks 'def main\(.*\):', # Ignore branches that don't pertain to this version of Python 'pragma: py{ ignore_python_version }', ] [tool.ruff] target-version = "py38" line-length = 120 extend-exclude = ["asdf/_extern/*", "asdf/_jsonschema/*", "docs/*"] [tool.ruff.lint] select = [ # minimal set to match pre-ruff behavior "E", # pycodestyle "F", # pyflakes, autoflake "I", # isort "S", # bandit "UP", # pyupgrade "RUF", # ruff specific, includes yesqa ] extend-ignore = [ "S310", # URL open for permitted schemes "RUF012", # mutable-class-default (typing related) ] [tool.ruff.lint.per-file-ignores] "test_*.py" = ["S101"] "asdf/_tests/_helpers.py" = ["S101"] "compatibility_tests/common.py" = ["S101"] [tool.flynt] exclude = ["asdf/_extern/*", "asdf/_jsonschema/*"] [tool.codespell] skip="*.pdf,*.asdf,.tox,asdf/_extern,asdf/_jsonschema,build,./tags,.git,docs/_build" ignore-words-list=""" fo,afile, """ ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1610985 asdf-3.4.0/pytest_asdf/0000755000175100001770000000000014653725331014376 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/pytest_asdf/__init__.py0000644000175100001770000000000014653725311016473 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/pytest_asdf/plugin.py0000644000175100001770000002531414653725311016251 0ustar00runnerdockerimport io import os import pathlib from dataclasses import dataclass import numpy as np import pytest import yaml # Avoid all imports of asdf at this level in order to avoid circular imports def pytest_addoption(parser): parser.addini("asdf_schema_root", "Root path indicating where schemas are stored") parser.addini("asdf_schema_skip_names", "Base names of files to skip in schema tests") parser.addini( "asdf_schema_skip_tests", "List of tests to skip, one per line, in format ::", ) parser.addini( "asdf_schema_xfail_tests", "List of tests to xfail, one per line, in format ::", ) parser.addini("asdf_schema_skip_examples", "Base names of schemas whose examples should not be tested") parser.addini( "asdf_schema_tests_enabled", "Controls whether schema tests are enabled by default", type="bool", default=False, ) parser.addini( "asdf_schema_validate_default", "Set to true to enable validation of the schema 'default' property", type="bool", default=True, ) parser.addini( "asdf_schema_ignore_unrecognized_tag", "Set to true to disable warnings when tag serializers are missing", type="bool", default=False, ) parser.addini( "asdf_schema_ignore_version_mismatch", "Set to true to disable warnings when missing explicit support for a tag", type="bool", default=True, ) parser.addoption("--asdf-tests", action="store_true", help="Enable ASDF schema tests") class AsdfSchemaFile(pytest.File): @classmethod def from_parent( cls, parent, *, fspath, skip_examples=False, validate_default=True, ignore_unrecognized_tag=False, ignore_version_mismatch=False, skip_tests=None, xfail_tests=None, **kwargs, ): path = pathlib.Path(fspath) kwargs["path"] = path if hasattr(super(), "from_parent"): result = super().from_parent(parent, **kwargs) else: result = AsdfSchemaFile(path, parent) result.skip_examples = skip_examples result.validate_default = validate_default result.ignore_unrecognized_tag = ignore_unrecognized_tag result.ignore_version_mismatch = ignore_version_mismatch result.skip_tests = [] if skip_tests is None else skip_tests result.xfail_tests = [] if xfail_tests is None else xfail_tests return result def _set_markers(self, item): if item.name in self.skip_tests or "*" in self.skip_tests: item.add_marker(pytest.mark.skip) if item.name in self.xfail_tests or "*" in self.xfail_tests: item.add_marker(pytest.mark.xfail) def collect(self): item = AsdfSchemaItem.from_parent(self, self.fspath, validate_default=self.validate_default, name="test_schema") self._set_markers(item) yield item if not self.skip_examples: for index, example in enumerate(self.find_examples_in_schema()): name = f"test_example_{index}" item = AsdfSchemaExampleItem.from_parent( self, self.fspath, example, index, ignore_unrecognized_tag=self.ignore_unrecognized_tag, ignore_version_mismatch=self.ignore_version_mismatch, name=name, ) self._set_markers(item) yield item def find_examples_in_schema(self): """Returns generator for all examples in schema at given path""" from asdf import treeutil with open(str(self.fspath), "rb") as fd: schema_tree = yaml.safe_load(fd) for node in treeutil.iter_tree(schema_tree): if isinstance(node, dict) and "examples" in node and isinstance(node["examples"], list): yield from node["examples"] class AsdfSchemaItem(pytest.Item): @classmethod def from_parent(cls, parent, schema_path, validate_default=True, **kwargs): if hasattr(super(), "from_parent"): result = super().from_parent(parent, **kwargs) else: name = kwargs.pop("name") result = AsdfSchemaItem(name, parent, **kwargs) result.schema_path = schema_path result.validate_default = validate_default return result def runtest(self): from asdf import schema # Make sure that each schema itself is valid. schema_tree = schema.load_schema( self.schema_path, resolve_references=True, ) schema.check_schema(schema_tree, validate_default=self.validate_default) def reportinfo(self): return self.fspath, 0, "" @dataclass class SchemaExample: description: str example: str _version: str = None other: any = None @classmethod def from_schema(cls, example: list): if len(example) == 1: _description = "" _example = example[0] elif len(example) == 2: _description = example[0] _example = example[1] _version = None _other = None elif len(example) > 2: _description = example[0] _example = example[2] _version = example[1] _other = example[3:] if len(example) > 3 else None else: msg = "Invalid example" raise RuntimeError(msg) return cls(_description, _example, _version, _other) @property def version(self): from asdf import versioning if self._version is None: return versioning.default_version version = self._version.lower().split("asdf-standard-")[1] return versioning.AsdfVersion(version) class AsdfSchemaExampleItem(pytest.Item): @classmethod def from_parent( cls, parent, schema_path, example, example_index, ignore_unrecognized_tag=False, ignore_version_mismatch=False, **kwargs, ): if hasattr(super(), "from_parent"): result = super().from_parent(parent, **kwargs) else: name = kwargs.pop("name") result = AsdfSchemaExampleItem(name, parent, **kwargs) result.filename = str(schema_path) result.example = SchemaExample.from_schema(example) result.ignore_unrecognized_tag = ignore_unrecognized_tag result.ignore_version_mismatch = ignore_version_mismatch return result def runtest(self): from asdf import AsdfFile, _block, generic_io from asdf.testing import helpers # Make sure that the examples in the schema files (and thus the # ASDF standard document) are valid. buff = helpers.yaml_to_asdf("example: " + self.example.example.strip(), version=self.example.version) ff = AsdfFile( uri=pathlib.Path(self.filename).expanduser().absolute().as_uri(), ignore_unrecognized_tag=self.ignore_unrecognized_tag, ignore_version_mismatch=self.ignore_version_mismatch, ) # Fake an external file ff2 = AsdfFile({"data": np.empty((1024 * 1024 * 8), dtype=np.uint8)}) ff._external_asdf_by_uri[ (pathlib.Path(self.filename).expanduser().absolute().parent / "external.asdf").as_uri() ] = ff2 wb = _block.writer.WriteBlock(np.zeros(1024 * 1024 * 8, dtype=np.uint8)) with generic_io.get_file(buff, mode="rw") as f: f.seek(0, 2) _block.writer.write_blocks(f, [wb, wb], streamed_block=wb) f.seek(0) try: ff._open_impl(ff, buff, mode="rw") except Exception: print(f"Example: {self.example.description}\n From file: {self.filename}") raise # Just test we can write it out. A roundtrip test # wouldn't always yield the correct result, so those have # to be covered by "real" unit tests. if b"external.asdf" not in buff.getvalue(): buff = io.BytesIO() ff.write_to(buff) def reportinfo(self): return self.fspath, 0, "" def _parse_test_list(content): result = {} if isinstance(content, str): content = content.split("\n") for line in content: line_ = line.strip() if len(line_) > 0: parts = line_.split("::", 1) path_suffix = pathlib.Path(parts[0]).as_posix() name = "*" if len(parts) == 1 else parts[-1] if path_suffix not in result: result[path_suffix] = [] result[path_suffix].append(name) return result def pytest_collect_file(file_path, parent): if not (parent.config.getini("asdf_schema_tests_enabled") or parent.config.getoption("asdf_tests")): return None schema_roots = parent.config.getini("asdf_schema_root").split() if not schema_roots: return None skip_names = parent.config.getini("asdf_schema_skip_names") skip_examples = parent.config.getini("asdf_schema_skip_examples") validate_default = parent.config.getini("asdf_schema_validate_default") ignore_unrecognized_tag = parent.config.getini("asdf_schema_ignore_unrecognized_tag") ignore_version_mismatch = parent.config.getini("asdf_schema_ignore_version_mismatch") skip_tests = _parse_test_list(parent.config.getini("asdf_schema_skip_tests")) xfail_tests = _parse_test_list(parent.config.getini("asdf_schema_xfail_tests")) schema_roots = [os.path.join(str(parent.config.rootpath), os.path.normpath(root)) for root in schema_roots] if file_path.suffix != ".yaml": return None for root in schema_roots: if str(file_path).startswith(root) and file_path.stem not in skip_names: posix_path = pathlib.Path(file_path).as_posix() schema_skip_tests = [] for suffix, names in skip_tests.items(): if posix_path.endswith(suffix): schema_skip_tests.extend(names) schema_xfail_tests = [] for suffix, names in xfail_tests.items(): if posix_path.endswith(suffix): schema_xfail_tests.extend(names) return AsdfSchemaFile.from_parent( parent, fspath=file_path, skip_examples=(file_path.stem in skip_examples), validate_default=validate_default, ignore_unrecognized_tag=ignore_unrecognized_tag, ignore_version_mismatch=ignore_version_mismatch, skip_tests=schema_skip_tests, xfail_tests=schema_xfail_tests, ) return None ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/requirements-dev.txt0000644000175100001770000000061214653725311016106 0ustar00runnerdockergit+https://github.com/asdf-format/asdf-standard git+https://github.com/asdf-format/asdf-transform-schemas git+https://github.com/yaml/pyyaml.git numpy>=0.0.dev0 # although we don't use scipy, we include it here so that any dependency # that uses it during these tests will use the development version # which is more likely to work with the above development version of numpy scipy>=0.0.dev0 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1722788569.1650984 asdf-3.4.0/setup.cfg0000644000175100001770000000004614653725331013672 0ustar00runnerdocker[egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1722788553.0 asdf-3.4.0/tox.ini0000644000175100001770000002161714653725311013371 0ustar00runnerdocker[tox] env_list = compatibility coverage py{39,310,311,312,313}{,-compatibility,-coverage,-jsonschema}{,-devdeps}{,-parallel}{,-pytestdev} asdf{-standard,-transform-schemas,-unit-schemas,-wcs-schemas,-coordinates-schemas,-astropy,-zarr,-compression} astrocut gwcs jwst stdatamodels stpipe roman_datamodels weldx sunpy dkist [testenv] set_env = devdeps: PIP_EXTRA_INDEX_URL = https://pypi.anaconda.org/scientific-python-nightly-wheels/simple deps = compatibility: virtualenv coverage: coverage devdeps: -rrequirements-dev.txt numpydev: cython oldestdeps: minimum_dependencies parallel: pytest-xdist pytestdev: git+https://github.com/pytest-dev/pytest extras = all,tests # astropy will complain if the home directory is missing pass_env = HOME package = editable commands_pre = python -m pip install --upgrade pip # Generate `requiremments-min.txt` oldestdeps: minimum_dependencies asdf --filename {env_tmp_dir}/requirements-min.txt # Force install everything from `requirements-min.txt` oldestdeps: pip install -r {env_tmp_dir}/requirements-min.txt pip freeze # coverage run must be used because the pytest-asdf plugin will interfere # with proper coverage measurement due to the order pytest loads its # entry points. commands = coverage: coverage run --source=asdf --rcfile={tox_root}/pyproject.toml -m \ pytest \ compatibility: compatibility_tests/ \ --remote-data \ --durations=10 \ jsonschema: --jsonschema \ parallel: --numprocesses auto \ # the OpenAstronomy workflow appends `--cov-report` in `{posargs}`, which `coverage` doesn't recognize !coverage: {posargs} coverage: coverage: coverage xml -o {tox_root}/coverage.xml coverage: coverage report [testenv:asdf-standard] change_dir = {env_tmp_dir} allowlist_externals = git bash extras = commands_pre = bash -c "pip freeze -q | grep 'asdf @' > {env_tmp_dir}/requirements.txt" git clone https://github.com/asdf-format/asdf-standard.git pip install -e asdf-standard[test] pip install -r {env_tmp_dir}/requirements.txt pip freeze commands = pytest asdf-standard [testenv:asdf-compression] change_dir = {env_tmp_dir} allowlist_externals = git bash extras = commands_pre = bash -c "pip freeze -q | grep 'asdf @' > {env_tmp_dir}/requirements.txt" git clone https://github.com/asdf-format/asdf-compression.git pip install -e asdf-compression[tests,all] pip install -r {env_tmp_dir}/requirements.txt pip freeze commands = pytest asdf-compression [testenv:asdf-zarr] change_dir = {env_tmp_dir} allowlist_externals = git bash extras = commands_pre = bash -c "pip freeze -q | grep 'asdf @' > {env_tmp_dir}/requirements.txt" git clone https://github.com/asdf-format/asdf-zarr.git pip install -e asdf-zarr[tests] pip install -r {env_tmp_dir}/requirements.txt pip freeze commands = pytest asdf-zarr [testenv:asdf-transform-schemas] change_dir = {env_tmp_dir} allowlist_externals = git bash extras = commands_pre = bash -c "pip freeze -q | grep 'asdf @' > {env_tmp_dir}/requirements.txt" git clone https://github.com/asdf-format/asdf-transform-schemas.git pip install -e asdf-transform-schemas[test] pip install -r {env_tmp_dir}/requirements.txt pip freeze commands = pytest asdf-transform-schemas [testenv:asdf-wcs-schemas] change_dir = {env_tmp_dir} allowlist_externals = git bash extras = commands_pre = bash -c "pip freeze -q | grep 'asdf @' > {env_tmp_dir}/requirements.txt" git clone https://github.com/asdf-format/asdf-wcs-schemas.git pip install -e asdf-wcs-schemas[test] pip install -r {env_tmp_dir}/requirements.txt pip freeze commands = pytest asdf-wcs-schemas [testenv:asdf-coordinates-schemas] change_dir = {env_tmp_dir} allowlist_externals = git bash extras = commands_pre = bash -c "pip freeze -q | grep 'asdf @' > {env_tmp_dir}/requirements.txt" git clone https://github.com/asdf-format/asdf-coordinates-schemas.git pip install -e asdf-coordinates-schemas[test] pip install -r {env_tmp_dir}/requirements.txt pip freeze commands = pytest asdf-coordinates-schemas [testenv:asdf-astropy] change_dir = {env_tmp_dir} allowlist_externals = git bash extras = commands_pre = bash -c "pip freeze -q | grep 'asdf @' > {env_tmp_dir}/requirements.txt" git clone https://github.com/astropy/asdf-astropy.git pip install -e asdf-astropy[test] pip install -r {env_tmp_dir}/requirements.txt pip freeze commands = pytest asdf-astropy [testenv:specutils] change_dir = {env_tmp_dir} allowlist_externals = git bash extras = commands_pre = bash -c "pip freeze -q | grep 'asdf @' > {env_tmp_dir}/requirements.txt" git clone https://github.com/astropy/specutils.git pip install -e specutils[test] pip install -r {env_tmp_dir}/requirements.txt pip freeze commands = pytest specutils [testenv:astrocut] change_dir = {env_tmp_dir} allowlist_externals = git bash extras = commands_pre = bash -c "pip freeze -q | grep 'asdf @' > {env_tmp_dir}/requirements.txt" git clone https://github.com/spacetelescope/astrocut.git pip install -e astrocut[test] pip install -r {env_tmp_dir}/requirements.txt pip freeze commands = pytest astrocut/astrocut/tests/test_asdf_cut.py [testenv:gwcs] change_dir = {env_tmp_dir} allowlist_externals = git bash extras = commands_pre = bash -c "pip freeze -q | grep 'asdf @' > {env_tmp_dir}/requirements.txt" git clone https://github.com/spacetelescope/gwcs.git pip install -e gwcs[test] pip install -r {env_tmp_dir}/requirements.txt pip freeze commands = pytest gwcs [testenv:jwst] deps= pytest-xdist change_dir = {env_tmp_dir} allowlist_externals = git bash extras = set_env = CRDS_SERVER_URL = https://jwst-crds.stsci.edu CRDS_PATH = /tmp/crds_cache CRDS_CLIENT_RETRY_COUNT = 3 CRDS_CLIENT_RETRY_DELAY_SECONDS = 20 commands_pre = bash -c "pip freeze -q | grep 'asdf @' > {env_tmp_dir}/requirements.txt" git clone https://github.com/spacetelescope/jwst.git pip install -e jwst[test] pip install -r {env_tmp_dir}/requirements.txt pip freeze commands = pytest --numprocesses auto jwst [testenv:stdatamodels] change_dir = {env_tmp_dir} allowlist_externals = git bash extras = set_env = CRDS_SERVER_URL = https://jwst-crds.stsci.edu CRDS_PATH = /tmp/crds_cache CRDS_CLIENT_RETRY_COUNT = 3 CRDS_CLIENT_RETRY_DELAY_SECONDS = 20 commands_pre = bash -c "pip freeze -q | grep 'asdf @' > {env_tmp_dir}/requirements.txt" git clone https://github.com/spacetelescope/stdatamodels.git pip install -e stdatamodels[test] pip install -r {env_tmp_dir}/requirements.txt pip freeze commands = pytest stdatamodels [testenv:stpipe] change_dir = {env_tmp_dir} allowlist_externals = git bash commands_pre = bash -c "pip freeze -q | grep 'asdf @' > {env_tmp_dir}/requirements.txt" git clone https://github.com/spacetelescope/stpipe.git pip install -e stpipe[test] pip install -r {env_tmp_dir}/requirements.txt pip freeze commands = pytest stpipe/tests [testenv:roman_datamodels] change_dir = {env_tmp_dir} allowlist_externals = git bash extras = commands_pre = bash -c "pip freeze -q | grep 'asdf @' > {env_tmp_dir}/requirements.txt" git clone https://github.com/spacetelescope/roman_datamodels.git pip install -e roman_datamodels[test] pip install -r {env_tmp_dir}/requirements.txt pip freeze commands = pytest roman_datamodels/tests [testenv:weldx] change_dir = {env_tmp_dir} allowlist_externals = git bash extras = commands_pre = bash -c "pip freeze -q | grep 'asdf @' > {env_tmp_dir}/requirements.txt" git clone https://github.com/BAMWelDX/weldx.git pip install -e weldx[test,media] pip install -r {env_tmp_dir}/requirements.txt pip freeze commands = pytest weldx/weldx/tests/asdf_tests weldx/weldx/schemas --asdf-tests [testenv:sunpy] change_dir = {env_tmp_dir} allowlist_externals = git bash extras = commands_pre = bash -c "pip freeze -q | grep 'asdf @' > {env_tmp_dir}/requirements.txt" git clone https://github.com/sunpy/sunpy.git pip install -e sunpy[tests,all] pip install -r {env_tmp_dir}/requirements.txt pip freeze commands = pytest sunpy/sunpy/io [testenv:dkist] change_dir = {env_tmp_dir} allowlist_externals = git bash extras = commands_pre = bash -c "pip freeze -q | grep 'asdf @' > {env_tmp_dir}/requirements.txt" git clone https://github.com/DKISTDC/dkist.git pip install -e dkist[tests] pip install -r {env_tmp_dir}/requirements.txt pip freeze commands = # the AsdfManifestURIMismatchWarning filter can be removed when a new sunpy # is released which contains the fixed manifests: # https://github.com/sunpy/sunpy/pull/7432 pytest dkist \ -W "ignore::asdf.exceptions.AsdfManifestURIMismatchWarning"