File: getting_started.rst

package info (click to toggle)
python-phx-class-registry 4.1.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 260 kB
  • sloc: python: 886; makefile: 19
file content (165 lines) | stat: -rw-r--r-- 4,386 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
Getting Started
===============
As you saw in the :doc:`introduction </index>`, you can create a new registry
using the :py:class:`class_registry.ClassRegistry` class.

:py:class:`ClassRegistry` defines a ``register`` method that you can use as a
decorator to add classes to the registry:

.. code-block:: python

   from class_registry import ClassRegistry

   pokedex = ClassRegistry()

   @pokedex.register('fire')
   class Charizard(object):
     pass

Once you've registered a class, you can then create a new instance using the
corresponding registry key:

.. code-block:: python

   sparky = pokedex['fire']
   assert isinstance(sparky, Charizard)

Note in the above example that ``sparky`` is an `instance` of ``Charizard``.

If you try to access a registry key that has no classes registered, it will
raise a :py:class:`class_registry.RegistryKeyError`:

.. code-block:: python

   from class_registry import RegistryKeyError

   try:
     tex = pokedex['spicy']
   except RegistryKeyError:
     pass


Registry Keys
-------------
By default, you have to provide the registry key whenever you register a new
class.  But, there's an easier way to do it!

When you initialize your :py:class:`ClassRegistry`, provide an ``attr_name``
parameter.  When you register new classes, your registry will automatically
extract the registry key using that attribute:

.. code-block:: python

   pokedex = ClassRegistry('element')

   @pokedex.register
   class Squirtle(object):
     element = 'water'

   beauregard = pokedex['water']
   assert isinstance(beauregard, Squirtle)

Note in the above example that the registry automatically extracted the registry
key for the ``Squirtle`` class using its ``element`` attribute.

Collisions
----------
What happens if two classes have the same registry key?

.. code-block:: python

   pokedex = ClassRegistry('element')

   @pokedex.register
   class Bulbasaur(object):
     element = 'grass'

   @pokedex.register
   class Ivysaur(object):
     element = 'grass'

   janet = pokedex['grass']
   assert isinstance(janet, Ivysaur)

As you can see, if two (or more) classes have the same registry key, whichever
one is registered last will override any of the other(s).

.. note::

    It is not always easy to predict the order in which classes will be
    registered, especially when they are spread across different modules, so you
    probably don't want to rely on this behaviour!

If you want to prevent collisions, you can pass ``unique=True`` to the
:py:class:`ClassRegistry` initializer to raise an exception whenever a collision
occurs:

.. code-block:: python

   from class_registry import RegistryKeyError

   pokedex = ClassRegistry('element', unique=True)

   @pokedex.register
   class Bulbasaur(object):
     element = 'grass'

   try:
     @pokedex.register
     class Ivysaur(object):
       element = 'grass'
   except RegistryKeyError:
     pass

   janet = pokedex['grass']
   assert isinstance(janet, Bulbasaur)

Because we passed ``unique=True`` to the :py:class:`ClassRegistry` initialiser,
attempting to register ``Ivysaur`` with the same registry key as ``Bulbasaur``
raised a :py:class:`RegistryKeyError`, so it didn't override ``Bulbasaur``.

Init Params
-----------
Every time you access a registry key in a :py:class:`ClassRegistry`, it creates
a new instance:

.. code-block:: python

   marlene = pokedex['grass']
   charlene = pokedex['grass']

   assert marlene is not charlene

Since you're creating a new instance every time, you also have the option of
providing args and kwargs to the class initialiser using the registry's
:py:meth:`get` method:

.. code-block:: python

   pokedex = ClassRegistry('element')

   @pokedex.register
   class Caterpie(object):
     element = 'bug'

     def __init__(self, level=1):
       super(Caterpie, self).__init__()
       self.level = level

   timmy = pokedex.get('bug')
   assert timmy.level == 1

   tommy = pokedex.get('bug', 16)
   assert tommy.level == 16

   tammy = pokedex.get('bug', level=42)
   assert tammy.level == 42

Any arguments that you provide to :py:meth:`get` will be passed directly to the
corresponding class' initialiser.

.. hint::

   You can create a registry that always returns the same instance per registry
   key by wrapping it in a :py:class:`ClassRegistryInstanceCache`.  See
   :doc:`factories_vs_registries` for more information.