pluggable-namespace 1.0.0__tar.gz
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.
- pluggable_namespace-1.0.0/MANIFEST.in +3 -0
- pluggable_namespace-1.0.0/PKG-INFO +161 -0
- pluggable_namespace-1.0.0/README.rst +117 -0
- pluggable_namespace-1.0.0/pyproject.toml +47 -0
- pluggable_namespace-1.0.0/setup.cfg +4 -0
- pluggable_namespace-1.0.0/setup.py +29 -0
- pluggable_namespace-1.0.0/src/_config/config.yaml +41 -0
- pluggable_namespace-1.0.0/src/_config/plugin/choices.py +37 -0
- pluggable_namespace-1.0.0/src/_config/plugin/contract/init.py +1 -0
- pluggable_namespace-1.0.0/src/_config/plugin/default.py +30 -0
- pluggable_namespace-1.0.0/src/_config/plugin/display_priority.py +34 -0
- pluggable_namespace-1.0.0/src/_config/plugin/group.py +31 -0
- pluggable_namespace-1.0.0/src/_config/plugin/init.py +318 -0
- pluggable_namespace-1.0.0/src/_config/plugin/options.py +14 -0
- pluggable_namespace-1.0.0/src/_config/plugin/os.py +10 -0
- pluggable_namespace-1.0.0/src/_config/plugin/positional.py +21 -0
- pluggable_namespace-1.0.0/src/_config/plugin/source.py +53 -0
- pluggable_namespace-1.0.0/src/_config/plugin/subcommands.py +82 -0
- pluggable_namespace-1.0.0/src/_config/plugin/type.py +15 -0
- pluggable_namespace-1.0.0/src/_log/config.yaml +82 -0
- pluggable_namespace-1.0.0/src/_log/plugin/basic.py +35 -0
- pluggable_namespace-1.0.0/src/_log/plugin/contract/init.py +1 -0
- pluggable_namespace-1.0.0/src/_log/plugin/init.py +167 -0
- pluggable_namespace-1.0.0/src/_log/plugin/timed_rolling.py +20 -0
- pluggable_namespace-1.0.0/src/_patt/config.yaml +10 -0
- pluggable_namespace-1.0.0/src/_patt/plugin/inst.py +286 -0
- pluggable_namespace-1.0.0/src/_pop/file.py +16 -0
- pluggable_namespace-1.0.0/src/_pop/sub.py +130 -0
- pluggable_namespace-1.0.0/src/_pop/test.py +121 -0
- pluggable_namespace-1.0.0/src/_rend/README.rst +17 -0
- pluggable_namespace-1.0.0/src/_rend/config.yaml +55 -0
- pluggable_namespace-1.0.0/src/_rend/exc/rend.py +16 -0
- pluggable_namespace-1.0.0/src/_rend/output/contracts/init.py +1 -0
- pluggable_namespace-1.0.0/src/_rend/output/json_out.py +19 -0
- pluggable_namespace-1.0.0/src/_rend/output/nested.py +191 -0
- pluggable_namespace-1.0.0/src/_rend/output/pretty.py +5 -0
- pluggable_namespace-1.0.0/src/_rend/output/raw.py +5 -0
- pluggable_namespace-1.0.0/src/_rend/output/yaml_out.py +37 -0
- pluggable_namespace-1.0.0/src/_rend/rend/contracts/init.py +1 -0
- pluggable_namespace-1.0.0/src/_rend/rend/init.py +136 -0
- pluggable_namespace-1.0.0/src/_rend/rend/jinja.py +85 -0
- pluggable_namespace-1.0.0/src/_rend/rend/json_file.py +20 -0
- pluggable_namespace-1.0.0/src/_rend/rend/toml_file.py +19 -0
- pluggable_namespace-1.0.0/src/_rend/rend/yaml_file.py +179 -0
- pluggable_namespace-1.0.0/src/_rend/rend/yaml_template.py +25 -0
- pluggable_namespace-1.0.0/src/_seed/config.yaml +32 -0
- pluggable_namespace-1.0.0/src/_seed/seed/init.py +27 -0
- pluggable_namespace-1.0.0/src/_seed/template/plugin/.github/workflows/ci.yaml +70 -0
- pluggable_namespace-1.0.0/src/_seed/template/plugin/.gitignore +165 -0
- pluggable_namespace-1.0.0/src/_seed/template/plugin/.gitlab-ci.yml +42 -0
- pluggable_namespace-1.0.0/src/_seed/template/plugin/.pre-commit-config.yaml +76 -0
- pluggable_namespace-1.0.0/src/_seed/template/plugin/README.rst.jinja +4 -0
- pluggable_namespace-1.0.0/src/_seed/template/plugin/copier.yml +6 -0
- pluggable_namespace-1.0.0/src/_seed/template/plugin/pyproject.toml.jinja +46 -0
- pluggable_namespace-1.0.0/src/_seed/template/plugin/src/{{name}}/__init__.py +0 -0
- pluggable_namespace-1.0.0/src/_seed/template/plugin/src/{{name}}/config.yaml.jinja +19 -0
- pluggable_namespace-1.0.0/src/_seed/template/plugin/src/{{name}}/plugin/init.py.jinja +9 -0
- pluggable_namespace-1.0.0/src/_seed/template/plugin/test/conftest.py.jinja +23 -0
- pluggable_namespace-1.0.0/src/_seed/template/plugin/test/test_init.py.jinja +25 -0
- pluggable_namespace-1.0.0/src/_seed/template/plugin/test/tpath/README.rst +7 -0
- pluggable_namespace-1.0.0/src/_seed/template/plugin/test/tpath/mods/config.yaml +9 -0
- pluggable_namespace-1.0.0/src/_seed/template/plugin/test/tpath/mods/src/init.py +6 -0
- pluggable_namespace-1.0.0/src/hub/README.rst +55 -0
- pluggable_namespace-1.0.0/src/hub/__main__.py +57 -0
- pluggable_namespace-1.0.0/src/hub/config.yaml +65 -0
- pluggable_namespace-1.0.0/src/hub/plugin/cli.py +125 -0
- pluggable_namespace-1.0.0/src/hub/plugin/completer.py +143 -0
- pluggable_namespace-1.0.0/src/hub/plugin/config.py +35 -0
- pluggable_namespace-1.0.0/src/hub/plugin/console.py +78 -0
- pluggable_namespace-1.0.0/src/hub/plugin/init.py +88 -0
- pluggable_namespace-1.0.0/src/hub/plugin/ref.py +55 -0
- pluggable_namespace-1.0.0/src/pluggable_namespace.egg-info/PKG-INFO +161 -0
- pluggable_namespace-1.0.0/src/pluggable_namespace.egg-info/SOURCES.txt +96 -0
- pluggable_namespace-1.0.0/src/pluggable_namespace.egg-info/dependency_links.txt +1 -0
- pluggable_namespace-1.0.0/src/pluggable_namespace.egg-info/entry_points.txt +2 -0
- pluggable_namespace-1.0.0/src/pluggable_namespace.egg-info/requires.txt +35 -0
- pluggable_namespace-1.0.0/src/pluggable_namespace.egg-info/top_level.txt +8 -0
- pluggable_namespace-1.0.0/src/pns/__init__.py +11 -0
- pluggable_namespace-1.0.0/src/pns/_contract.c +25301 -0
- pluggable_namespace-1.0.0/src/pns/_contract.py +375 -0
- pluggable_namespace-1.0.0/src/pns/_data.c +17423 -0
- pluggable_namespace-1.0.0/src/pns/_data.py +380 -0
- pluggable_namespace-1.0.0/src/pns/_debug.py +24 -0
- pluggable_namespace-1.0.0/src/pns/_hub.c +14700 -0
- pluggable_namespace-1.0.0/src/pns/_hub.py +178 -0
- pluggable_namespace-1.0.0/src/pns/contract.py +159 -0
- pluggable_namespace-1.0.0/src/pns/data.py +27 -0
- pluggable_namespace-1.0.0/src/pns/dir.py +217 -0
- pluggable_namespace-1.0.0/src/pns/hub.py +218 -0
- pluggable_namespace-1.0.0/src/pns/loop.py +79 -0
- pluggable_namespace-1.0.0/src/pns/mod.py +268 -0
- pluggable_namespace-1.0.0/src/pns/ref.py +98 -0
- pluggable_namespace-1.0.0/src/pns/shell.py +230 -0
- pluggable_namespace-1.0.0/src/pns/shim.py +123 -0
- pluggable_namespace-1.0.0/src/pns/verify.py +129 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: pluggable-namespace
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Pluggable namespaces
|
|
5
|
+
Author-email: Tyler Levy Conde <yonstib@gmail.com>
|
|
6
|
+
Classifier: Operating System :: OS Independent
|
|
7
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
11
|
+
Requires-Python: >=3.11
|
|
12
|
+
Description-Content-Type: text/x-rst
|
|
13
|
+
Requires-Dist: aioconsole
|
|
14
|
+
Requires-Dist: aiofiles
|
|
15
|
+
Requires-Dist: aiologger
|
|
16
|
+
Requires-Dist: argparse
|
|
17
|
+
Requires-Dist: PyYaml
|
|
18
|
+
Provides-Extra: console
|
|
19
|
+
Requires-Dist: aiomonitor; extra == "console"
|
|
20
|
+
Requires-Dist: prompt-toolkit; extra == "console"
|
|
21
|
+
Provides-Extra: rend
|
|
22
|
+
Requires-Dist: aio-yte; extra == "rend"
|
|
23
|
+
Requires-Dist: jinja2; extra == "rend"
|
|
24
|
+
Requires-Dist: toml; extra == "rend"
|
|
25
|
+
Provides-Extra: seed
|
|
26
|
+
Requires-Dist: copier; extra == "seed"
|
|
27
|
+
Provides-Extra: test
|
|
28
|
+
Requires-Dist: pexpect; extra == "test"
|
|
29
|
+
Requires-Dist: pytest; extra == "test"
|
|
30
|
+
Requires-Dist: pytest-asyncio; extra == "test"
|
|
31
|
+
Requires-Dist: setuptools; extra == "test"
|
|
32
|
+
Provides-Extra: full
|
|
33
|
+
Requires-Dist: aiomonitor; extra == "full"
|
|
34
|
+
Requires-Dist: prompt-toolkit; extra == "full"
|
|
35
|
+
Requires-Dist: aio-yte; extra == "full"
|
|
36
|
+
Requires-Dist: jinja2; extra == "full"
|
|
37
|
+
Requires-Dist: toml; extra == "full"
|
|
38
|
+
Requires-Dist: copier; extra == "full"
|
|
39
|
+
Requires-Dist: pexpect; extra == "full"
|
|
40
|
+
Requires-Dist: pytest; extra == "full"
|
|
41
|
+
Requires-Dist: pytest-asyncio; extra == "full"
|
|
42
|
+
Requires-Dist: setuptools; extra == "full"
|
|
43
|
+
Dynamic: provides-extra
|
|
44
|
+
|
|
45
|
+
===================
|
|
46
|
+
Pluggable Namespace
|
|
47
|
+
===================
|
|
48
|
+
This project is designed to facilitate the creation and management of pluggable software architectures using namespaces. The concept of pluggable namespaces enables the development of software that is modular and easy to extend.
|
|
49
|
+
|
|
50
|
+
Pluggable namespaces provide a framework for constructing applications composed entirely of interchangeable modules. This approach allows developers to scale their projects smoothly and integrate complex software components seamlessly.
|
|
51
|
+
|
|
52
|
+
Using pluggable namespaces, developers can build software in smaller, maintainable components. These components can then be combined and deployed as a single entity, simplifying the deployment process.
|
|
53
|
+
|
|
54
|
+
All of this is achieved using Python, one of the world's most popular and powerful programming languages.
|
|
55
|
+
|
|
56
|
+
Installation
|
|
57
|
+
============
|
|
58
|
+
|
|
59
|
+
You can install ``pluggable-namespace`` from PyPI:
|
|
60
|
+
|
|
61
|
+
.. code-block:: bash
|
|
62
|
+
|
|
63
|
+
pip3 install pluggable-namespace
|
|
64
|
+
|
|
65
|
+
Creating a pluggable application can be accomplished with just a few lines of code. The heart of every pluggable-namespace project is the creation of a hub, adding dynamic subsystems, and interacting with them through the hub's namespace.
|
|
66
|
+
|
|
67
|
+
.. code-block:: python
|
|
68
|
+
|
|
69
|
+
import pns.shim
|
|
70
|
+
import asyncio
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
async def main():
|
|
74
|
+
hub = await pns.shim.loaded_hub()
|
|
75
|
+
await hub.my_sub.init.cli()
|
|
76
|
+
|
|
77
|
+
if __name__ == "__main__":
|
|
78
|
+
asyncio.run(main())
|
|
79
|
+
|
|
80
|
+
Configuration
|
|
81
|
+
=============
|
|
82
|
+
When building a pluggable-namespace app, all configuration settings are stored in a ``config.yaml`` file.
|
|
83
|
+
|
|
84
|
+
.. code-block:: yaml
|
|
85
|
+
|
|
86
|
+
# Each configuration option for your module
|
|
87
|
+
config:
|
|
88
|
+
my_namespace:
|
|
89
|
+
my_opt:
|
|
90
|
+
default: True
|
|
91
|
+
|
|
92
|
+
# Options exposed on the CLI when your app controls the CLI
|
|
93
|
+
cli_config:
|
|
94
|
+
my_namespace:
|
|
95
|
+
my_opt:
|
|
96
|
+
help: Description of this option
|
|
97
|
+
subcommands:
|
|
98
|
+
- my_subcommand
|
|
99
|
+
group: My arg group
|
|
100
|
+
|
|
101
|
+
# Subcommands to expose for your project
|
|
102
|
+
subcommands:
|
|
103
|
+
my_namespace:
|
|
104
|
+
my_subcommand:
|
|
105
|
+
help: My subcommand
|
|
106
|
+
|
|
107
|
+
# Dynamic namespaces that your app merges onto and which folders extend those namespaces
|
|
108
|
+
dyne:
|
|
109
|
+
my_dyne:
|
|
110
|
+
- src_dir
|
|
111
|
+
|
|
112
|
+
# Python imports that your app uses, to be added to hub.lib for your app
|
|
113
|
+
import:
|
|
114
|
+
- asyncio
|
|
115
|
+
- importlib
|
|
116
|
+
- importlib.resources
|
|
117
|
+
- os
|
|
118
|
+
- toml
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
From the example above, all arguments are loaded onto the namespace under hub.OPT.my_namespace.
|
|
122
|
+
One ``config.yaml`` can add configuration options to multiple namespaces.
|
|
123
|
+
They are merged in the order found in sys.path.
|
|
124
|
+
|
|
125
|
+
Extending Namespaces
|
|
126
|
+
====================
|
|
127
|
+
|
|
128
|
+
locally
|
|
129
|
+
-------
|
|
130
|
+
|
|
131
|
+
Extending ``pluggable-namespace`` is straightforward with dynamic namespaces.
|
|
132
|
+
Extend any dynamic namespace on the hub by adding a directory containing a "config.yaml" to PYTHONPATH.
|
|
133
|
+
|
|
134
|
+
.. code-block:: bash
|
|
135
|
+
|
|
136
|
+
export PYTHONPATH=$PYTHONPATH:/path/to/project_root
|
|
137
|
+
|
|
138
|
+
Add a config.yaml to that directory:
|
|
139
|
+
|
|
140
|
+
.. code-block:: yaml
|
|
141
|
+
|
|
142
|
+
# project_root/config.yaml
|
|
143
|
+
dyne:
|
|
144
|
+
namespace:
|
|
145
|
+
# This references the directory project_root/foo
|
|
146
|
+
- foo
|
|
147
|
+
|
|
148
|
+
Now, every Python file in ``project_root/foo`` will be added to the hub under ``hub.namespace``.
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
With PyPI
|
|
152
|
+
---------
|
|
153
|
+
|
|
154
|
+
You can use the ``seed`` command to create all the boiler-plate code you need for a pluggable-namespace project.
|
|
155
|
+
|
|
156
|
+
.. code-block:: bash
|
|
157
|
+
|
|
158
|
+
hub seed.init.cli /path/to/project_root name=my_project
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
Now you can add all your code to /path/to/project_root/src/my_project
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
===================
|
|
2
|
+
Pluggable Namespace
|
|
3
|
+
===================
|
|
4
|
+
This project is designed to facilitate the creation and management of pluggable software architectures using namespaces. The concept of pluggable namespaces enables the development of software that is modular and easy to extend.
|
|
5
|
+
|
|
6
|
+
Pluggable namespaces provide a framework for constructing applications composed entirely of interchangeable modules. This approach allows developers to scale their projects smoothly and integrate complex software components seamlessly.
|
|
7
|
+
|
|
8
|
+
Using pluggable namespaces, developers can build software in smaller, maintainable components. These components can then be combined and deployed as a single entity, simplifying the deployment process.
|
|
9
|
+
|
|
10
|
+
All of this is achieved using Python, one of the world's most popular and powerful programming languages.
|
|
11
|
+
|
|
12
|
+
Installation
|
|
13
|
+
============
|
|
14
|
+
|
|
15
|
+
You can install ``pluggable-namespace`` from PyPI:
|
|
16
|
+
|
|
17
|
+
.. code-block:: bash
|
|
18
|
+
|
|
19
|
+
pip3 install pluggable-namespace
|
|
20
|
+
|
|
21
|
+
Creating a pluggable application can be accomplished with just a few lines of code. The heart of every pluggable-namespace project is the creation of a hub, adding dynamic subsystems, and interacting with them through the hub's namespace.
|
|
22
|
+
|
|
23
|
+
.. code-block:: python
|
|
24
|
+
|
|
25
|
+
import pns.shim
|
|
26
|
+
import asyncio
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
async def main():
|
|
30
|
+
hub = await pns.shim.loaded_hub()
|
|
31
|
+
await hub.my_sub.init.cli()
|
|
32
|
+
|
|
33
|
+
if __name__ == "__main__":
|
|
34
|
+
asyncio.run(main())
|
|
35
|
+
|
|
36
|
+
Configuration
|
|
37
|
+
=============
|
|
38
|
+
When building a pluggable-namespace app, all configuration settings are stored in a ``config.yaml`` file.
|
|
39
|
+
|
|
40
|
+
.. code-block:: yaml
|
|
41
|
+
|
|
42
|
+
# Each configuration option for your module
|
|
43
|
+
config:
|
|
44
|
+
my_namespace:
|
|
45
|
+
my_opt:
|
|
46
|
+
default: True
|
|
47
|
+
|
|
48
|
+
# Options exposed on the CLI when your app controls the CLI
|
|
49
|
+
cli_config:
|
|
50
|
+
my_namespace:
|
|
51
|
+
my_opt:
|
|
52
|
+
help: Description of this option
|
|
53
|
+
subcommands:
|
|
54
|
+
- my_subcommand
|
|
55
|
+
group: My arg group
|
|
56
|
+
|
|
57
|
+
# Subcommands to expose for your project
|
|
58
|
+
subcommands:
|
|
59
|
+
my_namespace:
|
|
60
|
+
my_subcommand:
|
|
61
|
+
help: My subcommand
|
|
62
|
+
|
|
63
|
+
# Dynamic namespaces that your app merges onto and which folders extend those namespaces
|
|
64
|
+
dyne:
|
|
65
|
+
my_dyne:
|
|
66
|
+
- src_dir
|
|
67
|
+
|
|
68
|
+
# Python imports that your app uses, to be added to hub.lib for your app
|
|
69
|
+
import:
|
|
70
|
+
- asyncio
|
|
71
|
+
- importlib
|
|
72
|
+
- importlib.resources
|
|
73
|
+
- os
|
|
74
|
+
- toml
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
From the example above, all arguments are loaded onto the namespace under hub.OPT.my_namespace.
|
|
78
|
+
One ``config.yaml`` can add configuration options to multiple namespaces.
|
|
79
|
+
They are merged in the order found in sys.path.
|
|
80
|
+
|
|
81
|
+
Extending Namespaces
|
|
82
|
+
====================
|
|
83
|
+
|
|
84
|
+
locally
|
|
85
|
+
-------
|
|
86
|
+
|
|
87
|
+
Extending ``pluggable-namespace`` is straightforward with dynamic namespaces.
|
|
88
|
+
Extend any dynamic namespace on the hub by adding a directory containing a "config.yaml" to PYTHONPATH.
|
|
89
|
+
|
|
90
|
+
.. code-block:: bash
|
|
91
|
+
|
|
92
|
+
export PYTHONPATH=$PYTHONPATH:/path/to/project_root
|
|
93
|
+
|
|
94
|
+
Add a config.yaml to that directory:
|
|
95
|
+
|
|
96
|
+
.. code-block:: yaml
|
|
97
|
+
|
|
98
|
+
# project_root/config.yaml
|
|
99
|
+
dyne:
|
|
100
|
+
namespace:
|
|
101
|
+
# This references the directory project_root/foo
|
|
102
|
+
- foo
|
|
103
|
+
|
|
104
|
+
Now, every Python file in ``project_root/foo`` will be added to the hub under ``hub.namespace``.
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
With PyPI
|
|
108
|
+
---------
|
|
109
|
+
|
|
110
|
+
You can use the ``seed`` command to create all the boiler-plate code you need for a pluggable-namespace project.
|
|
111
|
+
|
|
112
|
+
.. code-block:: bash
|
|
113
|
+
|
|
114
|
+
hub seed.init.cli /path/to/project_root name=my_project
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
Now you can add all your code to /path/to/project_root/src/my_project
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools", "wheel", "Cython"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pluggable-namespace"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Pluggable namespaces"
|
|
9
|
+
readme = "README.rst"
|
|
10
|
+
authors = [
|
|
11
|
+
{name = "Tyler Levy Conde", email = "yonstib@gmail.com"},
|
|
12
|
+
]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Operating System :: OS Independent",
|
|
15
|
+
"Programming Language :: Python :: 3.11",
|
|
16
|
+
"Programming Language :: Python :: 3.12",
|
|
17
|
+
"Development Status :: 5 - Production/Stable",
|
|
18
|
+
"License :: OSI Approved :: Apache Software License",
|
|
19
|
+
]
|
|
20
|
+
requires-python = ">=3.11"
|
|
21
|
+
dependencies = [
|
|
22
|
+
"aioconsole",
|
|
23
|
+
"aiofiles",
|
|
24
|
+
"aiologger",
|
|
25
|
+
"argparse",
|
|
26
|
+
"PyYaml",
|
|
27
|
+
]
|
|
28
|
+
dynamic = ["optional-dependencies"]
|
|
29
|
+
|
|
30
|
+
[project.scripts]
|
|
31
|
+
hub = "hub.__main__:main"
|
|
32
|
+
|
|
33
|
+
[tool.setuptools]
|
|
34
|
+
package-dir = {"" = "src"}
|
|
35
|
+
|
|
36
|
+
[tool.setuptools.packages.find]
|
|
37
|
+
where = ["src"]
|
|
38
|
+
namespaces = true
|
|
39
|
+
|
|
40
|
+
[tool.pytest.ini_options]
|
|
41
|
+
testpaths = "test"
|
|
42
|
+
addopts = "--tb native --full-trace --color=yes -vv"
|
|
43
|
+
asyncio_mode = "auto"
|
|
44
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
45
|
+
|
|
46
|
+
[tool.cython-lint]
|
|
47
|
+
max-line-length = 120
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from setuptools import setup
|
|
3
|
+
from setuptools.extension import Extension
|
|
4
|
+
from Cython.Build import cythonize
|
|
5
|
+
|
|
6
|
+
extensions = [
|
|
7
|
+
Extension(name="pns._ccontract", sources=["src/pns/_contract.py"]),
|
|
8
|
+
Extension(name="pns._cdata", sources=["src/pns/_data.py"]),
|
|
9
|
+
Extension(name="pns._chub", sources=["src/pns/_hub.py"]),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
SETUP_DIRNAME = Path(__file__).parent
|
|
13
|
+
|
|
14
|
+
requirement_extras = {}
|
|
15
|
+
REQUIREMENTS = SETUP_DIRNAME / "requirement"
|
|
16
|
+
assert REQUIREMENTS.exists()
|
|
17
|
+
for req_file in REQUIREMENTS.glob("*.txt"):
|
|
18
|
+
with open(req_file) as f:
|
|
19
|
+
requirement_extras[req_file.stem] = sorted(
|
|
20
|
+
line for line in f.read().splitlines() if line.strip()
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
requirement_extras["full"] = sum(requirement_extras.values(), [])
|
|
24
|
+
|
|
25
|
+
setup(
|
|
26
|
+
extras_require=requirement_extras,
|
|
27
|
+
ext_modules=cythonize(extensions),
|
|
28
|
+
include_package_data=True,
|
|
29
|
+
)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
|
|
2
|
+
cli_config:
|
|
3
|
+
pns:
|
|
4
|
+
config:
|
|
5
|
+
default: ~/.pns/config.yaml
|
|
6
|
+
os: PNS_CONFIG
|
|
7
|
+
help: The config file used for PNS
|
|
8
|
+
group: Config Options
|
|
9
|
+
options:
|
|
10
|
+
- -c
|
|
11
|
+
subcommands:
|
|
12
|
+
- __global__
|
|
13
|
+
|
|
14
|
+
dyne:
|
|
15
|
+
config:
|
|
16
|
+
- plugin
|
|
17
|
+
|
|
18
|
+
import:
|
|
19
|
+
- aiofiles
|
|
20
|
+
- aiofiles.os
|
|
21
|
+
- aiologger.handlers.files
|
|
22
|
+
- argparse
|
|
23
|
+
- asyncio
|
|
24
|
+
- ast
|
|
25
|
+
- collections
|
|
26
|
+
- pns.contract
|
|
27
|
+
- pns.data
|
|
28
|
+
- pns.exc
|
|
29
|
+
- pns.hub
|
|
30
|
+
- importlib
|
|
31
|
+
- importlib.resources
|
|
32
|
+
- logging
|
|
33
|
+
- msgpack
|
|
34
|
+
- os
|
|
35
|
+
- pathlib
|
|
36
|
+
- pickle
|
|
37
|
+
- signal
|
|
38
|
+
- sys
|
|
39
|
+
- traceback
|
|
40
|
+
- yaml
|
|
41
|
+
- typing
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
async def parse_opt(hub, opts: dict[str, object]) -> dict[str, object]:
|
|
2
|
+
"""
|
|
3
|
+
Handle choices that may come from a loaded mod.
|
|
4
|
+
|
|
5
|
+
You specify a sub on the hub for "choices" to dynamically use the loaded mods of that sub as the choices
|
|
6
|
+
|
|
7
|
+
I.e.
|
|
8
|
+
|
|
9
|
+
config:
|
|
10
|
+
my_app:
|
|
11
|
+
my_opt:
|
|
12
|
+
choices:
|
|
13
|
+
my_sub
|
|
14
|
+
|
|
15
|
+
Otherwise, you can specify a list of static choices that may be used
|
|
16
|
+
|
|
17
|
+
I.e.
|
|
18
|
+
|
|
19
|
+
config:
|
|
20
|
+
my_app:
|
|
21
|
+
my_opt:
|
|
22
|
+
choices:
|
|
23
|
+
- choice_1
|
|
24
|
+
- choice_2
|
|
25
|
+
"""
|
|
26
|
+
choices = opts.pop("choices", ())
|
|
27
|
+
if isinstance(choices, str):
|
|
28
|
+
finder = hub
|
|
29
|
+
for part in choices.split("."):
|
|
30
|
+
try:
|
|
31
|
+
finder = getattr(finder, part)
|
|
32
|
+
except AttributeError:
|
|
33
|
+
return {}
|
|
34
|
+
|
|
35
|
+
opts["choices"] = sorted(finder)
|
|
36
|
+
|
|
37
|
+
return {}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
async def sig_parse_opt(hub, opts: dict[str, object]) -> dict[str, object]: ...
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
async def __init__(hub):
|
|
2
|
+
hub._.REF_PATTERN = hub.lib.re.compile(r"^hub\.(\w+(\.\w+)+)\(\)$")
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
async def parse_opt(hub, opts: dict[str, object]) -> dict[str, object]:
|
|
6
|
+
"""
|
|
7
|
+
Remove 'default' from the argument opts, it will be handled by the config prioritizer, not argparse.
|
|
8
|
+
If the "default" is a function that exists on the hub, then call it to get the default value.
|
|
9
|
+
This allows you to call a function on the hub to do more processing on the default.
|
|
10
|
+
This could be useful for using a different value for the default based on OS.
|
|
11
|
+
|
|
12
|
+
I.e.
|
|
13
|
+
|
|
14
|
+
config:
|
|
15
|
+
my_app:
|
|
16
|
+
my_opt:
|
|
17
|
+
default: hub.my_sub.mod.func()
|
|
18
|
+
"""
|
|
19
|
+
default = opts.pop("default", None)
|
|
20
|
+
|
|
21
|
+
if default and isinstance(default, str):
|
|
22
|
+
match = hub._.REF_PATTERN.match(default)
|
|
23
|
+
if match:
|
|
24
|
+
ref = match.group(1)
|
|
25
|
+
func = hub.lib.pns.ref.find(hub, ref)
|
|
26
|
+
default = func()
|
|
27
|
+
if hub.lib.asyncio.iscoroutine(default):
|
|
28
|
+
default = await default
|
|
29
|
+
|
|
30
|
+
return {"default": default}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
async def parse_opt(hub, opts: dict[str, object]) -> dict[str, object]:
|
|
2
|
+
"""
|
|
3
|
+
Handle the display priority of positional arguments.
|
|
4
|
+
This ensures that positional arguments appear in the defined order
|
|
5
|
+
|
|
6
|
+
I.e.
|
|
7
|
+
|
|
8
|
+
config:
|
|
9
|
+
my_app:
|
|
10
|
+
my_opt_1:
|
|
11
|
+
positional: True
|
|
12
|
+
display_priority: 1
|
|
13
|
+
my_opt_2:
|
|
14
|
+
positional: True
|
|
15
|
+
display_priority: 2
|
|
16
|
+
"""
|
|
17
|
+
display_priority = opts.pop("display_priority", None)
|
|
18
|
+
return {"display_priority": display_priority}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
async def sort(hub, cli_args: list[dict[str, object]]) -> list[dict[str, object]]:
|
|
22
|
+
"""
|
|
23
|
+
Sort the CLI arguments by display_priority.
|
|
24
|
+
The negative display_priorities were applied to args with no display priority,
|
|
25
|
+
They will come in the order they were defined
|
|
26
|
+
"""
|
|
27
|
+
# Sort arguments by display_priority
|
|
28
|
+
return sorted(
|
|
29
|
+
cli_args,
|
|
30
|
+
key=lambda opt: (
|
|
31
|
+
opt["extra"]["display_priority"] is None,
|
|
32
|
+
opt["extra"]["display_priority"],
|
|
33
|
+
),
|
|
34
|
+
)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
async def parse_opt(hub, opts: dict[str, object]) -> dict[str, object]:
|
|
2
|
+
"""
|
|
3
|
+
This config value groups arguments together in the --help text.
|
|
4
|
+
|
|
5
|
+
config:
|
|
6
|
+
my_app:
|
|
7
|
+
my_opt:
|
|
8
|
+
group: my_group
|
|
9
|
+
other_opt:
|
|
10
|
+
group: my_group
|
|
11
|
+
"""
|
|
12
|
+
group = opts.pop("group", False)
|
|
13
|
+
return {"group": group}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
async def merge(hub, name: str, groups: dict[str, object], subcmd: str, subparser):
|
|
17
|
+
"""
|
|
18
|
+
Merge the group into the subparser if a group name is provided.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
name (str): The name of the group.
|
|
22
|
+
groups (dict): The existing groups dictionary.
|
|
23
|
+
subcmd (str): The subcommand name.
|
|
24
|
+
subparser (ArgumentParser): The subparser instance.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
ArgumentParser: The argument group added to the subparser.
|
|
28
|
+
"""
|
|
29
|
+
if name:
|
|
30
|
+
return groups[subcmd].setdefault(name, subparser.add_argument_group(name))
|
|
31
|
+
return subparser
|