# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['nv',
 'nv.utils.collections.registry',
 'nv.utils.collections.registry.implementations']

package_data = \
{'': ['*']}

setup_kwargs = {
    'name': 'nv-utils-registry',
    'version': '0.1.0',
    'description': 'Specialized mapping for retrieving content with default hirearchy of matching keys',
    'long_description': '# nv-utils-registry\nThis is a generic mapping container that implements some registration logic.\n\nAll the logic lies behind \n\n\n## Installation\nTo install this package, run:\n\n    pip install nv_utils_registry\n\nAs part of `nv.utils` namespace package, the `registry` module will be available \nas one of the library `collections`:\n\n    import nv.utils.collections.registry as registry\n\n\n## Usage\n\nThe registry is a simple container \nthat can be used to store and retrieve objects by a unique identifier class as key.\n\nAs a regular Python dictionary,\nonly hashable objects can be used as registry keys.\n\nIf the key class implements an `iter_defaults` method\nthat returns an iterable of default keys in a hierarchical order\n(i.e. from the most specific to the most general),\nthe registry will return the value associated with the first default key that matches an existing key.\n\nThe registry accepts a default value that will be returned if no key \n(including any alternative keys provided by `iter_defaults`) is found.\nHowever, if no default is provided,\nthe registry will raise a `KeyError` in the absence of a valid key.\n\n\n### Dictionary with a default\n\nLet\'s start with the simplest and silly version of it: \none that does nothing but implementing a dictionary with strings as keys and\na default value:\n\n    from nv.utils.collections.registry import BaseContentRegistry\n\n    class SillyRegistry(BaseRegistry):\n        registry_key_constructor = str\n\nIf you use this registry, you can store and retrieve objects by strings:\n\n    registry = SillyRegistry(default=\'oops\')\n\n    # You may use it as a regular dictionary\n    registry[\'foo\'] = \'bar\'\n    registry[\'foo\']\n    # \'bar\'\n\n    registry[\'whatever\']\n    # \'oops\'\n\n    # Or use its specialized methods\n    registry.get_content(\'foo\')\n    # \'bar\'\n\n    registry.get_content(\'whatever\', default=\'use this instead\')\n    # \'use this instead\'\n\n    registry.register_content(\'whatever\', \'you got it!\')\n    registry.get_content(\'whatever\')\n    # \'you got it!\'\n\nSo far, nothing really exciting.\n\n\n### Using the default hierarchy\n\nLet\'s move to a more useful version of this collection.\nLet\'s assume that you want to store and retrieve classes by a hierarchy of keys.\n\n    from dataclasses import dataclass\n\n    # Let\'s set frozen=true and order=True to have a hasahble dataclass\n    @dataclass(frozen=True, order=True)\n    class AnimalKey(BaseContentRegistry):\n        category: str\n        subcategory: str\n\n        def iter_defaults(self):\n            # This will teach how to find alternative default keys for this key,\n            # in this case, by adding a \'*\' progressively\n            cls = self.__class__\n            yield cls(self.category, "*")\n            yield cls("*", "*")\n\nNotice that we have implemented `iter_defaults` method, which will yield\na sequence of keys that will teach the dictionary how to look for a sequence of defaults\nfrom the more specific to the more generic.\n\n    # Let\'s create our custom registry\n    class AnimalRegistry(BaseRegistry):\n        registry_key_constructor = AnimalKey\n\n    registry = AnimalRegistry()\n\n    class GenericAnimal:\n        pass\n\n    # Now let\'s register some animal classes using a convenient decorator\n    @registry.register(\'mammal\', \'canine\')\n    class Canine:\n        pass\n\n    @registry.register(\'mammal\', \'feline\')\n    class Feline:\n        pass\n\n    # You can use the register_content method as well\n    class Ape:\n        pass\n    \n    registry.register_content(\'mammal\', \'ape\', Ape)\n\n    # Now let\'s add a default for the category \'mammal\'\n    @registry.register(\'mammal\', \'*\')\n    class GenericMammal:\n        pass\n\n    registry.register_content(\'reptile\', \'turtle\', Turtle)\n\n    # Now let\'s add a default for all categories\n    @registry.register(\'*\', \'*\')\n    class GenericAnimal:\n        pass\n\n    # Now let\'s retrieve the classes\n    cat_cls = registry.get_content(\'mammal\', \'feline\')         # Feline\n    dog_cls = registry.get_content(\'mammal\', \'canine\')         # Canine\n    hamster_cls = registry.get_content(\'mammal\', \'rodent\')     # GenericMammal\n    sea_turtle_cls = registry.get_content(category=\'reptile\', subcategory=\'turtle\')     # Turtle\n    chameleon_cls = registry.get_content(\'reptile\', \'lizard\')  # GenericAnimal\n    \n    # The decorator, get_content and register_content will recreate the key object\n    # by building it from its args or kwargs,\n    # but if you have the key object you can use the dictionary directly\n\n    canine_key = AnimalKey(\'mammal\', \'canine\')\n    wolf_cls = registry[canine_key]\n\n    fox_cls = registry.get_content_by_key(canine_key, default=None)\n\n\n### Customizing the behavior of our registry\n\nThe `BaseRegistry` class provides a way to customize its behavior while dealing with\nduplicate registrations (or changes to any of the existing values).\n\n    class AnimalRegistry(BaseRegistry, change_behavior=BaseRegistry.ChangeBehavior.RAISE):\n        registry_key_constructor = AnimalKey\n\n    registry = AnimalRegistry()\n\n    # Let\'s register some animal classes using a convenient decorator\n    @registry.register(\'mammal\', \'canine\')\n    class Canine:\n        pass\n\n    # This shall raise a TypeError\n    @registry.register(\'mammal\', \'canine\')\n    class AnotherCanine:\n        pass\n\n    # This shall also raise a TypeError\n    del registry[AnimalKey(\'mammal\', \'canine\')]\n\n    # However, this will not raise an error, as we are registering\n    # the same content under the same key again.\n    registry.register_content(Canine, \'mammal\', \'canine\')\n\nThis behavior can be customized by setting the `change_behavior` attribute to `WARN`\nif you want to be warned when you try to register under a key that is already registered,\nor to `IGNORE` if you want to ignore duplicate registrations (default).\n\nThe comparison is made via `==` operator of the key objects. \nIf you want to customize the comparison, you can override the `__eq__` method.\n\n\n### Using other mappings under the hood\n\nIf you need an alternative mapping to store the content, no problem. \nYou can provide your custom mapping at the `__init__` method,\nand that mapping will serve as the underlying storage.\n\nPlease notice that if you change the underlying mapping directly,\nthe registry will not be aware of the changes!\n\n    from collections import OrderedDict\n\n    custom_mapping = OrderedDict()\n\n    class AnimalRegistry(BaseRegistry):\n        registry_key_constructor = AnimalKey\n\n    # Registry instance will use the custom mapping\n    registry = AnimalRegistry(custom_mapping)\n\n\n### Bugs, suggestions, findings, etc.\n\nPlease submit any bug reports, suggestions, patches, etc. to\nthis github repo.\n',
    'author': 'Gustavo Santos',
    'author_email': 'gustavo@next.ventures',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/nextventures/nv-utils-registry.git',
    'packages': packages,
    'package_data': package_data,
    'python_requires': '>=3.10,<4.0',
}


setup(**setup_kwargs)
