Skip to content

Commit 4c25511

Browse files
authored
Merge pull request #186 from jdkandersson/enhancement/185-package-build
Enhancement/185 package build
2 parents ac4327b + 283abee commit 4c25511

File tree

101 files changed

+7281
-2780
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

101 files changed

+7281
-2780
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,13 @@
99
*.pyc
1010
*.pyo
1111
build/
12+
!open_alchemy/build/
13+
!tests/open_alchemy/build/
1214
dist/
15+
!examples/**/dist/
16+
examples/**/dist/dist
1317
htmlcov/
1418
venv
19+
venv36
1520
coverage.xml
1621
docs/source/_*

.pre-commit-config.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ repos:
44
hooks:
55
- id: black
66
language_version: python3.7
7+
exclude: "models_auto.py$|models_autogenerated.py$"
78
- repo: https://github.com/pre-commit/mirrors-isort
89
rev: v5.4.2
910
hooks:
@@ -35,3 +36,8 @@ repos:
3536
hooks:
3637
- exclude: "^docs.*.yaml$"
3738
id: prettier
39+
- repo: https://github.com/codespell-project/codespell
40+
rev: v1.17.1
41+
hooks:
42+
- id: codespell
43+
args: [-L connexion]

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Release Notes
22

3+
## Version _next_
4+
5+
- Refactor the models file generation to use the artifacts from the schemas.
6+
- Add `build_json` and `build_yaml` interfaces which can be used to produce a package with the models.
7+
38
## Version 1.5.4 - 2020-08-30
49

510
- Move `description` to be a top level property artifact for every property.

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ An example API has been defined using connexion and Flask here:
115115

116116
- initializing from JSON,
117117
- initializing from YAML,
118+
- build a package with the models for distribution,
118119
- automatically generate a models file,
119120
- `integer` (32 and 64 bit),
120121
- `number` (float only),

docs/source/index.rst

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ friendly.
5252
:samp:`init_yaml`
5353
^^^^^^^^^^^^^^^^^
5454

55+
Used to initialize the SQLAlchemy models based on a YAML OpenAPI specification
56+
which has been extended with any relevant OpenAlchemy extension properties.
57+
5558
The :samp:`init_yaml` interface requires the :samp:`PyYAML` library to be
5659
installed. The :samp:`init_yaml` interface accepts the following arguments:
5760

@@ -113,6 +116,36 @@ does not construct a declarative base. It accepts the following parameters:
113116
The return value is the :samp:`model_factory` as defined as part of the return
114117
value of :ref:`init-yaml`.
115118

119+
.. _build-yaml:
120+
121+
:samp:`build_yaml`
122+
^^^^^^^^^^^^^^^^^^
123+
124+
Used to build a package with the SQLAlchemy models (including type hints) based
125+
on a YAML OpenAPI specification which has been extended with any relevant
126+
OpenAlchemy extension properties.
127+
128+
The :samp:`build_yaml` interface requires the :samp:`PyYAML` library to be
129+
installed. The :samp:`build_yaml` interface accepts the following arguments:
130+
131+
* :samp:`spec_filename`: The name of the OpenAPI specification file. The file
132+
must by a YAML file.
133+
* :samp:`package_name`: The name of the package to be produced. This will be
134+
135+
1. the name of the package if it is uploaded to a package index and
136+
2. the name that is used to import the models after they have been installed).
137+
138+
* :samp:`dist_path`: The directory to output the package files.
139+
140+
.. _build-json:
141+
142+
:samp:`build_json`
143+
^^^^^^^^^^^^^^^^^^
144+
145+
The :samp:`build_json` interface is similar to the :ref:`build-yaml` interface
146+
except that :samp:`spec_filename` must be a JSON file and :samp:`PyYAML` is not
147+
a required dependency.
148+
116149
.. _models-file:
117150

118151
Models File

examples/all_of/column_models_auto.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
from open_alchemy import models
1010

11+
Base = models.Base # type: ignore
12+
1113

1214
class EmployeeDict(typing.TypedDict, total=False):
1315
"""TypedDict for properties that are not required."""

examples/all_of/model_models_auto.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
from open_alchemy import models
1010

11+
Base = models.Base # type: ignore
12+
1113

1214
class DivisionDict(typing.TypedDict, total=False):
1315
"""TypedDict for properties that are not required."""
@@ -105,9 +107,9 @@ def to_str(self) -> str:
105107
class EmployeeDict(typing.TypedDict, total=False):
106108
"""TypedDict for properties that are not required."""
107109

110+
salary: typing.Optional[float]
108111
id: typing.Optional[int]
109112
name: typing.Optional[str]
110-
salary: typing.Optional[float]
111113

112114

113115
class TEmployee(typing.Protocol):
@@ -117,9 +119,9 @@ class TEmployee(typing.Protocol):
117119
Person that works for a company.
118120
119121
Attrs:
122+
salary: The amount of money the employee is paid.
120123
id: Unique identifier for the object.
121124
name: The name of the object.
122-
salary: The amount of money the employee is paid.
123125
124126
"""
125127

@@ -129,41 +131,41 @@ class TEmployee(typing.Protocol):
129131
query: orm.Query
130132

131133
# Model properties
134+
salary: "sqlalchemy.Column[typing.Optional[float]]"
132135
id: "sqlalchemy.Column[typing.Optional[int]]"
133136
name: "sqlalchemy.Column[typing.Optional[str]]"
134-
salary: "sqlalchemy.Column[typing.Optional[float]]"
135137

136138
def __init__(
137139
self,
140+
salary: typing.Optional[float] = None,
138141
id: typing.Optional[int] = None,
139142
name: typing.Optional[str] = None,
140-
salary: typing.Optional[float] = None,
141143
) -> None:
142144
"""
143145
Construct.
144146
145147
Args:
148+
salary: The amount of money the employee is paid.
146149
id: Unique identifier for the object.
147150
name: The name of the object.
148-
salary: The amount of money the employee is paid.
149151
150152
"""
151153
...
152154

153155
@classmethod
154156
def from_dict(
155157
cls,
158+
salary: typing.Optional[float] = None,
156159
id: typing.Optional[int] = None,
157160
name: typing.Optional[str] = None,
158-
salary: typing.Optional[float] = None,
159161
) -> "TEmployee":
160162
"""
161163
Construct from a dictionary (eg. a POST payload).
162164
163165
Args:
166+
salary: The amount of money the employee is paid.
164167
id: Unique identifier for the object.
165168
name: The name of the object.
166-
salary: The amount of money the employee is paid.
167169
168170
Returns:
169171
Model instance based on the dictionary.

examples/app/models_autogenerated.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
from open_alchemy import models
1010

11+
Base = models.Base # type: ignore
12+
1113

1214
class _EmployeeDictBase(typing.TypedDict, total=True):
1315
"""TypedDict for properties that are required."""

examples/composite_index/models_auto.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
from open_alchemy import models
1010

11+
Base = models.Base # type: ignore
12+
1113

1214
class EmployeeDict(typing.TypedDict, total=False):
1315
"""TypedDict for properties that are not required."""

examples/composite_unique/models_auto.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
from open_alchemy import models
1010

11+
Base = models.Base # type: ignore
12+
1113

1214
class EmployeeDict(typing.TypedDict, total=False):
1315
"""TypedDict for properties that are not required."""

examples/default/models_auto.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
from open_alchemy import models
1010

11+
Base = models.Base # type: ignore
12+
1113

1214
class EmployeeDict(typing.TypedDict, total=False):
1315
"""TypedDict for properties that are not required."""

examples/inheritance/joined_models_auto.py

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
from open_alchemy import models
1010

11+
Base = models.Base # type: ignore
12+
1113

1214
class EmployeeDict(typing.TypedDict, total=False):
1315
"""TypedDict for properties that are not required."""
@@ -117,9 +119,9 @@ class ManagerDict(typing.TypedDict, total=False):
117119
"""TypedDict for properties that are not required."""
118120

119121
id: typing.Optional[int]
122+
manager_data: typing.Optional[str]
120123
name: typing.Optional[str]
121124
type: typing.Optional[str]
122-
manager_data: typing.Optional[str]
123125

124126

125127
class TManager(typing.Protocol):
@@ -130,9 +132,9 @@ class TManager(typing.Protocol):
130132
131133
Attrs:
132134
id: Unique identifier for the manager.
135+
manager_data: Data for the manager.
133136
name: The name of the employee.
134137
type: The type of the employee.
135-
manager_data: Data for the manager.
136138
137139
"""
138140

@@ -143,25 +145,25 @@ class TManager(typing.Protocol):
143145

144146
# Model properties
145147
id: "sqlalchemy.Column[typing.Optional[int]]"
148+
manager_data: "sqlalchemy.Column[typing.Optional[str]]"
146149
name: "sqlalchemy.Column[typing.Optional[str]]"
147150
type: "sqlalchemy.Column[typing.Optional[str]]"
148-
manager_data: "sqlalchemy.Column[typing.Optional[str]]"
149151

150152
def __init__(
151153
self,
152154
id: typing.Optional[int] = None,
155+
manager_data: typing.Optional[str] = None,
153156
name: typing.Optional[str] = None,
154157
type: typing.Optional[str] = None,
155-
manager_data: typing.Optional[str] = None,
156158
) -> None:
157159
"""
158160
Construct.
159161
160162
Args:
161163
id: Unique identifier for the manager.
164+
manager_data: Data for the manager.
162165
name: The name of the employee.
163166
type: The type of the employee.
164-
manager_data: Data for the manager.
165167
166168
"""
167169
...
@@ -170,18 +172,18 @@ def __init__(
170172
def from_dict(
171173
cls,
172174
id: typing.Optional[int] = None,
175+
manager_data: typing.Optional[str] = None,
173176
name: typing.Optional[str] = None,
174177
type: typing.Optional[str] = None,
175-
manager_data: typing.Optional[str] = None,
176178
) -> "TManager":
177179
"""
178180
Construct from a dictionary (eg. a POST payload).
179181
180182
Args:
181183
id: Unique identifier for the manager.
184+
manager_data: Data for the manager.
182185
name: The name of the employee.
183186
type: The type of the employee.
184-
manager_data: Data for the manager.
185187
186188
Returns:
187189
Model instance based on the dictionary.
@@ -228,9 +230,9 @@ class EngineerDict(typing.TypedDict, total=False):
228230
"""TypedDict for properties that are not required."""
229231

230232
id: typing.Optional[int]
233+
engineer_info: typing.Optional[str]
231234
name: typing.Optional[str]
232235
type: typing.Optional[str]
233-
engineer_info: typing.Optional[str]
234236

235237

236238
class TEngineer(typing.Protocol):
@@ -241,9 +243,9 @@ class TEngineer(typing.Protocol):
241243
242244
Attrs:
243245
id: Unique identifier for the engineer.
246+
engineer_info: Information for the manager.
244247
name: The name of the employee.
245248
type: The type of the employee.
246-
engineer_info: Information for the manager.
247249
248250
"""
249251

@@ -254,25 +256,25 @@ class TEngineer(typing.Protocol):
254256

255257
# Model properties
256258
id: "sqlalchemy.Column[typing.Optional[int]]"
259+
engineer_info: "sqlalchemy.Column[typing.Optional[str]]"
257260
name: "sqlalchemy.Column[typing.Optional[str]]"
258261
type: "sqlalchemy.Column[typing.Optional[str]]"
259-
engineer_info: "sqlalchemy.Column[typing.Optional[str]]"
260262

261263
def __init__(
262264
self,
263265
id: typing.Optional[int] = None,
266+
engineer_info: typing.Optional[str] = None,
264267
name: typing.Optional[str] = None,
265268
type: typing.Optional[str] = None,
266-
engineer_info: typing.Optional[str] = None,
267269
) -> None:
268270
"""
269271
Construct.
270272
271273
Args:
272274
id: Unique identifier for the engineer.
275+
engineer_info: Information for the manager.
273276
name: The name of the employee.
274277
type: The type of the employee.
275-
engineer_info: Information for the manager.
276278
277279
"""
278280
...
@@ -281,18 +283,18 @@ def __init__(
281283
def from_dict(
282284
cls,
283285
id: typing.Optional[int] = None,
286+
engineer_info: typing.Optional[str] = None,
284287
name: typing.Optional[str] = None,
285288
type: typing.Optional[str] = None,
286-
engineer_info: typing.Optional[str] = None,
287289
) -> "TEngineer":
288290
"""
289291
Construct from a dictionary (eg. a POST payload).
290292
291293
Args:
292294
id: Unique identifier for the engineer.
295+
engineer_info: Information for the manager.
293296
name: The name of the employee.
294297
type: The type of the employee.
295-
engineer_info: Information for the manager.
296298
297299
Returns:
298300
Model instance based on the dictionary.

0 commit comments

Comments
 (0)