pystructtype 0.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.
@@ -0,0 +1,64 @@
1
+ name: build
2
+ on: [push]
3
+
4
+ jobs:
5
+ test:
6
+ runs-on: ubuntu-latest
7
+ steps:
8
+ - name: Check out repo
9
+ uses: actions/checkout@v4
10
+
11
+ - name: Set up uv
12
+ uses: astral-sh/setup-uv@v5
13
+
14
+ - name: Set up Python
15
+ uses: actions/setup-python@v5
16
+ with:
17
+ python-version: 3.13
18
+
19
+ - name: Run Tests
20
+ run: |
21
+ uv sync
22
+ uv tool install tox
23
+ tox -e py313
24
+ check:
25
+ runs-on: ubuntu-latest
26
+ steps:
27
+ - name: Check out repo
28
+ uses: actions/checkout@v4
29
+
30
+ - name: Set up uv
31
+ uses: astral-sh/setup-uv@v5
32
+
33
+ - name: Set up Python
34
+ uses: actions/setup-python@v5
35
+ with:
36
+ python-version: 3.13
37
+
38
+ - name: Check Formatting
39
+ run: |
40
+ uv sync
41
+ uv tool install tox
42
+ tox -e check
43
+
44
+ type:
45
+ runs-on: ubuntu-latest
46
+ steps:
47
+ - name: Check out repo
48
+ uses: actions/checkout@v4
49
+
50
+ - name: Set up uv
51
+ uses: astral-sh/setup-uv@v5
52
+
53
+ - name: Set up Python
54
+ uses: actions/setup-python@v5
55
+ with:
56
+ python-version: 3.13
57
+
58
+ - name: Check Formatting
59
+ run: |
60
+ uv sync
61
+ uv tool install tox
62
+ tox -e type
63
+
64
+ # TODO: Add coverage, docs
@@ -0,0 +1,28 @@
1
+ name: Release
2
+ on:
3
+ push:
4
+ tags:
5
+ - "*"
6
+
7
+ jobs:
8
+ release:
9
+ runs-on: ubuntu-latest
10
+ environment: release
11
+ permissions:
12
+ id-token: write
13
+ steps:
14
+ - name: Checkout code
15
+ uses: actions/checkout@v4
16
+
17
+ - name: Set up uv
18
+ uses: astral-sh/setup-uv@v5
19
+
20
+ - name: Set up Python
21
+ uses: actions/setup-python@v5
22
+ with:
23
+ python-version: 3.13
24
+
25
+ - name: Release
26
+ run: |
27
+ uv build
28
+ uv publish --publish-url https://upload.pypi.org/legacy/ --trusted-publishing always
@@ -0,0 +1,16 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # Coverage
13
+ .coverage.*
14
+
15
+ # PyCharm
16
+ .idea*
@@ -0,0 +1 @@
1
+ 3.13.2
@@ -0,0 +1,14 @@
1
+ version: 2
2
+
3
+ build:
4
+ os: ubuntu-lts-latest
5
+ tools:
6
+ python: "3.13"
7
+ jobs:
8
+ post_install:
9
+ - pip install uv
10
+ - UV_PROJECT_ENVIRONMENT=$READTHEDOCS_VIRTUALENV_PATH uv sync --all-extras --link-mode=copy
11
+
12
+ sphinx:
13
+ configuration: docs/conf.py
14
+ fail_on_warning: true
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Fernando Chorney
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,276 @@
1
+ Metadata-Version: 2.4
2
+ Name: pystructtype
3
+ Version: 0.1.0
4
+ Summary: Leverage Python Types to Define C-Struct Interfaces
5
+ Project-URL: Homepage, https://github.com/fchorney/pystructtype
6
+ Project-URL: Documentation, https://pystructtype.readthedocs.io/en/latest/
7
+ Project-URL: Repository, https://github.com/fchorney/pystructtype
8
+ Project-URL: Issues, https://github.com/fchorney/pystructtype/issues
9
+ Author-email: fchorney <github@djsbx.com>
10
+ License-Expression: MIT
11
+ License-File: LICENSE.txt
12
+ Keywords: cstruct,struct,type
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Natural Language :: English
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Utilities
20
+ Requires-Python: >=3.13
21
+ Requires-Dist: loguru>=0.7.3
22
+ Description-Content-Type: text/markdown
23
+
24
+ # PyStructTypes
25
+
26
+ Leverage Python Types to Define C-Struct Interfaces
27
+
28
+
29
+ # Reasoning
30
+
31
+ I made this project for 2 reasons:
32
+ 1. I wanted to see if I could leverage the typing system to effectively automatically
33
+ decode and encode c-type structs in python.
34
+ 2. Build a tool to do this for a separate project I am working on.
35
+
36
+ I am aware of other very similar c-type struct to python class libraries available,
37
+ but I wanted to try something new so here we are.
38
+
39
+ This may or may not end up being super useful, as there are quite a few bits of
40
+ hacky metaprogramming to get the type system to play nicely for what I want, but
41
+ perhaps over time it can be cleaned up and made more useful.
42
+
43
+ # StructDataclass
44
+
45
+ The `StructDataclass` class is based off of the `Dataclass` class, and thus
46
+ is used in a similar fashion.
47
+
48
+ # Basic Structs
49
+
50
+ Basic structs can mostly be copied over 1:1
51
+
52
+ ```c
53
+ struct MyStruct {
54
+ int16_t myNum;
55
+ char myLetter;
56
+ };
57
+ ```
58
+
59
+ ```python
60
+ @struct_dataclass
61
+ class MyStruct(StructDataclass):
62
+ myNum: int16_t
63
+ myLetter: char_t
64
+
65
+ s = MyStruct()
66
+ s.decode([4, 2, 65])
67
+ # MyStruct(myNum=1026, myLetter=b"A")
68
+ s.decode([4, 2, 65], little_endian=True)
69
+ # MyStruct(myNum=516, myLetter=b"A")
70
+ ```
71
+
72
+ For arrays of basic elements, you need to Annotate them with
73
+ the `TypeMeta` object, and set their type to `list[_type_]`.
74
+
75
+ ```c
76
+ struct MyStruct {
77
+ uint8_t myInts[4];
78
+ uint16_t myBiggerInts[2];
79
+ };
80
+ ```
81
+ ```python
82
+ @struct_dataclass
83
+ class MyStruct(StructDataclass):
84
+ myInts: Annotated[list[uint8_t], TypeMeta(size=4)]
85
+ myBiggerInts: Annotated[list[uint16_t], TypeMeta(size=2)]
86
+
87
+ s = MyStruct()
88
+ s.decode([0, 64, 128, 255, 16, 0, 255, 255])
89
+ # MyStruct(myInts=[0, 64, 128, 255], myBiggerInts=[4096, 65535])
90
+ ```
91
+
92
+ You can also set defaults for both basic types and lists.
93
+
94
+ All values will default to 0 or the initialized value for the chosen class if no
95
+ specific value is set.
96
+
97
+ List defaults will set all items in the list to the same value. Currently
98
+ setting a complete default list for all values is not implemented.
99
+
100
+ ```c
101
+ struct MyStruct P
102
+ uint8_t myInt = 5;
103
+ uint8_t myInts[2];
104
+ ```
105
+
106
+ ```python
107
+ @struct_dataclass
108
+ class MyStruct(StructDataclass):
109
+ myInt: uint8_t = 5
110
+ myInts: Annnotated[list[uint8_t], TypeMeta(size=2, default=1)]
111
+
112
+ s = MyStruct()
113
+ # MyStruct(myInt=5, myInts=[1, 1])
114
+ s.decode([10, 5, 6])
115
+ # MyStruct(myInt=10, myInts=[5, 6])
116
+ ```
117
+
118
+ # The Bits Abstraction
119
+
120
+ This library includes a `bits` abstraction to map bits to variables for easier access.
121
+
122
+ One example of this is converting a C enum like so:
123
+
124
+ ```c
125
+ enum ConfigFlags {
126
+ lights_flag = 1 << 0,
127
+ platform_flag = 1 << 1,
128
+ };
129
+ #pragma pack(push, 1)
130
+ ```
131
+
132
+ ```python
133
+ @bits(uint8_t, {"lights_flag": 0, "platform_flag": 1})
134
+ class FlagsType(BitsType): ...
135
+
136
+ f = FlagsType()
137
+ f.decode([3])
138
+ # FlagsType(lights_flag=True, platform_flag=True)
139
+ f.decode([2])
140
+ # FlagsType(lights_flag=False, platform_flag=True)
141
+ f.decode([1])
142
+ # FlagsType(lights_flag=True, platform_flag=False)
143
+ ```
144
+
145
+ # Custom StructDataclass Processing and Extensions
146
+
147
+ There may be times when you want to make the python class do
148
+ cool fun python class type of stuff with the data structure.
149
+ We can extend the class functions `_decode` and `_encode` to
150
+ handle this processing.
151
+
152
+ In this example, lets say you want to be able to read/write the
153
+ class object as a list, using `__getitem__` and `__setitem__` as well
154
+ as keeping the data in a different data structure than what the
155
+ c struct defines.
156
+
157
+ ```c
158
+ struct MyStruct {
159
+ uint8_t enabledSensors[5];
160
+ };
161
+ ```
162
+
163
+ ```python
164
+ @struct_dataclass
165
+ class EnabledSensors(StructDataclass):
166
+ # We can define the actual data we are ingesting here
167
+ # This mirrors the `uint8_t enabledSensors[5]` data
168
+ _raw: Annotated[list[uint8_t], TypeMeta(size=5)]
169
+
170
+ # We use this to store the data in the way we actually want
171
+ _data: list[list[bool]] = field(default_factory=list)
172
+
173
+ def _decode(self, data: list[int]) -> None:
174
+ # First call the super function. This will store the raw values into `_raw`
175
+ super()._decode(data)
176
+
177
+ # Erase everything in self._data to remove any old data
178
+ self._data = []
179
+
180
+ # 2 Panels are packed into a single uint8_t, the left most 4 bits for the first
181
+ # and the right most 4 bits for the second
182
+ for bitlist in (list(map(bool, map(int, format(_byte, "#010b")[2:]))) for _byte in self._raw):
183
+ self._data.append(bitlist[0:4])
184
+ self._data.append(bitlist[4:])
185
+
186
+ # Remove the last item in self._data as there are only 9 panels
187
+ del self._data[-1]
188
+
189
+ def _encode(self) -> list[int]:
190
+ # Modify self._raw with updated values from self._data
191
+ for idx, items in enumerate(list_chunks(self._data, 2)):
192
+ # Last chunk
193
+ if len(items) == 1:
194
+ items.append([False, False, False, False])
195
+ self._raw[idx] = sum(v << i for i, v in enumerate(list(itertools.chain.from_iterable(items))[::-1]))
196
+
197
+ # Run the super function to return the encoded data from self._raw()
198
+ return super()._encode()
199
+
200
+ def __getitem__(self, index: int) -> list[bool]:
201
+ # This lets us access the data with square brackets
202
+ # ex. `config.enabled_sensors[Panel.UP][Sensor.RIGHT]`
203
+ return self._data[index]
204
+
205
+ def __setitem__(self, index: int, value: list[bool]) -> None:
206
+ # Only use this to set a complete set for a panel
207
+ # ex. `config.enabled_sensors[Panel.UP] = [True, True, False, True]`
208
+ if len(value) != 4 or not all(isinstance(x, bool) for x in value):
209
+ raise Exception("must set all 4 items at once")
210
+
211
+ s = EnabledSensors()
212
+ s.decode([15, 15, 15, 15, 0])
213
+
214
+ # The `self._data` here would look like:
215
+ # [
216
+ # [False, False, False, False],
217
+ # [True, True, True, True],
218
+ # [False, False, False, False],
219
+ # [True, True, True, True],
220
+ # [False, False, False, False],
221
+ # [True, True, True, True],
222
+ # [False, False, False, False],
223
+ # [True, True, True, True],
224
+ # [False, False, False, False],
225
+ # [False, False, False, False]
226
+ # ]
227
+
228
+ # With the get/set functioned defined, we can access the data
229
+ # with square accessors.
230
+ # s[1][2] == True
231
+ ```
232
+
233
+ # StructDataclass is Composable
234
+
235
+ You can use StructDataclasses in other StructDataclasses to create more complex
236
+ structs.
237
+
238
+ ```c
239
+ struct RGB {
240
+ uint8_t r;
241
+ uint8_t g;
242
+ uint8_t b;
243
+ };
244
+
245
+ struct LEDS {
246
+ RGB lights[3];
247
+ };
248
+ ```
249
+
250
+ ```python
251
+ @struct_dataclass
252
+ class RGB(StructDataclass):
253
+ r: uint8_t
254
+ g: uint8_t
255
+ b: uint8_t
256
+
257
+ @struct_dataclass
258
+ class LEDS(StructDataclass):
259
+ lights: Annotated[list[RGB], TypeMeta(size=3])]
260
+
261
+ l = LEDS()
262
+ l.decode([1, 2, 3, 4, 5, 6, 7, 8, 9])
263
+ # LEDS(lights=[RGB(r=1, g=2, b=3), RGB(r=4, g=5, b=6), RGB(r=7, g=8, b=9)])
264
+ ```
265
+
266
+ # Future Updates
267
+
268
+ - Bitfield: Similar to the `Bits` abstraction. An easy way to define bitfields
269
+ - C-Strings: Make a base class to handle C strings (arrays of chars)
270
+ - Potentially more ways to define bits (dicts/lists/etc).
271
+ - Potentially allowing list defaults to be entire pre-defined lists.
272
+ - ???
273
+
274
+ # Examples
275
+
276
+ You can see a more fully fledged example in the `test/examples.py` file.
@@ -0,0 +1,253 @@
1
+ # PyStructTypes
2
+
3
+ Leverage Python Types to Define C-Struct Interfaces
4
+
5
+
6
+ # Reasoning
7
+
8
+ I made this project for 2 reasons:
9
+ 1. I wanted to see if I could leverage the typing system to effectively automatically
10
+ decode and encode c-type structs in python.
11
+ 2. Build a tool to do this for a separate project I am working on.
12
+
13
+ I am aware of other very similar c-type struct to python class libraries available,
14
+ but I wanted to try something new so here we are.
15
+
16
+ This may or may not end up being super useful, as there are quite a few bits of
17
+ hacky metaprogramming to get the type system to play nicely for what I want, but
18
+ perhaps over time it can be cleaned up and made more useful.
19
+
20
+ # StructDataclass
21
+
22
+ The `StructDataclass` class is based off of the `Dataclass` class, and thus
23
+ is used in a similar fashion.
24
+
25
+ # Basic Structs
26
+
27
+ Basic structs can mostly be copied over 1:1
28
+
29
+ ```c
30
+ struct MyStruct {
31
+ int16_t myNum;
32
+ char myLetter;
33
+ };
34
+ ```
35
+
36
+ ```python
37
+ @struct_dataclass
38
+ class MyStruct(StructDataclass):
39
+ myNum: int16_t
40
+ myLetter: char_t
41
+
42
+ s = MyStruct()
43
+ s.decode([4, 2, 65])
44
+ # MyStruct(myNum=1026, myLetter=b"A")
45
+ s.decode([4, 2, 65], little_endian=True)
46
+ # MyStruct(myNum=516, myLetter=b"A")
47
+ ```
48
+
49
+ For arrays of basic elements, you need to Annotate them with
50
+ the `TypeMeta` object, and set their type to `list[_type_]`.
51
+
52
+ ```c
53
+ struct MyStruct {
54
+ uint8_t myInts[4];
55
+ uint16_t myBiggerInts[2];
56
+ };
57
+ ```
58
+ ```python
59
+ @struct_dataclass
60
+ class MyStruct(StructDataclass):
61
+ myInts: Annotated[list[uint8_t], TypeMeta(size=4)]
62
+ myBiggerInts: Annotated[list[uint16_t], TypeMeta(size=2)]
63
+
64
+ s = MyStruct()
65
+ s.decode([0, 64, 128, 255, 16, 0, 255, 255])
66
+ # MyStruct(myInts=[0, 64, 128, 255], myBiggerInts=[4096, 65535])
67
+ ```
68
+
69
+ You can also set defaults for both basic types and lists.
70
+
71
+ All values will default to 0 or the initialized value for the chosen class if no
72
+ specific value is set.
73
+
74
+ List defaults will set all items in the list to the same value. Currently
75
+ setting a complete default list for all values is not implemented.
76
+
77
+ ```c
78
+ struct MyStruct P
79
+ uint8_t myInt = 5;
80
+ uint8_t myInts[2];
81
+ ```
82
+
83
+ ```python
84
+ @struct_dataclass
85
+ class MyStruct(StructDataclass):
86
+ myInt: uint8_t = 5
87
+ myInts: Annnotated[list[uint8_t], TypeMeta(size=2, default=1)]
88
+
89
+ s = MyStruct()
90
+ # MyStruct(myInt=5, myInts=[1, 1])
91
+ s.decode([10, 5, 6])
92
+ # MyStruct(myInt=10, myInts=[5, 6])
93
+ ```
94
+
95
+ # The Bits Abstraction
96
+
97
+ This library includes a `bits` abstraction to map bits to variables for easier access.
98
+
99
+ One example of this is converting a C enum like so:
100
+
101
+ ```c
102
+ enum ConfigFlags {
103
+ lights_flag = 1 << 0,
104
+ platform_flag = 1 << 1,
105
+ };
106
+ #pragma pack(push, 1)
107
+ ```
108
+
109
+ ```python
110
+ @bits(uint8_t, {"lights_flag": 0, "platform_flag": 1})
111
+ class FlagsType(BitsType): ...
112
+
113
+ f = FlagsType()
114
+ f.decode([3])
115
+ # FlagsType(lights_flag=True, platform_flag=True)
116
+ f.decode([2])
117
+ # FlagsType(lights_flag=False, platform_flag=True)
118
+ f.decode([1])
119
+ # FlagsType(lights_flag=True, platform_flag=False)
120
+ ```
121
+
122
+ # Custom StructDataclass Processing and Extensions
123
+
124
+ There may be times when you want to make the python class do
125
+ cool fun python class type of stuff with the data structure.
126
+ We can extend the class functions `_decode` and `_encode` to
127
+ handle this processing.
128
+
129
+ In this example, lets say you want to be able to read/write the
130
+ class object as a list, using `__getitem__` and `__setitem__` as well
131
+ as keeping the data in a different data structure than what the
132
+ c struct defines.
133
+
134
+ ```c
135
+ struct MyStruct {
136
+ uint8_t enabledSensors[5];
137
+ };
138
+ ```
139
+
140
+ ```python
141
+ @struct_dataclass
142
+ class EnabledSensors(StructDataclass):
143
+ # We can define the actual data we are ingesting here
144
+ # This mirrors the `uint8_t enabledSensors[5]` data
145
+ _raw: Annotated[list[uint8_t], TypeMeta(size=5)]
146
+
147
+ # We use this to store the data in the way we actually want
148
+ _data: list[list[bool]] = field(default_factory=list)
149
+
150
+ def _decode(self, data: list[int]) -> None:
151
+ # First call the super function. This will store the raw values into `_raw`
152
+ super()._decode(data)
153
+
154
+ # Erase everything in self._data to remove any old data
155
+ self._data = []
156
+
157
+ # 2 Panels are packed into a single uint8_t, the left most 4 bits for the first
158
+ # and the right most 4 bits for the second
159
+ for bitlist in (list(map(bool, map(int, format(_byte, "#010b")[2:]))) for _byte in self._raw):
160
+ self._data.append(bitlist[0:4])
161
+ self._data.append(bitlist[4:])
162
+
163
+ # Remove the last item in self._data as there are only 9 panels
164
+ del self._data[-1]
165
+
166
+ def _encode(self) -> list[int]:
167
+ # Modify self._raw with updated values from self._data
168
+ for idx, items in enumerate(list_chunks(self._data, 2)):
169
+ # Last chunk
170
+ if len(items) == 1:
171
+ items.append([False, False, False, False])
172
+ self._raw[idx] = sum(v << i for i, v in enumerate(list(itertools.chain.from_iterable(items))[::-1]))
173
+
174
+ # Run the super function to return the encoded data from self._raw()
175
+ return super()._encode()
176
+
177
+ def __getitem__(self, index: int) -> list[bool]:
178
+ # This lets us access the data with square brackets
179
+ # ex. `config.enabled_sensors[Panel.UP][Sensor.RIGHT]`
180
+ return self._data[index]
181
+
182
+ def __setitem__(self, index: int, value: list[bool]) -> None:
183
+ # Only use this to set a complete set for a panel
184
+ # ex. `config.enabled_sensors[Panel.UP] = [True, True, False, True]`
185
+ if len(value) != 4 or not all(isinstance(x, bool) for x in value):
186
+ raise Exception("must set all 4 items at once")
187
+
188
+ s = EnabledSensors()
189
+ s.decode([15, 15, 15, 15, 0])
190
+
191
+ # The `self._data` here would look like:
192
+ # [
193
+ # [False, False, False, False],
194
+ # [True, True, True, True],
195
+ # [False, False, False, False],
196
+ # [True, True, True, True],
197
+ # [False, False, False, False],
198
+ # [True, True, True, True],
199
+ # [False, False, False, False],
200
+ # [True, True, True, True],
201
+ # [False, False, False, False],
202
+ # [False, False, False, False]
203
+ # ]
204
+
205
+ # With the get/set functioned defined, we can access the data
206
+ # with square accessors.
207
+ # s[1][2] == True
208
+ ```
209
+
210
+ # StructDataclass is Composable
211
+
212
+ You can use StructDataclasses in other StructDataclasses to create more complex
213
+ structs.
214
+
215
+ ```c
216
+ struct RGB {
217
+ uint8_t r;
218
+ uint8_t g;
219
+ uint8_t b;
220
+ };
221
+
222
+ struct LEDS {
223
+ RGB lights[3];
224
+ };
225
+ ```
226
+
227
+ ```python
228
+ @struct_dataclass
229
+ class RGB(StructDataclass):
230
+ r: uint8_t
231
+ g: uint8_t
232
+ b: uint8_t
233
+
234
+ @struct_dataclass
235
+ class LEDS(StructDataclass):
236
+ lights: Annotated[list[RGB], TypeMeta(size=3])]
237
+
238
+ l = LEDS()
239
+ l.decode([1, 2, 3, 4, 5, 6, 7, 8, 9])
240
+ # LEDS(lights=[RGB(r=1, g=2, b=3), RGB(r=4, g=5, b=6), RGB(r=7, g=8, b=9)])
241
+ ```
242
+
243
+ # Future Updates
244
+
245
+ - Bitfield: Similar to the `Bits` abstraction. An easy way to define bitfields
246
+ - C-Strings: Make a base class to handle C strings (arrays of chars)
247
+ - Potentially more ways to define bits (dicts/lists/etc).
248
+ - Potentially allowing list defaults to be entire pre-defined lists.
249
+ - ???
250
+
251
+ # Examples
252
+
253
+ You can see a more fully fledged example in the `test/examples.py` file.
@@ -0,0 +1,28 @@
1
+ {{obj.name}}
2
+ {{obj.name|length * "="}}
3
+
4
+ .. automodule:: {{obj.name}}{%- block subpackages %}
5
+ {%- if obj.subpackages %}
6
+
7
+ Subpackages
8
+ -----------
9
+
10
+ .. toctree::
11
+ :titlesonly:
12
+ :maxdepth: 1
13
+ {% for subpackage in obj.subpackages %}
14
+ {% if subpackage.display %}{{ subpackage.short_name }}/index.rst{% endif -%}
15
+ {%- endfor %}
16
+ {%- endif %}{%- endblock -%}{%- block submodules %}
17
+ {%- if obj.submodules %}
18
+
19
+ Submodules
20
+ ----------
21
+
22
+ .. toctree::
23
+ :titlesonly:
24
+ :maxdepth: 1
25
+ {% for submodule in obj.submodules %}
26
+ {% if submodule.display %}{{ submodule.short_name }}/index.rst{% endif -%}
27
+ {%- endfor %}
28
+ {%- endif %}{%- endblock -%}
@@ -0,0 +1 @@
1
+ {% extends "python/module.rst" %}