<commit_before># -*- coding: utf-8 -*-
# Licensed under a 3-clause BSD style license - see LICENSE.rst
"""
Framework and base classes for coordinate frames/"low-level" coordinate classes.
"""
from __future__ import (absolute_import, unicode_literals, division,
                        print_function)

# Standard library
import copy
import inspect

# Dependencies
import numpy as np

# Project
from ..extern import six
from .. import units as u
from .transformations import TransformGraph

__all__ = ['BaseCoordinateFrame', 'frame_transform_graph', 'GenericFrame']

# Frame attributes that must be times
TIME_FRAME_ATTRS = ('equinox', 'obstime')

# the graph used for all transformations between frames
frame_transform_graph = TransformGraph()


class FrameMeta(type):
    def __new__(cls, name, parents, clsdct):
        # somewhat hacky, but this is the best way to get the MRO according to
        # https://mail.python.org/pipermail/python-list/2002-December/167861.html
        mro = super(FrameMeta, cls).__new__(cls, name, parents, clsdct).__mro__
        parent_clsdcts = [c.__dict__ for c in mro]
        parent_clsdcts.insert(0, clsdct)

        #now look through the whole MRO for the relevant class attributes
        pref_repr = None
        pref_attrs = frame_attrs = {}
        found_pref_repr = found_pref_attrs = found_frame_attrs = False
        for clsdcti in parent_clsdcts:
            if not found_pref_repr and 'preferred_representation' in clsdcti:
                pref_repr = clsdcti['preferred_representation']
                found_pref_repr = True
            if not found_pref_attrs and 'preferred_attr_names' in clsdcti:
                pref_attrs = clsdcti['preferred_attr_names']
                found_pref_attrs = True
            if not found_frame_attrs and 'frame_attr_names' in clsdcti:
                frame_attrs = clsdcti['frame_attr_names']
                found_frame_attrs = True

            if found_pref_repr and found_pref_attrs and found_frame_attrs:
                break
        else:
            raise ValueError('Could not find the expected BaseCoordinateFrame '
                             'class attributes.  Are you mis-using FrameMeta?')

        if pref_repr:
            # create properties for the preferred_attr_names
            for propnm, reprnm in six.iteritems(pref_attrs):
                clsdct[propnm] = property(FrameMeta.repr_getter_factory(reprnm))

        #also make properties for the frame_attr_names to make them immutible
        #after creation
        for attrnm in frame_attrs:
            if attrnm in clsdct:
                if isinstance(clsdct[attrnm], property):
                    #means the property was defined already... so trust the
                    #subclasser and don't make a new one
                    continue
                else:
                    raise ValueError("A non-property exists that's *also* in frame_attr_names")
            clsdct[attrnm] = property(FrameMeta.frame_attr_factory(attrnm))

        return super(FrameMeta, cls).__new__(cls, name, parents, clsdct)

    @staticmethod
    def repr_getter_factory(reprnm):
        def getter(self):
            rep = self.represent_as(self.preferred_representation)
            return getattr(rep, reprnm)
        return getter

    @staticmethod
    def frame_attr_factory(attrnm):
        def getter(self):
            return getattr(self, '_'+ attrnm)
        return getter


@six.add_metaclass(FrameMeta)
class BaseCoordinateFrame(object):
    """
    The base class for coordinate frames.

    This class is intended to be subclassed to create instances of specific
    systems.  Subclasses can implement the following attributes.

    * `preferred_representation`
        A subclass of `~astropy.coordinates.BaseRepresentation` that will be
        treated as the "standard" representation of this frame, or None to have
        no special representation.

    * `preferred_attr_names`
        A dictionary mapping attribute names to be created on *this* class to
        names of attributes on the `preferred_representation`. If
        `preferred_representation` is None, this does nothing.

    * `preferred_attr_units`
        A dictionary mapping attribute names to their preferred human-readable
        units. Keys must also be keys in `preferred_attr_names`.

    * `frame_attr_names`
        A dictionary with keys that are the additional attributes necessary to
        specify the frame, and values that are the default values of those
        attributes.
    """

    preferred_representation = None
    preferred_attr_names = {}  # maps preferred name to "real" name on repr obj
    preferred_attr_units = {}  # maps preferred name to the "standard" unit/string repr
    frame_attr_names = {}  # maps attribute to default value

    def __init__(self, *args, **kwargs):
        from .representation import SphericalRepresentation, \
                                    UnitSphericalRepresentation, \
                                    BaseRepresentation

        representation = None  # if not set below, this is a frame with no data

        for fnm, fdefault in six.iteritems(self.frame_attr_names):

            # read-only properties for these attributes are made in the
            # metaclass  so we set the 'real' attrbiutes as the name prefaced
            # with an underscore

            if fnm in kwargs:
                value = kwargs.pop(fnm)
                # If attribute is a time (equinox, obstime) then validate and force
                # into a Time object by running through the Time constructor
                if fnm in TIME_FRAME_ATTRS:
                    value = _convert_to_time(fnm, value)
                setattr(self, '_' + fnm, value)
            else:
                setattr(self, '_' + fnm, fdefault)

        pref_rep = self.preferred_representation
        args = list(args)  # need to be able to pop them
        if (len(args) > 0) and (isinstance(args[0], BaseRepresentation) or
                                args[0] is None):
            representation = args.pop(0)
            if len(args) > 0:
                raise TypeError('Cannot create a frame with both a '
                                'representation and other positional arguments')

        elif pref_rep:
            pref_kwargs = {}
            for nmkw, nmrep in six.iteritems(self.preferred_attr_names):<commit_msg>change TIME_FRAME_ATTRS to self/class-level time_attr_names<commit_after># -*- coding: utf-8 -*-
# Licensed under a 3-clause BSD style license - see LICENSE.rst
"""
Framework and base classes for coordinate frames/"low-level" coordinate classes.
"""
from __future__ import (absolute_import, unicode_literals, division,
                        print_function)

# Standard library
import copy
import inspect

# Dependencies
import numpy as np

# Project
from ..extern import six
from .. import units as u
from .transformations import TransformGraph

__all__ = ['BaseCoordinateFrame', 'frame_transform_graph', 'GenericFrame']

# the graph used for all transformations between frames
frame_transform_graph = TransformGraph()


class FrameMeta(type):
    def __new__(cls, name, parents, clsdct):
        # somewhat hacky, but this is the best way to get the MRO according to
        # https://mail.python.org/pipermail/python-list/2002-December/167861.html
        mro = super(FrameMeta, cls).__new__(cls, name, parents, clsdct).__mro__
        parent_clsdcts = [c.__dict__ for c in mro]
        parent_clsdcts.insert(0, clsdct)

        #now look through the whole MRO for the relevant class attributes
        pref_repr = None
        pref_attrs = frame_attrs = {}
        found_pref_repr = found_pref_attrs = found_frame_attrs = False
        for clsdcti in parent_clsdcts:
            if not found_pref_repr and 'preferred_representation' in clsdcti:
                pref_repr = clsdcti['preferred_representation']
                found_pref_repr = True
            if not found_pref_attrs and 'preferred_attr_names' in clsdcti:
                pref_attrs = clsdcti['preferred_attr_names']
                found_pref_attrs = True
            if not found_frame_attrs and 'frame_attr_names' in clsdcti:
                frame_attrs = clsdcti['frame_attr_names']
                found_frame_attrs = True

            if found_pref_repr and found_pref_attrs and found_frame_attrs:
                break
        else:
            raise ValueError('Could not find the expected BaseCoordinateFrame '
                             'class attributes.  Are you mis-using FrameMeta?')

        if pref_repr:
            # create properties for the preferred_attr_names
            for propnm, reprnm in six.iteritems(pref_attrs):
                clsdct[propnm] = property(FrameMeta.repr_getter_factory(reprnm))

        #also make properties for the frame_attr_names to make them immutible
        #after creation
        for attrnm in frame_attrs:
            if attrnm in clsdct:
                if isinstance(clsdct[attrnm], property):
                    #means the property was defined already... so trust the
                    #subclasser and don't make a new one
                    continue
                else:
                    raise ValueError("A non-property exists that's *also* in frame_attr_names")
            clsdct[attrnm] = property(FrameMeta.frame_attr_factory(attrnm))

        return super(FrameMeta, cls).__new__(cls, name, parents, clsdct)

    @staticmethod
    def repr_getter_factory(reprnm):
        def getter(self):
            rep = self.represent_as(self.preferred_representation)
            return getattr(rep, reprnm)
        return getter

    @staticmethod
    def frame_attr_factory(attrnm):
        def getter(self):
            return getattr(self, '_'+ attrnm)
        return getter


@six.add_metaclass(FrameMeta)
class BaseCoordinateFrame(object):
    """
    The base class for coordinate frames.

    This class is intended to be subclassed to create instances of specific
    systems.  Subclasses can implement the following attributes.

    * `preferred_representation`
        A subclass of `~astropy.coordinates.BaseRepresentation` that will be
        treated as the "standard" representation of this frame, or None to have
        no special representation.

    * `preferred_attr_names`
        A dictionary mapping attribute names to be created on *this* class to
        names of attributes on the `preferred_representation`. If
        `preferred_representation` is None, this does nothing.

    * `preferred_attr_units`
        A dictionary mapping attribute names to their preferred human-readable
        units. Keys must also be keys in `preferred_attr_names`.

    * `frame_attr_names`
        A dictionary with keys that are the additional attributes necessary to
        specify the frame, and values that are the default values of those
        attributes.

    * `time_attr_names`
        A sequence of attribute names that must be `~astropy.time.Time` objects.
        When given  as keywords in the initializer, these will be converted if
        possible (e.g. from the string 'J2000' to the appropriate
        `~astropy.time.Time` object).  Defaults to ``('equinox', 'obstime')``.

    """

    preferred_representation = None
    preferred_attr_names = {}  # maps preferred name to "real" name on repr obj
    preferred_attr_units = {}  # maps preferred name to the "standard" unit/string repr
    frame_attr_names = {}  # maps attribute to default value
    time_attr_names = ('equinox', 'obstime')  # Attributes that must be Time objects

    def __init__(self, *args, **kwargs):
        from .representation import SphericalRepresentation, \
                                    UnitSphericalRepresentation, \
                                    BaseRepresentation

        representation = None  # if not set below, this is a frame with no data

        for fnm, fdefault in six.iteritems(self.frame_attr_names):

            # read-only properties for these attributes are made in the
            # metaclass  so we set the 'real' attrbiutes as the name prefaced
            # with an underscore

            if fnm in kwargs:
                value = kwargs.pop(fnm)
                # If attribute is a time (equinox, obstime) then validate and force
                # into a Time object by running through the Time constructor
                if fnm in self.time_attr_names:
                    value = _convert_to_time(fnm, value)
                setattr(self, '_' + fnm, value)
            else:
                setattr(self, '_' + fnm, fdefault)

        pref_rep = self.preferred_representation
        args = list(args)  # need to be able to pop them
        if (len(args) > 0) and (isinstance(args[0], BaseRepresentation) or
                                args[0] is None):
            representation = args.pop(0)
            if len(args) > 0:
                raise TypeError('Cannot create a frame with both a '
                                'representation and other positional arguments')

        elif pref_rep:
            pref_kwargs = {}
            for nmkw, nmrep in six.iteritems(self.preferred_attr_names):
{'fraction_non_alphanumeric': 0.06551541316367493, 'fraction_numerical': 0.003029614481557222, 'mean_word_length': 2.3109327983951857, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7368865', 'n_tokens_mistral': 3620, 'n_tokens_neox': 3443, 'n_words': 1177}