Interactive command-line tool for creating and managing geometric shapes. Built with clean architecture.
- Features
- Quick Start
- Project Structure
- Usage
- Persistent Storage
- Architecture
- Logging System
- Development
- License
-
Shape Management:
- Create points, lines, circles, squares, rectangles, ellipses
- List all shapes with formatted output
- Delete shapes by ID (with partial ID matching)
- Clear all shapes at once
- Count total shapes
-
Persistent Storage:
- Save current shapes to a JSON file
- Load shapes from a JSON file with intelligent merging
- Automatic conflict resolution (duplicate IDs are skipped)
- Configurable file location (default:
database/shapes.json)
-
Clean Architecture:
- Strict separation of concerns (Domain, Application, Infrastructure)
- Repository pattern for data storage
- Dependency injection ready
- Interface-based design
-
Enterprise Logging:
- Structured logging with
structlog - JSON output for production, colored console for development
- Context binding
- File rotation support
- Third-party logger hijacking
- Structured logging with
-
Production Ready:
- Full type hints with Python 3.14
- Ruff for linting and formatting
- Pre-commit hooks for code quality
- Docker support with
uvfor fast builds - Comprehensive test suite
- Python 3.14+
- uv
- Docker (optional)
# Clone the repository
git clone https://github.com/script-logic/vector-editor-cli.git
cd vector-editor-cli
# Install with uv
uv venv
uv pip install -e .# Start interactive CLI
uv run python main.py
# Using Docker
docker-compose up
# Using Makefile
make run├── database/ # Persistent storage (JSON files)
│ └── shapes.json # Default shape file
├── logs/ # Application logs
├── src/
│ └── vector_editor/
│ ├── application/ # Application layer
│ │ └── services/ # ShapeService (use cases)
│ ├── cli/ # CLI interface
│ │ ├── app.py # Click commands
│ │ └── formatting.py # Console output
│ ├── config/ # Configuration
│ │ └── config.py # Pydantic settings
│ ├── domain/ # Core business logic
│ │ ├── definitions/ # Shape definitions
│ │ ├── geometry/ # Geometric representations
│ │ ├── interfaces/ # Repository protocol
│ │ ├── primitives/ # Coordinates, Transform
│ │ └── placed_shape.py # Shape with ID & transform
│ ├── infrastructure/ # External concerns
│ │ ├── repositories/ # InMemoryShapeRepository
│ │ └── serialization.py # JSON serialization
│ ├── logger/ # Structured logging system
│ └── utils/ # Helpers (Singleton)
├── tests/ # Unit tests
├── main.py # Entry point
├── pyproject.toml # Project configuration
├── docker-compose.yml # Docker setup
└── Makefile # Development tasks
| Command | Description | Example |
|---|---|---|
point <x> <y> [--angle <degrees>] |
Create a point | point 10.5 -20 --angle 45 |
line <start_x> <start_y> <end_x> <end_y> [--angle <degrees>] |
Create a line from coordinates | line 0 0 10 10 |
line-polar <start_x> <start_y> <length> <angle_degrees> [--angle <additional_degrees>] |
Create a line by polar method | line 0 0 10 60 |
circle <center_x> <center_y> <radius> [--angle <degrees>] |
Create a circle | circle 5 -5 3 |
square <center_x> <center_y> <side_size> [--angle <degrees>] |
Create a square | square 1 1 4 -a 45 |
rectangle <center_x> <center_y> <width> <height> [--angle <degrees>] |
Create a rectangle | rectangle 2 3 4 5 |
ellipse <center_x> <center_y> <radius_x> <radius_y> [--angle <degrees>]" |
Create an ellipse | ellipse 3 4 2 3 |
list |
List all shapes | list |
delete <id> |
Delete shape by ID | delete 123e4567 |
clear |
Delete all shapes | clear |
count |
Show total shapes | count |
save [<filename>] |
Save shapes to file | save my_shapes.json |
load [<filename>] |
Load shapes from file | load my_shapes.json |
help [command] |
Show help | help circle |
q, quit, exit |
Exit CLI | q |
savewithout argument saves todatabase/shapes.json.- If the file already exists, you will be prompted:
- Append – loads existing shapes, merges with current (duplicate IDs are skipped), and saves combined set.
- Overwrite – replaces file content with current shapes.
loadwithout argument loads fromdatabase/shapes.json.- If there are shapes already in memory:
- Add – adds loaded shapes, skipping duplicates.
- Replace – clears memory and loads shapes from file.
This design ensures you never lose data unintentionally and have full control over merging.
- Domain Layer: Pure Python with dataclasses, no external dependencies.
- Repository Pattern: Abstract
IShapeRepositoryprotocol enables easy swapping of storage (in‑memory, file‑based, etc.). - Serialization: Infrastructure module converts domain objects to/from JSON.
- Dependency Injection: Services receive repository and config via constructor.
- Protocol-based Interfaces: Uses
typing.Protocolfor loose coupling.
A sophisticated, production-ready logging system built with structlog.
- Structured Logging: All logs are structured events, not just strings.
- Dual Output:
- Development: Beautiful colored console output.
- Production: JSON format for log aggregation.
- File Rotation: Built-in log rotation with size limits.
- Third-party Hijacking: Automatically configures logs for
pydantic.
Via config.py or .env(optional):
LoggingConfig(
debug=True, # False for JSON output
app_name="Vector Editor",
log_level="INFO",
enable_file_logging=False,
)
FileSystem(
db_dir=Path("database"),
db_json_file_name="shapes.json",
logs_dir=Path("logs"),
logs_file_name="app.log",
max_log_file_size_mb=10,
log_backup_count=5,
)# Install with dev dependencies
uv pip install -e . --group dev
# Activate venv
source .venv/bin/activate # or .venv\Scripts\activate
# Install pre-commit hooks
pre-commit install
# Run tests
make test
# Run linter
make lint
# Fix formatting
make fix
# Clean cache
make clean- ruff: Fast Python linter and formatter (line length 79).
- ty: Fast type checking.
- pytest: Comprehensive test suite with coverage.
- pre-commit: Automated checks before commits.
# Build and run
make docker-run
# Rebuild
make docker-rebuild
# Or manually
docker-compose run --rm vector-editor
docker-compose down# Run all tests
uv run pytest
# With coverage
uv run pytest --cov=src --cov-report=html
# Specific test
uv run pytest tests/unit/cli/test_cli.pyMIT License – free to use and modify.
Интерактивный инструмент командной строки для создания и управления геометрическими фигурами. Построен на принципах чистой архитектуры.
- Возможности
- Быстрый старт
- Структура проекта
- Использование
- Постоянное хранилище
- Архитектура
- Система логирования
- Разработка
- Лицензия
-
Управление фигурами:
- Создание точек, линий, кругов, квадратов, прямоугольников, эллипсов
- Просмотр всех фигур с форматированным выводом
- Удаление фигур по ID (с поддержкой частичного совпадения)
- Удаление всех фигур одной командой
- Подсчёт общего количества фигур
-
Постоянное хранилище:
- Сохранение текущих фигур в JSON-файл
- Загрузка фигур из JSON-файла с опциональным слиянием
- Автоматическое разрешение конфликтов (дублирующиеся ID пропускаются)
- Настраиваемое расположение файла (по умолчанию:
database/shapes.json)
-
Чистая архитектура:
- Чёткое разделение слоёв (домен, приложение, инфраструктура)
- Паттерн «Репозиторий» для хранения данных
- Готовность к внедрению зависимостей
- Проектирование на основе интерфейсов
-
Промышленное логирование:
- Структурированное логирование с помощью
structlog - Вывод в JSON для продакшена, цветной вывод для разработки
- Привязка контекста
- Поддержка ротации файлов
- Перехват логов сторонних библиотек
- Структурированное логирование с помощью
-
Готовность к продакшену:
- Полная типизация (Python 3.14)
- Линтинг и форматирование с Ruff
- Pre-commit хуки для контроля качества кода
- Поддержка Docker с
uvдля быстрой сборки - Комплексный набор тестов
- Python 3.14+
- uv
- Docker (опционально)
# Клонировать репозиторий
git clone https://github.com/script-logic/vector-editor-cli.git
cd vector-editor-cli
# Установка с помощью uv
uv venv
uv pip install -e .# Запуск интерактивного CLI
uv run python main.py
# С использованием Docker
docker-compose up
# С использованием Makefile
make run├── database/ # Постоянное хранилище (JSON-файлы)
│ └── shapes.json # Файл хранения по умолчанию
├── logs/ # Логи приложения
├── src/
│ └── vector_editor/
│ ├── application/ # Слой приложения
│ │ └── services/ # ShapeService
│ ├── cli/ # Интерфейс командной строки
│ │ ├── app.py # Команды Click
│ │ └── formatting.py # Вывод в консоль
│ ├── config/ # Конфигурация
│ │ └── config.py # Настройки Pydantic
│ ├── domain/ # Основная бизнес-логика
│ │ ├── definitions/ # Определения фигур
│ │ ├── geometry/ # Геометрические представления
│ │ ├── interfaces/ # Протокол репозитория
│ │ ├── primitives/ # Координаты, трансформация
│ │ └── placed_shape.py # Фигура с ID и трансформацией
│ ├── infrastructure/ # Внешние зависимости
│ │ ├── repositories/ # InMemoryShapeRepository
│ │ └── serialization.py # JSON-сериализация
│ ├── logger/ # Система структурированного логирования
│ └── utils/ # Вспомогательные утилиты (Singleton)
├── tests/ # Модульные тесты
├── main.py # Точка входа
├── pyproject.toml # Метаданные проекта
├── docker-compose.yml # Настройки Docker
└── Makefile # Задачи разработки
| Команда | Описание | Пример |
|---|---|---|
point <x> <y> [--angle <degrees>] |
Создать точку | point 10.5 -20 --angle 45 |
line <start_x> <start_y> <end_x> <end_y> [--angle <degrees>] |
Создать линию по координатам | line 0 0 10 10 |
line-polar <start_x> <start_y> <length> <angle_degrees> [--angle <additional_degrees>] |
Создать линию полярным методом | line 0 0 10 60 |
circle <center_x> <center_y> <radius> [--angle <degrees>] |
Создать круг | circle 5 -5 3 |
square <center_x> <center_y> <side_size> [--angle <degrees>] |
Создать квадрат | square 1 1 4 -a 45 |
rectangle <center_x> <center_y> <width> <height> [--angle <degrees>] |
Создать прямоугольник | rectangle 2 3 4 5 |
ellipse <center_x> <center_y> <radius_x> <radius_y> [--angle <degrees>]" |
Создать эллипс | ellipse 3 4 2 3 |
list |
Показать все фигуры | list |
delete <id> |
Удалить фигуру по ID | delete 123e4567 |
clear |
Удалить все фигуры | clear |
count |
Показать общее количество фигур | count |
save [<filename>] |
Сохранить фигуры в файл | save my_shapes.json |
load [<filename>] |
Загрузить фигуры из файла | load my_shapes.json |
help [command] |
Показать справку | help circle |
q, quit, exit |
Выйти из CLI | q |
saveбез аргумента сохраняет вdatabase/shapes.json.- Если файл уже существует, будет задан вопрос:
- Добавить – загружает существующие фигуры, объединяет с текущими (дублирующиеся ID пропускаются) и сохраняет объединённый набор.
- Перезаписать – заменяет содержимое файла текущими фигурами.
loadбез аргумента загружает изdatabase/shapes.json.- Если в памяти уже есть фигуры:
- Добавить – добавляет загруженные фигуры, пропуская дубликаты.
- Заменить – очищает память и загружает фигуры из файла.
Такое поведение гарантирует, что вы никогда не потеряете данные случайно и сохраняете полный контроль над слиянием.
- Слой домена: Чистый Python с датаклассами, без внешних зависимостей.
- Паттерн «Репозиторий»: Абстрактный протокол
IShapeRepositoryпозволяет легко заменять хранилище (в памяти, на основе файлов и т.д.). - Сериализация: Модуль инфраструктуры преобразует объекты домена в JSON и обратно.
- Внедрение зависимостей: Сервисы получают репозиторий и конфигурацию через конструктор.
- Интерфейсы на основе протоколов: Использование
typing.Protocolдля слабой связанности.
Сложная, готовая к продакшену система логирования на базе structlog.
- Структурированное логирование: Все логи — это структурированные события, а не просто строки.
- Два режима вывода:
- Разработка: красивый цветной вывод в консоль.
- Продакшен: JSON-формат для агрегации логов.
- Ротация файлов: Встроенная ротация логов с ограничением по размеру.
- Перехват сторонних логгеров: Автоматически настраивает логи для
pydantic.
Через config.py или .env (опционально):
LoggingConfig(
debug=True, # False для JSON-вывода
app_name="Vector Editor",
log_level="INFO",
enable_file_logging=False,
)
FileSystem(
db_dir=Path("database"),
db_json_file_name="shapes.json",
logs_dir=Path("logs"),
logs_file_name="app.log",
max_log_file_size_mb=10,
log_backup_count=5,
)# Установка с dev-зависимостями
uv pip install -e . --group dev
# Активировать виртуальное окружение
source .venv/bin/activate # или .venv\Scripts\activate
# Установить pre-commit хуки
pre-commit install
# Запустить тесты
make test
# Запустить линтер
make lint
# Исправить форматирование
make fix
# Очистить кеш
make clean- ruff: Быстрый линтер и форматтер Python (длина строки 79).
- ty: Быстрая проверка типов.
- pytest: Комплексный набор тестов с покрытием.
- pre-commit: Автоматические проверки перед коммитами.
# Собрать и запустить
make docker-run
# Пересобрать
make docker-rebuild
# Или вручную
docker-compose run --rm vector-editor
docker-compose down# Запустить все тесты
uv run pytest
# С отчётом о покрытии
uv run pytest --cov=src --cov-report=html
# Конкретный тест
uv run pytest tests/unit/cli/test_cli.pyЛицензия MIT – можно свободно использовать и модифицировать.