Skip to content

Commit efa4be9

Browse files
release: v0.1.0-beta.8 (#94)
## Description Release `v0.1.0-beta.8` aggregating database write/search performance optimizations, background execution isolation, soft delete lifecycle capabilities, complete interactive CLI revitalization, test suite modernization, and updated packaging/documentation metadata. ### Summary of Changes: - **Database Performance & Optimization**: - Optimized bulk repository methods (`create_multi`, `update_multi`, `delete_multi`) in `WriteRepositoryMixin` using native SQLAlchemy 2.0 `RETURNING` clauses and direct DBAPI `executemany` execution, eliminating N+1 select queries and ORM hydration overhead. - **Background Execution & Dependency Injection**: - Introduced `background_scope` async context manager for isolated IoC containers, dedicated `AsyncSession` instances, and context cloning. - Implemented `@background_task` decorator supporting sync (thread pool offloading) and async functions with automatic parameter auto-wiring. - Exported background utilities publicly via `zcore.kernel`. - **Advanced Search & Filtering**: - Added new search operators: `startswith`, `endswith`, `contains` (case-insensitive substring & collection matching), and `between` (range filtering with type coercion). - Introduced configurable `__max_search_depth__` on SQLAlchemy models to dynamically enforce inclusion relation path limits. - **Soft Delete Lifecycle**: - Added `SoftDeleteMixin` providing `deleted_at` timestamp tracking, `is_deleted` property, `soft_delete()` and `restore()` methods. - Integrated `scope_query()` checks across `BaseRepository.exist()` and query execution. - **Interactive CLI & Scaffolding Workflow**: - Revamped `zc` CLI with an interactive Questionary/Rich dashboard, workspace detection, and automated `.venv` creation via `uv`/`pip`. - Added multi-database configuration support (`SQLite`, `PostgreSQL`, `MySQL`). - Added granular domain scaffolding modes (`Full Boilerplate`, `Clean / Blank`, `Custom`). - Fixed scaffolded repository and service templates to align with single-generic class signatures (`BaseRepository[Model]`, `BaseService[Model]`). - **Test Suite Modernization**: - Upgraded test suite type annotations to PEP 585/604 built-in generics and `collections.abc` types. - Reorganized imports, improved ClassVar test-class typings, and cleaned up context managers. - **Metadata, Packaging & Documentation**: - Added maintainer metadata and Python 3.13 classifier support. - Added dedicated dependency groups for `postgres`, `mysql`, and `dev`. - Comprehensive documentation overhaul across `README.md`, `CONTRIBUTING.md`, `SECURITY.md`, and `CODE_OF_CONDUCT.md`. ## Type of change - [x] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [x] Refactoring (architectural or code cleanup with no functional changes) - [x] Documentation update ## How Has This Been Tested? - [x] Unit/Integration tests (`hatch test`) - Full test suite passed with 100% success rate across all domains (`test_db_lifecycle`, `test_repository`, `test_search`, `test_soft_delete`, `test_di`, `test_cli`, `test_web`, `test_security`, etc.). - [x] Static type check passing (`mypy src/`) ## Checklist: - [x] My code follows the style guidelines and architectural rules of this project - [x] I have performed a self-review of my own code - [x] My changes pass strict static type analysis (`mypy src/` generates no warnings) - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have updated the documentation in `zcore-docs` if applicable - [x] My changes generate no new runtime warnings - [x] I have added tests that prove my fix is effective or that my feature works
2 parents 49b2d22 + b8ea77c commit efa4be9

39 files changed

Lines changed: 1672 additions & 578 deletions

‎CODE_OF_CONDUCT.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ representative at an online or offline event.
6060

6161
Instances of abusive, harassing, or otherwise unacceptable behavior may be
6262
reported to the community leaders responsible for enforcement at
63-
.
63+
alialfostovar@gmail.com.
6464
All complaints will be reviewed and investigated promptly and fairly.
6565

6666
All community leaders are obligated to respect the privacy and security of the
@@ -106,7 +106,7 @@ Violating these terms may lead to a permanent ban.
106106
### 4. Permanent Ban
107107

108108
**Community Impact**: Demonstrating a pattern of violation of community
109-
standards, including sustained inappropriate behavior, harassment of an
109+
standards, including sustained inappropriate behavior, harassment of an
110110
individual, or aggression toward or disparagement of classes of individuals.
111111

112112
**Consequence**: A permanent ban from any sort of public interaction within
@@ -125,4 +125,4 @@ enforcement ladder](https://github.com/mozilla/diversity).
125125

126126
For answers to common questions about this code of conduct, see the FAQ at
127127
https://www.contributor-covenant.org/faq. Translations are available at
128-
https://www.contributor-covenant.org/translations.
128+
https://www.contributor-covenant.org/translations.

‎CONTRIBUTING.md‎

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -61,19 +61,30 @@ pip install -e ".[all,dev]"
6161
We aim for high test coverage on core architectural units. ZCore uses `pytest` and `pytest-asyncio` for asynchronous test suites.
6262

6363
### Test Architecture
64-
ZCore's codebase is highly modular. To ensure that components like the Kernel, Plugins, Dependency Injection (DI), Unit of Work (UOW), Router, and Middleware interact correctly, we organize our tests as follows:
64+
ZCore's tests are organized modularly across architectural domains:
6565

6666
```text
6767
tests/
68-
├── unit/ # Tests for isolated, single architectural units with mocks
69-
│ ├── test_repository.py
70-
│ └── test_zchema.py
71-
├── integration/ # Tests verifying interactions between modules
72-
│ ├── test_kernel_startup.py
73-
│ ├── test_plugin_loading.py
74-
│ └── test_request_scope.py
75-
└── e2e/ # Full end-to-end request/response flows using TestClient
76-
└── test_crud_flow.py
68+
├── test_cache.py
69+
├── test_cli.py
70+
├── test_context.py
71+
├── test_db_lifecycle.py
72+
├── test_di.py
73+
├── test_events.py
74+
├── test_exceptions.py
75+
├── test_kernel.py
76+
├── test_logging.py
77+
├── test_pagination.py
78+
├── test_repository.py
79+
├── test_search.py
80+
├── test_security.py
81+
├── test_service.py
82+
├── test_soft_delete.py
83+
├── test_storage.py
84+
├── test_streams.py
85+
├── test_testing_subsystem.py
86+
├── test_utils.py
87+
└── test_web.py
7788
```
7889

7990
### Running Tests Locally
@@ -84,11 +95,11 @@ pytest
8495

8596
If you prefer to run tests inside Hatch-isolated environments:
8697
```bash
87-
hatch run test
98+
hatch test
8899
```
89100

90101
### Writing Tests
91-
- **Asynchronous Tests:** Ensure your async tests are decorated with `@pytest.mark.asyncio`.
102+
- **Asynchronous Tests:** Ensure your async tests are decorated with `@pytest.mark.anyio` or `@pytest.mark.asyncio`.
92103
- **Isolation:** Tests should not leave behind lingering SQLite databases, active sessions, or running background threads.
93104
- **Mocks:** When writing tests that require external services like Redis, implement mock fallbacks where appropriate to ensure the test suite can run fully offline.
94105

@@ -107,8 +118,8 @@ mypy src/
107118
### 2. Linting & Formatting
108119
Ensure your code is clean, PEP-8 compliant, and structured consistently. We recommend using `ruff` for formatting and linting:
109120
```bash
110-
ruff check src/
111-
ruff format src/
121+
ruff check .
122+
ruff format --check .
112123
```
113124

114125
---
@@ -124,14 +135,17 @@ ZCore uses the **Conventional Commits** specification to automate our changelog
124135
Common types include:
125136
- `feat`: A new feature (corresponds to a minor version bump).
126137
- `fix`: A bug fix (corresponds to a patch version bump).
138+
- `perf`: A code change that improves performance.
127139
- `docs`: Documentation updates.
140+
- `style`: Changes that do not affect the meaning of the code (white-space, formatting, etc.).
128141
- `refactor`: Code changes that neither fix a bug nor add a feature.
129142
- `test`: Adding or correcting tests.
143+
- `build`: Changes that affect the build system or external dependencies.
130144
- `ci`: Changes to our CI/CD workflows or scripts.
131145

132146
*Examples:*
133-
- `feat(di): add redis plugin support`
134-
- `fix(uow): resolve transaction rollback issue on async commit`
147+
- `feat(di): add background_scope and background_task decorator`
148+
- `perf(db): optimize create_multi using insert returning clause`
135149
- `docs(zchema): update guide for dynamic schema pruning`
136150

137151
---
@@ -148,12 +162,12 @@ flowchart LR
148162
D --> E[Submit PR]
149163
```
150164

151-
1. **Branch Naming:** Use descriptive branch names (e.g., `feature/add-s3-provider` or `bugfix/fix-uow-flush`).
165+
1. **Branch Naming:** Use descriptive branch names (e.g., `feat/add-s3-provider` or `fix/uow-flush-isolation`).
152166
2. **Atomic Commits:** Keep your commits focused on single logical changes and adhere to the conventional commits schema.
153167
3. **Documentation:** If you are adding a new feature or modifying an existing protocol, you **must** update the corresponding documentation page under the `docs/` folder.
154168

155169
### 🛡️ CI/CD & Branch Protection
156-
Our repository has strict branch protection rules configured on `master` and `develop`.
170+
Our repository has strict branch protection rules configured on `main` and `develop`.
157171
- **Mandatory CI Checks:** Your Pull Request cannot be merged unless all status checks (Linting with Ruff, Type-checking with Mypy, and Test Suites with Pytest) pass successfully in our GitHub Actions pipeline.
158172
- **No Direct Pushes:** All code changes must go through a Pull Request. Direct pushes to protected branches are blocked.
159173

@@ -164,4 +178,4 @@ Our repository has strict branch protection rules configured on `master` and `de
164178
By contributing to ZCore, you agree that your contributions will be licensed under the project's **Apache License 2.0**.
165179

166180
- **No CLA Required:** We do not currently require a signed Contributor License Agreement (CLA) for individual contributions.
167-
- **Certificate of Origin:** By submitting a Pull Request, you assert that you have the right to submit this code and that it conforms to an open-source contribution under the Apache 2.0 terms.
181+
- **Certificate of Origin:** By submitting a Pull Request, you assert that you have the right to submit this code and that it conforms to an open-source contribution under the Apache 2.0 terms.

‎LICENSE‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@
186186
same "printed page" as the copyright notice for easier
187187
identification within third-party archives.
188188

189-
Copyright [yyyy] [name of copyright owner]
189+
Copyright 2024-2026 Ali Alf Ostovar / Baseryn
190190

191191
Licensed under the Apache License, Version 2.0 (the "License");
192192
you may not use this file except in compliance with the License.

‎README.md‎

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,21 @@ While FastAPI provides a high-performance engine for HTTP, it leaves the archite
3838
- **⚡ Scoped Dependency Injection** — High-performance constructor auto-wiring for Singleton, Transient, and request-scoped dependencies.
3939
- **🏗️ Modular Plugin Architecture** — Organize business domains into decoupled plugins with topological dependency ordering.
4040
- **🔍 Secure Dynamic Search Engine** — Nested JSON filters, eager loading, cursor/offset pagination, and column-level access controls.
41-
- **📦 Zero-Boilerplate CLI** — From `pip install` to running secure CRUD endpoints in under two minutes.
41+
- **📦 Interactive TUI & Scaffolding Engine** — Context-aware terminal dashboard, lightning-fast `uv` virtualenv orchestration, and granular layer-by-layer domain generators.
4242

4343
---
4444

4545
## Why ZCore?
4646

4747
| Concern | Raw FastAPI | With ZCore |
4848
|---------|-------------|------------|
49-
| **Endpoint Scaffolding** | Manually write 7+ routes and handlers per model | One `BaseRouter` class $\rightarrow$ 7 secure endpoints out-of-the-box |
49+
| **Endpoint Scaffolding** | Manually write 7+ routes and handlers per model | One `BaseRouter` class → 7 secure endpoints out-of-the-box |
5050
| **Data Leakage** | Multiple Pydantic models per role; manual conditionals | `Zchema` auto-prunes restricted fields per active context |
5151
| **Database Transactions** | Scattered `commit()` / `rollback()` calls | `UnitOfWork` guarantees atomicity + post-commit domain events |
5252
| **Dependency Wiring** | Deeply nested, verbose `Depends()` parameter chains | Clean constructor auto-wiring via IoC container + `Inject[T]` |
5353
| **Search & Pagination** | Hand-crafted SQL parsing per endpoint | Declarative JSON filters + keyset cursor and offset pagination |
54-
| **Project Layout** | No standard; every team reinvents the wheel | `zc init` + `zc startapp` — decoupled domain modularity |
55-
| **Startup Orchestration** | Fragile `@app.on_event` chains | `Plugin` protocol with dependency DAG $\rightarrow$ topological sorting |
54+
| **Project Tooling & Layout** | Manual folder creation, fragmented glue scripts | `zc` interactive TUI with auto `uv` setup & granular layer picking |
55+
| **Startup Orchestration** | Fragile `@app.on_event` chains | `Plugin` protocol with dependency DAG → topological sorting |
5656

5757
---
5858

@@ -66,9 +66,16 @@ pip install fastapi-zcore-framework[all]
6666

6767
### 2. Scaffold
6868

69+
Launch the interactive wizard or run directly:
70+
6971
```bash
72+
# Interactive mode (prompts for DB driver, uv/.venv installation, etc.)
7073
zc init my_app && cd my_app
71-
zc startapp tasks --template
74+
zc startapp tasks
75+
76+
# Or instant non-interactive scaffolding with defaults
77+
zc init my_app -y && cd my_app
78+
zc startapp tasks -y
7279
```
7380

7481
### 3. Define
@@ -94,7 +101,7 @@ class Task(Base):
94101
zc run
95102
```
96103

97-
Your API is live at **`http://127.0.0.1:8000`** with 6 CRUD endpoints and dynamic search ready.
104+
Your API is live at **`http://127.0.0.1:8000`** with 7 secure endpoints (CRUD + Dynamic Search) ready.
98105

99106
> 📖 **Full walkthrough:** [Quick Start Guide](https://baseryn.github.io/zcore-docs/docs/quick-start)
100107
@@ -209,19 +216,42 @@ A dynamic query builder that translates nested JSON filters into safe SQLAlchemy
209216
</details>
210217

211218
<details>
212-
<summary><strong>📦 CLI Scaffolding</strong></summary>
219+
<summary><strong>📦 Interactive TUI & Scaffolding Engine</strong></summary>
213220
<br>
214221

215-
Stop writing boilerplate. The `zc` CLI generates consistent, production-ready domain modules and environment templates with a single command.
222+
The `zc` CLI gives you a rich, interactive Terminal User Interface (TUI) powered by Questionary and Rich. It features:
223+
224+
* **Workspace & Context Awareness:** Detects whether you are inside an active project, in a root workspace containing multiple services, or starting fresh.
225+
* **Automated `uv` / `.venv` Setup:** Initializes isolated virtual environments and installs dependencies automatically using `uv` (recommended) or standard `pip`.
226+
* **Multi-Engine Driver Bootstrapping:** Configures SQLite (`aiosqlite`), PostgreSQL (`asyncpg`), or MySQL (`aiomysql`) in `.env` and `requirements.txt` out-of-the-box.
227+
* **Granular Architectural Scaffolding:** Generates modular domain apps in 3 modes (*Full Boilerplate*, *Clean/Blank*, or *Custom Layer Selection* across Models, Schemas, Repositories, Services, Routers, Plugins, and Pytest suites).
228+
229+
```text
230+
$ zc
231+
232+
⚡ ZCore Framework v0.1.0-Beta • Modern Modular Monolith
233+
FastAPI • SQLAlchemy 2.0 • Pydantic V2
234+
235+
? What framework task would you like to perform? 📦 init — Scaffold a new full ZCore project
236+
┌ Initialize New ZCore Project
237+
│
238+
? Project directory name: core_api
239+
? Select primary database driver: PostgreSQL (asyncpg) — Production Ready
240+
? Initialize virtual environment (.venv) and install dependencies? Yes (uv)
241+
│ ✓ Environment & dependencies installed successfully.
242+
└ Project 'core_api' ready!
243+
```
244+
245+
#### CLI Command Reference
216246

217-
| Command | Purpose |
218-
|---------|---------|
219-
| `zc init <name>` | Create a new project with settings, `.env`, and `main.py` |
220-
| `zc startapp <name>` | Scaffold an empty domain module |
221-
| `zc startapp <name> --template` | Scaffold with full Model, Schema, Repo, Service, Router, and Plugin boilerplate |
222-
| `zc run` | Launch Uvicorn with auto-reload and environment-aware config |
223-
| `zc gensecret` | Generate a 64-character cryptographically secure secret key |
224-
| `zc genenv` | Introspect registered `Settings` classes and scaffold `.env.example` |
247+
| Command | Interactive | Non-Interactive Flags | Purpose |
248+
|---------|:-----------:|-----------------------|---------|
249+
| `zc` | ✅ | — | Launch interactive orchestration dashboard |
250+
| `zc init [name]` | ✅ | `--db [sqlite\|postgres\|mysql]`, `-y` | Bootstrap a new project with settings, `.env`, and dependencies |
251+
| `zc startapp [name]` | ✅ | `--template / --no-template`, `--test / --no-test`, `-y` | Scaffold domain modules with granular layer selection |
252+
| `zc run` | ✅ | — | Launch local Uvicorn dev server with auto-reload |
253+
| `zc gensecret` | — | — | Generate a 64-character cryptographically secure `SECRET_KEY` |
254+
| `zc genenv` | ✅ | `-o <output>`, `-f / --force` | Introspect active `Settings` classes and scaffold `.env.example` |
225255
</details>
226256

227257
---
@@ -245,7 +275,7 @@ Contributions are welcome! Please read our guidelines before submitting a PR.
245275

246276
- **Issues:** Bug reports and feature requests via [GitHub Issues](https://github.com/Baseryn/zcore/issues)
247277
- **PRs:** Open a pull request with a clear description of the change
248-
- **Local Setup:** `pip install -e ".[all]"` and run `hatch test` to verify
278+
- **Local Setup:** `pip install -e ".[all,dev]"` and run `hatch test` to verify
249279

250280
---
251281

@@ -257,5 +287,5 @@ See [LICENSE](https://github.com/Baseryn/zcore/blob/master/LICENSE) for details.
257287
---
258288

259289
<p align="center">
260-
<sub>Built with ☕ and architectural rigor by <a href="https://github.com/alialfostovar">Ali Alf Ostovar</a>.</sub>
290+
<sub>Built with ☕ and architectural rigor by <a href="https://github.com/alialfostovar">Ali Alf Ostovar</a> / <a href="https://github.com/Baseryn">Baseryn</a>.</sub>
261291
</p>

‎SECURITY.md‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Security Policy
22

3-
We take the security of ZCore, and the applications built on top of it, extremely seriously. Security is a core pillar of ZCore's design philosophy, integrated deeply into its architecture [security/jwt.py, security/hashing.py] rather than treated as an afterthought.
3+
We take the security of ZCore, and the applications built on top of it, extremely seriously. Security is a core pillar of ZCore's design philosophy, integrated deeply into its architecture (`zcore/security/security.py`, `zcore/web/projection.py`) rather than treated as an afterthought.
44

55
If you believe you have found a security vulnerability in ZCore, please read this document to learn how to report it responsibly.
66

@@ -87,9 +87,9 @@ The following are generally **not considered** security vulnerabilities in ZCore
8787

8888
## Hardened Defaults in ZCore
8989

90-
ZCore is built with strict, "secure-by-default" configurations [security/jwt.py, storage/local.py]:
91-
- **Production Secret Guard:** The framework will raise a fatal traceback and refuse to start in a production environment if the default fallback `SECRET_KEY` is detected [security/jwt.py].
92-
- **Argon2id default configuration:** We enforce high-entropy password hashing out-of-the-box [security/hashing.py].
93-
- **Path Traversal Protection:** The local storage provider strictly verifies resolved filesystem paths before running write or unlink operations [storage/local.py].
90+
ZCore is built with strict, "secure-by-default" configurations:
91+
- **Production Secret Guard:** The framework will raise a fatal traceback and refuse to start in a production environment if the default fallback `SECRET_KEY` is detected (`zcore/security/security.py`).
92+
- **Argon2id default configuration:** We enforce high-entropy password hashing out-of-the-box (`zcore/security/security.py`).
93+
- **Path Traversal Protection:** The local storage provider strictly verifies resolved filesystem paths before running write or unlink operations (`zcore/storage/local.py`).
9494

9595
*Note: ZCore only fails-fast (crashes) on fatal security configurations. Missing optional configuration elements (e.g., optional caching backends) will only raise non-fatal warnings.*

‎pyproject.toml‎

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,16 @@ license = { text = "Apache License 2.0" }
1212
authors = [
1313
{ name = "Ali Alf Ostovar", email = "240363843+alialfostovar@users.noreply.github.com" }
1414
]
15+
maintainers = [
16+
{ name = "Baseryn" }
17+
]
1518
classifiers = [
1619
"Development Status :: 4 - Beta",
1720
"Intended Audience :: Developers",
1821
"License :: OSI Approved :: Apache Software License",
1922
"Programming Language :: Python :: 3.11",
2023
"Programming Language :: Python :: 3.12",
24+
"Programming Language :: Python :: 3.13",
2125
"Framework :: FastAPI",
2226
"Topic :: Software Development :: Libraries :: Application Frameworks",
2327
]
@@ -30,13 +34,23 @@ dependencies = [
3034
"jsonschema>=4.21.0",
3135
"python-multipart>=0.0.9",
3236
"uvicorn>=0.22.0",
37+
"questionary>=2.0.1",
38+
"rich>=13.7.0",
3339
]
3440

3541
[project.optional-dependencies]
3642
db = [
3743
"sqlalchemy[asyncio]>=2.0.28",
3844
"aiosqlite>=0.20.0",
3945
]
46+
postgres = [
47+
"sqlalchemy[asyncio]>=2.0.28",
48+
"asyncpg>=0.29.0",
49+
]
50+
mysql = [
51+
"sqlalchemy[asyncio]>=2.0.28",
52+
"aiomysql>=0.2.0",
53+
]
4054
redis = [
4155
"redis>=5.0.3",
4256
]
@@ -50,9 +64,18 @@ crypto = [
5064
"argon2-cffi>=23.1.0",
5165
"pyjwt>=2.8.0",
5266
]
67+
dev = [
68+
"pytest>=8.0.0",
69+
"pytest-asyncio>=0.23.0",
70+
"httpx>=0.27.0",
71+
"mypy>=1.9.0",
72+
"ruff>=0.3.0",
73+
]
5374
all = [
5475
"sqlalchemy[asyncio]>=2.0.28",
5576
"aiosqlite>=0.20.0",
77+
"asyncpg>=0.29.0",
78+
"aiomysql>=0.2.0",
5679
"redis>=5.0.3",
5780
"aiofiles>=23.2.1",
5881
"argon2-cffi>=23.1.0",
@@ -81,11 +104,11 @@ testpaths = ["tests"]
81104

82105
[tool.hatch.envs.hatch-test]
83106
extra-dependencies = [
84-
'pytest-asyncio',
85-
'httpx'
107+
"pytest-asyncio",
108+
"httpx"
86109
]
87110
features = [
88-
'all'
111+
"all"
89112
]
90113

91114
[tool.ruff]

‎src/zcore/__init__.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from zcore.db.repository import BaseRepository
88
from zcore.db.search import SearchRequest
99
from zcore.db.setup import Base, SessionDep, db_manager, get_db
10+
from zcore.db.soft_delete import SoftDeleteMixin
1011
from zcore.db.uow import UnitOfWork
1112
from zcore.kernel.di import Inject, container
1213
from zcore.kernel.engine import Kernel
@@ -35,6 +36,7 @@
3536
"SearchRequest",
3637
"Security",
3738
"SessionDep",
39+
"SoftDeleteMixin",
3840
"UnitOfWork",
3941
"ZContext",
4042
"ZCoreAPIRoute",
@@ -141,5 +143,10 @@ def __getattr__(name: str) -> Any:
141143
from zcore.kernel.events import EventDispatcher
142144

143145
return EventDispatcher
146+
147+
if name == "SoftDeleteMixin":
148+
from zcore.db.soft_delete import SoftDeleteMixin
149+
150+
return SoftDeleteMixin
144151

145152
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")

0 commit comments

Comments
 (0)