88![ Example] ( /etc/convert.png )
99
1010json2python-models is a [ Python] ( https://www.python.org/ ) tool that can generate Python models classes
11- (dataclasses, [ attrs] ( https://github.com/python-attrs/attrs ) ) from JSON dataset.
11+ ([ pydantic] ( https://github.com/samuelcolvin/pydantic ) , dataclasses, [ attrs] ( https://github.com/python-attrs/attrs ) )
12+ from JSON dataset.
1213
1314## Features
1415
@@ -17,11 +18,11 @@ json2python-models is a [Python](https://www.python.org/) tool that can generate
1718* Fields and models ** names** generation (unicode support included)
1819* Similar ** models generalization**
1920* Handling ** recursive data** structures (i.e family tree)
20- * Detecting ** string literals ** (i.e. datetime or just stringify numbers)
21- and providing decorators to easily convert into Python representation
21+ * Detecting ** string serializable types ** (i.e. datetime or just stringify numbers)
22+ * Detecting fields containing string constants ( ` Literal['foo', 'bar'] ` )
2223* Generation models as ** tree** (nested models) or ** list**
2324* Specifying when dictionaries should be processed as ** ` dict ` type** (by default every dict is considered as some model)
24- * ** CLI** tool
25+ * ** CLI** API with a lot of options
2526
2627## Table of Contents
2728
@@ -38,7 +39,26 @@ json2python-models is a [Python](https://www.python.org/) tool that can generate
3839* [ Contributing] ( #contributing )
3940* [ License] ( #license )
4041
41- ## Example
42+ ## Examples
43+
44+ ### Part of Path of Exile public items API
45+
46+ ``` python
47+ from pydantic import BaseModel, Field
48+ from typing import List, Optional
49+ from typing_extensions import Literal
50+
51+
52+ class Tab (BaseModel ):
53+ id_: str = Field(... , alias = " id" )
54+ public: bool
55+ stash_type: Literal[" CurrencyStash" , " NormalStash" , " PremiumStash" ] = Field(... , alias = " stashType" )
56+ items: List[' Item' ]
57+ account_name: Optional[str ] = Field(None , alias = " accountName" )
58+ last_character_name: Optional[str ] = Field(None , alias = " lastCharacterName" )
59+ stash: Optional[str ] = None
60+ league: Optional[Literal[" Hardcore" , " Standard" ]] = None
61+ ```
4262
4363### F1 Season Results
4464
@@ -83,47 +103,46 @@ driver_standings.json
83103```
84104
85105```
86- json2models -f attrs - l DriverStandings driver_standings.json
106+ json2models -f pydantic -s flat - l DriverStandings - driver_standings.json
87107```
88108
89109``` python
90- import attr
91- from json_to_models.dynamic_typing import IntString, IsoDateString
110+ r """
111+ generated by json2python-models v0.1.2 at Mon May 4 17:46:30 2020
112+ command: /opt/projects/json2python-models/venv/bin/json2models -f pydantic -s flat -l DriverStandings - driver_standings.json
113+ """
114+ from pydantic import BaseModel, Field
92115from typing import List
93-
94-
95- @attr.s
96- class DriverStandings :
97- @attr.s
98- class DriverStanding :
99- @attr.s
100- class Driver :
101- driver_id: str = attr.ib()
102- permanent_number: IntString = attr.ib(converter = IntString)
103- code: str = attr.ib()
104- url: str = attr.ib()
105- given_name: str = attr.ib()
106- family_name: str = attr.ib()
107- date_of_birth: IsoDateString = attr.ib(converter = IsoDateString)
108- nationality: str = attr.ib()
109-
110- @attr.s
111- class Constructor :
112- constructor_id: str = attr.ib()
113- url: str = attr.ib()
114- name: str = attr.ib()
115- nationality: str = attr.ib()
116-
117- position: IntString = attr.ib(converter = IntString)
118- position_text: IntString = attr.ib(converter = IntString)
119- points: IntString = attr.ib(converter = IntString)
120- wins: IntString = attr.ib(converter = IntString)
121- driver: ' Driver' = attr.ib()
122- constructors: List[' Constructor' ] = attr.ib()
123-
124- season: IntString = attr.ib(converter = IntString)
125- round : IntString = attr.ib(converter = IntString)
126- driver_standings: List[' DriverStanding' ] = attr.ib()
116+ from typing_extensions import Literal
117+
118+ class DriverStandings (BaseModel ):
119+ season: int
120+ round_: int = Field(... , alias = " round" )
121+ DriverStandings: List[' DriverStanding' ]
122+
123+ class DriverStanding (BaseModel ):
124+ position: int
125+ position_text: int = Field(... , alias = " positionText" )
126+ points: int
127+ wins: int
128+ driver: ' Driver' = Field(... , alias = " Driver" )
129+ constructors: List[' Constructor' ] = Field(... , alias = " Constructors" )
130+
131+ class Driver (BaseModel ):
132+ driver_id: str = Field(... , alias = " driverId" )
133+ permanent_number: int = Field(... , alias = " permanentNumber" )
134+ code: str
135+ url: str
136+ given_name: str = Field(... , alias = " givenName" )
137+ family_name: str = Field(... , alias = " familyName" )
138+ date_of_birth: str = Field(... , alias = " dateOfBirth" )
139+ nationality: str
140+
141+ class Constructor (BaseModel ):
142+ constructor_id: str = Field(... , alias = " constructorId" )
143+ url: str
144+ name: str
145+ nationality: Literal[" Austrian" , " German" , " American" , " British" , " Italian" , " French" ]
127146```
128147
129148</p >
@@ -139,14 +158,19 @@ class DriverStandings:
139158It requires a lit bit of tweaking:
140159* Some fields store routes/models specs as dicts
141160* There is a lot of optinal fields so we reduce merging threshold
161+ * Disable string literals
142162
143163```
144- json_to_models -s flat -f dataclasses -m Swagger testing_tools/swagger.json
145- --dict-keys-fields securityDefinitions paths responses definitions properties
146- --merge percent_50 number
164+ json2models -s flat -f dataclasses -m Swagger testing_tools/swagger.json \
165+ --dict-keys-fields securityDefinitions paths responses definitions properties \
166+ --merge percent_50 number --max-strings-literals 0
147167```
148168
149169``` python
170+ r """
171+ generated by json2python-models v0.1.2 at Mon May 4 18:08:09 2020
172+ command: /opt/projects/json2python-models/json_to_models/__main__.py -s flat -f dataclasses -m Swagger testing_tools/swagger.json --max-strings-literals 0 --dict-keys-fields securityDefinitions paths responses definitions properties --merge percent_50 number
173+ """
150174from dataclasses import dataclass, field
151175from json_to_models.dynamic_typing import FloatString
152176from typing import Any, Dict, List, Optional, Union
@@ -192,15 +216,15 @@ class Path:
192216
193217@dataclass
194218class Property :
195- type : str
196- format : Optional[str ] = None
219+ type_ : str
220+ format_ : Optional[str ] = None
197221 xnullable: Optional[bool ] = None
198222 items: Optional[' Item_Schema' ] = None
199223
200224
201225@dataclass
202226class Property_2E :
203- type : str
227+ type_ : str
204228 title: Optional[str ] = None
205229 read_only: Optional[bool ] = None
206230 max_length: Optional[int ] = None
@@ -209,26 +233,26 @@ class Property_2E:
209233 enum: Optional[List[str ]] = field(default_factory = list )
210234 maximum: Optional[int ] = None
211235 minimum: Optional[int ] = None
212- format : Optional[str ] = None
236+ format_ : Optional[str ] = None
213237
214238
215239@dataclass
216240class Item :
217- ref: Optional[str ] = None
218241 title: Optional[str ] = None
219- type : Optional[str ] = None
242+ type_: Optional[str ] = None
243+ ref: Optional[str ] = None
220244 max_length: Optional[int ] = None
221245 min_length: Optional[int ] = None
222246
223247
224248@dataclass
225249class Parameter_SecurityDefinition :
226- name: str
227- in_: str
250+ name: Optional[ str ] = None
251+ in_: Optional[ str ] = None
228252 required: Optional[bool ] = None
229253 schema: Optional[' Item_Schema' ] = None
230- type : Optional[str ] = None
231254 description: Optional[str ] = None
255+ type_: Optional[str ] = None
232256
233257
234258@dataclass
@@ -253,10 +277,10 @@ class Response:
253277
254278@dataclass
255279class Definition_Schema :
256- ref: Optional[ str ] = None
280+ type_: str
257281 required: Optional[List[str ]] = field(default_factory = list )
258- type : Optional[str ] = None
259- properties : Optional[Dict[ str , Union[ ' Property_2E ' , ' Property ' ]]] = field( default_factory = dict )
282+ properties : Optional[Dict[ str , Union[ ' Property ' , ' Property_2E ' ]]] = field( default_factory = dict )
283+ ref : Optional[str ] = None
260284```
261285
262286</p >
@@ -309,8 +333,8 @@ Arguments:
309333
310334* ` -f ` , ` --framework ` - Model framework for which python code is generated.
311335 ` base ` (default) mean no framework so code will be generated without any decorators and additional meta-data.
312- * ** Format** : ` -f {base,attrs,dataclasses,custom} `
313- * ** Example** : ` -f attrs `
336+ * ** Format** : ` -f {base, pydantic, attrs, dataclasses, custom} `
337+ * ** Example** : ` -f pydantic `
314338 * ** Default** : ` -f base `
315339
316340* ` -s ` , ` --structure ` - Models composition style.
@@ -327,6 +351,13 @@ Arguments:
327351
328352* ` --strings-converters ` - Enable generation of string types converters (i.e. ` IsoDatetimeString ` or ` BooleanString ` ).
329353 * ** Default** : disabled
354+
355+ * ` --max-strings-literals ` - Generate ` Literal['foo', 'bar'] ` when field have less than NUMBER string constants as values.
356+ * ** Format** : ` --max-strings-literals <NUMBER> `
357+ * ** Default** : 10 (generator classes could override it)
358+ * ** Example** : ` --max-strings-literals 5 ` - only 5 literals will be saved and used to code generation
359+ * ** Note** : There could not be more than ** 15** literals per field (for performance reasons)
360+ * ** Note** : ` attrs ` code generator do not use Literals and just generate ` str ` fields instead
330361
331362* ` --merge ` - Merge policy settings. Possible values are:
332363 * ** Format** : ` --merge MERGE_POLICY [MERGE_POLICY ...] `
@@ -369,7 +400,7 @@ One of model arguments (`-m` or `-l`) is required.
369400
370401### Low level API
371402
372- > Coming soon (Wiki)
403+ \-
373404
374405## Tests
375406
0 commit comments