astro py:docs

- Index
- Modules

### Navigation

- asdf v1.3.3 »
- Module code »
- asdf »

# Source code for asdf.versioning

    # Licensed under a 3-clause BSD style license - see LICENSE.rst
    # -*- coding: utf-8 -*-

    """
    This module deals with things that change between different versions
    of the ASDF spec.
    """

    from __future__ import absolute_import, division, unicode_literals, print_function

    import six
    import yaml
    from functools import total_ordering

    if getattr(yaml, '__with_libyaml__', None):  # pragma: no cover
        _yaml_base_loader = yaml.CSafeLoader
    else:  # pragma: no cover
        _yaml_base_loader = yaml.SafeLoader

    from semantic_version import Version, SpecItem, Spec

    from . import generic_io
    from . import resolver
    from . import util

    _version_map = {}
    def get_version_map(version):
        version_map = _version_map.get(version)

        if version_map is None:
            version_map_path = resolver.DEFAULT_URL_MAPPING[0][1].replace(
                '{url_suffix}', 'asdf/version_map-{0}'.format(version))
            try:
                with generic_io.get_file(version_map_path, 'r') as fd:
                    version_map = yaml.load(
                        fd, Loader=_yaml_base_loader)
            except:
                raise ValueError(
                    "Could not load version map for version {0}".format(version))
            _version_map[version] = version_map

        return version_map

    @total_ordering
    class AsdfVersionMixin(object):
        """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, SpecItem):
                return other == self
            if isinstance(other, (six.string_types, 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, (six.string_types, 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(AsdfVersion, self).__init__(version)

    class AsdfSpec(SpecItem, Spec):

        def __init__(self, *args, **kwargs):
            super(AsdfSpec, self).__init__(*args, **kwargs)

        def match(self, version):
            if isinstance(version, (six.string_types, tuple, list)):
                version = AsdfVersion(version)
            return super(AsdfSpec, self).match(version)

        def __iterate_versions(self, versions):
            for v in versions:
                if isinstance(v, (six.string_types, tuple, list)):
                    v = AsdfVersion(v)
                yield v

        def select(self, versions):
            return super(AsdfSpec, self).select(self.__iterate_versions(versions))

        def filter(self, versions):
            return super(AsdfSpec, self).filter(self.__iterate_versions(versions))

        def __eq__(self, other):
            """Equality between Spec and Version, string, or tuple, means match"""
            if isinstance(other, SpecItem):
                return super(AsdfSpec, self).__eq__(other)
            return self.match(other)

        def __ne__(self, other):
            return not self.__eq__(other)

        def __hash__(self):
            return super(AsdfSpec, self).__hash__()

    default_version = AsdfVersion('1.1.0')

    supported_versions = [
        AsdfVersion('1.0.0'),
        AsdfVersion('1.1.0')
    ]

    class VersionedMixin(object):
        _version = default_version

        @property
        def version(self):
            return self._version

        @version.setter
        def version(self, version):
            if version not in supported_versions:
                human_versions = util.human_list(
                    [str(x) for x in supported_versions])
                raise ValueError(
                    "asdf only understands how to handle ASDF versions {0}. "
                    "Got '{1}'".format(human_versions, version))

            self._version = version

        @property
        def version_string(self):
            return str(self._version)

        @property
        def version_map(self):
            try:
                version_map = get_version_map(self.version_string)
            except ValueError:
                raise ValueError(
                    "Don't have information about version {0}".format(
                        self.version_string))
            return version_map