Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 18 additions & 27 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,45 +7,36 @@ on:
branches: [ main ]

jobs:
flake8_py3:
flake8:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.7
uses: actions/setup-python@v2
- uses: actions/checkout@v4
- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: 3.7
python-version: '3.11'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest

- name: Run flake8 (suo)
uses: julianwachholz/flake8-action@v2
with:
checkName: 'flake8_py3'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
pip install flake8
- name: Run flake8
run: flake8 py_models_parser/ tests/

tests:
tox:
runs-on: ubuntu-latest
needs: [flake8_py3]
needs: [flake8]
strategy:
matrix:
python: [3.7, 3.8, 3.9, '3.10', '3.11']
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install poetry
poetry install
env:
POETRY_VIRTUALENVS_CREATE: false
- name: Test with pytest
run: |
pytest tests/ -vv
pip install tox tox-gh-actions
- name: Run tox
run: tox -e py$(echo ${{ matrix.python-version }} | tr -d '.')
219 changes: 219 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
# Архитектура py-models-parser

## О проекте

**Py-Models-Parser** — текстовый парсер Python моделей и определений таблиц, который извлекает структурную информацию из различных ORM-фреймворков без необходимости импортировать исходный код.

Парсер использует PEG (Parsing Expression Grammar) через библиотеку `parsimonious` для анализа текста кода как строк.

## Поддерживаемые модели

- SQLAlchemy ORM
- Gino ORM
- Tortoise ORM
- Encode ORM
- Django ORM Models
- Pydantic
- Python Enums
- Pony ORM
- Piccolo ORM
- Pydal Tables (Web2Py)
- Python Dataclasses
- Чистые Python классы
- OpenAPI 3.0/Swagger specifications

## Структура проекта

```
py-models-parser/
├── py_models_parser/ # Основной пакет
│ ├── __init__.py # Публичный API
│ ├── core.py # Основная логика парсинга
│ ├── grammar.py # PEG грамматика
│ ├── visitor.py # Visitor для преобразования AST
│ ├── types.py # Определения типов и триггеры
│ ├── utils.py # Утилиты
│ ├── cli.py # CLI интерфейс
│ └── parsers/
│ ├── pydal.py # Специализированный парсер для Pydal
│ └── openapi.py # Парсер OpenAPI/Swagger спецификаций
├── tests/ # Тесты
│ ├── test_*.py # Тесты для каждого типа моделей
│ └── data/ # Тестовые данные
├── tox.ini # Конфигурация tox для мультиверсионного тестирования
└── pyproject.toml # Конфигурация Poetry
```

## Основные компоненты

### 1. Public API (`__init__.py`)

Экспортирует функции:
- `parse(models: str)` — парсинг строки с Python моделями
- `parse_from_file(file_path)` — парсинг Python моделей из файла
- `dump_result(output, file_path)` — сохранение результатов в JSON
- `parse_openapi(content: str)` — парсинг OpenAPI спецификации из строки
- `parse_openapi_file(file_path)` — парсинг OpenAPI спецификации из файла

### 2. Core (`core.py`)

Главный модуль с логикой парсинга:

| Функция | Назначение |
|---------|-----------|
| `parse()` | Главная функция парсинга |
| `parse_from_file()` | Парсинг из файла |
| `pre_processing()` | Удаление импортов, комментариев, декораторов |
| `get_models_type()` | Определение типа модели |
| `sqlalchemy_type_identify()` | Различие SQLAlchemy ORM и Core |
| `format_ouput()` | Постобработка результатов |
| `process_models_attr()` | Разрешение ссылок на другие модели |
| `clear_parents()` | Удаление служебной информации |

### 3. Grammar (`grammar.py`)

PEG-грамматика для парсинга:

```
expr → (class/if_else/call_result/...)* - корневое выражение
class → class_def attr_def* funct_def* - определение класса
class_def → class_name args? ":"* - сигнатура класса
attr_def → id type? ("=" right_part)* - атрибут
type → ":" (id args_in_brackets / id) - аннотация типа
args → "(" (list/call_result/...)* ")" - аргументы
```

### 4. Visitor (`visitor.py`)

Класс `Visitor(NodeVisitor)` для преобразования AST в структуры данных:

| Метод | Назначение |
|-------|-----------|
| `visit_class_name()` | Извлечение названия класса |
| `visit_class_def()` | Обработка определения класса |
| `visit_attr_def()` | Обработка атрибута |
| `visit_right_part()` | Анализ правой части присваивания |
| `visit_type()` | Парсинг аннотаций типов |
| `extract_orm_attr()` | Извлечение параметров ORM |
| `_process_attr()` | Классификация атрибутов |

### 5. Types (`types.py`)

Конфигурация для распознавания типов моделей:

```python
orm_triggers = ["Column", "Field", "relationship"]
pony_orm_fields = ["Required", "Set", "Optional", "PrimaryKey"]
ormar_and_piccollo_types = ["Integer", "String", "Text", ...]
```

### 6. CLI (`cli.py`)

Интерфейс командной строки:

```bash
pmp path_to_models.py [-d output.json]
```

## Поток данных

```
Входной Python-код
┌─────────────────────┐
│ pre_processing() │ Удаление импортов, комментариев
│ get_models_type() │ Определение типа модели
└─────────┬───────────┘
┌─────────────────────┐
│ grammar.parse() │ PEG парсинг → AST
└─────────┬───────────┘
┌─────────────────────┐
│ Visitor.visit() │ Обход AST
│ extract_orm_attr() │ Распознавание ORM-параметров
└─────────┬───────────┘
┌─────────────────────┐
│ format_ouput() │ Постобработка
│ process_models_attr │
│ clear_parents() │
└─────────┬───────────┘
Структурированный JSON
```

## Выходной формат

```python
{
"name": str, # Имя класса/модели
"parents": [str], # Родительские классы
"attrs": [
{
"name": str, # Имя атрибута
"type": str, # Тип данных
"default": str, # Значение по умолчанию
"properties": { # Метаданные
"primary_key": bool,
"nullable": bool,
"foreign_key": str,
...
}
}
],
"properties": { # Свойства модели
"table_name": str,
"table_args": str,
...
}
}
```

## Зависимости

**Runtime:**
- `parsimonious` ^0.10.0 — PEG парсер для Python моделей
- `pyyaml` ^6.0 — парсер YAML для OpenAPI спецификаций

**Development:**
- `pytest` ^7.4
- `tox` — мультиверсионное тестирование

**Python:** 3.9, 3.10, 3.11, 3.12, 3.13

## Использование

```python
# Парсинг Python моделей из строки
from py_models_parser import parse
result = parse(models_string)

# Парсинг Python моделей из файла
from py_models_parser import parse_from_file
result = parse_from_file("path/to/models.py")

# Парсинг OpenAPI спецификации
from py_models_parser import parse_openapi, parse_openapi_file
result = parse_openapi(openapi_yaml_string)
result = parse_openapi_file("path/to/openapi.yaml")
```

```bash
# CLI
pmp models.py -d output.json
```

## Расширение

Для добавления поддержки нового ORM:

1. Добавить триггеры в `types.py`
2. Расширить грамматику в `grammar.py` (при необходимости)
3. Добавить методы в `visitor.py` для специфики ORM
4. Создать специализированный парсер в `parsers/` (опционально)
12 changes: 12 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
**v1.0.0**
Breaking Changes:
1. Dropped support for Python 3.7 and 3.8
2. Minimum required Python version is now 3.9

New Features:
1. Added support for Python 3.12 and 3.13
2. Added OpenAPI 3.0/Swagger specification parser (parse_openapi, parse_openapi_file)
3. Added tox for multi-version testing
4. Added ARCHITECTURE.md with project documentation
5. Added pyyaml dependency for OpenAPI parsing

**v0.7.0**
Updates:
1. Added support for latest version of parsimonious.
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,18 @@ For model from point 1 (above) library will produce the result:


## Changelog
**v1.0.0**
Breaking Changes:
1. Dropped support for Python 3.7 and 3.8
2. Minimum required Python version is now 3.9

New Features:
1. Added support for Python 3.12 and 3.13
2. Added OpenAPI 3.0/Swagger specification parser (parse_openapi, parse_openapi_file)
3. Added tox for multi-version testing
4. Added ARCHITECTURE.md with project documentation
5. Added pyyaml dependency for OpenAPI parsing

**v0.7.0**
Updates:
1. Added support for latest version of parsimonious.
Expand Down
42 changes: 41 additions & 1 deletion docs/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ Py-Models-Parser can parse & extract information from models & table definitions
* Piccolo ORM models (https://piccolo-orm.readthedocs.io/en/latest/piccolo/schema/defining.html),
* Pydal Tables definitions (http://www.web2py.com/books/default/chapter/29/06/the-database-abstraction-layer#The-DAL-A-quick-tour),
* Python Dataclasses (https://docs.python.org/3/library/dataclasses.html),
* pure Python Classes (https://docs.python.org/3/tutorial/classes.html#class-objects)
* pure Python Classes (https://docs.python.org/3/tutorial/classes.html#class-objects),
* OpenAPI 3.0/Swagger specifications (https://swagger.io/specification/)

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

Expand Down Expand Up @@ -124,6 +125,32 @@ Library detect automaticaly that type of models you tries to parse. You can chec
result = parse_from_file(file_path)


#. Parse OpenAPI/Swagger specifications:

.. code-block:: python


from py_models_parser import parse_openapi, parse_openapi_file

# Parse from string
openapi_spec = """
openapi: "3.0.0"
components:
schemas:
User:
type: object
properties:
id:
type: integer
name:
type: string
"""
result = parse_openapi(openapi_spec)

# Or parse from file (supports both YAML and JSON)
result = parse_openapi_file("path/to/openapi.yaml")


#. Parse models from file with command line

.. code-block:: bash
Expand Down Expand Up @@ -202,6 +229,19 @@ TODO: in next Release
Changelog
---------

**v1.0.0**
Breaking Changes:

#. Dropped support for Python 3.7 and 3.8
#. Minimum required Python version is now 3.9

New Features:

#. Added support for Python 3.12 and 3.13
#. Added OpenAPI 3.0/Swagger specification parser (parse_openapi, parse_openapi_file)
#. Added tox for multi-version testing
#. Added ARCHITECTURE.md with project documentation

**v0.7.0**
Updates:

Expand Down
9 changes: 8 additions & 1 deletion py_models_parser/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
from py_models_parser.core import dump_result, parse, parse_from_file
from py_models_parser.parsers.openapi import parse_openapi, parse_openapi_file

__all__ = ["parse", "parse_from_file", "dump_result"]
__all__ = [
"parse",
"parse_from_file",
"dump_result",
"parse_openapi",
"parse_openapi_file",
]
Loading