<commit_before>"""
Resources.

This file is part of the everest project.
See LICENSE.txt for licensing, CONTRIBUTORS.txt for contributor information.

Created on Nov 3, 2011.
"""
from everest.entities.utils import get_entity_class
from everest.entities.utils import identifier_from_slug
from everest.querying.base import SpecificationVisitorBase
from everest.querying.interfaces import ISpecificationVisitor
from everest.querying.specifications import AscendingOrderSpecification
from everest.querying.utils import get_filter_specification_factory
from everest.representers.interfaces import ILinkedDataElement
from everest.resources.attributes import ResourceAttributeControllerMixin
from everest.resources.attributes import ResourceAttributeKinds
from everest.resources.attributes import get_resource_class_attributes
from everest.resources.descriptors import terminal_attribute
from everest.resources.interfaces import ICollectionResource
from everest.resources.interfaces import IMemberResource
from everest.resources.interfaces import IResource
from everest.resources.link import Link
from everest.resources.utils import as_member
from everest.resources.utils import get_member_class
from everest.resources.utils import resource_to_url
from everest.resources.utils import url_to_resource
from pyramid.security import Allow
from pyramid.security import Authenticated
from pyramid.traversal import model_path
from zope.interface import implements # pylint: disable=E0611,F0401
from zope.interface import providedBy as provided_by # pylint: disable=E0611,F0401
import uuid

__docformat__ = "reStructuredText en"
__all__ = ['Collection',
           'Member',
           'Resource',
           ]


class Resource(object):
    """
    This is the abstract base class for all resources.
    """
    implements(IResource)

    #: Authentication specifier. Override as needed.
    __acl__ = [
        (Allow, Authenticated, 'view'),
        (Allow, Authenticated, 'create'),
        (Allow, Authenticated, 'update'),
        (Allow, Authenticated, 'delete'),
        ]
    #: The parent of this resource. This is `None` for the service resource.
    __parent__ = None
    #: The name of the resource. This has to be unique within the parent.
    __name__ = None
    #: The relation identifier to show in links to this resource. Needs to
    #: be specified in derived classes.
    relation = None
    #: Descriptive title for this resource.
    title = ''
    #: Detailed description of this resource.
    description = ''

    def __init__(self):
        """
        Constructor:
        """
        if self.__class__ is Resource:
            raise NotImplementedError('Abstract class')
        if self.__class__.relation is None:
            raise ValueError('Resource classes must have a relation '
                             'attribute.')
        #: A set of links to other resources.
        self.links = set()

    def add_link(self, link):
        """
        Adds a link to another resource.

        :param link: a resource link
        :type link: :class:`everest.resources.base.Link`
        """
        self.links.add(link)

    @property
    def path(self):
        """
        Returns the path to this resource in the tree of resources.
        """
        return model_path(self)

    @property
    def urn(self):
        """
        Returns the URN for this resource (globally unique identifier).
        """
        return uuid.uuid5(uuid.NAMESPACE_URL, self.path).urn

    @classmethod
    def create_from_data(cls, data_element):
        """
        Creates a resource instance from the given data element (tree).

        :param data_element: data element (hierarchical) to create a resource
            from
        :type data_element: object implementing
         :class:`everest.resources.representers.interfaces.IExplicitDataElement`
        """
        return data_element.mapping.map_to_resource(data_element)


class Member(ResourceAttributeControllerMixin, Resource):
    """
    This is an abstract class for all member resources.
    """
    implements(IMemberResource)

    id = terminal_attribute(int, 'id')

    def __init__(self, entity, name=None):
        """
        Constructor:

        :param name: unique name of the member within the collection
        :type name: :class:`string`
        :param entity: the associated entity (domain object)
        :type entity: an object implementing an interface derived from
                :class:`everest.entities.interfaces.IEntity`
        """
        if self.__class__ is Member:
            raise NotImplementedError('Abstract class')
        if not isinstance(entity, get_entity_class(self)):
            raise ValueError(
                    'Invalid entity class "%s" for %s resource class.'
                    % (entity.__class__.__name__, self.__class__.__name__))
        super(Member, self).__init__()
        self.__entity = entity
        # Add the rel="self" link.
        self.add_link(Link(self, "self"))
        self.__name = name

    def _get__name__(self):
        # The name of a member resource defaults to the slug of the underlying
        # entity.
        return self.__name or self.__entity.slug

    def _set__name__(self, name):
        self.__name = name

    __name__ = property(_get__name__, _set__name__)

    @classmethod
    def create_from_entity(cls, entity):
        """
        Class factory method creating a new resource from the given entity.
        """
        return cls(entity)

    def get_entity(self):
        """
        Returns the entity this resource manages.

        :return: an object implementing
            :class:`everest.entities.interfaces.IEntity`.
        """
        return self.__entity

    def delete(self):
        """
        Deletes this member.

        Deleting a member resource means removing it from its parent
        resource.
        """
        self.__parent__.remove(self)

    def update_from_data(self, data_element):
        """
        Updates this member from the given data element.

        :param data_element: data element (hierarchical) to create a resource
            from
        :type data_element: object implementing
         `:class:everest.resources.representers.interfaces.IExplicitDataElement`

        """
        mp = data_element.mapping
        for attr in mp.attribute_iterator():
            if attr.kind == ResourceAttributeKinds.TERMINAL:
                other_value = data_element.get_terminal(attr)
                if other_value is None:
                    # Optional attribute - continue.
                    continue
                else:
                    setattr(self, attr.name, other_value)
            else: # attr.kind MEMBER or COLLECTION
                rc_data_el = data_element.get_nested(attr)
                if rc_data_el is None:<commit_msg>Added update_from_entity to the Member class.<commit_after>"""
Resources.

This file is part of the everest project.
See LICENSE.txt for licensing, CONTRIBUTORS.txt for contributor information.

Created on Nov 3, 2011.
"""
from everest.entities.utils import get_entity_class
from everest.entities.utils import identifier_from_slug
from everest.querying.base import SpecificationVisitorBase
from everest.querying.interfaces import ISpecificationVisitor
from everest.querying.specifications import AscendingOrderSpecification
from everest.querying.utils import get_filter_specification_factory
from everest.representers.interfaces import ILinkedDataElement
from everest.resources.attributes import ResourceAttributeControllerMixin
from everest.resources.attributes import ResourceAttributeKinds
from everest.resources.attributes import get_resource_class_attributes
from everest.resources.descriptors import terminal_attribute
from everest.resources.interfaces import ICollectionResource
from everest.resources.interfaces import IMemberResource
from everest.resources.interfaces import IResource
from everest.resources.link import Link
from everest.resources.utils import as_member
from everest.resources.utils import get_member_class
from everest.resources.utils import resource_to_url
from everest.resources.utils import url_to_resource
from pyramid.security import Allow
from pyramid.security import Authenticated
from pyramid.traversal import model_path
from zope.interface import implements # pylint: disable=E0611,F0401
from zope.interface import providedBy as provided_by # pylint: disable=E0611,F0401
import uuid

__docformat__ = "reStructuredText en"
__all__ = ['Collection',
           'Member',
           'Resource',
           ]


class Resource(object):
    """
    This is the abstract base class for all resources.
    """
    implements(IResource)

    #: Authentication specifier. Override as needed.
    __acl__ = [
        (Allow, Authenticated, 'view'),
        (Allow, Authenticated, 'create'),
        (Allow, Authenticated, 'update'),
        (Allow, Authenticated, 'delete'),
        ]
    #: The parent of this resource. This is `None` for the service resource.
    __parent__ = None
    #: The name of the resource. This has to be unique within the parent.
    __name__ = None
    #: The relation identifier to show in links to this resource. Needs to
    #: be specified in derived classes.
    relation = None
    #: Descriptive title for this resource.
    title = ''
    #: Detailed description of this resource.
    description = ''

    def __init__(self):
        """
        Constructor:
        """
        if self.__class__ is Resource:
            raise NotImplementedError('Abstract class')
        if self.__class__.relation is None:
            raise ValueError('Resource classes must have a relation '
                             'attribute.')
        #: A set of links to other resources.
        self.links = set()

    def add_link(self, link):
        """
        Adds a link to another resource.

        :param link: a resource link
        :type link: :class:`everest.resources.base.Link`
        """
        self.links.add(link)

    @property
    def path(self):
        """
        Returns the path to this resource in the tree of resources.
        """
        return model_path(self)

    @property
    def urn(self):
        """
        Returns the URN for this resource (globally unique identifier).
        """
        return uuid.uuid5(uuid.NAMESPACE_URL, self.path).urn

    @classmethod
    def create_from_data(cls, data_element):
        """
        Creates a resource instance from the given data element (tree).

        :param data_element: data element (hierarchical) to create a resource
            from
        :type data_element: object implementing
         :class:`everest.resources.representers.interfaces.IExplicitDataElement`
        """
        return data_element.mapping.map_to_resource(data_element)


class Member(ResourceAttributeControllerMixin, Resource):
    """
    This is an abstract class for all member resources.
    """
    implements(IMemberResource)

    id = terminal_attribute(int, 'id')

    def __init__(self, entity, name=None):
        """
        Constructor:

        :param name: unique name of the member within the collection
        :type name: :class:`string`
        :param entity: the associated entity (domain object)
        :type entity: an object implementing an interface derived from
                :class:`everest.entities.interfaces.IEntity`
        """
        if self.__class__ is Member:
            raise NotImplementedError('Abstract class')
        if not isinstance(entity, get_entity_class(self)):
            raise ValueError(
                    'Invalid entity class "%s" for %s resource class.'
                    % (entity.__class__.__name__, self.__class__.__name__))
        super(Member, self).__init__()
        self.__entity = entity
        # Add the rel="self" link.
        self.add_link(Link(self, "self"))
        self.__name = name

    def _get__name__(self):
        # The name of a member resource defaults to the slug of the underlying
        # entity.
        return self.__name or self.__entity.slug

    def _set__name__(self, name):
        self.__name = name

    __name__ = property(_get__name__, _set__name__)

    @classmethod
    def create_from_entity(cls, entity):
        """
        Class factory method creating a new resource from the given entity.
        """
        return cls(entity)

    def get_entity(self):
        """
        Returns the entity this resource manages.

        :return: an object implementing
            :class:`everest.entities.interfaces.IEntity`.
        """
        return self.__entity

    def delete(self):
        """
        Deletes this member.

        Deleting a member resource means removing it from its parent
        resource.
        """
        self.__parent__.remove(self)

    def update_from_entity(self, new_entity):
        """
        Updates this member from the given new entity.
        
        See :method:`Collection.update_from_entity`.
        """
        self.__parent__.update_from_entity(self, new_entity)

    def update_from_data(self, data_element):
        """
        Updates this member from the given data element.

        :param data_element: data element (hierarchical) to create a resource
            from
        :type data_element: object implementing
         `:class:everest.resources.representers.interfaces.IExplicitDataElement`

        """
        mp = data_element.mapping
        for attr in mp.attribute_iterator():
            if attr.kind == ResourceAttributeKinds.TERMINAL:
                other_value = data_element.get_terminal(attr)
                if other_value is None:
                    # Optional attribute - continue.
                    continue
                else:
                    setattr(self, attr.name, other_value)
            else: # attr.kind MEMBER or COLLECTION
                rc_data_el = data_element.get_nested(attr)
                if rc_data_el is None:
{'fraction_non_alphanumeric': 0.07557017230285265, 'fraction_numerical': 0.0031457782226353044, 'mean_word_length': 2.6042257150219017, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1846524', 'n_tokens_mistral': 3674, 'n_tokens_neox': 3544, 'n_words': 1135}