neobuilder6 6.1.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.
Files changed (55) hide show
  1. neobuilder6-6.1.0/LICENSE +22 -0
  2. neobuilder6-6.1.0/PKG-INFO +231 -0
  3. neobuilder6-6.1.0/README.md +194 -0
  4. neobuilder6-6.1.0/neobuilder6/__init__.py +5 -0
  5. neobuilder6-6.1.0/neobuilder6/cli/__init__.py +0 -0
  6. neobuilder6-6.1.0/neobuilder6/cli/neobuilder.py +48 -0
  7. neobuilder6-6.1.0/neobuilder6/data/templates/dataclass.jinja2 +12 -0
  8. neobuilder6-6.1.0/neobuilder6/data/templates/dataclass_module.jinja2 +34 -0
  9. neobuilder6-6.1.0/neobuilder6/data/templates/grpc_receiver.jinja2 +21 -0
  10. neobuilder6-6.1.0/neobuilder6/data/templates/grpc_sender.jinja2 +21 -0
  11. neobuilder6-6.1.0/neobuilder6/data/templates/init.jinja2 +0 -0
  12. neobuilder6-6.1.0/neobuilder6/data/templates/interface.jinja2 +22 -0
  13. neobuilder6-6.1.0/neobuilder6/data/templates/macros/indentclude.jinja2 +2 -0
  14. neobuilder6-6.1.0/neobuilder6/data/templates/package_aliases.jinja2 +10 -0
  15. neobuilder6-6.1.0/neobuilder6/data/templates/parts/_enum_map.jinja2 +1 -0
  16. neobuilder6-6.1.0/neobuilder6/data/templates/parts/_interface_method.jinja2 +2 -0
  17. neobuilder6-6.1.0/neobuilder6/data/templates/parts/_interface_service.jinja2 +10 -0
  18. neobuilder6-6.1.0/neobuilder6/data/templates/parts/_nested_messages.jinja2 +1 -0
  19. neobuilder6-6.1.0/neobuilder6/data/templates/root_init.jinja2 +12 -0
  20. neobuilder6-6.1.0/neobuilder6/descwrap/__init__.py +2 -0
  21. neobuilder6-6.1.0/neobuilder6/descwrap/_field.py +188 -0
  22. neobuilder6-6.1.0/neobuilder6/descwrap/_method.py +57 -0
  23. neobuilder6-6.1.0/neobuilder6/generators/__init__.py +0 -0
  24. neobuilder6-6.1.0/neobuilder6/generators/servicebuilders/__init__.py +27 -0
  25. neobuilder6-6.1.0/neobuilder6/generators/servicebuilders/base.py +99 -0
  26. neobuilder6-6.1.0/neobuilder6/generators/servicebuilders/grpc_receiver.py +92 -0
  27. neobuilder6-6.1.0/neobuilder6/generators/servicebuilders/grpc_sender.py +65 -0
  28. neobuilder6-6.1.0/neobuilder6/generators/servicebuilders/grpc_server.py +54 -0
  29. neobuilder6-6.1.0/neobuilder6/generators/servicebuilders/implementation.py +49 -0
  30. neobuilder6-6.1.0/neobuilder6/generators/servicebuilders/interface.py +84 -0
  31. neobuilder6-6.1.0/neobuilder6/generators/symbols/__init__.py +4 -0
  32. neobuilder6-6.1.0/neobuilder6/generators/symbols/common.py +68 -0
  33. neobuilder6-6.1.0/neobuilder6/generators/symbols/dataclass.py +471 -0
  34. neobuilder6-6.1.0/neobuilder6/generators/symbols/modules.py +232 -0
  35. neobuilder6-6.1.0/neobuilder6/generators/symbols/service.py +139 -0
  36. neobuilder6-6.1.0/neobuilder6/neobuilder/__init__.py +455 -0
  37. neobuilder6-6.1.0/neobuilder6/neobuilder/render/__init__.py +66 -0
  38. neobuilder6-6.1.0/neobuilder6/neobuilder/render/renderer.py +37 -0
  39. neobuilder6-6.1.0/neobuilder6/structs/__init__.py +5 -0
  40. neobuilder6-6.1.0/neobuilder6/structs/_base.py +3 -0
  41. neobuilder6-6.1.0/neobuilder6/structs/protofile.py +20 -0
  42. neobuilder6-6.1.0/neobuilder6/structs/pytype.py +91 -0
  43. neobuilder6-6.1.0/neobuilder6.egg-info/PKG-INFO +231 -0
  44. neobuilder6-6.1.0/neobuilder6.egg-info/SOURCES.txt +53 -0
  45. neobuilder6-6.1.0/neobuilder6.egg-info/dependency_links.txt +1 -0
  46. neobuilder6-6.1.0/neobuilder6.egg-info/entry_points.txt +3 -0
  47. neobuilder6-6.1.0/neobuilder6.egg-info/requires.txt +5 -0
  48. neobuilder6-6.1.0/neobuilder6.egg-info/top_level.txt +1 -0
  49. neobuilder6-6.1.0/pyproject.toml +65 -0
  50. neobuilder6-6.1.0/setup.cfg +4 -0
  51. neobuilder6-6.1.0/setup.py +6 -0
  52. neobuilder6-6.1.0/tests/test_alias_imports.py +70 -0
  53. neobuilder6-6.1.0/tests/test_neobuilder.py +116 -0
  54. neobuilder6-6.1.0/tests/test_services.py +277 -0
  55. neobuilder6-6.1.0/tests/test_zdataclassbuilder.py +1163 -0
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Thordur Matthiasson
4
+ Copyright (c) 2022-2024 CCP Games
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
@@ -0,0 +1,231 @@
1
+ Metadata-Version: 2.4
2
+ Name: neobuilder6
3
+ Version: 6.1.0
4
+ Summary: Builds Neobuf Packages from Protobuf files using Protoplasm6! :D (a continuation fork of CCP Games' neobuilder)
5
+ Author-email: Thordur Matthiasson <doddi79@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/doddi79/neobuilder6
8
+ Project-URL: Documentation, https://github.com/doddi79/neobuilder6/blob/main/README.md
9
+ Project-URL: Repository, https://github.com/doddi79/neobuilder6.git
10
+ Project-URL: Issues, https://github.com/doddi79/neobuilder6/issues
11
+ Project-URL: Changelog, https://github.com/doddi79/neobuilder6/blob/main/CHANGELOG.md
12
+ Keywords: protobuf,proto,grpc,protoplasm,protoplasm6,neobuf,dataclasses,codegen,tools,utils
13
+ Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Programming Language :: Python
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
23
+ Classifier: Topic :: Software Development
24
+ Classifier: Topic :: Software Development :: Code Generators
25
+ Classifier: Topic :: Software Development :: Libraries
26
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
+ Classifier: Topic :: Utilities
28
+ Requires-Python: >=3.10
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Requires-Dist: protoplasm6<7,>=6.0
32
+ Requires-Dist: batutils<3,>=2.2
33
+ Requires-Dist: grpcio-tools<2,>=1.80
34
+ Requires-Dist: Jinja2<4,>=3.1
35
+ Requires-Dist: semver<4,>=3.0.2
36
+ Dynamic: license-file
37
+
38
+ # NeoBuilder6
39
+
40
+ Builds Neobuf Packages from Protobuf files using Protoplasm6! :D
41
+
42
+ See the **[Public API index](docs/api-index.md)** for a task-oriented reference of
43
+ the CLI, the Python API and the generated code layout.
44
+
45
+ ## Note
46
+
47
+ This is a fork of the [`neobuilder`](https://github.com/ccpgames/neobuilder)
48
+ package (v5.3.1) by CCP Games, made in order to continue its development and
49
+ maintenance. The package _and_ module are now called `neobuilder6` (starting
50
+ at version 6.0.0) and the code it generates uses
51
+ [`protoplasm6`](https://github.com/doddi79/protoplasm6) (the fork of
52
+ `protoplasm`).
53
+
54
+ ## What it does
55
+
56
+ Given a directory of `*.proto` files, Neobuilder6 builds a Python package
57
+ ("Neobuf package") containing, for each `foo.proto`:
58
+
59
+ | File | What |
60
+ |-------------------------|------------------------------------------------------------------------------------|
61
+ | `foo_pb2.py` | The plain `protoc` generated protobuf code |
62
+ | `foo_pb2.pyi` | Type stubs for `foo_pb2.py` so IDEs and type checkers understand it (skip with `--no-pyi`) |
63
+ | `foo_pb2_grpc.py` | The plain `protoc` generated gRPC code (if `foo.proto` has a `service`) |
64
+ | `foo_dc.py` | Python dataclasses for every message and enum, extending Protoplasm6's `DataclassBase` |
65
+ | `foo_api.py` | Interface classes for every `service` with plain Python methods per RPC |
66
+ | `foo_grpc_receiver.py` | gRPC servicers that forward calls to your implementation of the interface |
67
+ | `foo_grpc_sender.py` | gRPC clients that implement the interface by calling a remote service |
68
+
69
+ ...along with `__init__.py` files everywhere, a root `__init__.py` with a
70
+ `__version__` (and the Protoplasm6 and Neobuilder6 versions used), a
71
+ `VERSION` file and an `__everything__.py` module that imports every module
72
+ (call `your_package.load_symbols()` to make sure the protobuf symbol database
73
+ knows every message, e.g. for `Any` unpacking).
74
+
75
+ The `__init__.py` of every directory that matches a proto package also
76
+ "alias imports" everything in that proto package, so e.g.
77
+ `from myshop.orders import *` gets you every message and enum declared with
78
+ `package myshop.orders;`, no matter which `.proto` file they're in (use
79
+ `--no-alias-imports` to skip this).
80
+
81
+ See the [Protoplasm6 README](https://github.com/doddi79/protoplasm6) for how
82
+ to use the generated code.
83
+
84
+ ## Installation
85
+
86
+ ```
87
+ pip install neobuilder6
88
+ ```
89
+
90
+ This installs Protoplasm6, `grpcio-tools` (which provides `protoc`) and creates
91
+ the `neobuild` command (and its alias `neobuild6`) in Python's `Scripts`/`bin`
92
+ folder. Neobuilder6 requires Python 3.10+.
93
+
94
+ ## Usage
95
+
96
+ Assuming you've got a package called `sandbox` and you're storing your
97
+ protobuf files in a directory called `proto` (i.e. `./proto/sandbox/**.proto`)
98
+ and you want to spit out the build into the directory `build` just go:
99
+
100
+ ```
101
+ neobuild sandbox
102
+ ```
103
+
104
+ The resulting `./build/sandbox` package depends on `protoplasm6` (with the
105
+ same major version and the same or later minor version as the Neobuilder6
106
+ used to build it) and on a `protobuf` runtime matching the `grpcio-tools` that
107
+ built it (the `*_pb2.py` files check this when imported).
108
+
109
+ You can also run it from Python:
110
+
111
+ ```python
112
+ from neobuilder6.neobuilder import NeoBuilder
113
+
114
+ NeoBuilder(package='sandbox', protopath='./proto', build_root='./build').build()
115
+ ```
116
+
117
+ ### Versioning your package
118
+
119
+ If you place a plain text file called `VERSION` in the root of your proto
120
+ package (e.g. `./proto/sandbox/VERSION` from the example above) and skip any
121
+ versioning parameters (`--major`/`-m` or `--patch`/`-p`) Neobuilder6 will use
122
+ that file for versioning.
123
+
124
+ The first line in the file should be the semantic version number (`x.y.z`,
125
+ and if there's a 4th part like in `x.y.z.a` it's ignored) and any following
126
+ lines are treated as a "commit message" that's written to the built package's
127
+ `VERSION` file.
128
+
129
+ Without a `VERSION` file, the version of the previous build (if found in the
130
+ build root) is bumped (minor by default) or `0.1.0` is used for a first build.
131
+
132
+ ### Full CLI usage
133
+
134
+ ```
135
+ usage: neobuild [-h] [-m | -p] [-b [BUILDROOT]] [-v] [-i | --pyi | --no-pyi]
136
+ [--alias-imports | --no-alias-imports] [-I INCLUDE]
137
+ package [protopath]
138
+
139
+ Builds neobuf packages with protoplasm6.
140
+
141
+ positional arguments:
142
+ package Package name
143
+ protopath Path to the root of the protobuf files (default="./proto")
144
+
145
+ options:
146
+ -h, --help show this help message and exit
147
+ -m, --major Bump the major version number instead of the minor
148
+ -p, --patch Bump the patch version number instead of the minor
149
+ -b, --buildroot [BUILDROOT]
150
+ Path to the root of the output build files (default="./build")
151
+ -v, --verbose Spits out DEBUG level logs
152
+ -i, --pyi, --no-pyi Builds *.pyi type stubs for the pb2 files as well (default=True, use --no-
153
+ pyi to skip)
154
+ --alias-imports, --no-alias-imports
155
+ Alias imports everything in each proto package in the __init__.py of the
156
+ corresponding Python package, e.g. so "from myshop.orders import *" works
157
+ (default=True, use --no-alias-imports to skip)
158
+ -I, --include INCLUDE
159
+ Optional additional proto paths to include (can be used multiple times)
160
+
161
+ Neobuilder6 v6.1.0 - Protoplasm6 v6.1.0
162
+ ```
163
+
164
+ ## Neobuilder6 & Protoplasm6 (the chicken and the egg)
165
+
166
+ The two packages depend on each other in a slightly odd way:
167
+
168
+ - **Neobuilder6 depends on Protoplasm6** at build time (it uses some of its
169
+ utilities, e.g. for type casting and method I/O types) and the code it
170
+ generates imports Protoplasm6 at runtime.
171
+ - **Protoplasm6 depends on Neobuilder6 only for its unit tests**, which use
172
+ Neobuilder6 to build the protos they test against. It's installed with
173
+ `--no-deps` there to avoid a circular install.
174
+
175
+ ### Versioning
176
+
177
+ The versioning of Neobuilder6 and Protoplasm6 (major and minor versions) go
178
+ hand in hand; i.e. when Protoplasm6's major or minor versions bump, a new
179
+ Neobuilder6 should also be released with the same major and minor version,
180
+ even if there's no actual code change needed in Neobuilder6 to support
181
+ whatever changed in Protoplasm6.
182
+
183
+ Neobuilder6 releases are NOT guaranteed to be backwards compatible with older
184
+ versions of Protoplasm6 and trying to run Neobuilder6 built code with a
185
+ Protoplasm6 release whose major and/or minor versions lag behind will more
186
+ often than not just break. A difference in the patch version should most
187
+ often be fine, as should using a Protoplasm6 release that's one or more minor
188
+ versions ahead of the Neobuilder6 used to build code.
189
+
190
+ In order to keep this synchronous development and release simple, Neobuilder6
191
+ should generally NOT depend on new features added to the Protoplasm6 release
192
+ with the same version, so that it can build code for its corresponding
193
+ Protoplasm6 version without having that latest version actually installed.
194
+
195
+ ### Releasing
196
+
197
+ 1. Release Protoplasm6 first (its unit tests need Neobuilder6, installed with
198
+ `--no-deps`, e.g. straight from its `main` branch or a sibling checkout)
199
+ 2. Then release Neobuilder6 (which can then pull the new Protoplasm6 from
200
+ PyPI)
201
+
202
+ See [CI/CD](#cicd) for how GitHub Actions handle this.
203
+
204
+ ## Development
205
+
206
+ With both repos checked out side by side:
207
+
208
+ ```
209
+ python -m venv .venv
210
+ .venv/Scripts/activate # or: source .venv/bin/activate
211
+ pip install -e ../protoplasm6
212
+ pip install -e .
213
+ python -m unittest discover -v -f ./tests
214
+ ```
215
+
216
+ ### CI/CD
217
+
218
+ GitHub Actions run the unit tests (on Python 3.10 to 3.14) for pushes to
219
+ `main` and for all pull requests, and publish to PyPI (after running the
220
+ tests again and checking that the release tag, e.g. `v6.1.0` or `6.1.0`,
221
+ matches `__version__`) whenever a GitHub release (or pre-release) is created.
222
+ Publishing needs a `PYPI_UPLOAD_TOKEN` repository secret.
223
+
224
+ Since the tests of each package need the other one, CI installs
225
+ Protoplasm6 from the branch with the **same name** in its repo if there is
226
+ one (so changes spanning both repos can be tested together, e.g. with a pull
227
+ request from the same branch name in both) or from `main` otherwise. When
228
+ publishing, Protoplasm6 comes from PyPI if a matching release is there
229
+ (otherwise from `main`).
230
+
231
+ When releasing both packages, release Protoplasm6 first, then Neobuilder6.
@@ -0,0 +1,194 @@
1
+ # NeoBuilder6
2
+
3
+ Builds Neobuf Packages from Protobuf files using Protoplasm6! :D
4
+
5
+ See the **[Public API index](docs/api-index.md)** for a task-oriented reference of
6
+ the CLI, the Python API and the generated code layout.
7
+
8
+ ## Note
9
+
10
+ This is a fork of the [`neobuilder`](https://github.com/ccpgames/neobuilder)
11
+ package (v5.3.1) by CCP Games, made in order to continue its development and
12
+ maintenance. The package _and_ module are now called `neobuilder6` (starting
13
+ at version 6.0.0) and the code it generates uses
14
+ [`protoplasm6`](https://github.com/doddi79/protoplasm6) (the fork of
15
+ `protoplasm`).
16
+
17
+ ## What it does
18
+
19
+ Given a directory of `*.proto` files, Neobuilder6 builds a Python package
20
+ ("Neobuf package") containing, for each `foo.proto`:
21
+
22
+ | File | What |
23
+ |-------------------------|------------------------------------------------------------------------------------|
24
+ | `foo_pb2.py` | The plain `protoc` generated protobuf code |
25
+ | `foo_pb2.pyi` | Type stubs for `foo_pb2.py` so IDEs and type checkers understand it (skip with `--no-pyi`) |
26
+ | `foo_pb2_grpc.py` | The plain `protoc` generated gRPC code (if `foo.proto` has a `service`) |
27
+ | `foo_dc.py` | Python dataclasses for every message and enum, extending Protoplasm6's `DataclassBase` |
28
+ | `foo_api.py` | Interface classes for every `service` with plain Python methods per RPC |
29
+ | `foo_grpc_receiver.py` | gRPC servicers that forward calls to your implementation of the interface |
30
+ | `foo_grpc_sender.py` | gRPC clients that implement the interface by calling a remote service |
31
+
32
+ ...along with `__init__.py` files everywhere, a root `__init__.py` with a
33
+ `__version__` (and the Protoplasm6 and Neobuilder6 versions used), a
34
+ `VERSION` file and an `__everything__.py` module that imports every module
35
+ (call `your_package.load_symbols()` to make sure the protobuf symbol database
36
+ knows every message, e.g. for `Any` unpacking).
37
+
38
+ The `__init__.py` of every directory that matches a proto package also
39
+ "alias imports" everything in that proto package, so e.g.
40
+ `from myshop.orders import *` gets you every message and enum declared with
41
+ `package myshop.orders;`, no matter which `.proto` file they're in (use
42
+ `--no-alias-imports` to skip this).
43
+
44
+ See the [Protoplasm6 README](https://github.com/doddi79/protoplasm6) for how
45
+ to use the generated code.
46
+
47
+ ## Installation
48
+
49
+ ```
50
+ pip install neobuilder6
51
+ ```
52
+
53
+ This installs Protoplasm6, `grpcio-tools` (which provides `protoc`) and creates
54
+ the `neobuild` command (and its alias `neobuild6`) in Python's `Scripts`/`bin`
55
+ folder. Neobuilder6 requires Python 3.10+.
56
+
57
+ ## Usage
58
+
59
+ Assuming you've got a package called `sandbox` and you're storing your
60
+ protobuf files in a directory called `proto` (i.e. `./proto/sandbox/**.proto`)
61
+ and you want to spit out the build into the directory `build` just go:
62
+
63
+ ```
64
+ neobuild sandbox
65
+ ```
66
+
67
+ The resulting `./build/sandbox` package depends on `protoplasm6` (with the
68
+ same major version and the same or later minor version as the Neobuilder6
69
+ used to build it) and on a `protobuf` runtime matching the `grpcio-tools` that
70
+ built it (the `*_pb2.py` files check this when imported).
71
+
72
+ You can also run it from Python:
73
+
74
+ ```python
75
+ from neobuilder6.neobuilder import NeoBuilder
76
+
77
+ NeoBuilder(package='sandbox', protopath='./proto', build_root='./build').build()
78
+ ```
79
+
80
+ ### Versioning your package
81
+
82
+ If you place a plain text file called `VERSION` in the root of your proto
83
+ package (e.g. `./proto/sandbox/VERSION` from the example above) and skip any
84
+ versioning parameters (`--major`/`-m` or `--patch`/`-p`) Neobuilder6 will use
85
+ that file for versioning.
86
+
87
+ The first line in the file should be the semantic version number (`x.y.z`,
88
+ and if there's a 4th part like in `x.y.z.a` it's ignored) and any following
89
+ lines are treated as a "commit message" that's written to the built package's
90
+ `VERSION` file.
91
+
92
+ Without a `VERSION` file, the version of the previous build (if found in the
93
+ build root) is bumped (minor by default) or `0.1.0` is used for a first build.
94
+
95
+ ### Full CLI usage
96
+
97
+ ```
98
+ usage: neobuild [-h] [-m | -p] [-b [BUILDROOT]] [-v] [-i | --pyi | --no-pyi]
99
+ [--alias-imports | --no-alias-imports] [-I INCLUDE]
100
+ package [protopath]
101
+
102
+ Builds neobuf packages with protoplasm6.
103
+
104
+ positional arguments:
105
+ package Package name
106
+ protopath Path to the root of the protobuf files (default="./proto")
107
+
108
+ options:
109
+ -h, --help show this help message and exit
110
+ -m, --major Bump the major version number instead of the minor
111
+ -p, --patch Bump the patch version number instead of the minor
112
+ -b, --buildroot [BUILDROOT]
113
+ Path to the root of the output build files (default="./build")
114
+ -v, --verbose Spits out DEBUG level logs
115
+ -i, --pyi, --no-pyi Builds *.pyi type stubs for the pb2 files as well (default=True, use --no-
116
+ pyi to skip)
117
+ --alias-imports, --no-alias-imports
118
+ Alias imports everything in each proto package in the __init__.py of the
119
+ corresponding Python package, e.g. so "from myshop.orders import *" works
120
+ (default=True, use --no-alias-imports to skip)
121
+ -I, --include INCLUDE
122
+ Optional additional proto paths to include (can be used multiple times)
123
+
124
+ Neobuilder6 v6.1.0 - Protoplasm6 v6.1.0
125
+ ```
126
+
127
+ ## Neobuilder6 & Protoplasm6 (the chicken and the egg)
128
+
129
+ The two packages depend on each other in a slightly odd way:
130
+
131
+ - **Neobuilder6 depends on Protoplasm6** at build time (it uses some of its
132
+ utilities, e.g. for type casting and method I/O types) and the code it
133
+ generates imports Protoplasm6 at runtime.
134
+ - **Protoplasm6 depends on Neobuilder6 only for its unit tests**, which use
135
+ Neobuilder6 to build the protos they test against. It's installed with
136
+ `--no-deps` there to avoid a circular install.
137
+
138
+ ### Versioning
139
+
140
+ The versioning of Neobuilder6 and Protoplasm6 (major and minor versions) go
141
+ hand in hand; i.e. when Protoplasm6's major or minor versions bump, a new
142
+ Neobuilder6 should also be released with the same major and minor version,
143
+ even if there's no actual code change needed in Neobuilder6 to support
144
+ whatever changed in Protoplasm6.
145
+
146
+ Neobuilder6 releases are NOT guaranteed to be backwards compatible with older
147
+ versions of Protoplasm6 and trying to run Neobuilder6 built code with a
148
+ Protoplasm6 release whose major and/or minor versions lag behind will more
149
+ often than not just break. A difference in the patch version should most
150
+ often be fine, as should using a Protoplasm6 release that's one or more minor
151
+ versions ahead of the Neobuilder6 used to build code.
152
+
153
+ In order to keep this synchronous development and release simple, Neobuilder6
154
+ should generally NOT depend on new features added to the Protoplasm6 release
155
+ with the same version, so that it can build code for its corresponding
156
+ Protoplasm6 version without having that latest version actually installed.
157
+
158
+ ### Releasing
159
+
160
+ 1. Release Protoplasm6 first (its unit tests need Neobuilder6, installed with
161
+ `--no-deps`, e.g. straight from its `main` branch or a sibling checkout)
162
+ 2. Then release Neobuilder6 (which can then pull the new Protoplasm6 from
163
+ PyPI)
164
+
165
+ See [CI/CD](#cicd) for how GitHub Actions handle this.
166
+
167
+ ## Development
168
+
169
+ With both repos checked out side by side:
170
+
171
+ ```
172
+ python -m venv .venv
173
+ .venv/Scripts/activate # or: source .venv/bin/activate
174
+ pip install -e ../protoplasm6
175
+ pip install -e .
176
+ python -m unittest discover -v -f ./tests
177
+ ```
178
+
179
+ ### CI/CD
180
+
181
+ GitHub Actions run the unit tests (on Python 3.10 to 3.14) for pushes to
182
+ `main` and for all pull requests, and publish to PyPI (after running the
183
+ tests again and checking that the release tag, e.g. `v6.1.0` or `6.1.0`,
184
+ matches `__version__`) whenever a GitHub release (or pre-release) is created.
185
+ Publishing needs a `PYPI_UPLOAD_TOKEN` repository secret.
186
+
187
+ Since the tests of each package need the other one, CI installs
188
+ Protoplasm6 from the branch with the **same name** in its repo if there is
189
+ one (so changes spanning both repos can be tested together, e.g. with a pull
190
+ request from the same branch name in both) or from `main` otherwise. When
191
+ publishing, Protoplasm6 comes from PyPI if a matching release is there
192
+ (otherwise from `main`).
193
+
194
+ When releasing both packages, release Protoplasm6 first, then Neobuilder6.
@@ -0,0 +1,5 @@
1
+ __version__ = '6.1.0'
2
+
3
+ __author__ = 'Thordur Matthiasson <doddi79@gmail.com>'
4
+ __license__ = 'MIT License'
5
+ __copyright__ = 'Copyright 2026 - Thordur Matthiasson, Copyright 2019-2024 - CCP Games ehf'
File without changes
@@ -0,0 +1,48 @@
1
+ import argparse
2
+
3
+ from neobuilder6.neobuilder import NeoBuilder
4
+
5
+
6
+ def main():
7
+ parser = argparse.ArgumentParser(prog='neobuild',
8
+ description='Builds neobuf packages with protoplasm6.',
9
+ epilog=(f'Neobuilder6 v{NeoBuilder.neobuilder_version()} - '
10
+ f'Protoplasm6 v{NeoBuilder.protoplasm_version()}'))
11
+ version_group = parser.add_mutually_exclusive_group()
12
+ version_group.add_argument('-m', '--major', action="store_true",
13
+ help='Bump the major version number instead of the minor')
14
+ version_group.add_argument('-p', '--patch', action="store_true",
15
+ help='Bump the patch version number instead of the minor')
16
+ parser.add_argument('package', help='Package name')
17
+ parser.add_argument('protopath', help='Path to the root of the protobuf files (default="./proto")',
18
+ default='./proto', nargs='?')
19
+ parser.add_argument('-b', '--buildroot', help='Path to the root of the output build files (default="./build")',
20
+ default='./build', nargs='?')
21
+ parser.add_argument('-v', '--verbose', action="store_true",
22
+ help='Spits out DEBUG level logs')
23
+ parser.add_argument('-i', '--pyi', action=argparse.BooleanOptionalAction, default=True,
24
+ help='Builds *.pyi type stubs for the pb2 files as well (default=True, use --no-pyi to skip)')
25
+ parser.add_argument('--alias-imports', action=argparse.BooleanOptionalAction, default=True,
26
+ help='Alias imports everything in each proto package in the __init__.py of the '
27
+ 'corresponding Python package, e.g. so "from myshop.orders import *" works '
28
+ '(default=True, use --no-alias-imports to skip)')
29
+ parser.add_argument('-I', '--include', action='append', help="Optional additional proto paths to include (can be used multiple times)", default=[])
30
+
31
+ args = parser.parse_args()
32
+
33
+ n = NeoBuilder(
34
+ package=args.package,
35
+ protopath=args.protopath,
36
+ build_root=args.buildroot,
37
+ major=args.major,
38
+ patch=args.patch,
39
+ verbose=args.verbose,
40
+ include_pyi=args.pyi,
41
+ extra_includes=args.include,
42
+ alias_imports=args.alias_imports,
43
+ )
44
+ n.build()
45
+
46
+
47
+ if __name__ == '__main__':
48
+ main()
@@ -0,0 +1,12 @@
1
+ {% from 'macros/indentclude.jinja2' import indentclude with context %}
2
+ @dataclasses.dataclass
3
+ class {{ class_name }}(bases.DataclassBase):
4
+ __proto_cls__ = pb2.{{ proto_cls_name }}
5
+
6
+ {{ indentclude('parts/_nested_messages.jinja2', 4) }}
7
+
8
+ {{ indentclude('parts/_enum_map.jinja2', 4) }}
9
+
10
+ {% for pf in field_map %}
11
+ {{ pf }}
12
+ {% endfor %}
@@ -0,0 +1,34 @@
1
+ # Auto-Generated file - DO NOT EDIT!
2
+ # Source module: {{ module_full_name }}
3
+ # Generated at: {{ iso_timestamp }}
4
+ from __future__ import annotations
5
+ __all__ = [
6
+ {% for a in all_list %}
7
+ '{{ a }}',
8
+ {% endfor %}
9
+ ]
10
+ import dataclasses
11
+ import datetime
12
+ import enum
13
+ import typing
14
+ from protoplasm6.casting import dictators
15
+ from protoplasm6 import plasm
16
+ {{ imports }}
17
+ {{ proto_import }}
18
+
19
+ import logging
20
+ log = logging.getLogger(__name__)
21
+
22
+
23
+ {% if enum_list %}
24
+ {% for enum in enum_list %}
25
+ {{ enum }}
26
+
27
+ {% endfor %}
28
+ {% endif %}
29
+ {% if message_list %}
30
+ {% for msg in message_list %}
31
+ {{ msg }}
32
+
33
+ {% endfor -%}
34
+ {%- endif -%}
@@ -0,0 +1,21 @@
1
+ # Auto-Generated file - DO NOT EDIT!
2
+ # Source module: {{ module_full_name }}
3
+ # Generated at: {{ iso_timestamp }}
4
+ __all__ = [
5
+ {% for a in all_list %}
6
+ '{{ a }}',
7
+ {% endfor %}
8
+ ]
9
+ import datetime
10
+ import typing
11
+ from protoplasm6 import plasm
12
+ {{ imports }}
13
+ if typing.TYPE_CHECKING:
14
+ from grpc import ServicerContext
15
+ {{ api_import }}
16
+
17
+ import logging
18
+ log = logging.getLogger(__name__)
19
+
20
+
21
+ {{ services }}
@@ -0,0 +1,21 @@
1
+ # Auto-Generated file - DO NOT EDIT!
2
+ # Source module: {{ module_full_name }}
3
+ # Generated at: {{ iso_timestamp }}
4
+ from __future__ import annotations
5
+ __all__ = [
6
+ {% for a in all_list %}
7
+ '{{ a }}',
8
+ {% endfor %}
9
+ ]
10
+ import datetime
11
+ import typing
12
+ from protoplasm6 import plasm
13
+ {{ imports }}
14
+ if typing.TYPE_CHECKING:
15
+ from grpc import ChannelCredentials
16
+
17
+ import logging
18
+ log = logging.getLogger(__name__)
19
+
20
+
21
+ {{ services }}
@@ -0,0 +1,22 @@
1
+ {% from 'macros/indentclude.jinja2' import indentclude with context %}
2
+ # Auto-Generated file - DO NOT EDIT!
3
+ # Source module: {{ module_full_name }}
4
+ # Generated at: {{ iso_timestamp }}
5
+ __all__ = [
6
+ {% for a in all_clause %}
7
+ '{{ a }}',
8
+ {% endfor %}
9
+ ]
10
+ import datetime
11
+ import typing
12
+ from protoplasm6 import plasm
13
+
14
+ {% for import_line in import_lines %}
15
+ {{ import_line }}
16
+ {% endfor %}
17
+
18
+ import logging
19
+ log = logging.getLogger(__name__)
20
+
21
+
22
+ {{ services }}
@@ -0,0 +1,2 @@
1
+ {%- macro _inc(file_name, this) -%}{% include file_name with context %}{% endmacro %}
2
+ {%- macro indentclude(file_name, spaces=4, this={}) -%}{{ _inc(file_name, this)|indent(spaces) }}{%- endmacro -%}
@@ -0,0 +1,10 @@
1
+ # Auto-Generated file - DO NOT EDIT!
2
+ # Proto package alias imports, i.e. everything in the `{{ proto_package }}` proto package
3
+ __all__ = [
4
+ {% for name in names %}
5
+ '{{ name }}',
6
+ {% endfor %}
7
+ ]
8
+ {% for module in modules %}
9
+ from {{ module }} import *
10
+ {% endfor %}
@@ -0,0 +1 @@
1
+ # ENUMS GO HERE...
@@ -0,0 +1,2 @@
1
+ def {{ this.method_under_name }}(self{{ this.input_params }}) -> {{ this.return_type_hint }}:
2
+ raise plasm.Unimplemented()
@@ -0,0 +1,10 @@
1
+ {% from 'macros/indentclude.jinja2' import indentclude with context %}
2
+ class {{ service_name }}Interface:
3
+ {% if is_grpc %}
4
+ __servicer_cls__ = {{ service_name }}GrpcServicer
5
+
6
+ {% endif %}
7
+ {% for method in method_list %}
8
+ {{ indentclude('parts/_interface_method.jinja2', (indent_spaces + 4), method) }}
9
+
10
+ {% endfor %}
@@ -0,0 +1 @@
1
+ # NESTED MESSAGES GO HERE...
@@ -0,0 +1,12 @@
1
+ __version__ = '{{ version }}'{% if version == '' %} # NO VERSION NUMBERS FOUND?!? :({% endif +%}
2
+ __protoplasm_version__ = '{{ protoplasm_version }}'
3
+ __neobuilder_version__ = '{{ neobuilder_version }}'
4
+
5
+
6
+ def load_symbols():
7
+ from {{ package_name }} import __everything__{% if alias_init %}
8
+
9
+
10
+
11
+ {{ alias_init }}
12
+ {%- endif %}