File: PKG-INFO

package info (click to toggle)
python-persisting-theory 1.0-3
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 196 kB
  • sloc: python: 423; makefile: 3
file content (292 lines) | stat: -rw-r--r-- 7,230 bytes parent folder | download | duplicates (2)
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
Metadata-Version: 2.1
Name: persisting-theory
Version: 1.0
Summary: Registries that can autodiscover values accross your project apps
Home-page: https://code.agate.blue/agate/persisting-theory
Author: Agate Blue
License: BSD
Platform: UNKNOWN
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
License-File: COPYING

Introduction
============

Persisting-theory is a small python utility designed to automate data discovering and access inside a list of packages. Use case: you are building an application that will have pluggable components. You want to allow these components to register data so it can be accessed by any other component of your app.
If you ever used Django framework, you may remember this:

.. code-block:: python

    from django.contrib import admin
    admin.autodiscover()

Basically, persisting-theory will do the same, except that it let you declare what you want to autodiscover.

Okay, I'm bad at explaining things, and english is not my mother tongue. Let's build a simple example.

Quickstart
==========

Install
*******

Install the package from `PyPi <https://pypi.python.org/pypi/persisting-theory/>`_. via pip (or any other tool)::

    pip install persisting-theory

Persisting-theory does not require any dependency but a python installation (it has been tested on python 2.7 and python 3.4).

Setup
*****

A basic setup:

.. code-block:: python

    # registries.py

    from persiting_theory import Registry

    class CallbacksRegistry(Registry):
        """
            Allow your apps to register callbacks
        """
        # the package where the registry will try to find callbacks in each app
        look_into = "callbacks_registry"

    callbacks_registry = CallbacksRegistry()


    # app1/callbacks_registry.py

    from registries import callbacks_registry

    @callbacks_registry.register
    def dog():
        print("Wouf")


    # app2/callbacks_registry.py

    from registries import callbacks_registry

    @callbacks_registry.register
    def cat():
        print("Meow")


    # dosomething.py

    from registries import callbacks_registry

    APPS = (
        'app1',
        'app2',
    )

    # Trigger autodiscovering process
    callbacks_registry.autodiscover(APPS)

    for callback in callbacks_registry.values():
        callback()

        # Wouf
        # Meow

API
===

``Registry`` inherits from python built-in `collections.OrderedDict`, which means you can use regular dict methods to access registered data:

.. code-block:: python

    callbacks_registry.get("dog")()  #  will print Wouf
    assert callbacks_registry.get("chicken", None) is None

Registry.register()
*******************

You can use this function as a decorator for registering functions and classes:

.. code-block:: python

    from persisting_theory import Registry

    class AwesomeRegistry(Registry):
        pass

    r = AwesomeRegistry()

    # register a class
    @r.register
    class AwesomeClass:
        pass

    # register a function
    @r.register
    def awesome_function():
        pass

    # By default, the key in the registry for a given value is obtained from the function or class name, if possible

    assert r.get("AwesomeClass") == AwesomeClass
    assert r.get("awesome_function") == awesome_function

    # You can override this behaviour:

    @r.register(name="Chuck")
    class AwesomeClass:
        pass

    @r.register(name="Norris")
    def awesome_function():
        pass

    assert r.get("Chuck") == AwesomeClass
    assert r.get("Norris") == awesome_function


    # You can also use the register method as is

    awesome_var = "Chuck Norris"
    r.register(awesome_var, name="Who am I ?")

    assert r.get("Who am I ?") == awesome_var

    # I f you are not registering a function or a class, you MUST provide a name argument

Registry.validate()
*******************

By default, a registry will accept any registered value. Sometimes, it's not what you want, so you can restrict what kind of data your registry accepts:

.. code-block:: python

    from persisting_theory import Registry

    class StartsWithAwesomeRegistry(Registry):

        def validate(self, data):
            if isinstance(data, str):
                return data.startswith("awesome")
            return False

    r = StartsWithAwesomeRegistry()

    # will pass registration
    r.register("awesome day", name="awesome_day")

    # will fail and raise ValueError
    r.register("not so awesome day", name="not_so_awesome_day")

Registry.prepare_data()
***********************

If you want to manipulate your data before registering it, override this method. In this example, we prefix every registered string with 'hello':

.. code-block:: python

    from persisting_theory import Registry

    class HelloRegistry(Registry):

        def prepare_data(self, data):
            return 'hello ' + data

    r = HelloRegistry()

    class Greeting:
        def __init__(self, first_name):
            self.first_name = first_name


    r.register(Greeting('World'), name="world")
    r.register(Greeting('agate'), name="agate")

    assert r.register.get('world') == "hello World"
    assert r.register.get('agate') == "hello agate"


Registry.prepare_name()
***********************

In a similar way, you can manipulate the name of registered data. This can help if you want to avoid repetitions. Let's improve our previous example:

.. code-block:: python

    from persisting_theory import Registry

    class HelloRegistry(Registry):

        def prepare_data(self, data):
            return 'hello ' + data

        def prepare_name(self, data, name=None):
            return self.data.first_name.lower()

    r = HelloRegistry()

    class Greeting:
        def __init__(self, first_name):
            self.first_name = first_name


    r.register(Greeting('World'))
    r.register(Greeting('agate'))

    assert r.register.get('world') == "hello World"
    assert r.register.get('agate') == "hello agate"

Going meta
**********

If you have multiple registries, or want to allow your apps to declare their own registries, this is for you:

.. code-block:: python

    # registries.py

    from persisting_theory import meta_registry, Registry

    class RegistryA(Registry):
        look_into = "a"

    class RegistryB(Registry):
        look_into = "b"

    registry_a = RegistryA()
    meta_registry.register(registry_a, name="registry_a")

    registry_b = RegistryB()
    meta_registry.register(registry_b, name="registry_b")


    # dosomethingelse.py

    from persisting_theory import meta_registry

    # will import registries declared in `registries` packages, and trigger autodiscover() on each of them
    meta_registry.autodiscover(apps=("app1", "app2"))


What the hell is that name ?
============================

It's an anagram for "python registries".

Contribute
==========

Contributions, bug reports, and "thank you" are welcomed.

License
=======

The project is licensed under BSD licence.