From f95539bd04408353f5e35256e614459d0aa1c58d Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Mon, 8 Apr 2019 16:58:02 -0400 Subject: [PATCH 01/10] Move schema tester into separate module. Register pytest plugin --- asdf/tests/schema_tester/__init__.py | 1 + asdf/tests/{schema_tester.py => schema_tester/plugin.py} | 2 +- asdf/version.py | 2 +- setup.cfg | 2 ++ 4 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 asdf/tests/schema_tester/__init__.py rename asdf/tests/{schema_tester.py => schema_tester/plugin.py} (99%) diff --git a/asdf/tests/schema_tester/__init__.py b/asdf/tests/schema_tester/__init__.py new file mode 100644 index 000000000..9dce85d06 --- /dev/null +++ b/asdf/tests/schema_tester/__init__.py @@ -0,0 +1 @@ +# Licensed under a 3-clause BSD style license - see LICENSE.rst diff --git a/asdf/tests/schema_tester.py b/asdf/tests/schema_tester/plugin.py similarity index 99% rename from asdf/tests/schema_tester.py rename to asdf/tests/schema_tester/plugin.py index bade9b6d3..314969d5b 100644 --- a/asdf/tests/schema_tester.py +++ b/asdf/tests/schema_tester/plugin.py @@ -18,7 +18,7 @@ from asdf import treeutil from asdf import util from asdf import versioning -from . import helpers, CustomTestType +from .. import helpers, CustomTestType _ctx = AsdfFile() _resolver = _ctx.resolver diff --git a/asdf/version.py b/asdf/version.py index 3f49b9076..95d757da1 100644 --- a/asdf/version.py +++ b/asdf/version.py @@ -1,7 +1,7 @@ from pkg_resources import get_distribution, DistributionNotFound try: - version = get_distribution(__package__).version + version = get_distribution('asdf').version except DistributionNotFound: # package is not installed version = "unknown" diff --git a/setup.cfg b/setup.cfg index 6c18b5b9a..c4c11512f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -58,6 +58,8 @@ console_scripts = asdftool = asdf.commands.main:main asdf_extensions = builtin = asdf.extension:BuiltinExtension +pytest11 = + asdf_schema_tester = asdf.tests.schema_tester.plugin [build_sphinx] source-dir = docs From 0fb7c3fe4b22d0a06c700d27f446ad544f21487c Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Tue, 9 Apr 2019 08:44:21 -0400 Subject: [PATCH 02/10] Remove schema tester from pytest_plugins in conftest.py --- conftest.py | 1 - 1 file changed, 1 deletion(-) diff --git a/conftest.py b/conftest.py index 76c9e5692..0751eb1bd 100644 --- a/conftest.py +++ b/conftest.py @@ -25,7 +25,6 @@ pytest_plugins = [ - 'asdf.tests.schema_tester', 'astropy.tests.plugins.display' ] From 2e59e95c8083538d8c3db75a91ca408c213695db Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Tue, 9 Apr 2019 09:11:53 -0400 Subject: [PATCH 03/10] Disable schema tester by default. Add config option to enable --- asdf/tests/schema_tester/plugin.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/asdf/tests/schema_tester/plugin.py b/asdf/tests/schema_tester/plugin.py index 314969d5b..3152dcba2 100644 --- a/asdf/tests/schema_tester/plugin.py +++ b/asdf/tests/schema_tester/plugin.py @@ -64,6 +64,9 @@ def pytest_addoption(parser): 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") class AsdfSchemaFile(pytest.File): @@ -189,6 +192,9 @@ def runtest(self): def pytest_collect_file(path, parent): + if not parent.config.getini('asdf_schema_tests_enabled'): + return + schema_roots = parent.config.getini('asdf_schema_root').split() if not schema_roots: return From 48f0f0f211a6a033407bda7a824f4830ebee0554 Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Tue, 9 Apr 2019 09:14:52 -0400 Subject: [PATCH 04/10] Add command line option to enable schema tests --- asdf/tests/schema_tester/plugin.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/asdf/tests/schema_tester/plugin.py b/asdf/tests/schema_tester/plugin.py index 3152dcba2..6c79862d4 100644 --- a/asdf/tests/schema_tester/plugin.py +++ b/asdf/tests/schema_tester/plugin.py @@ -67,6 +67,9 @@ def pytest_addoption(parser): parser.addini( "asdf_schema_tests_enabled", "Controls whether schema tests are enabled by default") + parser.addoption('--asdf-tests', action='store_true', + help='Enable ASDF schema tests') + class AsdfSchemaFile(pytest.File): @@ -192,7 +195,8 @@ def runtest(self): def pytest_collect_file(path, parent): - if not parent.config.getini('asdf_schema_tests_enabled'): + if not (parent.config.getini('asdf_schema_tests_enabled') or + parent.config.getoption('asdf_tests')): return schema_roots = parent.config.getini('asdf_schema_root').split() From 9ee91b376abea3f8313b82d9161fee7ace5fcef1 Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Tue, 9 Apr 2019 09:22:36 -0400 Subject: [PATCH 05/10] Update schema tester documentation --- docs/asdf/extensions.rst | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/asdf/extensions.rst b/docs/asdf/extensions.rst index 294b644d3..801cb2990 100644 --- a/docs/asdf/extensions.rst +++ b/docs/asdf/extensions.rst @@ -722,25 +722,11 @@ Packages that provide their own schemas can test them using ASDF's Schemas are tested for overall validity, and any examples given within the schemas are also tested. -The schema tester plugin is automatically made available when the ASDF package -is installed. In order to enable testing, the following steps are required: - -1. Add `asdf.tests.schema_tester` to the list of pytest plugins in the - top-level `conftest.py` file for your package. If that file does not already - exist, creating a `conftest.py` file containing the following should be - sufficient (see `this - `_ for more - information on `conftest.py` files): - -.. code:: python - - pytest_plugins = [ - 'asdf.tests.schema_tester' - ] - -2. Add the directory containing your schema files to the pytest section of your - project's `setup.cfg` file. If you do not already have such a file, creating - a `setup.cfg` with the following should be sufficient: +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 +`setup.cfg` file. If you do not already have such a file, creating a +`setup.cfg` with the following should be sufficient: .. code:: ini @@ -752,8 +738,22 @@ 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 `setup.cfg` 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 `setup.cfg` 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]`` section of your `setup.cfg` file. 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. From a4ae8cd02c2f2ee2327563aa22161f012a3ab546 Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Tue, 9 Apr 2019 09:29:26 -0400 Subject: [PATCH 06/10] Update change log --- CHANGES.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 4e174d674..84a0b834a 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,10 +5,14 @@ - 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] + 2.3.4 (unreleased) ------------------ -- Fix bug in ``NDArrayType.__len__``. It must be a method, not a +- Fix bug in ``NDArrayType.__len__``. It must be a method, not a property. [#673] 2.3.3 (2019-04-02) From ec3120fd3796e8ed30aa942a8a4c9c4bf2c80607 Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Tue, 9 Apr 2019 09:29:56 -0400 Subject: [PATCH 07/10] Enable the schema tests by default for this package --- setup.cfg | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.cfg b/setup.cfg index c4c11512f..9eca1d07e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -83,6 +83,8 @@ text_file_format = rst asdf_schema_root = asdf-standard/schemas asdf/schemas asdf_schema_skip_names = asdf-schema-1.0.0 draft-01 asdf_schema_skip_examples = domain-1.0.0 frame-1.0.0 frame-1.1.0 +# Enable the schema tests by default +asdf_schema_tests_enabled = true addopts = --doctest-rst [flake8] From a05fef8094e86db78093596de1be1779deabc644 Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Tue, 9 Apr 2019 14:22:47 -0400 Subject: [PATCH 08/10] Move schema tester plugin into top-level package --- {asdf/tests/schema_tester => pytest_asdf}/__init__.py | 0 {asdf/tests/schema_tester => pytest_asdf}/plugin.py | 2 +- setup.cfg | 3 ++- 3 files changed, 3 insertions(+), 2 deletions(-) rename {asdf/tests/schema_tester => pytest_asdf}/__init__.py (100%) rename {asdf/tests/schema_tester => pytest_asdf}/plugin.py (99%) diff --git a/asdf/tests/schema_tester/__init__.py b/pytest_asdf/__init__.py similarity index 100% rename from asdf/tests/schema_tester/__init__.py rename to pytest_asdf/__init__.py diff --git a/asdf/tests/schema_tester/plugin.py b/pytest_asdf/plugin.py similarity index 99% rename from asdf/tests/schema_tester/plugin.py rename to pytest_asdf/plugin.py index 6c79862d4..c972be960 100644 --- a/asdf/tests/schema_tester/plugin.py +++ b/pytest_asdf/plugin.py @@ -18,7 +18,7 @@ from asdf import treeutil from asdf import util from asdf import versioning -from .. import helpers, CustomTestType +from asdf.tests import helpers, CustomTestType _ctx = AsdfFile() _resolver = _ctx.resolver diff --git a/setup.cfg b/setup.cfg index 9eca1d07e..6c3bc143a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -25,6 +25,7 @@ packages = asdf asdf.schemas asdf.reference_files + pytest_asdf package_dir = asdf.schemas = asdf-standard/schemas asdf.reference_files = asdf-standard/reference_files @@ -59,7 +60,7 @@ console_scripts = asdf_extensions = builtin = asdf.extension:BuiltinExtension pytest11 = - asdf_schema_tester = asdf.tests.schema_tester.plugin + asdf_schema_tester = pytest_asdf.plugin [build_sphinx] source-dir = docs From c0bb8353128ac74a4c995cc3df974928c7096176 Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Wed, 10 Apr 2019 09:56:13 -0400 Subject: [PATCH 09/10] Refactor schema tester plugin to avoid circular imports --- pytest_asdf/extension.py | 32 ++++++++++++++++++++++ pytest_asdf/plugin.py | 58 +++++++++------------------------------- 2 files changed, 44 insertions(+), 46 deletions(-) create mode 100644 pytest_asdf/extension.py diff --git a/pytest_asdf/extension.py b/pytest_asdf/extension.py new file mode 100644 index 000000000..62a4f04e3 --- /dev/null +++ b/pytest_asdf/extension.py @@ -0,0 +1,32 @@ +from asdf import extension +from asdf.tests import CustomTestType + + +class LabelMapperTestType(CustomTestType): + version = '1.0.0' + name = 'transform/label_mapper' + + +class RegionsSelectorTestType(CustomTestType): + version = '1.0.0' + name = 'transform/regions_selector' + + +class TestExtension(extension.BuiltinExtension): + """This class defines an extension that represents tags whose + implementations current reside in other repositories (such as GWCS) but + whose schemas are defined in ASDF. This provides a workaround for schema + validation testing since we want to pass without warnings, but the fact + that these tag classes are not defined within ASDF means that warnings + occur unless this extension is used. Eventually these schemas may be moved + out of ASDF and into other repositories, or ASDF will potentially provide + abstract base classes for the tag implementations. + """ + @property + def types(self): + return [LabelMapperTestType, RegionsSelectorTestType] + + @property + def tag_mapping(self): + return [('tag:stsci.edu:asdf', + 'http://stsci.edu/schemas/asdf{tag_suffix}')] diff --git a/pytest_asdf/plugin.py b/pytest_asdf/plugin.py index c972be960..1bae833de 100644 --- a/pytest_asdf/plugin.py +++ b/pytest_asdf/plugin.py @@ -10,50 +10,7 @@ import numpy as np -import asdf -from asdf import AsdfFile -from asdf import block -from asdf import schema -from asdf import extension -from asdf import treeutil -from asdf import util -from asdf import versioning -from asdf.tests import helpers, CustomTestType - -_ctx = AsdfFile() -_resolver = _ctx.resolver - - -class LabelMapperTestType(CustomTestType): - version = '1.0.0' - name = 'transform/label_mapper' - - -class RegionsSelectorTestType(CustomTestType): - version = '1.0.0' - name = 'transform/regions_selector' - - -class TestExtension(extension.BuiltinExtension): - """This class defines an extension that represents tags whose - implementations current reside in other repositories (such as GWCS) but - whose schemas are defined in ASDF. This provides a workaround for schema - validation testing since we want to pass without warnings, but the fact - that these tag classes are not defined within ASDF means that warnings - occur unless this extension is used. Eventually these schemas may be moved - out of ASDF and into other repositories, or ASDF will potentially provide - abstract base classes for the tag implementations. - """ - @property - def types(self): - return [LabelMapperTestType, RegionsSelectorTestType] - - @property - def tag_mapping(self): - return [('tag:stsci.edu:asdf', - 'http://stsci.edu/schemas/asdf{tag_suffix}')] - - +# Avoid all imports of asdf at this level in order to avoid circular imports def pytest_addoption(parser): @@ -71,7 +28,6 @@ def pytest_addoption(parser): help='Enable ASDF schema tests') - class AsdfSchemaFile(pytest.File): def __init__(self, *args, skip_examples=False, **kwargs): @@ -86,6 +42,8 @@ def collect(self): 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) @@ -103,9 +61,12 @@ def __init__(self, schema_path, parent): self.schema_path = schema_path def runtest(self): + from asdf import AsdfFile, schema + ctx = AsdfFile() + # Make sure that each schema itself is valid. schema_tree = schema.load_schema( - self.schema_path, resolver=_resolver, resolve_references=True) + self.schema_path, resolver=ctx.resolver, resolve_references=True) schema.check_schema(schema_tree) @@ -123,6 +84,7 @@ def should_skip(name, version): return False def parse_schema_filename(filename): + from asdf import versioning components = filename[filename.find('schemas') + 1:].split(os.path.sep) tag = 'tag:{}:{}'.format(components[1], '/'.join(components[2:])) name, version = versioning.split_tag_version(tag.replace('.yaml', '')) @@ -137,6 +99,7 @@ def __init__(self, schema_path, parent, example): self.example = example def _find_standard_version(self, name, version): + from asdf import versioning for sv in versioning.supported_versions: map_version = versioning.get_version_map(sv)['tags'].get(name) if map_version is not None and version == map_version: @@ -145,6 +108,9 @@ def _find_standard_version(self, name, version): return versioning.default_version def runtest(self): + from asdf import AsdfFile, block, util + from asdf.tests import helpers + from .extension import TestExtension name, version = parse_schema_filename(self.filename) if should_skip(name, version): From 5ee090d5c91aec1bf3011a62aaf45648620ff199 Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Wed, 10 Apr 2019 10:17:28 -0400 Subject: [PATCH 10/10] Refactor so AsdfFile is not needed for resolver --- asdf/extension.py | 6 ++++++ pytest_asdf/plugin.py | 7 ++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/asdf/extension.py b/asdf/extension.py index 17d491051..da920dcd5 100644 --- a/asdf/extension.py +++ b/asdf/extension.py @@ -244,4 +244,10 @@ def reset(self): self._extension_list = None self._package_metadata = {} + def resolver(self, uri): + tag_mapping = self.extension_list.tag_mapping + url_mapping = self.extension_list.url_mapping + return url_mapping(tag_mapping(uri)) + + default_extensions = _DefaultExtensions() diff --git a/pytest_asdf/plugin.py b/pytest_asdf/plugin.py index 1bae833de..75cee86a5 100644 --- a/pytest_asdf/plugin.py +++ b/pytest_asdf/plugin.py @@ -61,12 +61,13 @@ def __init__(self, schema_path, parent): self.schema_path = schema_path def runtest(self): - from asdf import AsdfFile, schema - ctx = AsdfFile() + from asdf import schema + from asdf.extension import default_extensions # Make sure that each schema itself is valid. schema_tree = schema.load_schema( - self.schema_path, resolver=ctx.resolver, resolve_references=True) + self.schema_path, resolver=default_extensions.resolver, + resolve_references=True) schema.check_schema(schema_tree)