Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically register the schema tester pytest plugin #676

Merged
merged 10 commits into from
Apr 10, 2019
6 changes: 5 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions asdf/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. This is potentially useful elsewhere to get the full-bells-and-whistles resolver so that we don't have to instantiate a dummy AsdfFile object just to get to the resolver.



default_extensions = _DefaultExtensions()
2 changes: 1 addition & 1 deletion asdf/version.py
Original file line number Diff line number Diff line change
@@ -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"
1 change: 0 additions & 1 deletion conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@


pytest_plugins = [
'asdf.tests.schema_tester',
'astropy.tests.plugins.display'
]

Expand Down
38 changes: 19 additions & 19 deletions docs/asdf/extensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
<https://docs.pytest.org/en/2.7.3/plugins.html?highlight=re>`_ 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

Expand All @@ -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.
1 change: 1 addition & 0 deletions pytest_asdf/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
32 changes: 32 additions & 0 deletions pytest_asdf/extension.py
Original file line number Diff line number Diff line change
@@ -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}')]
67 changes: 22 additions & 45 deletions asdf/tests/schema_tester.py → pytest_asdf/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 . 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):
Expand All @@ -64,6 +21,11 @@ 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")
parser.addoption('--asdf-tests', action='store_true',
help='Enable ASDF schema tests')


class AsdfSchemaFile(pytest.File):
Expand All @@ -80,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)

Expand All @@ -97,9 +61,13 @@ def __init__(self, schema_path, parent):
self.schema_path = schema_path

def runtest(self):
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=_resolver, resolve_references=True)
self.schema_path, resolver=default_extensions.resolver,
resolve_references=True)
schema.check_schema(schema_tree)


Expand All @@ -117,6 +85,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', ''))
Expand All @@ -131,6 +100,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:
Expand All @@ -139,6 +109,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):
Expand Down Expand Up @@ -189,6 +162,10 @@ def runtest(self):


def pytest_collect_file(path, parent):
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()
if not schema_roots:
return
Expand Down
5 changes: 5 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -58,6 +59,8 @@ console_scripts =
asdftool = asdf.commands.main:main
asdf_extensions =
builtin = asdf.extension:BuiltinExtension
pytest11 =
asdf_schema_tester = pytest_asdf.plugin

[build_sphinx]
source-dir = docs
Expand All @@ -81,6 +84,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]
Expand Down