Skip to content

Commit 923dc9e

Browse files
committed
add support for differen pydal properties & python lists
1 parent 272d994 commit 923dc9e

File tree

8 files changed

+432
-55
lines changed

8 files changed

+432
-55
lines changed

CHANGELOG.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
**v0.5.0**
22
1. Added base support for Pydal tables definition
3+
2. Added support for python list syntax like []
34

45
**v0.4.0**
56
1. return tuples (multiple values) is parsed correctly now

README.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -171,12 +171,16 @@ For model from point 1 (above) library will produce the result:
171171

172172
## TODO: in next Release
173173

174-
1. Add more tests for supported models (and fix existed not covered cases): Django ORM, Pydantic, Enums, Dataclasses, SQLAlchemy Models, GinoORM models, TortoiseORM models, PonyORM, Pydal tables definitions
174+
1. Add more tests for supported models (and fix existed not covered cases): Django ORM, Pydantic, Enums, Dataclasses, SQLAlchemy Models, GinoORM models, TortoiseORM models, PonyORM, for lists
175175
2. Add support for SQLAlchemy Core Tables
176176
3. Add support for Piccolo ORM models
177177

178178

179179
## Changelog
180+
**v0.5.0**
181+
1. Added base support for Pydal tables definition
182+
2. Added support for python list syntax like []
183+
180184
**v0.4.0**
181185
1. return tuples (multiple values) is parsed correctly now
182186
2. symbols like `*&^%$#!±~`§<>` now does not cause any errors

docs/README.rst

+19-13
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,21 @@ Py-Models-Parser
2222

2323
It's as second Parser that done by me, first is a https://github.com/xnuinside/simple-ddl-parser for SQL DDL with different dialects.
2424

25-
Py-Models-Parser can parse & extract information from models:
25+
Py-Models-Parser can parse & extract information from models & table definitions:
2626

2727

28-
* Sqlalchemy ORM,
29-
* Gino ORM,
30-
* Tortoise ORM,
31-
* Django ORM Model,
32-
* Pydantic,
33-
* Python Enum,
34-
* Pony ORM,
35-
* Python Dataclasses
36-
* pure Python Classes
28+
* Sqlalchemy ORM (https://docs.sqlalchemy.org/en/14/orm/),
29+
* Gino ORM (https://python-gino.org/),
30+
* Tortoise ORM (https://tortoise-orm.readthedocs.io/en/latest/),
31+
* Django ORM Model (https://docs.djangoproject.com/en/3.2/topics/db/queries/),
32+
* Pydantic (https://pydantic-docs.helpmanual.io/),
33+
* Python Enum (https://docs.python.org/3/library/enum.html),
34+
* Pony ORM (https://ponyorm.org/),
35+
* Pydal Tables definitions (http://www.web2py.com/books/default/chapter/29/06/the-database-abstraction-layer#The-DAL-A-quick-tour),
36+
* Python Dataclasses (https://docs.python.org/3/library/dataclasses.html),
37+
* pure Python Classes (https://docs.python.org/3/tutorial/classes.html#class-objects)
3738

38-
Number of supported models will be increased, check 'TODO' section.
39+
Number of supported models will be increased, check 'TODO' section, if you want to have support of different models types - please open the issue.
3940

4041
Py-Models-Parser written with PEG parser and it's python implementation - parsimonious. It's pretty new and I did not cover all possible test cases, so if you will have an issue - please just open an issue in this case with example, I will fix it as soon as possible.
4142

@@ -193,14 +194,19 @@ TODO: in next Release
193194
---------------------
194195

195196

196-
#. Add more tests for supported models (and fix existed not covered cases): Django ORM, Pydantic, Enums, Dataclasses, SQLAlchemy Models, GinoORM models, TortoiseORM models
197+
#. Add more tests for supported models (and fix existed not covered cases): Django ORM, Pydantic, Enums, Dataclasses, SQLAlchemy Models, GinoORM models, TortoiseORM models, PonyORM, for lists
197198
#. Add support for SQLAlchemy Core Tables
198-
#. Add support for Pony ORM models
199199
#. Add support for Piccolo ORM models
200200

201201
Changelog
202202
---------
203203

204+
**v0.5.0**
205+
206+
207+
#. Added base support for Pydal tables definition
208+
#. Added support for python list syntax like []
209+
204210
**v0.4.0**
205211

206212

py_models_parser/grammar.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ class = class_def attr_def* funct_def*
1515
string = one_quote_str / double_quotes_str
1616
one_quote_str = ~"\'[^\']+\'"i
1717
double_quotes_str = ~'"[^\"]+"'i
18+
list = "[" (call_result / attr_def / args / id / text)* ","* "]"
1819
funct_def = intend? "def" id args? ":"* ws?
1920
args_in_brackets = "[" ((id/string)* ","* )* "]"
20-
args = "(" (( call_result / args / attr_def / id )* ","* )* ")"
21+
args = "(" (( list / call_result / args / attr_def / id )* ","* )* ")"
2122
call_result = id args ws?
2223
class_name = "class" id
2324
id = (((dot_id / text)+ ) * / dot_id / text) ws?

py_models_parser/parsers/pydal.py

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
from typing import Dict, List
2+
3+
pydal_order_field_args = {
4+
1: "length",
5+
3: "required",
6+
4: "requires",
7+
5: "ondelete",
8+
6: "notnull",
9+
7: "unique",
10+
}
11+
12+
13+
def _pydal_table_properties(table_def: Dict, value: str) -> Dict:
14+
table_prop = value.split(",")
15+
previos_prop = None
16+
for num, prop in enumerate(table_prop):
17+
if num == len(table_prop) - 1:
18+
prop = prop.replace(")", "")
19+
prop = prop.strip().split("=")
20+
if len(prop) > 1:
21+
table_def["properties"][prop[0].strip()] = prop[1].strip()
22+
previos_prop = prop[0].strip()
23+
else:
24+
# like lists
25+
table_def["properties"][previos_prop] += f", {prop[0]}"
26+
27+
return table_def
28+
29+
30+
def pydal_column_properties(attr: Dict, column: List) -> Dict:
31+
properties = {}
32+
default = None
33+
_type = None
34+
for num, param in enumerate(column[1:]):
35+
param = param.strip().split("=")
36+
if len(param) > 1:
37+
if "default" == param[0]:
38+
default = param[1]
39+
elif "type" == param[0]:
40+
_type = param[1]
41+
else:
42+
properties[param[0]] = param[1]
43+
else:
44+
if param[0]:
45+
if num == 0:
46+
_type = param[0]
47+
elif num == 2:
48+
default = param[0]
49+
else:
50+
order_param = pydal_order_field_args.get(num)
51+
if order_param:
52+
properties[order_param] = param[0]
53+
54+
attr.update({"properties": properties, "default": default, "type": _type})
55+
return attr
56+
57+
58+
def process_pydal_table_definition(pydal_def: str) -> Dict:
59+
table_def = {
60+
"attrs": [],
61+
"name": "name",
62+
"properties": {},
63+
}
64+
pydal_def = pydal_def.split("Field(")
65+
66+
table_def["name"] = pydal_def[0].split(",")[0].split("define_table(")[1]
67+
for column in pydal_def[1:]:
68+
_column = column.strip().replace(") ,", "),").split("),")
69+
if len(_column) == 2 and _column[-1] != "":
70+
table_def = _pydal_table_properties(table_def, _column[-1])
71+
column = column.replace(")", "").strip().split(",")
72+
column_name = column[0]
73+
attr = {"name": column_name}
74+
attr = pydal_column_properties(attr, column)
75+
table_def["attrs"].append(attr)
76+
return table_def

py_models_parser/visitor.py

+3-38
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
from parsimonious.nodes import NodeVisitor
44

5+
from py_models_parser.parsers.pydal import process_pydal_table_definition
6+
57

68
class Visitor(NodeVisitor):
79
def visit_class_name(self, node, visited_children):
@@ -116,46 +118,9 @@ def visit_call_result(self, node, visited_children):
116118
value = node.text.strip()
117119
if "define_table" in value:
118120
# mean this is a pydal method
119-
return self.process_pydal_table_definition(value)
121+
return process_pydal_table_definition(value)
120122
return visited_children or node
121123

122-
@staticmethod
123-
def process_pydal_table_definition(pydal_def: str) -> Dict:
124-
table_def = {
125-
"attrs": [],
126-
"name": "name",
127-
"properties": {},
128-
}
129-
pydal_def = pydal_def.split("Field(")
130-
table_def["name"] = pydal_def[0].split(",")[0].split("define_table(")[1]
131-
for column in pydal_def[1:]:
132-
column = column.replace(")", "").strip().split(",")
133-
column_name = column[0]
134-
default = None
135-
_type = None
136-
properties = {}
137-
for num, param in enumerate(column[1:]):
138-
param = param.strip().split("=")
139-
if len(param) > 1:
140-
if "default" == param[0]:
141-
default = param[1]
142-
elif "type" == param[0]:
143-
_type = param[1]
144-
else:
145-
properties[param[0]] = param[1]
146-
else:
147-
if num == 0 and param[0]:
148-
_type = param[0]
149-
table_def["attrs"].append(
150-
{
151-
"name": column_name,
152-
"default": default,
153-
"type": _type,
154-
"properties": properties,
155-
}
156-
)
157-
return table_def
158-
159124
def visit_attr_def(self, node, visited_children):
160125
"""Makes a dict of the section (as key) and the key/value pairs."""
161126
left = node.children[1].children[0].children[0].text.strip()

pyproject.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[tool.poetry]
22
name = "py-models-parser"
3-
version = "0.4.0"
4-
description = "Parser for Different Python Models (Pydantic, Enums, ORMs: Tortoise, SqlAlchemy, GinoORM, PonyORM) to extract information about columns(attrs), model, table args,etc in one format."
3+
version = "0.5.0"
4+
description = "Parser for Different Python Models (Pydantic, Enums, ORMs: Tortoise, SqlAlchemy, GinoORM, PonyORM, Pydal tables) to extract information about columns(attrs), model, table args,etc in one format."
55
authors = ["Iuliia Volkova <[email protected]>"]
66
license = "MIT"
77
readme = "docs/README.rst"

0 commit comments

Comments
 (0)