iPOPO 3.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. ipopo-3.1.0.dist-info/METADATA +548 -0
  2. ipopo-3.1.0.dist-info/RECORD +111 -0
  3. ipopo-3.1.0.dist-info/WHEEL +4 -0
  4. ipopo-3.1.0.dist-info/licenses/LICENSE +202 -0
  5. pelix/__init__.py +33 -0
  6. pelix/constants.py +328 -0
  7. pelix/framework.py +1949 -0
  8. pelix/http/__init__.py +481 -0
  9. pelix/http/basic.py +1047 -0
  10. pelix/http/routing.py +415 -0
  11. pelix/internals/__init__.py +33 -0
  12. pelix/internals/events.py +190 -0
  13. pelix/internals/hooks.py +231 -0
  14. pelix/internals/registry.py +1544 -0
  15. pelix/ipopo/__init__.py +35 -0
  16. pelix/ipopo/constants.py +593 -0
  17. pelix/ipopo/contexts.py +567 -0
  18. pelix/ipopo/core.py +1261 -0
  19. pelix/ipopo/decorators.py +2198 -0
  20. pelix/ipopo/handlers/__init__.py +33 -0
  21. pelix/ipopo/handlers/constants.py +290 -0
  22. pelix/ipopo/handlers/properties.py +227 -0
  23. pelix/ipopo/handlers/provides.py +344 -0
  24. pelix/ipopo/handlers/requires.py +653 -0
  25. pelix/ipopo/handlers/requiresbest.py +221 -0
  26. pelix/ipopo/handlers/requiresbroadcast.py +472 -0
  27. pelix/ipopo/handlers/requiresmap.py +644 -0
  28. pelix/ipopo/handlers/requiresvarfilter.py +297 -0
  29. pelix/ipopo/handlers/temporal.py +360 -0
  30. pelix/ipopo/instance.py +896 -0
  31. pelix/ipopo/waiting.py +309 -0
  32. pelix/ipv6utils.py +88 -0
  33. pelix/ldapfilter.py +927 -0
  34. pelix/misc/__init__.py +220 -0
  35. pelix/misc/eventadmin_printer.py +113 -0
  36. pelix/misc/init_handler.py +396 -0
  37. pelix/misc/jabsorb.py +322 -0
  38. pelix/misc/log.py +502 -0
  39. pelix/misc/mqtt_client.py +615 -0
  40. pelix/misc/ssl_wrap.py +81 -0
  41. pelix/misc/xmpp.py +483 -0
  42. pelix/remote/__init__.py +472 -0
  43. pelix/remote/beans.py +843 -0
  44. pelix/remote/discovery/__init__.py +33 -0
  45. pelix/remote/discovery/mdns.py +538 -0
  46. pelix/remote/discovery/mqtt.py +347 -0
  47. pelix/remote/discovery/multicast.py +548 -0
  48. pelix/remote/discovery/redis.py +476 -0
  49. pelix/remote/discovery/zookeeper.py +704 -0
  50. pelix/remote/dispatcher.py +831 -0
  51. pelix/remote/edef_io.py +423 -0
  52. pelix/remote/json_rpc.py +293 -0
  53. pelix/remote/registry.py +267 -0
  54. pelix/remote/transport/__init__.py +33 -0
  55. pelix/remote/transport/commons.py +394 -0
  56. pelix/remote/transport/jabsorb_rpc.py +357 -0
  57. pelix/remote/transport/mqtt_rpc.py +573 -0
  58. pelix/remote/xml_rpc.py +283 -0
  59. pelix/rsa/__init__.py +1601 -0
  60. pelix/rsa/edef.py +430 -0
  61. pelix/rsa/endpointdescription.py +527 -0
  62. pelix/rsa/providers/__init__.py +33 -0
  63. pelix/rsa/providers/discovery/__init__.py +395 -0
  64. pelix/rsa/providers/discovery/discovery_etcd.py +412 -0
  65. pelix/rsa/providers/discovery/etcd3/__init__.py +548 -0
  66. pelix/rsa/providers/discovery/etcd3/etcdrpc/__init__.py +0 -0
  67. pelix/rsa/providers/discovery/etcd3/etcdrpc/auth.proto +49 -0
  68. pelix/rsa/providers/discovery/etcd3/etcdrpc/auth_pb2.py +43 -0
  69. pelix/rsa/providers/discovery/etcd3/etcdrpc/auth_pb2.pyi +43 -0
  70. pelix/rsa/providers/discovery/etcd3/etcdrpc/auth_pb2_grpc.py +24 -0
  71. pelix/rsa/providers/discovery/etcd3/etcdrpc/kv.proto +61 -0
  72. pelix/rsa/providers/discovery/etcd3/etcdrpc/kv_pb2.py +41 -0
  73. pelix/rsa/providers/discovery/etcd3/etcdrpc/kv_pb2.pyi +38 -0
  74. pelix/rsa/providers/discovery/etcd3/etcdrpc/kv_pb2_grpc.py +24 -0
  75. pelix/rsa/providers/discovery/etcd3/etcdrpc/rpc.proto +858 -0
  76. pelix/rsa/providers/discovery/etcd3/etcdrpc/rpc_pb2.py +227 -0
  77. pelix/rsa/providers/discovery/etcd3/etcdrpc/rpc_pb2.pyi +754 -0
  78. pelix/rsa/providers/discovery/etcd3/etcdrpc/rpc_pb2_grpc.py +1845 -0
  79. pelix/rsa/providers/distribution/__init__.py +755 -0
  80. pelix/rsa/providers/distribution/py4j.py +465 -0
  81. pelix/rsa/providers/distribution/xmlrpc.py +310 -0
  82. pelix/rsa/remoteserviceadmin.py +1560 -0
  83. pelix/rsa/shell.py +620 -0
  84. pelix/rsa/topologymanagers/__init__.py +214 -0
  85. pelix/rsa/topologymanagers/basic.py +112 -0
  86. pelix/services/__init__.py +513 -0
  87. pelix/services/configadmin.py +1288 -0
  88. pelix/services/eventadmin.py +299 -0
  89. pelix/services/eventadmin_mqtt.py +255 -0
  90. pelix/services/fileinstall.py +397 -0
  91. pelix/services/mqtt.py +521 -0
  92. pelix/shell/__init__.py +317 -0
  93. pelix/shell/__main__.py +42 -0
  94. pelix/shell/beans.py +295 -0
  95. pelix/shell/completion/__init__.py +122 -0
  96. pelix/shell/completion/core.py +172 -0
  97. pelix/shell/completion/decorators.py +84 -0
  98. pelix/shell/completion/ipopo.py +302 -0
  99. pelix/shell/completion/pelix.py +254 -0
  100. pelix/shell/configadmin.py +206 -0
  101. pelix/shell/console.py +705 -0
  102. pelix/shell/core.py +893 -0
  103. pelix/shell/eventadmin.py +86 -0
  104. pelix/shell/ipopo.py +338 -0
  105. pelix/shell/log.py +172 -0
  106. pelix/shell/parser.py +704 -0
  107. pelix/shell/remote.py +762 -0
  108. pelix/shell/report.py +705 -0
  109. pelix/shell/xmpp.py +498 -0
  110. pelix/threadpool.py +461 -0
  111. pelix/utilities.py +637 -0
@@ -0,0 +1,548 @@
1
+ Metadata-Version: 2.4
2
+ Name: iPOPO
3
+ Version: 3.1.0
4
+ Summary: A service-oriented component model framework
5
+ Project-URL: Homepage, https://ipopo.readthedocs.io/
6
+ Project-URL: Documentation, https://ipopo.readthedocs.io/
7
+ Project-URL: Issues, http://github.com/tcalmant/ipopo/issues
8
+ Project-URL: Source, http://github.com/tcalmant/ipopo/
9
+ Author-email: Thomas Calmant <thomas.calmant+github@gmail.com>
10
+ License-Expression: Apache-2.0
11
+ License-File: LICENSE
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: Apache Software License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: jsonrpclib-pelix>=0.4.3
24
+ Provides-Extra: etcd2
25
+ Requires-Dist: osgiservicebridge>=1.5.8; extra == 'etcd2'
26
+ Requires-Dist: python-etcd==0.4.5; extra == 'etcd2'
27
+ Provides-Extra: mqtt
28
+ Requires-Dist: paho-mqtt>=2.1; extra == 'mqtt'
29
+ Provides-Extra: redis
30
+ Requires-Dist: redis>=2.10; extra == 'redis'
31
+ Provides-Extra: rsa
32
+ Requires-Dist: grpcio-tools>=1.71.0; extra == 'rsa'
33
+ Requires-Dist: grpcio>=1.71.0; extra == 'rsa'
34
+ Requires-Dist: osgiservicebridge>=1.5.8; extra == 'rsa'
35
+ Provides-Extra: xmpp
36
+ Requires-Dist: slixmpp==1.10; extra == 'xmpp'
37
+ Provides-Extra: yaml
38
+ Requires-Dist: pyyaml>=6.0; extra == 'yaml'
39
+ Provides-Extra: zeroconf
40
+ Requires-Dist: zeroconf==0.19; extra == 'zeroconf'
41
+ Provides-Extra: zookeeper
42
+ Requires-Dist: kazoo==2.8.0; extra == 'zookeeper'
43
+ Description-Content-Type: text/x-rst
44
+
45
+ .. image:: https://ipopo.readthedocs.io/en/latest/_images/logo_texte_200.png
46
+ :alt: iPOPO logo
47
+ :width: 200px
48
+ :align: center
49
+ :target: https://ipopo.readthedocs.io/
50
+
51
+ iPOPO: A Service-Oriented Component Model for Python
52
+ ####################################################
53
+
54
+ .. image:: https://img.shields.io/badge/GitHub-Repository-black?logo=github
55
+ :target: https://github.com/tcalmant/ipopo/
56
+ :alt: GitHub repository
57
+
58
+ .. image:: https://img.shields.io/badge/ReadTheDocs-Documentation-black?logo=readthedocs
59
+ :target: https://ipopo.readthedocs.io/
60
+ :alt: ReadTheDocs
61
+
62
+ .. image:: https://img.shields.io/pypi/v/ipopo.svg
63
+ :target: https://pypi.python.org/pypi/ipopo/
64
+ :alt: Latest Version
65
+
66
+ .. image:: https://img.shields.io/pypi/l/ipopo.svg
67
+ :target: https://pypi.python.org/pypi/ipopo/
68
+ :alt: License
69
+
70
+ .. image:: https://github.com/tcalmant/ipopo/actions/workflows/ci-build.yml/badge.svg?branch=v3
71
+ :target: https://github.com/tcalmant/ipopo/actions/workflows/ci-build.yml
72
+ :alt: GitHub Actions CI status
73
+
74
+ .. image:: https://coveralls.io/repos/github/tcalmant/ipopo/badge.svg?branch=v3
75
+ :target: https://coveralls.io/github/tcalmant/ipopo?branch=v3
76
+ :alt: Coveralls status
77
+
78
+ `iPOPO <https://ipopo.readthedocs.io/>`_ is a Python-based Service-Oriented
79
+ Component Model (SOCM) based on Pelix, a dynamic service platform.
80
+ They are inspired on two popular Java technologies for the development of
81
+ long-lived applications: the
82
+ `iPOJO <https://web.archive.org/web/20210616112915/http://felix.apache.org/documentation/subprojects/apache-felix-ipojo.html>`_
83
+ component model and the `OSGi <https://www.osgi.org/>`_ Service Platform.
84
+ iPOPO enables to conceive long-running and modular IT services.
85
+
86
+ See https://ipopo.readthedocs.io/ for documentation and more information.
87
+
88
+
89
+ Note on this version
90
+ ====================
91
+
92
+ This is the 3.x branch of iPOPO, which is intended to work with Python 3.10+.
93
+ The iPOPO API didn't change much between v1 and v3: all code working with iPOPO
94
+ v1 should be compatible with iPOPO v3 (as long as the Python syntax and
95
+ packages are compatible with newer Python versions).
96
+ If that's not the case, please fill in a bug report on
97
+ `GitHub issues <https://github.com/tcalmant/ipopo/issues>`_.
98
+
99
+ If you are working with Python between 2.7 and 3.7, you must instead use the
100
+ [1.x branch](https://github.com/tcalmant/ipopo/tree/v1) of iPOPO.
101
+ Note that iPOPO has not been tested with versions 3.8 and 3.9.
102
+
103
+ [Version 2.x](https://github.com/tcalmant/ipopo/tree/v2) was a trial to
104
+ implement iPOPO with ``asyncio`` for Python 3.7, but has been stalled due to
105
+ various issues and lack of contributions.
106
+
107
+ Usage survey
108
+ ============
109
+
110
+ In order to gain insight from the iPOPO community, I've put a
111
+ `really short survey <https://docs.google.com/forms/d/1zx18_Rg27mjdGrlbtr9fWFmVnZNINo9XCfrYJbr4oJI>`_
112
+ on Google Forms (no login required).
113
+
114
+ Please, feel free to answer it, the more answers, the better.
115
+ All feedback is really appreciated.
116
+
117
+ .. contents::
118
+
119
+ Install
120
+ #######
121
+
122
+ Option 1: Using pip
123
+ ===================
124
+
125
+ iPOPO is available on `PyPI <http://pypi.python.org/pypi/iPOPO>`_ and can be
126
+ installed using ``pip``:
127
+
128
+ .. code-block:: bash
129
+
130
+ # Install system-wide
131
+ $ sudo pip install iPOPO
132
+
133
+ # ... or user-wide installation
134
+ $ pip install --user iPOPO
135
+
136
+
137
+ Option 2: From source
138
+ =====================
139
+
140
+ .. code-block:: bash
141
+
142
+ $ git clone https://github.com/tcalmant/ipopo.git
143
+ $ cd ipopo
144
+ $ python setup.py install
145
+
146
+
147
+ Check install
148
+ =============
149
+
150
+ To check if Pelix is installed correctly, run the following command:
151
+
152
+ .. code-block:: bash
153
+
154
+ $ python -m pelix.shell --version
155
+ Pelix 3.0.0 from /home/tcalmant/git/ipopo/pelix/__init__.py
156
+
157
+ Concepts
158
+ ########
159
+
160
+ Pelix brings the concept of *bundle* in Python.
161
+ A bundle is a module with a life cycle: it can be installed, started, stopped,
162
+ updated and *uninstalled*.
163
+
164
+ A bundle can declare a class acting as bundle activator, using the
165
+ ``@BundleActivator`` decorator.
166
+ This class will be instantiated by the framework and its ``start()`` and
167
+ ``stop()`` method will be called to notify the bundle about its activation and
168
+ deactivation.
169
+
170
+ When it is active, a bundle can register services.
171
+ A service is an object implementing a specification and associated to a set of
172
+ properties.
173
+ A component will then be able to select and consume a service according to the
174
+ specification(s) it provides and to its properties.
175
+
176
+ The components are a concept brought by iPOPO.
177
+ A component, or component instance, is an object managed by a container.
178
+ The container handles the interactions between the component and the Pelix
179
+ framework.
180
+ That way, the component contains only the code required for its task, not for
181
+ its bindings with the framework.
182
+ A component is an instance of a component factory, a class `manipulated <https://ipopo.readthedocs.io/en/latest/refcards/ipopo.html>`_
183
+ by iPOPO `decorators <https://ipopo.readthedocs.io/en/latest/refcards/ipopo_decorators.html>`_.
184
+
185
+ For more information, see the `concepts page <https://ipopo.readthedocs.io/en/latest/refcards/index.html>`_.
186
+
187
+
188
+ Sample
189
+ ######
190
+
191
+ This sample gives a quick overview of the usage of iPOPO.
192
+ For more information, take a look at `iPOPO in 10 minutes <https://ipopo.readthedocs.io/en/latest/quickstart.html>`_.
193
+
194
+
195
+ Service specification
196
+ =====================
197
+
198
+ In iPOPO v3, you can use a Python `procotol <https://docs.python.org/3/library/typing.html#typing.Protocol>`_
199
+ to define the specification of a service.
200
+ A specification class/protocol should be decorated with ``@Specification`` to be
201
+ given a unique name.
202
+ The components providing that specification should then inherit that specification
203
+ class/protocol in order for the development tools you use to be able to warn if
204
+ a method is missing or uses invalid types.
205
+
206
+ Note that it is possible to skip that step and use a string constant as
207
+ specification like in iPOPO v1.
208
+
209
+ Here is a sample description of an Hello World service specification:
210
+
211
+ .. code-block:: python
212
+
213
+ from typing import Protocol
214
+ from pelix.constants import Specification
215
+
216
+ @Specification("sample.hello")
217
+ class HelloWorld(Protocol):
218
+ """
219
+ Hello world specification: definition of the methods a component providing
220
+ that service must implement
221
+ """
222
+
223
+ def hello(self, name: str) -> None:
224
+ """
225
+ Prints hello
226
+ """
227
+ ...
228
+
229
+ def bye(self, name: str) -> None:
230
+ """
231
+ Prints bye
232
+ """
233
+ ...
234
+
235
+ Service provider
236
+ ================
237
+
238
+ The following code defines a component factory (a class) which instances will
239
+ provide a ``sample.hello`` service.
240
+
241
+ .. code-block:: python
242
+
243
+ # iPOPO decorators
244
+ from pelix.ipopo.decorators import ComponentFactory, Provides, Instantiate
245
+
246
+ # Import the specification, if we want to use its type
247
+ from specification import HelloWorld
248
+
249
+ # Manipulates the class and sets its (unique) factory name
250
+ @ComponentFactory("hello-provider-factory")
251
+ # Indicate that the components will provide a service
252
+ @Provides(HelloWorld)
253
+ # Like in iPOPOv1, We could also use the specification name directly:
254
+ # @Provides("sample.hello")
255
+ # Tell iPOPO to instantiate a component instance as soon as the file is loaded
256
+ @Instantiate("hello-provider-auto")
257
+ # When using Python protocols, it is recommended to inherit from it to
258
+ # benefit from types handling of IDEs.
259
+ class HelloProvider(HelloWorld):
260
+ """
261
+ A sample service provider
262
+ """
263
+ def hello(self, name="world"):
264
+ """
265
+ Says hello
266
+ """
267
+ print("Hello,", name, "!")
268
+
269
+ def bye(self, name="cruel world"):
270
+ """
271
+ Says bye
272
+ """
273
+ print("Bye,", name, "!")
274
+
275
+ Due to the ``@Instantiate`` decorator, iPOPO will
276
+ automatically instantiate a component when the bundle providing this component
277
+ factory will be started.
278
+ It is also possible to instantiate a component using shell commands or via the
279
+ iPOPO runtime service
280
+ (see `use_ipopo <https://ipopo.readthedocs.io/en/latest/refcards/ipopo.html#pelix.ipopo.constants.use_ipopo>`_).
281
+
282
+ Each component instance will provide a ``sample.hello`` service, which can be
283
+ consumed by any bundle or any other component.
284
+
285
+
286
+ Service consumer
287
+ ================
288
+
289
+ The following code defines a component factory (a class) which instances will
290
+ consume a ``sample.hello`` service. If multiple services are available, iPOPO
291
+ will select the one with the highest rank and the lowest service ID
292
+ (*i.e.* the oldest service).
293
+
294
+ In iPOPO v3, it is again recommended to use typing as much as possible.
295
+ For injected fields and properties, the fields injected with ``@Requires`` should
296
+ be defined at class level with the right type hint: type, optional, list, ...
297
+ based on the requirement configuration.
298
+
299
+ .. code-block:: python
300
+
301
+ from pelix.ipopo.decorators import ComponentFactory, Instantiate, Invalidate, Requires, Validate
302
+ from specification import HelloWorld
303
+
304
+ # Manipulates the class and sets its (unique) factory name
305
+ @ComponentFactory("hello-consumer-factory")
306
+ # Indicate that the components require a sample.hello service to work
307
+ # and to inject the found service in the _svc field
308
+ # We could also use the specification name instead of the type
309
+ @Requires("_svc", HelloWorld)
310
+ # Tell iPOPO to instantiate a component instance as soon as the file is loaded
311
+ @Instantiate("hello-consumer-auto")
312
+ class HelloConsumer:
313
+ """
314
+ A sample service consumer
315
+ """
316
+
317
+ # Define the injected field type for static typing (optional)
318
+ _svc: HelloWorld
319
+
320
+ @Validate
321
+ def validate(self, context):
322
+ """
323
+ Component validated: all its requirements have been injected
324
+ """
325
+ self._svc.hello("Consumer")
326
+
327
+ @Invalidate
328
+ def invalidate(self, context):
329
+ """
330
+ Component invalidated: one of its requirements is going away
331
+ """
332
+ self._svc.bye("Consumer")
333
+
334
+ When the bundle providing this component factory will be started, iPOPO will
335
+ automatically instantiate a component, due to the ``@Instantiate`` decorator.
336
+
337
+ Each component instance will require a ``sample.hello`` service. Once iPOPO
338
+ has injected all the required services (here, a single ``sample.hello`` service)
339
+ in a component instance, this instance will be considered *valid* and iPOPO
340
+ will call its method decorated by ``@Validate``.
341
+ There, the component can consume its dependencies, start threads, etc.
342
+ It is recommended for this method to start threads and to return quickly, as it
343
+ blocks iPOPO and the Pelix framework.
344
+
345
+ When a required service is unregistered by its provider, the component
346
+ instances consuming it are invalidated.
347
+ When the method decorated by ``@Invalidate`` is called, the service is still
348
+ injected and should be usable (except for special cases, like remote services).
349
+
350
+
351
+ Run!
352
+ ====
353
+
354
+ To run this sample, you'll need to copy the snippets above in different files:
355
+
356
+ * copy the *Service specification* snipper in a file named *specification.py*
357
+ * copy the *Service provider* snippet in a file named *provider.py*
358
+ * copy the *Service consumer* snippet in a file named *consumer.py*
359
+
360
+ You can also find those files in the project repository in the
361
+ ``samples/hello_world`` folder.
362
+
363
+ Then, run a Pelix shell in the same folder as those files, and execute the
364
+ commands listed in this trace:
365
+
366
+ .. code-block:: bash
367
+
368
+ $ python -m pelix.shell
369
+ ** Pelix Shell prompt **
370
+ $ # Install the bundles
371
+ $ install provider
372
+ Bundle ID: 15
373
+ $ install consumer
374
+ Bundle ID: 16
375
+ $ # Start the bundles (the order isn't important here)
376
+ $ start 15 16
377
+ Starting bundle 15 (provider)...
378
+ Starting bundle 16 (consumer)...
379
+ Hello, Consumer !
380
+ $ # View iPOPO instances
381
+ $ instances
382
+ +----------------------+------------------------------+-------+
383
+ | Name | Factory | State |
384
+ +======================+==============================+=======+
385
+ | hello-consumer-auto | hello-consumer-factory | VALID |
386
+ +----------------------+------------------------------+-------+
387
+ | hello-provider-auto | hello-provider-factory | VALID |
388
+ +----------------------+------------------------------+-------+
389
+ | ipopo-shell-commands | ipopo-shell-commands-factory | VALID |
390
+ +----------------------+------------------------------+-------+
391
+ 3 components running
392
+ $ # View details about the consumer
393
+ $ instance hello-consumer-auto
394
+ Name.....: hello-consumer-auto
395
+ Factory..: hello-consumer-factory
396
+ Bundle ID: 16
397
+ State....: VALID
398
+ Services.:
399
+ Dependencies:
400
+ Field: _svc
401
+ Specification: sample.hello
402
+ Filter......: None
403
+ Optional.....: False
404
+ Aggregate....: False
405
+ Handler......: SimpleDependency
406
+ Bindings:
407
+ ServiceReference(ID=18, Bundle=15, Specs=['sample.hello'])
408
+ Properties:
409
+ +---------------+---------------------+
410
+ | Key | Value |
411
+ +===============+=====================+
412
+ | instance.name | hello-consumer-auto |
413
+ +---------------+---------------------+
414
+
415
+ $ # Modify the provider file (e.g. change the 'Hello' string by 'Hi')
416
+ $ # Update the provider bundle (ID: 15)
417
+ $ update 15
418
+ Updating bundle 15 (provider)...
419
+ Bye, Consumer !
420
+ Hi, Consumer !
421
+ $ # Play with other commands (see help)
422
+
423
+ First, the ``install`` commands are used to install the bundle: they will be
424
+ imported but their activator won't be called. If this command fails, the bundle
425
+ is not installed and is not referenced by the framework.
426
+
427
+ If the installation succeeded, the bundle can be started: it's activator is
428
+ called (if any). Then, iPOPO detects the component factories provided by the
429
+ bundle and instantiates the components declared using the ``@Instantiate``
430
+ decorator.
431
+
432
+ The ``instances`` and ``instance`` commands can be use to print the state and
433
+ bindings of the components. Some other commands are very useful, like ``sl``
434
+ and ``sd`` to list the registered services and print their details. Use the
435
+ ``help`` command to see which ones can be used.
436
+
437
+ The last part of the trace shows what happens when updating a bundle.
438
+ First, update the source code of the provider bundle, *e.g.* by changing the
439
+ string it prints in the ``hello()`` method.
440
+ Then, tell the framework to update the bundle using the ``update`` command.
441
+ This command requires a bundle ID, which has been given as a result of the
442
+ ``install`` command and can be found using ``bl``.
443
+
444
+ When updating a bundle, the framework stops it and reloads it (using
445
+ `importlib.reload <https://docs.python.org/3/library/importlib.html#importlib.reload>`_).
446
+ If the update fails, the old version is kept.
447
+ If the bundle was active before the update, it is restarted by the framework.
448
+
449
+ Stopping a bundle causes iPOPO to kill the component instance(s) of the
450
+ factories it provided.
451
+ Therefore, no one provides the ``sample.hello`` service, which causes the
452
+ consumer component to be invalidated.
453
+ When the provider bundle is restarted, a new provider component is instantiated
454
+ and its service is injected in the consumer, which becomes valid again.
455
+
456
+
457
+ Batteries included
458
+ ##################
459
+
460
+ Pelix/iPOPO comes with some useful services:
461
+
462
+ * Pelix Shell: a simple shell to control the framework (manage bundles,
463
+ show the state of components, ...).
464
+ The shell is split in 5 parts:
465
+
466
+ * the parser: a shell interpreter class, which can be reused to create other
467
+ shells (with a basic support of variables);
468
+ * the shell core service: callable from any bundle, it executes the given
469
+ command lines;
470
+ * the UIs: text UI (console) and remote shell (TCP/TLS, XMPP)
471
+ * the commands providers: iPOPO commands, report, EventAdmin, ...
472
+ * the completion providers: Pelix, iPOPO
473
+
474
+ See the `shell tutorial <http://ipopo.readthedocs.io/en/latest/quickstart.html#play-with-the-shell>`_
475
+ for more information.
476
+
477
+ * An HTTP service, based on the HTTP server from the standard library.
478
+ It provides the concept of *servlet*, borrowed from Java.
479
+
480
+ See the `HTTP service reference <http://ipopo.readthedocs.io/en/latest/refcards/http.html>`_
481
+ for more information.
482
+
483
+ There is also a `routing utility class <http://ipopo.readthedocs.io/en/latest/refcards/http_routing.html>`_,
484
+ based on decorators, which eases the development of REST-like servlets.
485
+
486
+ * Remote Services: export and import services to/from other Pelix framework or
487
+ event Java OSGi frameworks!
488
+
489
+ See the `remote services reference <http://ipopo.readthedocs.io/en/latest/refcards/remote_services.html>`_
490
+ and the `Remote Service Admin reference <https://ipopo.readthedocs.io/en/latest/refcards/rsa.html>`_
491
+ for more information.
492
+ The former should be used to link iPOPO instances while the latter targets both iPOPO and Java OSGi frameworks.
493
+
494
+ Pelix also provides an implementation of the `EventAdmin service <http://ipopo.readthedocs.io/en/latest/refcards/eventadmin.html>`_,
495
+ inspired from the `OSGi specification <http://www.osgi.org/Specifications/HomePage>`_.
496
+
497
+ Feedback
498
+ ########
499
+
500
+ Feel free to send feedback on your experience of Pelix/iPOPO, via the mailing
501
+ lists:
502
+
503
+ * User list: https://groups.google.com/g/ipopo-users
504
+ * Development list: https://groups.google.com/g/ipopo-dev
505
+ * GitHub Discussions: https://github.com/tcalmant/ipopo/discussions
506
+
507
+ Bugs and features requests can be submitted using the
508
+ `Issue Tracker <https://github.com/tcalmant/ipopo/issues>`_ on GitHub.
509
+
510
+
511
+ Contributing
512
+ ############
513
+
514
+ All contributions are welcome!
515
+
516
+ #. Create an `issue <https://github.com/tcalmant/ipopo/issues>`_ to discuss
517
+ about your idea or the problem you encounter
518
+ #. `Fork <https://github.com/tcalmant/ipopo/fork>`_ the project
519
+ #. Develop your changes
520
+ #. Check your code with `pylint <https://pypi.python.org/pypi/pylint/>`_
521
+ and `pep8 <https://pypi.python.org/pypi/pep8>`_
522
+ #. If necessary, write some unit tests
523
+ #. Commit your changes, indicating in each commit a reference to the issue
524
+ you're working on
525
+ #. Push the commits on your repository
526
+ #. Create a *Pull Request*
527
+ #. Enjoy!
528
+
529
+ Please note that your contributions will be released under the project's
530
+ license, which is the `Apache Software License 2.0 <https://www.apache.org/licenses/LICENSE-2.0>`__.
531
+
532
+
533
+ Compatibility
534
+ #############
535
+
536
+ Pelix and iPOPO are tested using
537
+ `GitHub actions <https://github.com/tcalmant/ipopo/actions>`_
538
+ targetting Python 3.10, 3.11, 3.12 and 3.13.
539
+
540
+ iPOPO v3 doesn't support Python 2 neither versions earlier than 3.10.
541
+ If you need to work with those versions of Python, please use iPOPO v1.
542
+ You can then use Remote Services to allow interactions between iPOPO v1 and v3.
543
+
544
+
545
+ License
546
+ #######
547
+
548
+ iPOPO is released under the `Apache Software License 2.0 <https://www.apache.org/licenses/LICENSE-2.0>`__.
@@ -0,0 +1,111 @@
1
+ pelix/__init__.py,sha256=gNQp4BnONn2PWSiRBNgrzd8pvgOIkaY25YNiK6bVpLY,969
2
+ pelix/constants.py,sha256=a60_J-pQ2Twxn9mJssMPHBrW-BIqTWdybBKU5F2OzJ8,9435
3
+ pelix/framework.py,sha256=29WHURe4CEGI0-0CAlzvm1Bs87jYbvviGNEBLCI5D7I,67834
4
+ pelix/ipv6utils.py,sha256=BcKB943Ife8DHOtZ1yPm5CW2a01wEoR2MDROINeWjhM,2619
5
+ pelix/ldapfilter.py,sha256=zmiJ5ud8bt8Je0brlYJSFhs9glUWqXPCwffLGgU98eI,27582
6
+ pelix/threadpool.py,sha256=9LCDVUCxil4nnV55SNYrA25NqPPuq2j69h-i8WHqzTk,15240
7
+ pelix/utilities.py,sha256=v8CU344hmlUUJGKfZ4YiWPzj75Cr5qmlccCkmjMPMS8,18007
8
+ pelix/http/__init__.py,sha256=KSwKn_2xBnpCb2UVBIEgZyTg_AEY2TRheDysFpSSCEw,13294
9
+ pelix/http/basic.py,sha256=xJM7vZtmHs7L2rkMwcbvGtEP3_7eRZ20ReDGpXtaFf8,33791
10
+ pelix/http/routing.py,sha256=L-WD3OKNT3PLHUYTnNf0Nui8rN_P73s3v8aP-g_ZpJM,13751
11
+ pelix/internals/__init__.py,sha256=kpe6BFNHUc__Nhz3Rx5-hjz2VzHJPWTKuT8Dipd0LNs,990
12
+ pelix/internals/events.py,sha256=ZUZAUOWnLrqzZwY_GdIJ2BXfrUNtet8pFlZMI9uDtJI,5018
13
+ pelix/internals/hooks.py,sha256=RMVEW1gUnxg6HyQiBGqWh3TSncx4Mrny2uvNCCZIcoI,6059
14
+ pelix/internals/registry.py,sha256=qpyw8nI6dh2X7mMuIEsnqIuWlXqEBk8-oZ4D5tyY2vk,53893
15
+ pelix/ipopo/__init__.py,sha256=Z5cLpYtpe07UoV0GPSqc-J9x3MwC7IVC5nAxWL2f0u4,1014
16
+ pelix/ipopo/constants.py,sha256=R1rG8kwcHI2-faD6GqzGL25B8CDYltpfllilPsWRu5I,18885
17
+ pelix/ipopo/contexts.py,sha256=ggx-rQXqcBdKziUKPnmZKb6mEdfiZTPmsM_Z-mnb-Yc,18627
18
+ pelix/ipopo/core.py,sha256=QaPGjcfEHVCuSh7TCX-9y70fMe1mk3tqWvvyq97XLVs,48243
19
+ pelix/ipopo/decorators.py,sha256=ZMgEquanwJUQCHkB7z9LeVaXF6Y7vNrcDdmxO-TW0Ac,77060
20
+ pelix/ipopo/instance.py,sha256=v1rkpyk0wsZaGa73sb8DmW4IXHEdCxD8664wjO71-_s,30476
21
+ pelix/ipopo/waiting.py,sha256=4dV_WvQujTQ0g-h6QxW2PETH72THA0KJXrrMT6iv3S0,9883
22
+ pelix/ipopo/handlers/__init__.py,sha256=snr7FRi1MLOPbQfp0jrfmGChStAJ1x-ZxTm_9WIiRHo,982
23
+ pelix/ipopo/handlers/constants.py,sha256=SYKK_UqbhtcJshfkjRS7f3GIcdeF7z9cJhTVvvyV2lo,8266
24
+ pelix/ipopo/handlers/properties.py,sha256=XdWkXJA1mtCUnH-tRi8Imp77RwnY1qBPgVghyHBjI28,7609
25
+ pelix/ipopo/handlers/provides.py,sha256=C8zQ_cwCCcFfreHzr-y6Nu7RWIFsQWv8thq3cbZvbAI,11947
26
+ pelix/ipopo/handlers/requires.py,sha256=GM4tMEPaX7MhY6HpfUmaPzlvIKTiKwqXWsj-XanY_Kw,22227
27
+ pelix/ipopo/handlers/requiresbest.py,sha256=r8sAzPCDEj8hAOWFgR5qd6YsBjaJBJAiSKVyFivQY2E,8057
28
+ pelix/ipopo/handlers/requiresbroadcast.py,sha256=uuMKTJ1RgPAomCLUZ-onH8wBLKzyjfKZahdlo3-cyOI,15391
29
+ pelix/ipopo/handlers/requiresmap.py,sha256=axMMTSQPvFpxXaCt47GMturTWN-2lSDOSVt1g57VgOw,22953
30
+ pelix/ipopo/handlers/requiresvarfilter.py,sha256=WpArukWtfT9wKfoKSHrmQUNLh_0uDZnHgL11mmUSw1Y,9928
31
+ pelix/ipopo/handlers/temporal.py,sha256=PzitGKTa7_h_9329HN0pS7PBrbJ9OlLTB5cMp9OWD60,12116
32
+ pelix/misc/__init__.py,sha256=-I9TucqRz9Vg7HokWa4IByZFuz4WFHQQsZptJb-JAN0,5558
33
+ pelix/misc/eventadmin_printer.py,sha256=Zdvovtiyp18qhq-6NHI9e_wpxJ4jWmfHbp6CwPcTA4U,3387
34
+ pelix/misc/init_handler.py,sha256=zASY2mrGy5dz7La6DmpNNg5aV3X4rhggJxf_LS8PiYU,12682
35
+ pelix/misc/jabsorb.py,sha256=3PRsFHTAPSKZuie9BbdF2_tK_SDgibhN43z3VDYjU4A,10244
36
+ pelix/misc/log.py,sha256=KAUeGWv9ZHSNyITJchc4EUHW9XqdLVBM_ZizD7p3Cm0,15023
37
+ pelix/misc/mqtt_client.py,sha256=16EjKqGRVX8AYtr3jHMnVyBiD4FhsNb7ur1xONsyv_M,20522
38
+ pelix/misc/ssl_wrap.py,sha256=ehW4sDoG9DA45Wpo4PmFzcK2D15Yw5qUDDKgly6vaGI,2715
39
+ pelix/misc/xmpp.py,sha256=0ktPJfFZO7LGT5TvAZa3mgAFmsRYVAIrthD3C4kOvZ4,14997
40
+ pelix/remote/__init__.py,sha256=EJElaToYgXPliQPgcGiPgOAfvcol1WjX-p2gusFZQ5I,15704
41
+ pelix/remote/beans.py,sha256=A_WnMMhjfR3akS31zDWIWNt4DUF2wMqmch4UsCQxf0U,26123
42
+ pelix/remote/dispatcher.py,sha256=6KMfs7dCs8v5gHy2tdvj-gQjTs6QNjOdnpY1mdluE7Q,28739
43
+ pelix/remote/edef_io.py,sha256=Zp3G2kj_1YpwtkVLmACe_A9nQtN0YFnekCLwixgmORo,13804
44
+ pelix/remote/json_rpc.py,sha256=Xwr0UIm124teJMZ7JYbV_bUnxIbqXVg_AHGfiNKksew,8951
45
+ pelix/remote/registry.py,sha256=m2JHMJVpnP9Lus37RBmYriIx4TTb0YG6ifpMcZZAbHs,8933
46
+ pelix/remote/xml_rpc.py,sha256=wm4oEoLEbPxmG6yecA8MLJIVpx4i42IS9ica0yHJNqE,8628
47
+ pelix/remote/discovery/__init__.py,sha256=2iOb9U3RB_4UAaUfLZ0y7BBujKwlsbQ5tJPO8JxHCKo,990
48
+ pelix/remote/discovery/mdns.py,sha256=9LlzU5Zg8zuchCs4l5CiyCi3hiu82_235F-Fjcgnv1o,18273
49
+ pelix/remote/discovery/mqtt.py,sha256=rh6Vo9-aPePaCcV2wnRNv-RPr5yLa1tdqqcrmeZqg-A,11442
50
+ pelix/remote/discovery/multicast.py,sha256=2RZlXh5Zi9CuhaDVyElaz3lf4wAMEs9Wd2pxIKlPkZ0,17837
51
+ pelix/remote/discovery/redis.py,sha256=8joEztev8oCBt9ubWEUMWwUKgYf7x8qqZ8gtR3jB3qw,16485
52
+ pelix/remote/discovery/zookeeper.py,sha256=zsDH6mQQiMg1YKFUfNh0A8n78APJRAxQYV0e_S15ODs,23072
53
+ pelix/remote/transport/__init__.py,sha256=IgZHmdfg1EkYN-FxOVSITNoCKJ3b6rw-gTHzMiHcGMU,991
54
+ pelix/remote/transport/commons.py,sha256=nJo0S8q-XfuiPvepbLmPLFADMuIDOb_XG6dHQz0SzhQ,12555
55
+ pelix/remote/transport/jabsorb_rpc.py,sha256=-RucnJp4iBjYpKbyI7yBtL4vIYeDAKU74X8tOBmUtvE,11203
56
+ pelix/remote/transport/mqtt_rpc.py,sha256=4V6i_Y78Ddtd51PofRvmIV9b5WBThkmgysH_27-osBI,17235
57
+ pelix/rsa/__init__.py,sha256=wr5GXe4BQ4OwfNdl7KtjFHIQwPmgbspo_mpSLJU99R0,51147
58
+ pelix/rsa/edef.py,sha256=hRZShx_-jPfe1NJylYGRX03byxviYht-udKHztUagJs,13472
59
+ pelix/rsa/endpointdescription.py,sha256=vp0lVVOwOzWGeokZMH0X41Sb1Xo0DzJpOinuYUz_sTE,19260
60
+ pelix/rsa/remoteserviceadmin.py,sha256=GYmQCWT0yoJgG-lLu0pGVcJoRn2SUq0tYxQ17sbStJc,57547
61
+ pelix/rsa/shell.py,sha256=LDWda-fplzAw3X7sXtjzrwi1KFFoTpJs95tTHBBcAQU,22175
62
+ pelix/rsa/providers/__init__.py,sha256=jyWmo8F8DeGtsSxsXgSY_4wAkezQpou91wHN_zdYLsA,999
63
+ pelix/rsa/providers/discovery/__init__.py,sha256=piBsJ-8kSjs36E-fWJ8RXf39mtOdkMHdVzgfsV14oyc,14396
64
+ pelix/rsa/providers/discovery/discovery_etcd.py,sha256=uzxTaUNWtHh5HGVayL6IEdgbFr0YjGCjqa7afKnWlBk,16526
65
+ pelix/rsa/providers/discovery/etcd3/__init__.py,sha256=pC5bWQj78plMgI0cJL1_pviaMBzceX8-sIyG2WVYLDA,22722
66
+ pelix/rsa/providers/discovery/etcd3/etcdrpc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
67
+ pelix/rsa/providers/discovery/etcd3/etcdrpc/auth.proto,sha256=3sFOnD_rdm5XkR3uaQHsDuOXrjPRdx2KKJ-rq9t1Tcg,1213
68
+ pelix/rsa/providers/discovery/etcd3/etcdrpc/auth_pb2.py,sha256=L7NdQSCvBNSECL-WHULI_982RV_tFTqW5Neh--2Xwxc,2128
69
+ pelix/rsa/providers/discovery/etcd3/etcdrpc/auth_pb2.pyi,sha256=9Tfj4AkQsn2OmqS3QfS14hu_S6cFOLSSPeLpslExTUI,1958
70
+ pelix/rsa/providers/discovery/etcd3/etcdrpc/auth_pb2_grpc.py,sha256=SVM19AK4uy6OVQGKkbN8lZjAs8WJvVsbt4tYUZjUrkg,885
71
+ pelix/rsa/providers/discovery/etcd3/etcdrpc/kv.proto,sha256=VxYn2585gMoCRYS29F1EgZpsCNWvy_mH8ZPW3hNTatQ,2119
72
+ pelix/rsa/providers/discovery/etcd3/etcdrpc/kv_pb2.py,sha256=oAf7O3ZyUX8ivUmGV4f-Hs4MeqjXDenIncu2nLtCtKo,2076
73
+ pelix/rsa/providers/discovery/etcd3/etcdrpc/kv_pb2.pyi,sha256=pTR7wYoqPODyiyGp1S8c5d891n16Gu9EMGCywd66EEs,1714
74
+ pelix/rsa/providers/discovery/etcd3/etcdrpc/kv_pb2_grpc.py,sha256=Ec5jtGRMY_qlRjNk7XkrcUlELy19tU1ViHhK1_WCvn4,883
75
+ pelix/rsa/providers/discovery/etcd3/etcdrpc/rpc.proto,sha256=zLXScPEYzJOgKA2XnvrQ2oJAWjTSd2usp2VAAonKW4Y,28947
76
+ pelix/rsa/providers/discovery/etcd3/etcdrpc/rpc_pb2.py,sha256=AxxUJsftuPGHMFOQC7ENBR1OmaGwUi2swTxaqo3lbog,28556
77
+ pelix/rsa/providers/discovery/etcd3/etcdrpc/rpc_pb2.pyi,sha256=AS6WLvsZrRvzXPsoGuu8DE8EL3tdwua0T6GnflkHOx0,32919
78
+ pelix/rsa/providers/discovery/etcd3/etcdrpc/rpc_pb2_grpc.py,sha256=S1jZJRm0SjWWBK52Z94Gc3V4cLnW1G8ocJuKhs2_43I,69142
79
+ pelix/rsa/providers/distribution/__init__.py,sha256=vNsLmPpkUEmDVEMOwDTEM-s8sTqedMGZCvd3jH_R7Z8,27925
80
+ pelix/rsa/providers/distribution/py4j.py,sha256=kZeLssdzDQaJzp_keQgOWmyPYEeNt5gYKy9dKYfe_pY,17196
81
+ pelix/rsa/providers/distribution/xmlrpc.py,sha256=ytBqU17RaSfusbxOOv9ybFxRTkP9to2ykTNVoW-IXno,12263
82
+ pelix/rsa/topologymanagers/__init__.py,sha256=ble6Yhv2xkwCzl0pOG6vvyV5TIyilwsNkCkC2U68nWc,8077
83
+ pelix/rsa/topologymanagers/basic.py,sha256=r3g_qUUInCZKZlQ4AHcISftK1C6C6q_wDJK_w2iGDQo,4302
84
+ pelix/services/__init__.py,sha256=BXLTawKC_sJUvgrB5MGGZN8hmnQF2Y2lWS64f4pS5QM,15598
85
+ pelix/services/configadmin.py,sha256=nEp8iV_YCeYRPzKxnJIJdLuAadE8d-TgoqFuDuPgivk,43729
86
+ pelix/services/eventadmin.py,sha256=rm425xMx5Len26QCsBX_Cka1uvT2JgRfhidUHAvp6qw,10260
87
+ pelix/services/eventadmin_mqtt.py,sha256=hQ7952W1UcIXGfwSaECYAxbwwJB1Hw9OFcoiSwq54dA,8262
88
+ pelix/services/fileinstall.py,sha256=tBbAfJFHGYFhHgNdK2HWcl3XPeVuAewEwxi7-UzawQU,13041
89
+ pelix/services/mqtt.py,sha256=XyjJAS46nRHDOj-ZNWIG5GhhHhWOhxGUNCIeX06CZv4,16847
90
+ pelix/shell/__init__.py,sha256=cs7bmBo2-XnLKjmTxAe7Mt4kQuHOKJfrRpIs_yvF3OI,9152
91
+ pelix/shell/__main__.py,sha256=qNjfNa_1Ed3BG7Uc3EFiIbtYsVS0goiEbjkyDj94MT8,1152
92
+ pelix/shell/beans.py,sha256=r7YVlwPR9Q6hkAOWWuCGl9ObDIrBPUJwDUQmoPNrPIs,8890
93
+ pelix/shell/configadmin.py,sha256=J2DssK6Uj-OJ7Wm0EXkCy1AVRJjkfekwAA9SPa5eqgc,6396
94
+ pelix/shell/console.py,sha256=9ENA6D1LzukAE3V_kHDzCMv76_OhdDDs_ccjwkHcL20,21305
95
+ pelix/shell/core.py,sha256=2dPTvKXe9AwXMU3xaQbOsPbu2pQyEOR9H42RVU-p000,29676
96
+ pelix/shell/eventadmin.py,sha256=OpFKkslk5Zc4WYC-efbNURvFZqX9P0K2urbvaAKPtvE,2568
97
+ pelix/shell/ipopo.py,sha256=WrhfFWnx49Yt_iGXqGdqI52daNtmbTKpGFKzew6qbI8,11814
98
+ pelix/shell/log.py,sha256=1iOOwH2uw87eaCULxHn2ENSKvUrQxC5fvOP0viPWXIY,5269
99
+ pelix/shell/parser.py,sha256=l9IWCIeFJNq-ziBdAeSGqbi6J495q9pl-UCjbA52jZ4,23354
100
+ pelix/shell/remote.py,sha256=u_KM4d0qHqBFsjf1aDDTyADOObrtv6yUq4AR6o5w8vw,24121
101
+ pelix/shell/report.py,sha256=uNJ34yHqf8sjjI8GZzReY56Wl9bptJT98kkr1fsLzrY,23211
102
+ pelix/shell/xmpp.py,sha256=sCCWW4CR-peV_dYxQofeM6px5QgHIBLvwgZP8IdZ9Wc,14805
103
+ pelix/shell/completion/__init__.py,sha256=QoPEYiFpVvVzMQ6kETq206IAbJil6zmASk0Xzi-I5sM,3400
104
+ pelix/shell/completion/core.py,sha256=EHgS5y-vg1ntnBUOTZwJOspcJ4TAkPP81AfFmlsl1Rk,5160
105
+ pelix/shell/completion/decorators.py,sha256=jBE7Y69RS07ipfVf6v6-OSv5cj6oEHyvSNzQryFoM6s,2466
106
+ pelix/shell/completion/ipopo.py,sha256=YxwO56BkzLK-NRdkozzdDxz9iKrM3eksyz1p8Jo1vBk,10362
107
+ pelix/shell/completion/pelix.py,sha256=dJ73Ae-WOuo1FGEF18NlFjMsWswe3Ki1sYEyN8SxSwA,8289
108
+ ipopo-3.1.0.dist-info/METADATA,sha256=mFQE5D_LX1p7nT67NSSu1QF6s_uKm6piZnFCbPA1qlk,20726
109
+ ipopo-3.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
110
+ ipopo-3.1.0.dist-info/licenses/LICENSE,sha256=sdKHDxoA5Nf1ZXbl8IcMuhCeBB-K9mhmz1tJlHjmVOc,11359
111
+ ipopo-3.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any