diff --git a/.github/workflows/cli_test.yaml b/.github/workflows/cli_test.yaml index 7feef03..e40df67 100644 --- a/.github/workflows/cli_test.yaml +++ b/.github/workflows/cli_test.yaml @@ -1,6 +1,6 @@ name: CLI Test -on: [ push, workflow_call, pull_request ] +on: [push, workflow_call, pull_request] jobs: test: @@ -8,54 +8,54 @@ jobs: strategy: matrix: - app_type: [ "Blank", "SyncORM", "AsyncORM", "MongoDB", "PostgresSync", "PostgresAsync", "MySQLSync", "MySQLAsync" ] + app_type: ["Blank", "SyncORM", "AsyncORM", "MongoDB", "PostgresSync", "PostgresAsync", "MySQLSync", "MySQLAsync"] steps: - name: Check out repository code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: - python-version: '3.8' + python-version: '3.10' - name: Install dependencies run: | - python -m pip install --upgrade pip - pip install . + pip install poetry + poetry install - name: Test CLI Commands run: | app_name="${{ matrix.app_type }}App" case "${{ matrix.app_type }}" in "Blank") - pynest generate application -n "$app_name" + poetry run pynest generate application -n "$app_name" ;; "SyncORM") - pynest generate application -n "$app_name" -db sqlite + poetry run pynest generate application -n "$app_name" -db sqlite ;; "AsyncORM") - pynest generate application -n "$app_name" -db sqlite --is-async + poetry run pynest generate application -n "$app_name" -db sqlite --is-async ;; "MongoDB") - pynest generate application -n "$app_name" -db mongodb + poetry run pynest generate application -n "$app_name" -db mongodb ;; "PostgresSync") - pynest generate application -n "$app_name" -db postgresql + poetry run pynest generate application -n "$app_name" -db postgresql ;; "PostgresAsync") - pynest generate application -n "$app_name" -db postgresql --is-async + poetry run pynest generate application -n "$app_name" -db postgresql --is-async ;; "MySQLSync") - pynest generate application -n "$app_name" -db mysql + poetry run pynest generate application -n "$app_name" -db mysql ;; "MySQLAsync") - pynest generate application -n "$app_name" -db mysql --is-async + poetry run pynest generate application -n "$app_name" -db mysql --is-async ;; esac cd "$app_name" - pynest generate resource -n user + poetry run pynest generate resource -n user - name: Verify Boilerplate run: | @@ -74,7 +74,6 @@ jobs: exit 1 fi - # List of expected files declare -a files=("main.py" "requirements.txt" "README.md") declare -a src_level_files=("app_module.py" "app_service.py" "app_controller.py") @@ -100,7 +99,6 @@ jobs: fi done - # Check each file in the list of module_files for file in "${module_files[@]}"; do if [ -f "$app_name/src/user/$file" ]; then diff --git a/.github/workflows/deploy_docs.yaml b/.github/workflows/deploy_docs.yaml index ffe9bdb..6b59796 100644 --- a/.github/workflows/deploy_docs.yaml +++ b/.github/workflows/deploy_docs.yaml @@ -2,13 +2,11 @@ name: Deploy Docs on: [workflow_call, workflow_dispatch] -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages permissions: contents: read pages: write id-token: write -# Allow one concurrent deployment concurrency: group: "pages" cancel-in-progress: true @@ -27,15 +25,15 @@ jobs: - name: Copy License File run: cp LICENSE docs/license.md - - name: Set up Python 3.10 + - name: Set up Python uses: actions/setup-python@v4 with: python-version: "3.10" - - name: Install MKDocs + - name: Install dependencies run: | - pip install --upgrade pip - pip install mkdocs-material mkdocstrings-python + pip install poetry + poetry install --with docs - name: Build docs run: mkdocs build --clean @@ -50,4 +48,4 @@ jobs: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v1 \ No newline at end of file + uses: actions/deploy-pages@v1 diff --git a/.github/workflows/integration_test.yaml b/.github/workflows/integration_test.yaml index c82f624..ab7a9e6 100644 --- a/.github/workflows/integration_test.yaml +++ b/.github/workflows/integration_test.yaml @@ -12,17 +12,17 @@ jobs: steps: - name: Check out repository code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: - python-version: '3.8' + python-version: '3.10' - name: Install dependencies run: | - python -m pip install --upgrade pip - pip install . + pip install poetry + poetry install - name: Start Application run: | @@ -38,15 +38,15 @@ jobs: fi if [ "${{ matrix.app_type }}" == "Blank" ]; then - pynest generate application -n "$app_name" + poetry run pynest generate application -n "$app_name" else - pynest generate application -n "$app_name" -db sqlite $is_async - pip install aiosqlite + poetry run pynest generate application -n "$app_name" -db sqlite $is_async + poetry add aiosqlite fi cd "$app_name" - pynest generate resource -n user - uvicorn "src.app_module:http_server" --host "0.0.0.0" --port 8000 --reload & + poetry run pynest generate resource -n user + poetry run uvicorn "src.app_module:http_server" --host "0.0.0.0" --port 8000 --reload & - name: Wait for the server to start run: sleep 10 diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index b9c3ae7..89ce472 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -5,21 +5,23 @@ on: [push, workflow_call, pull_request] jobs: test: runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10", "3.11"] + steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v3 + + - name: Install Python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} - - name: Install Python - id: setup_python - uses: actions/setup-python@v4 - with: - python-version: | - 3.7 - 3.8 - 3.9 - 3.10 - 3.11 + - name: Install dependencies + run: | + pip install poetry + poetry install --with test - - name: Run tests - run: | - pip install -r requirements-tests.txt - pytest tests \ No newline at end of file + - name: Run tests + run: | + poetry run pytest tests diff --git a/README.md b/README.md index 985ac6d..35324d1 100644 --- a/README.md +++ b/README.md @@ -23,20 +23,26 @@ PyNest is designed to help structure your APIs in an intuitive, easy to understand, and enjoyable way. -With PyNest, you can build scalable and maintainable APIs with ease. The framework supports dependency injection, type +`With PyNest, you can build scalable and maintainable APIs with ease. The framework supports dependency injection, type annotations, decorators, and code generation, making it easy to write clean and testable code. This framework is not a direct port of NestJS to Python but rather a re-imagining of the framework specifically for Python developers, including backend engineers and ML engineers. It aims to assist them in building better and faster APIs for their data applications. - +` ## Getting Started To get started with PyNest, you'll need to install it using pip: -```bash -pip install pynest-api -``` +=== "pip" + ```bash + pip install pynest-api + ``` + +=== "Poetry" + ```bash + poetry add pynest-api + ``` ### Start with cli @@ -47,13 +53,15 @@ pynest generate appplication -n my_app_name this command will create a new project with the following structure: ```text -├── app.py ├── main.py ├── requirements.txt ├── .gitignore ├── README.md ├── src │ ├── __init__.py +│ ├── app_module.py +│ ├── app_controller.py +│ ├── app_service.py ``` once you have created your app, get into the folder and run the following command: @@ -65,7 +73,7 @@ cd my_app_name run the server with the following command: ```bash -uvicorn "app:app" --host "0.0.0.0" --port "8000" --reload +uvicorn "src.app_module:http_server" --host "0.0.0.0" --port "8000" --reload ``` Now you can visit [OpenAPI](http://localhost:8000/docs) in your browser to see the default API documentation. @@ -75,20 +83,20 @@ Now you can visit [OpenAPI](http://localhost:8000/docs) in your browser to see t To add a new module to your application, you can use the pynest generate module command: ```bash -pynest generate resource -n users +pynest generate resource -n user ``` -This will create a new resource called ```users``` in your application with the following structure under the ```src``` +This will create a new resource called ```user``` in your application with the following structure under the ```src``` folder: ```text ├── users │ ├── __init__.py -│ ├── users_controller.py -│ ├── users_service.py -│ ├── users_model.py -│ ├── users_entity.py -│ ├── users_module.py +│ ├── user_controller.py +│ ├── user_service.py +│ ├── user_model.py +│ ├── user_entity.py +│ ├── user_module.py ``` The users module will immediately register itself with the application and will be available for use. @@ -113,6 +121,7 @@ and their descriptions: - `--app-name`/`-n`: The name of the nest app (required). - `--db-type`/`-db`: The type of the database (optional). You can specify PostgreSQL, MySQL, SQLite, or MongoDB. - `--is-async`: Whether the project should be asynchronous (optional, default is False). + - `--is-cli`: For creating CLI-based application (optional, default is False). ### `generate` command group @@ -133,7 +142,7 @@ and their descriptions: `pynest generate application -n my_app_name -db postgresql --is-async` * create new module - - `pynest generate resource -n users` + `pynest generate resource -n user` ## Key Features @@ -162,15 +171,6 @@ controllers, services, and providers with types to make your code more robust. PyNest includes a code generation tool that can create boilerplate code for modules, controllers, and other components. This saves you time and helps you focus on writing the code that matters. -## Future Plans - -- [ ] Create plugins Marketplace for modules where developers can share their modules and download modules created by - others. -- [ ] Implement IOC mechanism and introduce Module decorator -- [ ] Add support for new databases -- [ ] Create out-of-the-box authentication module that can be easily integrated into any application. -- [ ] Add support for other testing frameworks and create testing templates. -- [ ] Add support for other web frameworks (Litestar, blackship, etc.) - Same Architecture, different engine. ## Contributing diff --git a/docs/async_orm.md b/docs/async_orm.md index 6a6d512..10541a1 100644 --- a/docs/async_orm.md +++ b/docs/async_orm.md @@ -35,7 +35,7 @@ pip install asyncpg #### Create a new project ```bash -pynest create-nest-app -n my_app_name -db postgresql --is-async +pynest generate application -n my_app_name -db postgresql --is-async ``` this command will create a new project with the following structure: @@ -76,21 +76,21 @@ once you have created your app, this is the code that support the asynchronous f `config.py` ```python -from nest.core.database.orm_provider import AsyncOrmProvider +from nest.database.orm_provider import AsyncOrmProvider import os from dotenv import load_dotenv load_dotenv() config = AsyncOrmProvider( - db_type="postgresql", - config_params=dict( - host=os.getenv("POSTGRESQL_HOST", "localhost"), - db_name=os.getenv("POSTGRESQL_DB_NAME", "default_nest_db"), - user=os.getenv("POSTGRESQL_USER", "postgres"), - password=os.getenv("POSTGRESQL_PASSWORD", "postgres"), - port=int(os.getenv("POSTGRESQL_PORT", 5432)), - ) + db_type="postgresql", + config_params=dict( + host=os.getenv("POSTGRESQL_HOST", "localhost"), + db_name=os.getenv("POSTGRESQL_DB_NAME", "default_nest_db"), + user=os.getenv("POSTGRESQL_USER", "postgres"), + password=os.getenv("POSTGRESQL_PASSWORD", "postgres"), + port=int(os.getenv("POSTGRESQL_PORT", 5432)), + ) ) ``` @@ -116,7 +116,7 @@ class AppService: `app_controller.py` ```python -from nest.core import Controller, Get +from nest.web import Controller, Get from .app_service import AppService @@ -143,7 +143,8 @@ from .example.example_module import ExampleModule from .app_controller import AppController from .app_service import AppService -from nest.core import Module, PyNestFactory +from nest.core import Module +from nest.web import PyNestWebFactory @Module( @@ -155,7 +156,7 @@ class AppModule: pass -app = PyNestFactory.create(AppModule, description="This is my FastAPI app drive by Async ORM Engine", title="My App", +app = PyNestWebFactory.create(AppModule, description="This is my FastAPI app drive by Async ORM Engine", title="My App", version="1.0.0", debug=True) http_server = app.get_server() @@ -171,7 +172,7 @@ decorator. The imports array includes the modules required by this module. In this case, ExampleModule is imported. The controllers and providers arrays are empty here, indicating this module doesn't directly provide any controllers or services. -`PyNestFactory.create()` is a command to create an instance of the application. +`PyNestWebFactory.create()` is a command to create an instance of the application. The AppModule is passed as an argument, which acts as the root module of the application. Additional metadata like description, title, version, and debug flag are also provided @@ -225,7 +226,7 @@ There are two ways of creating service. from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession -from nest.core.decorators.database import async_db_request_handler +from nest.database import async_db_request_handler from nest.core import Injectable from .example_entity import Example as ExampleEntity @@ -234,18 +235,18 @@ from .example_model import Example @Injectable class ExampleService: - @async_db_request_handler - async def add_example(self, example: Example, session: AsyncSession): - new_example = ExampleEntity(**example.dict()) - session.add(new_example) - await session.commit() - return new_example.id - - @async_db_request_handler - async def get_example(self, session: AsyncSession): - query = select(ExampleEntity) - result = await session.execute(query) - return result.scalars().all() + @async_db_request_handler + async def add_example(self, example: Example, session: AsyncSession): + new_example = ExampleEntity(**example.dict()) + session.add(new_example) + await session.commit() + return new_example.id + + @async_db_request_handler + async def get_example(self, session: AsyncSession): + query = select(ExampleEntity) + result = await session.execute(query) + return result.scalars().all() ``` 2. In that way, the service init the async session in the constructor, and each function that depends on the database is @@ -255,7 +256,7 @@ class ExampleService: from .examples_model import Examples from .examples_entity import Examples as ExamplesEntity from src.config import config -from nest.core.decorators.database import async_db_request_handler +from nest.database import async_db_request_handler from nest.core import Injectable from sqlalchemy import select @@ -263,26 +264,26 @@ from sqlalchemy import select @Injectable class ExamplesService: - def __init__(self): - self.orm_config = config - self.session = self.orm_config.get_session - - @async_db_request_handler - async def add_examples(self, examples: Examples): - examples_entity = ExamplesEntity( - **examples.dict() - ) - async with self.session() as session: - session.add(examples_entity) - await session.commit() - return examples_entity.id - - @async_db_request_handler - async def get_examples(self): - query = select(ExamplesEntity) - async with self.session() as session: - result = await session.execute(query) - return result.scalars().all() + def __init__(self): + self.orm_config = config + self.session = self.orm_config.get_session + + @async_db_request_handler + async def add_examples(self, examples: Examples): + examples_entity = ExamplesEntity( + **examples.dict() + ) + async with self.session() as session: + session.add(examples_entity) + await session.commit() + return examples_entity.id + + @async_db_request_handler + async def get_examples(self): + query = select(ExamplesEntity) + async with self.session() as session: + result = await session.execute(query) + return result.scalars().all() ``` create a controller to handle the requests and responses. The controller should call the service to execute business @@ -293,7 +294,7 @@ Here we have also two ways of creating the controller. 1. In that way, the controller's functions are getting the async session from the config ```python -from nest.core import Controller, Get, Post, Depends +from nest.web import Controller, Get, Post, Depends from .examples_service import ExamplesService from .examples_model import Examples @@ -321,7 +322,7 @@ class ExamplesController: in his constructor. ```python -from nest.core import Controller, Get, Post +from nest.web import Controller, Get, Post from .examples_service import ExamplesService from .examples_model import Examples diff --git a/docs/blank.md b/docs/blank.md index c6ea9aa..9ce4284 100644 --- a/docs/blank.md +++ b/docs/blank.md @@ -1,4 +1,4 @@ -# Blank Application with PyNest +___# Blank Application with PyNest ## Introduction @@ -24,8 +24,8 @@ pip install pynest-api #### Create a new project ```bash -pynest create-nest-app -n my_app_name -``` +pynest generate application -n my_app_name +```___ this command will create a new project with the following structure: @@ -77,7 +77,7 @@ class AppService: `app_controller.py` ```python -from nest.core import Controller, Get +from nest.web import Controller, Get from .app_service import AppService @@ -96,7 +96,8 @@ class AppController: `app_module.py` ```python -from nest.core import PyNestFactory, Module +from nest.core import Module +from nest.web import PyNestWebFactory from src.example.example_module import ExampleModule from .app_controller import AppController from .app_service import AppService @@ -112,7 +113,7 @@ class AppModule: pass -app = PyNestFactory.create(AppModule, description="This is my FastAPI app", title="My App", version="1.0.0", debug=True) +app = PyNestWebFactory.create(AppModule, description="This is my FastAPI app", title="My App", version="1.0.0", debug=True) http_server: FastAPI = app.get_server() ``` @@ -120,7 +121,7 @@ http_server: FastAPI = app.get_server() `@Module(...)`: This is a decorator that defines a module. In PyNest, a module is a class annotated with a `@Module()` decorator. The imports array includes the modules required by this module. In this case, ExampleModule is imported. The controllers and providers arrays are empty here, indicating this module doesn't directly provide any controllers or services. -`PyNestFactory.create()` is a command to create an instance of the application. +`PyNestWebFactory.create()` is a command to create an instance of the application. The AppModule is passed as an argument, which acts as the root module of the application. Additional metadata like description, title, version, and debug flag are also provided @@ -171,7 +172,7 @@ logic. `example_controller.py` ```python -from nest.core import Controller, Get, Post +from nest.web import Controller, Get, Post from .examples_service import ExamplesService from .examples_model import Examples diff --git a/nest/core/database/__init__.py b/docs/cli_app.md similarity index 100% rename from nest/core/database/__init__.py rename to docs/cli_app.md diff --git a/docs/controllers.md b/docs/controllers.md index d148eb9..2780442 100644 --- a/docs/controllers.md +++ b/docs/controllers.md @@ -9,7 +9,8 @@ This decorator is required to define a controller and specify an optional route which helps group related routes and minimize repetitive code. ```python -from nest.core import Controller, Get, Post +from nest.web import Controller, Get, Post +from src.book.book_service import BookService @Controller('/books') class BookController: @@ -29,7 +30,7 @@ class BookController: Let's take this step by step: ```python -from nest.core import Controller, Get, Post +from nest.web import Controller, Get, Post ``` PyNest exposes an api for creating Controllers, a class that is responsible for the module routing and requests handling. @@ -76,7 +77,7 @@ Each controller can have multiple routes, and different routes can perform diffe ### Example ```python -from nest.core import Controller, Get, Post +from nest.web import Controller, Get, Post @Controller('/book') class BookController: @@ -106,7 +107,7 @@ Since pynest is an abstraction of fastapi, we can use those methods in the same ### Example ```python -from nest.core import Controller, Get, Post +from nest.web import Controller, Get, Post from .book_service import BookService from typing import List @@ -170,7 +171,7 @@ POST, PUT, DELETE, etc. ### Full CRUD Example ```python -from nest.core import Controller, Get, Post, Put, Delete +from nest.web import Controller, Get, Post, Put, Delete from .book_service import BookService from .book_models import Book diff --git a/docs/dependency_injection.md b/docs/dependency_injection.md index 4014799..2e35d7b 100644 --- a/docs/dependency_injection.md +++ b/docs/dependency_injection.md @@ -43,7 +43,7 @@ class LoggerModule: ### Injecting the Provider into a Controller ```python # app_controller.py -from nest.core import Controller, Get +from nest.web import Controller, Get from src.providers.logger.logger_service import LoggerService @Controller('/') diff --git a/docs/getting_started.md b/docs/getting_started.md index 83fbce6..edde9d8 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -4,11 +4,17 @@ This guide will help you get started with setting up a new PyNest project, creat ## Installation -To install PyNest, ensure you have Python 3.9+ installed. Then, install PyNest using pip: +To install PyNest, ensure you have Python 3.10+ installed. Then, install PyNest using your preferred package manager: -```bash -pip install pynest-api -``` +=== "pip" + ```bash + pip install pynest-api + ``` + +=== "Poetry" + ```bash + poetry add pynest-api + ``` ## Creating a New Project 📂 @@ -19,6 +25,20 @@ mkdir my_pynest_project cd my_pynest_project ``` +You can simply use the pynest-cli to create the project structure: + +=== "pip" + ```bash + pynest generate application -n . + ``` + +=== "Poetry" + ```bash + poetry run pynest generate application -n . + ``` + +Or you can create the file structure manually. + ## Creating the Application Structure 🏗️ We'll create the basic structure of a PyNest application. Here's what it will look like: @@ -42,7 +62,8 @@ The app_module.py file is where we define our main application module. Create th ```python # src/app_module.py -from nest.core import Module, PyNestFactory +from nest.core import Module +from nest.web import PyNestWebFactory from .app_controller import AppController from .app_service import AppService @@ -53,12 +74,13 @@ from .app_service import AppService class AppModule: pass -app = PyNestFactory.create( +app = PyNestWebFactory.create( AppModule, description="This is my PyNest app", title="My App", version="1.0.0", - debug=True, + # here you can add more of the fastapi kwargs as describe here - + # https://fastapi.tiangolo.com/reference/fastapi/#fastapi.FastAPI ) http_server = app.get_server() @@ -90,7 +112,7 @@ The app_controller.py file will handle the routing and responses. Create the fil ```python # src/app_controller.py -from nest.core import Controller, Get +from nest.web import Controller, Get from .app_service import AppService @Controller("/") @@ -111,10 +133,9 @@ The main.py file will run our PyNest application. Create the file and add the fo # main.py import uvicorn -from src.app_module import http_server if __name__ == "__main__": - uvicorn.run(http_server, host="0.0.0.0", port=8000, reload=True) + uvicorn.run("src.app_module:http_server", host="0.0.0.0", port=8000, reload=True) ``` ### File Structure 🗂️ diff --git a/docs/index.html b/docs/index.html index 3c0694c..4250eae 100644 --- a/docs/index.html +++ b/docs/index.html @@ -449,7 +449,8 @@
-from nest.core import PyNestFactory, Module, Controller, Get, Injectable
+from nest.core import Module, Injectable
+from nest.web import Controller, Get
@Injectable()
class AppService:
@@ -473,7 +474,7 @@ Get Started with PyNest
class AppModule:
pass
-app = PyNestFactory.create(
+app = PyNestWebFactory.create(
AppModule,
description="This is my PyNest app.",
title="PyNest Application",
diff --git a/docs/mongodb.md b/docs/mongodb.md
index 85cd40b..f292afb 100644
--- a/docs/mongodb.md
+++ b/docs/mongodb.md
@@ -37,22 +37,27 @@ read more about motor [here](https://motor.readthedocs.io/en/stable/)
Ensure you have the latest version of PyNest and SQLAlchemy 2.0 installed. You can install them using pip:
-```bash
-pip install pynest-api
-```
+=== "pip"
+ ```bash
+ pip install pynest-api[mongo, fastapi]
+ ```
+
+=== "Poetry"
+ ```bash
+ poetry add pynest-api[mongo, fastapi]
+ ```
## Start with cli
#### Create a new project
```bash
-pynest create-nest-app -n my_app_name -db mongodb
+pynest generate application -n my_app_name -db mongodb
```
this command will create a new project with the following structure:
```text
-├── app.py
├── main.py
|── requirements.txt
|── README.md
@@ -67,19 +72,19 @@ this command will create a new project with the following structure:
once you have created your app, you can create a new module:
```bash
-pynest g module -n examples
+pynest g module -n example
```
-This will create a new module called examples in your application with the following structure under the src folder:
+This will create a new module called `example` in your application with the following structure under the src folder:
```text
-├── examples
+├── example
│ ├── __init__.py
-│ ├── examples_controller.py
-│ ├── examples_service.py
-│ ├── examples_model.py
-│ ├── examples_entity.py
-│ ├── examples_module.py
+│ ├── example_controller.py
+│ ├── example_service.py
+│ ├── example_model.py
+│ ├── example_entity.py
+│ ├── example_module.py
```
Let's go over the boilerplate code that support the mongo integration:
@@ -87,26 +92,26 @@ Let's go over the boilerplate code that support the mongo integration:
`config.py`
```python
-from nest.core.database.odm_provider import OdmProvider
-from src.examples.examples_entity import Examples
+from nest.database.odm_provider import OdmProvider
+from src.example.example_entity import Example
import os
from dotenv import load_dotenv
load_dotenv()
config = OdmProvider(
- config_params={{
+ config_params={
"db_name": os.getenv("DB_NAME", "default_nest_db"),
"host": os.getenv("DB_HOST", "localhost"),
"user": os.getenv("DB_USER", "root"),
"password": os.getenv("DB_PASSWORD", "root"),
"port": os.getenv("DB_PORT", 27017),
- }},
- document_models=[Examples]
+ },
+ document_models=[Example]
)
```
-Note: you can add any parameters that needed in order to configure the database connection.
+Note: you can add any parameters that needed in order to configure the database connection inside the config params.
`app_service.py`
@@ -127,9 +132,9 @@ class AppService:
`app_controller.py`
```python
-from nest.core import Controller, Get
+from nest.web import Controller, Get
-from .app_service import AppService
+from src.app_service import AppService
@Controller("/")
@@ -148,17 +153,18 @@ Now we need to declare the App object and register the module in
`app_module.py`
```python
-from .config import config
+from src.config import config
-from nest.core import Module, PyNestFactory
-from src.examples.examples_module import ExamplesModule
+from nest.core import Module
+from nest.web import PyNestWebFactory
+from src.example.example_module import ExampleModule
-from .app_controller import AppController
-from .app_service import AppService
+from src.app_controller import AppController
+from src.app_service import AppService
@Module(
- imports=[ExamplesModule],
+ imports=[ExampleModule],
controllers=[AppController],
providers=[AppService],
)
@@ -166,7 +172,7 @@ class AppModule:
pass
-app = PyNestFactory.create(
+app = PyNestWebFactory.create(
AppModule,
description="This is my FastAPI app drive by MongoDB Engine",
title="My App",
@@ -187,11 +193,11 @@ decorator.
The imports array includes the modules required by this module. In this case, ExampleModule is imported. The controllers
and providers arrays are empty here, indicating this module doesn't directly provide any controllers or services.
-`PyNestFactory.create()` is a command to create an instance of the application.
+`PyNestWebFactory.create()` is a command to create an instance of the application.
The AppModule is passed as an argument, which acts as the root module of the application.
Additional metadata like description, title, version, and debug flag are also provided
-`http_server: FastAPI = app.get_server()`: Retrieves the HTTP server instance from the application.
+`http_server = app.get_server()`: Retrieves the HTTP server instance from the application.
### Creating Entity
@@ -220,7 +226,7 @@ Define your model using Pydantic. For example, the Examples model:
from pydantic import BaseModel
-class Examples(BaseModel):
+class Example(BaseModel):
name: str
```
@@ -229,9 +235,9 @@ class Examples(BaseModel):
Implement services to handle business logic.
```python
-from .examples_model import Examples
-from .examples_entity import Examples as ExamplesEntity
-from nest.core.decorators.database import db_request_handler
+from .example_model import Examples
+from .example_entity import Example as ExamplesEntity
+from nest.database import db_request_handler
from nest.core import Injectable
@@ -239,15 +245,15 @@ from nest.core import Injectable
class ExamplesService:
@db_request_handler
- async def add_examples(self, examples: Examples):
- new_examples = ExamplesEntity(
- **examples.dict()
+ async def add_example(self, example: Examples):
+ new_example = ExamplesEntity(
+ **example.dict()
)
- await new_examples.save()
- return new_examples.id
+ await new_example.save()
+ return new_example.id
@db_request_handler
- async def get_examples(self):
+ async def get_example(self):
return await ExamplesEntity.find_all().to_list()
```
@@ -255,25 +261,25 @@ create a controller to handle the requests and responses. The controller should
logic.
```python
-from nest.core import Controller, Get, Post
+from nest.web import Controller, Get, Post
-from .examples_service import ExamplesService
-from .examples_model import Examples
+from .example_service import ExampleService
+from .example_model import Example
-@Controller("examples")
-class ExamplesController:
+@Controller("example")
+class ExampleController:
- def __init__(self, service: ExamplesService):
+ def __init__(self, service: ExampleService):
self.service = service
@Get("/")
- async def get_examples(self):
- return await self.service.get_examples()
+ async def get_example(self):
+ return await self.service.get_example()
@Post("/")
- async def add_examples(self, examples: Examples):
- return await self.service.add_examples(examples)
+ async def add_example(self, example: Example):
+ return await self.service.add_example(example)
```
### Creating Module
@@ -282,15 +288,15 @@ Create a module to register the controller and service.
```python
from nest.core import Module
-from .examples_controller import ExamplesController
-from .examples_service import ExamplesService
+from .example_controller import ExampleController
+from .example_service import ExampleService
@Module(
- controllers=[ExamplesController],
- providers=[ExamplesService]
+ controllers=[ExampleController],
+ providers=[ExampleService]
)
-class ExamplesModule:
+class ExampleModule:
pass
```
diff --git a/docs/providers.md b/docs/providers.md
index a6fb106..d5825dd 100644
--- a/docs/providers.md
+++ b/docs/providers.md
@@ -82,7 +82,7 @@ In this Service, the `LoggerService` is injected into the `S3Service` via the co
`s3_controller.py`
```python
-from nest.core import Controller, Post
+from nest.web import Controller, Post
from .s3_service import S3Service
@Controller('/s3')
diff --git a/docs/sync_orm.md b/docs/sync_orm.md
index b69b251..55690b3 100644
--- a/docs/sync_orm.md
+++ b/docs/sync_orm.md
@@ -25,7 +25,7 @@ pip install pynest-api
#### Create a new project
```bash
-pynest create-nest-app -n my_app_name -db postgresql
+pynest generate application -n my_app_name -db postgresql
```
this command will create a new project with the following structure:
@@ -66,7 +66,7 @@ Let's go over the boilerplate code that generated by the cli:
`config.py`
```python
-from nest.core.database.orm_provider import OrmProvider
+from nest.database.orm_provider import OrmProvider
import os
from dotenv import load_dotenv
@@ -103,7 +103,7 @@ class AppService:
`app_controller.py`
```python
-from nest.core import Controller, Get
+from nest.web import Controller, Get
from .app_service import AppService
@@ -123,7 +123,8 @@ class AppController:
```python
from src.config import config
-from nest.core import PyNestFactory, Module
+from nest.core import Module
+from nest.web import PyNestWebFactory
from src.example.example_module import ExampleModule
from fastapi import FastAPI
@@ -135,7 +136,7 @@ class AppModule:
pass
-app = PyNestFactory.create(AppModule, description="This is my FastAPI app drive by ORM Engine", title="My App",
+app = PyNestWebFactory.create(AppModule, description="This is my FastAPI app drive by ORM Engine", title="My App",
version="1.0.0", debug=True)
http_server: FastAPI = app.get_server()
@@ -151,7 +152,7 @@ decorator.
The imports array includes the modules required by this module. In this case, ExampleModule is imported. The controllers
and providers arrays are empty here, indicating this module doesn't directly provide any controllers or services.
-`PyNestFactory.create()` is a command to create an instance of the application.
+`PyNestWebFactory.create()` is a command to create an instance of the application.
The AppModule is passed as an argument, which acts as the root module of the application.
Additional metadata like description, title, version, and debug flag are also provided
@@ -185,7 +186,7 @@ Implement services to handle business logic.
from src.config import config
from .examples_model import Examples
from .examples_entity import Examples as ExamplesEntity
-from nest.core.decorators.database import db_request_handler
+from nest.database import db_request_handler
from nest.core import Injectable
@@ -218,7 +219,7 @@ business logic.
`examples_controller.py`
```python
-from nest.core import Controller, Get, Post, Depends
+from nest.web import Controller, Get, Post, Depends
from .examples_service import ExamplesService
from .examples_model import Examples
diff --git a/examples/BlankApp/src/app_controller.py b/examples/BlankApp/src/app_controller.py
index 286e872..8ee9b09 100644
--- a/examples/BlankApp/src/app_controller.py
+++ b/examples/BlankApp/src/app_controller.py
@@ -1,4 +1,4 @@
-from nest.core import Controller, Get
+from nest.web import Controller, Get
from .app_service import AppService
diff --git a/examples/BlankApp/src/app_module.py b/examples/BlankApp/src/app_module.py
index a84edbd..a437e1a 100644
--- a/examples/BlankApp/src/app_module.py
+++ b/examples/BlankApp/src/app_module.py
@@ -1,6 +1,7 @@
from fastapi import FastAPI
-from nest.core import Module, PyNestFactory
+from nest.core import Module
+from nest.web import PyNestWebFactory
from .app_controller import AppController
from .app_service import AppService
@@ -18,7 +19,7 @@ class AppModule:
pass
-app = PyNestFactory.create(
+app = PyNestWebFactory.create(
AppModule,
description="This is my FastAPI app.",
title="My App",
diff --git a/examples/BlankApp/src/example/example_controller.py b/examples/BlankApp/src/example/example_controller.py
index fcfd0d8..62138e4 100644
--- a/examples/BlankApp/src/example/example_controller.py
+++ b/examples/BlankApp/src/example/example_controller.py
@@ -1,4 +1,4 @@
-from nest.core import Controller, Get, HttpCode, Post
+from nest.web import Controller, Get, Post
from .example_model import Example
from .example_service import ExampleService
@@ -14,6 +14,5 @@ def get_example(self):
return self.service.get_example()
@Post("/")
- @HttpCode(201)
def add_example(self, example: Example):
return self.service.add_example(example)
diff --git a/examples/BlankApp/src/example/example_service.py b/examples/BlankApp/src/example/example_service.py
index dd7cfb2..14c0073 100644
--- a/examples/BlankApp/src/example/example_service.py
+++ b/examples/BlankApp/src/example/example_service.py
@@ -1,4 +1,4 @@
-from nest.core.decorators import Injectable
+from nest.core import Injectable
from ..user.user_service import UserService
from .example_model import Example
diff --git a/examples/BlankApp/src/product/product_controller.py b/examples/BlankApp/src/product/product_controller.py
index 063260f..076c97f 100644
--- a/examples/BlankApp/src/product/product_controller.py
+++ b/examples/BlankApp/src/product/product_controller.py
@@ -1,4 +1,4 @@
-from nest.core import Controller, Get, Post
+from nest.web import Controller, Get, Post
from .product_model import Product
from .product_service import ProductService
diff --git a/examples/BlankApp/src/user/user_controller.py b/examples/BlankApp/src/user/user_controller.py
index b59d9f6..5920b97 100644
--- a/examples/BlankApp/src/user/user_controller.py
+++ b/examples/BlankApp/src/user/user_controller.py
@@ -1,4 +1,4 @@
-from nest.core import Controller, Depends, Get, Post
+from nest.web import Controller, Get, Post
from .user_model import User
from .user_service import UserService
diff --git a/examples/BlankApp/src/user/user_service.py b/examples/BlankApp/src/user/user_service.py
index 90354ba..2d92805 100644
--- a/examples/BlankApp/src/user/user_service.py
+++ b/examples/BlankApp/src/user/user_service.py
@@ -1,6 +1,6 @@
import time
-from nest.core.decorators import Injectable
+from nest.core import Injectable
from .user_model import User
@@ -9,8 +9,6 @@
class UserService:
def __init__(self):
self.database = []
- time.sleep(5)
- print("UserService initialized")
def get_user(self):
return self.database
diff --git a/examples/CommandLineApp/src/app_controller.py b/examples/CommandLineApp/src/app_controller.py
index f509a6c..8563cd6 100644
--- a/examples/CommandLineApp/src/app_controller.py
+++ b/examples/CommandLineApp/src/app_controller.py
@@ -1,4 +1,4 @@
-from nest.core.decorators.cli.cli_decorators import CliCommand, CliController
+from nest.cli.cli_decorators import CliCommand, CliController
from .app_service import AppService
diff --git a/examples/CommandLineApp/src/app_module.py b/examples/CommandLineApp/src/app_module.py
index 0c5b7fb..91d740b 100644
--- a/examples/CommandLineApp/src/app_module.py
+++ b/examples/CommandLineApp/src/app_module.py
@@ -1,6 +1,5 @@
+from nest.cli.cli_factory import CLIAppFactory
from nest.core import Module
-from nest.core.cli_factory import CLIAppFactory
-from nest.core.pynest_factory import PyNestFactory
from .app_controller import AppController
from .app_service import AppService
diff --git a/examples/CommandLineApp/src/user/user_controller.py b/examples/CommandLineApp/src/user/user_controller.py
index 08d2547..70ce440 100644
--- a/examples/CommandLineApp/src/user/user_controller.py
+++ b/examples/CommandLineApp/src/user/user_controller.py
@@ -1,7 +1,7 @@
import click
from examples.CommandLineApp.src.user.user_service import UserService
-from nest.core.decorators.cli.cli_decorators import CliCommand, CliController
+from nest.cli.cli_decorators import CliCommand, CliController
class ListOptions:
diff --git a/examples/MongoApp/src/app_controller.py b/examples/MongoApp/src/app_controller.py
index 286e872..8ee9b09 100644
--- a/examples/MongoApp/src/app_controller.py
+++ b/examples/MongoApp/src/app_controller.py
@@ -1,4 +1,4 @@
-from nest.core import Controller, Get
+from nest.web import Controller, Get
from .app_service import AppService
diff --git a/examples/MongoApp/src/app_module.py b/examples/MongoApp/src/app_module.py
index f186cce..a16fecc 100644
--- a/examples/MongoApp/src/app_module.py
+++ b/examples/MongoApp/src/app_module.py
@@ -1,4 +1,5 @@
-from nest.core import Module, PyNestFactory
+from nest.core import Module
+from nest.web import PyNestWebFactory
from .app_controller import AppController
from .app_service import AppService
@@ -17,7 +18,7 @@ class AppModule:
pass
-app = PyNestFactory.create(
+app = PyNestWebFactory.create(
AppModule,
description="This is my FastAPI app drive by MongoDB Engine",
title="My App",
diff --git a/examples/MongoApp/src/config.py b/examples/MongoApp/src/config.py
index 78256ad..e786903 100644
--- a/examples/MongoApp/src/config.py
+++ b/examples/MongoApp/src/config.py
@@ -2,7 +2,7 @@
from dotenv import load_dotenv
-from nest.core.database.odm_provider import OdmProvider
+from nest.database.odm_provider import OdmProvider
from .example.example_entity import Example
from .product.product_entity import Product
diff --git a/examples/MongoApp/src/example/example_controller.py b/examples/MongoApp/src/example/example_controller.py
index dd5dcea..35036f7 100644
--- a/examples/MongoApp/src/example/example_controller.py
+++ b/examples/MongoApp/src/example/example_controller.py
@@ -1,4 +1,4 @@
-from nest.core import Controller, Get, Post
+from nest.web import Controller, Get, Post
from .example_model import Example
from .example_service import ExampleService
diff --git a/examples/MongoApp/src/example/example_service.py b/examples/MongoApp/src/example/example_service.py
index cc08a52..e196d83 100644
--- a/examples/MongoApp/src/example/example_service.py
+++ b/examples/MongoApp/src/example/example_service.py
@@ -1,5 +1,5 @@
from nest.core import Injectable
-from nest.core.decorators.database import db_request_handler
+from nest.database import db_request_handler
from .example_entity import Example as ExampleEntity
from .example_model import Example
diff --git a/examples/MongoApp/src/product/product_controller.py b/examples/MongoApp/src/product/product_controller.py
index 0966eb6..85d31a8 100644
--- a/examples/MongoApp/src/product/product_controller.py
+++ b/examples/MongoApp/src/product/product_controller.py
@@ -1,4 +1,4 @@
-from nest.core import Controller, Depends, Get, Post
+from nest.web import Controller, Depends, Get, Post
from .product_model import Product
from .product_service import ProductService
diff --git a/examples/MongoApp/src/product/product_service.py b/examples/MongoApp/src/product/product_service.py
index f0f72a9..3606c0c 100644
--- a/examples/MongoApp/src/product/product_service.py
+++ b/examples/MongoApp/src/product/product_service.py
@@ -1,5 +1,5 @@
from nest.core import Injectable
-from nest.core.decorators.database import db_request_handler
+from nest.database import db_request_handler
from .product_entity import Product as ProductEntity
from .product_model import Product
diff --git a/examples/MongoApp/src/user/user_controller.py b/examples/MongoApp/src/user/user_controller.py
index d873f5b..b7b4752 100644
--- a/examples/MongoApp/src/user/user_controller.py
+++ b/examples/MongoApp/src/user/user_controller.py
@@ -1,4 +1,4 @@
-from nest.core import Controller, Depends, Get, Post
+from nest.web import Controller, Depends, Get, Post
from .user_model import User
from .user_service import UserService
diff --git a/examples/MongoApp/src/user/user_service.py b/examples/MongoApp/src/user/user_service.py
index 90bed1b..f0e0773 100644
--- a/examples/MongoApp/src/user/user_service.py
+++ b/examples/MongoApp/src/user/user_service.py
@@ -1,5 +1,5 @@
from nest.core import Injectable
-from nest.core.decorators.database import db_request_handler
+from nest.database import db_request_handler
from .user_entity import User as UserEntity
from .user_model import User
diff --git a/examples/OrmAsyncApp/src/app_controller.py b/examples/OrmAsyncApp/src/app_controller.py
index 9c64b53..0ea5b09 100644
--- a/examples/OrmAsyncApp/src/app_controller.py
+++ b/examples/OrmAsyncApp/src/app_controller.py
@@ -1,4 +1,4 @@
-from nest.core import Controller, Get
+from nest.web import Controller, Get
from .app_service import AppService
diff --git a/examples/OrmAsyncApp/src/app_module.py b/examples/OrmAsyncApp/src/app_module.py
index 1a25138..82d05d8 100644
--- a/examples/OrmAsyncApp/src/app_module.py
+++ b/examples/OrmAsyncApp/src/app_module.py
@@ -1,5 +1,5 @@
-from nest.core import Module, PyNestFactory
-
+from nest.core import Module
+from nest.web import PyNestWebFactory
from .app_controller import AppController
from .app_service import AppService
from .config import config
@@ -17,7 +17,7 @@ class AppModule:
pass
-app = PyNestFactory.create(
+app = PyNestWebFactory.create(
AppModule,
description="This is my FastAPI app drive by Async ORM Engine",
title="My App",
diff --git a/examples/OrmAsyncApp/src/config.py b/examples/OrmAsyncApp/src/config.py
index deaa2d2..2814f6d 100644
--- a/examples/OrmAsyncApp/src/config.py
+++ b/examples/OrmAsyncApp/src/config.py
@@ -2,7 +2,7 @@
from dotenv import load_dotenv
-from nest.core.database.orm_provider import AsyncOrmProvider
+from nest.database.orm_provider import AsyncOrmProvider
load_dotenv()
diff --git a/examples/OrmAsyncApp/src/example/example_controller.py b/examples/OrmAsyncApp/src/example/example_controller.py
index 4f5f6fa..4caf94d 100644
--- a/examples/OrmAsyncApp/src/example/example_controller.py
+++ b/examples/OrmAsyncApp/src/example/example_controller.py
@@ -1,6 +1,6 @@
from sqlalchemy.ext.asyncio import AsyncSession
-from nest.core import Controller, Depends, Get, Post
+from nest.web import Controller, Depends, Get, Post
from ..config import config
from .example_model import Example
diff --git a/examples/OrmAsyncApp/src/example/example_service.py b/examples/OrmAsyncApp/src/example/example_service.py
index 18a6813..85d2630 100644
--- a/examples/OrmAsyncApp/src/example/example_service.py
+++ b/examples/OrmAsyncApp/src/example/example_service.py
@@ -2,7 +2,7 @@
from sqlalchemy.ext.asyncio import AsyncSession
from nest.core import Injectable
-from nest.core.decorators.database import async_db_request_handler
+from nest.database import async_db_request_handler
from .example_entity import Example as ExampleEntity
from .example_model import Example
diff --git a/examples/OrmAsyncApp/src/product/product_controller.py b/examples/OrmAsyncApp/src/product/product_controller.py
index 432fe7e..c967536 100644
--- a/examples/OrmAsyncApp/src/product/product_controller.py
+++ b/examples/OrmAsyncApp/src/product/product_controller.py
@@ -1,6 +1,6 @@
from sqlalchemy.ext.asyncio import AsyncSession
-from nest.core import Controller, Depends, Get, Post
+from nest.web import Controller, Depends, Get, Post
from ..config import config
from .product_model import Product
diff --git a/examples/OrmAsyncApp/src/product/product_service.py b/examples/OrmAsyncApp/src/product/product_service.py
index 18e54d5..0baf88a 100644
--- a/examples/OrmAsyncApp/src/product/product_service.py
+++ b/examples/OrmAsyncApp/src/product/product_service.py
@@ -2,7 +2,7 @@
from sqlalchemy.ext.asyncio import AsyncSession
from nest.core import Injectable
-from nest.core.decorators.database import async_db_request_handler
+from nest.database import async_db_request_handler
from .product_entity import Product as ProductEntity
from .product_model import Product
diff --git a/examples/OrmAsyncApp/src/user/user_controller.py b/examples/OrmAsyncApp/src/user/user_controller.py
index e02408e..b1d344f 100644
--- a/examples/OrmAsyncApp/src/user/user_controller.py
+++ b/examples/OrmAsyncApp/src/user/user_controller.py
@@ -1,6 +1,6 @@
from sqlalchemy.ext.asyncio import AsyncSession
-from nest.core import Controller, Depends, Get, Post
+from nest.web import Controller, Depends, Get, Post
from ..config import config
from .user_model import User
diff --git a/examples/OrmAsyncApp/src/user/user_service.py b/examples/OrmAsyncApp/src/user/user_service.py
index dc9866a..306139e 100644
--- a/examples/OrmAsyncApp/src/user/user_service.py
+++ b/examples/OrmAsyncApp/src/user/user_service.py
@@ -6,7 +6,7 @@
from sqlalchemy.ext.asyncio import AsyncSession
from nest.core import Injectable
-from nest.core.decorators.database import async_db_request_handler
+from nest.database import async_db_request_handler
from .user_entity import User as UserEntity
from .user_model import User
diff --git a/examples/OrmSyncApp/src/app_controller.py b/examples/OrmSyncApp/src/app_controller.py
index 286e872..8ee9b09 100644
--- a/examples/OrmSyncApp/src/app_controller.py
+++ b/examples/OrmSyncApp/src/app_controller.py
@@ -1,4 +1,4 @@
-from nest.core import Controller, Get
+from nest.web import Controller, Get
from .app_service import AppService
diff --git a/examples/OrmSyncApp/src/app_module.py b/examples/OrmSyncApp/src/app_module.py
index 9ae3d40..2177333 100644
--- a/examples/OrmSyncApp/src/app_module.py
+++ b/examples/OrmSyncApp/src/app_module.py
@@ -1,4 +1,5 @@
-from nest.core import Module, PyNestFactory
+from nest.core import Module
+from nest.web import PyNestWebFactory
from .app_controller import AppController
from .app_service import AppService
@@ -17,7 +18,7 @@ class AppModule:
pass
-app = PyNestFactory.create(
+app = PyNestWebFactory.create(
AppModule,
description="This is my FastAPI app drive by Sync ORM Engine",
title="My App",
diff --git a/examples/OrmSyncApp/src/config.py b/examples/OrmSyncApp/src/config.py
index 822f72b..06f6632 100644
--- a/examples/OrmSyncApp/src/config.py
+++ b/examples/OrmSyncApp/src/config.py
@@ -2,7 +2,7 @@
from dotenv import load_dotenv
-from nest.core.database.orm_provider import OrmProvider
+from nest.database.orm_provider import OrmProvider
load_dotenv()
diff --git a/examples/OrmSyncApp/src/example/example_controller.py b/examples/OrmSyncApp/src/example/example_controller.py
index 5fe6378..14dace7 100644
--- a/examples/OrmSyncApp/src/example/example_controller.py
+++ b/examples/OrmSyncApp/src/example/example_controller.py
@@ -1,4 +1,4 @@
-from nest.core import Controller, Depends, Get, Post
+from nest.web import Controller, Depends, Get, Post
from .example_model import Example
from .example_service import ExampleService
diff --git a/examples/OrmSyncApp/src/example/example_service.py b/examples/OrmSyncApp/src/example/example_service.py
index 076c24d..c0df60b 100644
--- a/examples/OrmSyncApp/src/example/example_service.py
+++ b/examples/OrmSyncApp/src/example/example_service.py
@@ -1,5 +1,5 @@
from nest.core import Injectable
-from nest.core.decorators.database import db_request_handler
+from nest.database import db_request_handler
from ..config import config
from .example_entity import Example as ExampleEntity
diff --git a/examples/OrmSyncApp/src/product/product_controller.py b/examples/OrmSyncApp/src/product/product_controller.py
index 44addac..b241306 100644
--- a/examples/OrmSyncApp/src/product/product_controller.py
+++ b/examples/OrmSyncApp/src/product/product_controller.py
@@ -1,4 +1,4 @@
-from nest.core import Controller, Depends, Get, Post
+from nest.web import Controller, Depends, Get, Post
from .product_model import Product
from .product_service import ProductService
diff --git a/examples/OrmSyncApp/src/product/product_service.py b/examples/OrmSyncApp/src/product/product_service.py
index 69d0f76..e89ac25 100644
--- a/examples/OrmSyncApp/src/product/product_service.py
+++ b/examples/OrmSyncApp/src/product/product_service.py
@@ -1,5 +1,5 @@
from nest.core import Injectable
-from nest.core.decorators.database import db_request_handler
+from nest.database import db_request_handler
from ..config import config
from .product_entity import Product as ProductEntity
diff --git a/examples/OrmSyncApp/src/user/user_controller.py b/examples/OrmSyncApp/src/user/user_controller.py
index 43f008f..d287d38 100644
--- a/examples/OrmSyncApp/src/user/user_controller.py
+++ b/examples/OrmSyncApp/src/user/user_controller.py
@@ -1,4 +1,4 @@
-from nest.core import Controller, Depends, Get, Post
+from nest.web import Controller, Depends, Get, Post
from .user_model import User
from .user_service import UserService
diff --git a/examples/OrmSyncApp/src/user/user_service.py b/examples/OrmSyncApp/src/user/user_service.py
index 798f42d..00de753 100644
--- a/examples/OrmSyncApp/src/user/user_service.py
+++ b/examples/OrmSyncApp/src/user/user_service.py
@@ -1,5 +1,5 @@
from nest.core import Injectable
-from nest.core.decorators.database import db_request_handler
+from nest.database import db_request_handler
from ..config import config
from .user_entity import User as UserEntity
diff --git a/mkdocs.yml b/mkdocs.yml
index f955e53..3e4fde2 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -38,6 +38,8 @@ markdown_extensions:
- pymdownx.inlinehilite
- pymdownx.snippets
- pymdownx.superfences
+ - pymdownx.tabbed:
+ alternate_style: true
diff --git a/nest/__init__.py b/nest/__init__.py
index 493f741..260c070 100644
--- a/nest/__init__.py
+++ b/nest/__init__.py
@@ -1 +1 @@
-__version__ = "0.3.0"
+__version__ = "0.3.1"
diff --git a/nest/cli/__init__.py b/nest/cli/__init__.py
index e69de29..29cd4c0 100644
--- a/nest/cli/__init__.py
+++ b/nest/cli/__init__.py
@@ -0,0 +1,2 @@
+from nest.cli.cli_decorators import CliCommand, CliController
+from nest.cli.pynest_cli_factory import PyNestCLIFactory
diff --git a/nest/core/decorators/cli/cli_decorators.py b/nest/cli/cli_decorators.py
similarity index 90%
rename from nest/core/decorators/cli/cli_decorators.py
rename to nest/cli/cli_decorators.py
index 3d82011..0d1854b 100644
--- a/nest/core/decorators/cli/cli_decorators.py
+++ b/nest/cli/cli_decorators.py
@@ -2,12 +2,7 @@
import click
-from nest.core import Controller
-from nest.core.decorators.utils import (
- get_instance_variables,
- parse_dependencies,
- parse_params,
-)
+from nest.core.utils import get_instance_variables, parse_dependencies, parse_params
def CliController(name: str, **kwargs):
diff --git a/nest/cli/click_handlers.py b/nest/cli/click_handlers.py
deleted file mode 100644
index 0f9ed63..0000000
--- a/nest/cli/click_handlers.py
+++ /dev/null
@@ -1,70 +0,0 @@
-from pathlib import Path
-
-import yaml
-
-from nest.common.templates.templates_factory import TemplateFactory
-
-
-def get_metadata():
- setting_path = Path(__file__).parent.parent / "settings.yaml"
- assert setting_path.exists(), "settings.yaml file not found"
- with open(setting_path, "r") as file:
- file = yaml.load(file, Loader=yaml.FullLoader)
-
- config = file["config"]
- db_type = config["db_type"]
- is_async = config["is_async"]
- return db_type, is_async
-
-
-def create_nest_app(app_name: str = ".", db_type: str = None, is_async: bool = False):
- """
- Create a new nest app
-
- :param app_name: The name of the app
- :param db_type: The type of the database (sqlite, mysql, postgresql)
- :param is_async: whether the project should be async or not (only for relational databases)
-
- The files structure are:
-
- ├── app_module.py
- ├── config.py (only for databases)
- ├── main.py
- ├── requirements.txt
- ├── .gitignore
- ├── src
- │ ├── __init__.py
-
- in addition to those files, a setting.yaml file will be created in the package level that will help managed configurations
- """
- template_factory = TemplateFactory()
- template = template_factory.get_template(
- module_name="example", db_type=db_type, is_async=is_async
- )
- template.generate_project(app_name)
-
-
-def create_nest_module(name: str):
- """
- Create a new nest module
-
- :param name: The name of the module
-
- The files structure are:
- ├── ...
- ├── src
- │ ├── __init__.py
- │ ├── module_name
- ├── __init__.py
- ├── module_name_controller.py
- ├── module_name_service.py
- ├── module_name_model.py
- ├── module_name_entity.py (only for databases)
- ├── module_name_module.py
- """
- db_type, is_async = get_metadata()
- template_factory = TemplateFactory()
- template = template_factory.get_template(
- module_name=name, db_type=db_type, is_async=is_async
- )
- template.generate_module(name)
diff --git a/nest/core/cli_factory.py b/nest/cli/pynest_cli_factory.py
similarity index 95%
rename from nest/core/cli_factory.py
rename to nest/cli/pynest_cli_factory.py
index 99284be..c575db2 100644
--- a/nest/core/cli_factory.py
+++ b/nest/cli/pynest_cli_factory.py
@@ -6,7 +6,7 @@
from nest.core.pynest_factory import AbstractPyNestFactory, ModuleType
-class CLIAppFactory(AbstractPyNestFactory):
+class PyNestCLIFactory(AbstractPyNestFactory):
def __init__(self):
super().__init__()
diff --git a/nest/cli/src/app_controller.py b/nest/cli/src/app_controller.py
index 55d3163..73d2522 100644
--- a/nest/cli/src/app_controller.py
+++ b/nest/cli/src/app_controller.py
@@ -1,5 +1,7 @@
+import click
+
+from nest.cli import CliCommand, CliController
from nest.cli.src.app_service import AppService
-from nest.core.decorators.cli.cli_decorators import CliCommand, CliController
@CliController("app")
@@ -10,9 +12,9 @@ def __init__(self, app_service: AppService):
@CliCommand("info")
def get_app_info(self):
app_info = self.app_service.get_app_info()
- print(app_info)
+ click.echo(app_info)
@CliCommand("version", help="Get the version of the app")
def get_app_version(self):
app_info = self.app_service.get_app_info()
- print(app_info["app_version"])
+ click.echo(app_info["app_version"])
diff --git a/nest/cli/src/app_module.py b/nest/cli/src/app_module.py
index b16e234..92c99c4 100644
--- a/nest/cli/src/app_module.py
+++ b/nest/cli/src/app_module.py
@@ -1,8 +1,8 @@
+from nest.cli import PyNestCLIFactory
from nest.cli.src.app_controller import AppController
from nest.cli.src.app_service import AppService
from nest.cli.src.generate.generate_module import GenerateModule
from nest.core import Module
-from nest.core.cli_factory import CLIAppFactory
@Module(
@@ -14,4 +14,4 @@ class AppModule:
pass
-nest_cli = CLIAppFactory().create(AppModule)
+nest_cli = PyNestCLIFactory().create(AppModule)
diff --git a/nest/cli/src/generate/generate_controller.py b/nest/cli/src/generate/generate_controller.py
index 381dc84..6d84eb5 100644
--- a/nest/cli/src/generate/generate_controller.py
+++ b/nest/cli/src/generate/generate_controller.py
@@ -1,9 +1,8 @@
import click
-from click import Option
+from nest.cli.cli_decorators import CliCommand, CliController
from nest.cli.src.generate.generate_model import SharedOptions
from nest.cli.src.generate.generate_service import GenerateService
-from nest.core.decorators.cli.cli_decorators import CliCommand, CliController
@CliController("generate")
diff --git a/nest/cli/src/utils.py b/nest/cli/src/utils.py
new file mode 100644
index 0000000..c013cd3
--- /dev/null
+++ b/nest/cli/src/utils.py
@@ -0,0 +1,17 @@
+from pathlib import Path
+
+import yaml
+
+from nest.common.templates.templates_factory import TemplateFactory
+
+
+def get_metadata():
+ setting_path = Path(__file__).parent.parent / "settings.yaml"
+ assert setting_path.exists(), "settings.yaml file not found"
+ with open(setting_path, "r") as file:
+ file = yaml.load(file, Loader=yaml.FullLoader)
+
+ config = file["config"]
+ db_type = config["db_type"]
+ is_async = config["is_async"]
+ return db_type, is_async
diff --git a/nest/cli/templates/abstract_empty_template.py b/nest/cli/templates/abstract_empty_template.py
deleted file mode 100644
index 702464e..0000000
--- a/nest/cli/templates/abstract_empty_template.py
+++ /dev/null
@@ -1,35 +0,0 @@
-from nest.core.templates.abstract_base_template import AbstractBaseTemplate
-
-
-class AbstractEmptyTemplate(AbstractBaseTemplate):
- def __init__(self):
- super().__init__(is_empty=True)
-
- def generate_app_file(self) -> str:
- return f"""from nest.core.app import App
- from src.examples.examples_module import ExamplesModule
-
- app = App(
- description="Blank PyNest service",
- modules=[
- ExamplesModule,
- ]
- )
- """
-
- def generate_controller_file(self, name) -> str:
- return f"""from nest.core import Controller, Get, Post, Depends, Delete, Put
-
- from src.{name}.{name}_service import {self.capitalized_name}Service
- from src.{name}.{name}_model import {self.capitalized_name}
-
-
- @Controller("{name}")
- class {self.capitalized_name}Controller:
-
- service: {self.capitalized_name}Service = Depends({self.capitalized_name}Service)
-
- @Get("/get_{name}")
- {self.is_async}def get_{name}(self):
- return {self.is_await}self.service.get_{name}()
-"""
diff --git a/nest/cli/templates/base_template.py b/nest/cli/templates/base_template.py
index 7d490a3..3682d42 100644
--- a/nest/cli/templates/base_template.py
+++ b/nest/cli/templates/base_template.py
@@ -123,7 +123,7 @@ class {self.capitalized_module_name}Module:
@staticmethod
def app_controller_file():
- return f"""from nest.core import Controller, Get, Post
+ return f"""from nest.web import Controller, Get, Post
from .app_service import AppService
@@ -284,7 +284,11 @@ def get_ast_tree(file_path: Union[str, Path]) -> ast.Module:
return ast.parse(source)
def append_import(
- self, file_path: str, module_path: str, class_name: str, import_exception: str
+ self,
+ file_path: Union[str, Path],
+ module_path: str,
+ class_name: str,
+ import_exception: str,
) -> ast.Module:
tree = self.get_ast_tree(file_path)
import_node = ast.ImportFrom(
@@ -304,7 +308,7 @@ def append_import(
return tree
- def append_module_to_app(self, path_to_app_py: str):
+ def append_module_to_app(self, path_to_app_py: Union[str, Path]):
tree = self.append_import(
file_path=path_to_app_py,
module_path=f"src.{self.module_name}.{self.module_name}_module",
@@ -366,9 +370,9 @@ def generate_module(self, module_name: str, path: str = None):
raise NotImplementedError
def generate_empty_controller_file(self) -> str:
- return f"""from nest.core import Controller
+ return f"""from nest.web import Controller
-@Controller("{self.module_name}")
+@Controller("{self.module_name}", tag="{self.module_name}")
class {self.capitalized_module_name}Controller:
...
"""
diff --git a/nest/cli/templates/blank_template.py b/nest/cli/templates/blank_template.py
index 50b1fd2..d47ad43 100644
--- a/nest/cli/templates/blank_template.py
+++ b/nest/cli/templates/blank_template.py
@@ -9,7 +9,8 @@ def __init__(self, module_name: str):
super().__init__(module_name)
def app_file(self):
- return f"""from nest.core import PyNestFactory, Module
+ return f"""from nest.core import Module
+from nest.web import PyNestWebFactory
from .app_controller import AppController
from .app_service import AppService
@@ -20,7 +21,7 @@ class AppModule:
pass
-app = PyNestFactory.create(
+app = PyNestWebFactory.create(
AppModule,
description="This is my PyNest app.",
title="PyNest Application",
@@ -73,12 +74,12 @@ def add_{self.module_name}(self, {self.module_name}: {self.capitalized_module_na
"""
def controller_file(self):
- return f"""from nest.core import Controller, Get, Post
+ return f"""from nest.web import Controller, Get, Post
from .{self.module_name}_service import {self.capitalized_module_name}Service
from .{self.module_name}_model import {self.capitalized_module_name}
-@Controller("{self.module_name}")
+@Controller("{self.module_name}", tag="{self.module_name}")
class {self.capitalized_module_name}Controller:
def __init__(self, {self.module_name}_service: {self.capitalized_module_name}Service):
diff --git a/nest/cli/templates/cli_templates.py b/nest/cli/templates/cli_templates.py
index 2720fcc..87980e9 100644
--- a/nest/cli/templates/cli_templates.py
+++ b/nest/cli/templates/cli_templates.py
@@ -1,7 +1,6 @@
from pathlib import Path
from nest.cli.templates.base_template import BaseTemplate
-from nest.core.decorators.cli.cli_decorators import CliCommand, CliController
class ClickTemplate(BaseTemplate):
@@ -9,8 +8,7 @@ def __init__(self, module_name: str):
super().__init__(module_name)
def app_file(self):
- return f"""from nest.core.pynest_factory import PyNestFactory
-from nest.core.cli_factory import CLIAppFactory
+ return f"""from nest.cli import PyNestCLIFactory
from nest.core import Module
from src.app_service import AppService
from src.app_controller import AppController
@@ -25,10 +23,10 @@ class AppModule:
pass
-cli_app = CLIAppFactory().create(AppModule)
+nest_app = PyNestCLIFactory().create(AppModule)
if __name__ == "__main__":
- cli_app()
+ nest_app()
"""
def module_file(self):
@@ -46,7 +44,7 @@ class {self.module_name.capitalize()}Module:
"""
def controller_file(self):
- return f"""from nest.core.decorators.cli.cli_decorators import CliCommand, CliController
+ return f"""from nest.cli import CliCommand, CliController
from src.{self.module_name}.{self.module_name}_service import {self.module_name.capitalize()}Service
@CliController("{self.module_name}")
@@ -78,7 +76,7 @@ def settings_file(self):
"""
def app_controller_file(self):
- return f"""from nest.core.decorators.cli.cli_decorators import CliCommand, CliController
+ return f"""from nest.cli import CliCommand, CliController
from src.app_service import AppService
@@ -105,10 +103,10 @@ def app_service_file(self):
class AppService:
def version(self):
- print(click.style("1.0.0", fg="blue"))
+ click.echo(click.style("1.0.0", fg="blue"))
def info(self):
- print(click.style("This is a cli nest app!", fg="green"))
+ click.echo(click.style("This is a cli nest app!", fg="green"))
"""
def create_module(self, module_name: str, src_path: Path):
diff --git a/nest/cli/templates/mongo_db_template.py b/nest/cli/templates/mongo_db_template.py
deleted file mode 100644
index eb1338c..0000000
--- a/nest/cli/templates/mongo_db_template.py
+++ /dev/null
@@ -1,95 +0,0 @@
-from abc import ABC
-
-from nest.cli.templates.abstract_base_template import AbstractBaseTemplate
-
-
-class MongoDbTemplate(AbstractBaseTemplate, ABC):
- def __init__(self, name: str):
- self.name = name
- self.db_type = "mongodb"
- super().__init__(self.name, self.db_type)
-
- def generate_service_file(self) -> str:
- return f"""from src.{self.name}.{self.name}_model import {self.capitalized_name}
-from src.{self.name}.{self.name}_entity import {self.capitalized_name} as {self.capitalized_name}Entity
-from nest.core.decorators import db_request_handler
-from functools import lru_cache
-
-
-@lru_cache()
-class {self.capitalized_name}Service:
-
- @db_request_handler
- async def get_{self.name}(self):
- return await {self.capitalized_name}Entity.find_all().to_list()
-
- @db_request_handler
- async def add_{self.name}(self, {self.name}: {self.capitalized_name}):
- new_{self.name} = {self.capitalized_name}Entity(
- **{self.name}.dict()
- )
- await new_{self.name}.save()
- return new_{self.name}.id
-
-
- @db_request_handler
- async def update_{self.name}(self, {self.name}: {self.capitalized_name}):
- return await {self.capitalized_name}Entity.find_one_and_update(
- {{"id": {self.name}.id}}, {self.name}.dict()
- )
-
- @db_request_handler
- async def delete_{self.name}(self, {self.name}: {self.capitalized_name}):
- return await {self.capitalized_name}Entity.find_one_and_delete(
- {{"id": {self.name}.id}}
- )
-"""
-
- def generate_orm_config_file(self) -> str:
- return f"""from nest.core.database.base_odm import OdmService
-from src.examples.examples_entity import Examples
-import os
-from dotenv import load_dotenv
-
-load_dotenv()
-
-config = OdmService(
- db_type="{self.db_type}",
- config_params={{
- "db_name": os.getenv("DB_NAME"),
- "host": os.getenv("DB_HOST"),
- "user": os.getenv("DB_USER"),
- "password": os.getenv("DB_PASSWORD"),
- "port": os.getenv("DB_PORT"),
- }},
- document_models=[Examples]
-)
-"""
-
- def generate_entity_file(self) -> str:
- return f"""from beanie import Document
-
-
-class {self.capitalized_name}(Document):
- name: str
-
- class Config:
- schema_extra = {{
- "example": {{
- "name": "Example Name",
- }}
- }}
-"""
-
- def generate_requirements_file(self) -> str:
- return f"""click==8.1.6
-fastapi==0.95.1
-python-dotenv==1.0.0
-uvicorn==0.23.1
-motor==3.2.0
-beanie==1.20.0
-pynest-api=={self.version}
- """
-
- def generate_dockerfile(self) -> str:
- pass
diff --git a/nest/cli/templates/mongo_template.py b/nest/cli/templates/mongo_template.py
index c36bdab..4be314a 100644
--- a/nest/cli/templates/mongo_template.py
+++ b/nest/cli/templates/mongo_template.py
@@ -16,7 +16,7 @@ def __init__(self, module_name: str):
def config_file(self):
return f"""import os
from dotenv import load_dotenv
-from nest.core.database.odm_provider import OdmProvider
+from nest.database.odm_provider import OdmProvider
load_dotenv()
@@ -47,7 +47,7 @@ class {self.capitalized_module_name}(Document):
name: str
class Config:
- schema_extra = {{
+ json_schema_extra = {{
"example": {{
"name": "Example Name",
}}
@@ -55,13 +55,13 @@ class Config:
"""
def controller_file(self):
- return f"""from nest.core import Controller, Get, Post
+ return f"""from nest.web import Controller, Get, Post
from .{self.module_name}_service import {self.capitalized_module_name}Service
from .{self.module_name}_model import {self.capitalized_module_name}
-@Controller("{self.module_name}")
+@Controller("{self.module_name}", tag="{self.module_name}")
class {self.capitalized_module_name}Controller:
def __init__(self, {self.module_name}_service: {self.capitalized_module_name}Service):
@@ -79,22 +79,19 @@ async def add_{self.module_name}(self, {self.module_name}: {self.capitalized_mod
def service_file(self):
return f"""from .{self.module_name}_model import {self.capitalized_module_name}
from .{self.module_name}_entity import {self.capitalized_module_name} as {self.capitalized_module_name}Entity
-from nest.core.decorators.database import db_request_handler
from nest.core import Injectable
-@Injectable
+@Injectable()
class {self.capitalized_module_name}Service:
- @db_request_handler
async def add_{self.module_name}(self, {self.module_name}: {self.capitalized_module_name}):
new_{self.module_name} = {self.capitalized_module_name}Entity(
- **{self.module_name}.dict()
+ **{self.module_name}.model_dump()
)
await new_{self.module_name}.save()
return new_{self.module_name}.id
- @db_request_handler
async def get_{self.module_name}(self):
return await {self.capitalized_module_name}Entity.find_all().to_list()
"""
diff --git a/nest/cli/templates/mysql_template.py b/nest/cli/templates/mysql_template.py
index 83a22f7..b40feca 100644
--- a/nest/cli/templates/mysql_template.py
+++ b/nest/cli/templates/mysql_template.py
@@ -44,7 +44,7 @@ def __init__(self, module_name: str):
)
def config_file(self):
- return """from nest.core.database.orm_provider import AsyncOrmProvider
+ return """from nest.database.orm_provider import AsyncOrmProvider
import os
from dotenv import load_dotenv
diff --git a/nest/cli/templates/orm_template.py b/nest/cli/templates/orm_template.py
index 5230e4a..f7c0780 100644
--- a/nest/cli/templates/orm_template.py
+++ b/nest/cli/templates/orm_template.py
@@ -13,7 +13,8 @@ def __init__(self, module_name: str, db_type: Database):
self.db_type = db_type
def app_file(self):
- return f"""from nest.core import PyNestFactory, Module
+ return f"""from nest.core import Module
+from nest.web import PyNestWebFactory
from .config import config
from .app_controller import AppController
from .app_service import AppService
@@ -24,7 +25,7 @@ class AppModule:
pass
-app = PyNestFactory.create(
+app = PyNestWebFactory.create(
AppModule,
description="This is my PyNest app.",
title="PyNest Application",
@@ -94,11 +95,11 @@ def service_file(self):
return f"""from .{self.module_name}_model import {self.capitalized_module_name}
from .{self.module_name}_entity import {self.capitalized_module_name} as {self.capitalized_module_name}Entity
from src.config import config
-from nest.core.decorators.database import db_request_handler
+from nest.database.utils import db_request_handler
from nest.core import Injectable
-@Injectable
+@Injectable()
class {self.capitalized_module_name}Service:
def __init__(self):
@@ -108,7 +109,7 @@ def __init__(self):
@db_request_handler
def add_{self.module_name}(self, {self.module_name}: {self.capitalized_module_name}):
new_{self.module_name} = {self.capitalized_module_name}Entity(
- **{self.module_name}.dict()
+ **{self.module_name}.model_dump()
)
self.session.add(new_{self.module_name})
self.session.commit()
@@ -121,13 +122,13 @@ def get_{self.module_name}(self):
"""
def controller_file(self):
- return f"""from nest.core import Controller, Get, Post
+ return f"""from nest.web import Controller, Get, Post
from .{self.module_name}_service import {self.capitalized_module_name}Service
from .{self.module_name}_model import {self.capitalized_module_name}
-@Controller("{self.module_name}")
+@Controller("{self.module_name}", tag="{self.module_name}")
class {self.capitalized_module_name}Controller:
def __init__(self, {self.module_name}_service: {self.capitalized_module_name}Service):
@@ -206,7 +207,8 @@ def generate_project(self, project_name: str):
class AsyncORMTemplate(ORMTemplate, ABC):
def app_file(self):
- return f"""from nest.core import PyNestFactory, Module
+ return f"""from nest.web import PyNestWebFactory
+from nest.core import Module
from .config import config
from .app_controller import AppController
from .app_service import AppService
@@ -217,7 +219,7 @@ class AppModule:
pass
-app = PyNestFactory.create(
+app = PyNestWebFactory.create(
AppModule,
description="This is my Async PyNest app.",
title="PyNest Application",
@@ -256,56 +258,62 @@ class {self.capitalized_module_name}(config.Base):
"""
def service_file(self):
- return f"""from .{self.module_name}_model import {self.capitalized_module_name}
-from .{self.module_name}_entity import {self.capitalized_module_name} as {self.capitalized_module_name}Entity
-from nest.core.decorators.database import async_db_request_handler
+ return f"""from nest.database.utils import async_db_request_handler
from nest.core import Injectable
+from .{self.module_name}_model import {self.capitalized_module_name}
+from .{self.module_name}_entity import {self.capitalized_module_name} as {self.capitalized_module_name}Entity
+from src.config import config
+
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
-@Injectable
+@Injectable()
class {self.capitalized_module_name}Service:
+ def __init__(self):
+ self.session: AsyncSession = config.get_session
+
@async_db_request_handler
- async def add_{self.module_name}(self, {self.module_name}: {self.capitalized_module_name}, session: AsyncSession):
- new_{self.module_name} = {self.capitalized_module_name}Entity(
- **{self.module_name}.dict()
- )
- session.add(new_{self.module_name})
- await session.commit()
- return new_{self.module_name}.id
+ async def add_{self.module_name}(self, {self.module_name}: {self.capitalized_module_name}):
+ async with self.session() as session:
+ new_{self.module_name} = {self.capitalized_module_name}Entity(
+ **{self.module_name}.model_dump()
+ )
+ session.add(new_{self.module_name})
+ await session.commit()
+ return new_{self.module_name}.id
@async_db_request_handler
- async def get_{self.module_name}(self, session: AsyncSession):
- query = select({self.capitalized_module_name}Entity)
- result = await session.execute(query)
- return result.scalars().all()
+ async def get_{self.module_name}(self):
+ async with self.session() as session:
+ query = select({self.capitalized_module_name}Entity)
+ result = await session.execute(query)
+ return result.scalars().all()
"""
def controller_file(self):
- return f"""from nest.core import Controller, Get, Post, Depends
+ return f"""from nest.web import Controller, Get, Post
from sqlalchemy.ext.asyncio import AsyncSession
-from src.config import config
from .{self.module_name}_service import {self.capitalized_module_name}Service
from .{self.module_name}_model import {self.capitalized_module_name}
-@Controller("{self.module_name}")
+@Controller("{self.module_name}", tag="{self.module_name}")
class {self.capitalized_module_name}Controller:
def __init__(self, {self.module_name}_service: {self.capitalized_module_name}Service):
self.{self.module_name}_service = {self.module_name}_service
@Get("/")
- async def get_{self.module_name}(self, session: AsyncSession = Depends(config.get_db)):
+ async def get_{self.module_name}(self):
return await self.{self.module_name}_service.get_{self.module_name}(session)
@Post("/")
- async def add_{self.module_name}(self, {self.module_name}: {self.capitalized_module_name}, session: AsyncSession = Depends(config.get_db)):
- return await self.{self.module_name}_service.add_{self.module_name}({self.module_name}, session)
+ async def add_{self.module_name}(self, {self.module_name}: {self.capitalized_module_name}):
+ return await self.{self.module_name}_service.add_{self.module_name}({self.module_name})
"""
def settings_file(self):
diff --git a/nest/cli/templates/postgres_template.py b/nest/cli/templates/postgres_template.py
index ced9957..a427173 100644
--- a/nest/cli/templates/postgres_template.py
+++ b/nest/cli/templates/postgres_template.py
@@ -12,7 +12,7 @@ def __init__(self, module_name: str):
)
def config_file(self):
- return """from nest.core.database.orm_provider import OrmProvider
+ return """from nest.database.orm_provider import OrmProvider
import os
from dotenv import load_dotenv
@@ -44,7 +44,7 @@ def __init__(self, module_name: str):
)
def config_file(self):
- return """from nest.core.database.orm_provider import AsyncOrmProvider
+ return """from nest.database.orm_provider import AsyncOrmProvider
import os
from dotenv import load_dotenv
diff --git a/nest/cli/templates/relational_db_template.py b/nest/cli/templates/relational_db_template.py
deleted file mode 100644
index f915076..0000000
--- a/nest/cli/templates/relational_db_template.py
+++ /dev/null
@@ -1,123 +0,0 @@
-from abc import ABC
-
-from nest import __version__ as version
-from nest.cli.templates.abstract_base_template import AbstractBaseTemplate
-
-
-class RelationalDBTemplate(AbstractBaseTemplate, ABC):
- def __init__(self, name, db_type):
- super().__init__(name, db_type)
-
- def generate_service_file(self) -> str:
- return f"""from src.{self.name}.{self.name}_model import {self.capitalized_name}
-from src.{self.name}.{self.name}_entity import {self.capitalized_name} as {self.capitalized_name}Entity
-from orm_config import config
-from nest.core.decorators import db_request_handler
-from functools import lru_cache
-
-
-@lru_cache()
-class {self.capitalized_name}Service:
-
- def __init__(self):
- self.orm_config = config
- self.session = self.orm_config.get_db()
-
- @db_request_handler
- def add_{self.name}(self, {self.name}: {self.capitalized_name}):
- new_{self.name} = {self.capitalized_name}Entity(
- **{self.name}.dict()
- )
- self.session.add(new_{self.name})
- self.session.commit()
- return new_{self.name}.id
-
- @db_request_handler
- def get_{self.name}(self):
- return self.session.query({self.capitalized_name}Entity).all()
-
- @db_request_handler
- def delete_{self.name}(self, {self.name}_id: int):
- self.session.query({self.capitalized_name}Entity).filter_by(id={self.name}_id).delete()
- self.session.commit()
- return {self.name}_id
-
- @db_request_handler
- def update_{self.name}(self, {self.name}_id: int, {self.name}: {self.capitalized_name}):
- self.session.query({self.capitalized_name}Entity).filter_by(id={self.name}_id).update(
- {self.name}.dict()
- )
- self.session.commit()
- return {self.name}_id
- """
-
- def generate_entity_file(self) -> str:
- return f"""from orm_config import config
-from sqlalchemy import Column, Integer, String, Float
-
-
-class {self.capitalized_name}(config.Base):
- __tablename__ = "{self.name}"
-
- id = Column(Integer, primary_key=True, autoincrement=True)
- name = Column(String, unique=True)
- """
-
- def generate_requirements_file(self) -> str:
- return f"""anyio==3.6.2
-click==8.1.3
-fastapi==0.95.1
-fastapi-utils==0.2.1
-greenlet==2.0.2
-h11==0.14.0
-idna==3.4
-pydantic==1.10.7
-python-dotenv==1.0.0
-sniffio==1.3.0
-SQLAlchemy==1.4.48
-starlette==0.26.1
-typing_extensions==4.5.0
-uvicorn==0.22.0
-pynest-api=={version}
- """
-
- def generate_dockerfile(self) -> str:
- pass
-
- def generate_orm_config_file(self) -> str:
- base_template = f"""from nest.core.database.base_orm import OrmService
-import os
-from dotenv import load_dotenv
-
-load_dotenv()
-
-
- """
-
- if self.db_type == "sqlite":
- return f"""{base_template}
- config = OrmService(
- db_type="{self.db_type}",
- config_params=dict(
- db_name=os.getenv("SQLITE_DB_NAME", "{self.name}_db"),
- )
- )
- """
- else:
- return f"""{base_template}
- config = OrmService(
- db_type="{self.db_type}",
- config_params=dict(
- host=os.getenv("{self.db_type.upper()}_HOST"),
- db_name=os.getenv("{self.db_type.upper()}_DB_NAME"),
- user=os.getenv("{self.db_type.upper()}_USER"),
- password=os.getenv("{self.db_type.upper()}_PASSWORD"),
- port=int(os.getenv("{self.db_type.upper()}_PORT")),
- )
- )
- """
-
-
-if __name__ == "__main__":
- relational_db_template = RelationalDBTemplate("users", "mysql")
- print(relational_db_template.generate_orm_config_file())
diff --git a/nest/cli/templates/sqlite_template.py b/nest/cli/templates/sqlite_template.py
index 28e29fe..449022c 100644
--- a/nest/cli/templates/sqlite_template.py
+++ b/nest/cli/templates/sqlite_template.py
@@ -12,7 +12,7 @@ def __init__(self, module_name: str):
)
def config_file(self):
- return """from nest.core.database.orm_provider import OrmProvider
+ return """from nest.database.orm_provider import OrmProvider
import os
from dotenv import load_dotenv
@@ -45,7 +45,7 @@ def __init__(self, module_name: str):
)
def config_file(self):
- return """from nest.core.database.orm_provider import AsyncOrmProvider
+ return """from nest.database.orm_provider import AsyncOrmProvider
import os
from dotenv import load_dotenv
diff --git a/nest/core/__init__.py b/nest/core/__init__.py
index 50a4cc8..e1e8a40 100644
--- a/nest/core/__init__.py
+++ b/nest/core/__init__.py
@@ -1,16 +1,3 @@
-from fastapi import Depends
-
-from nest.core.decorators import (
- Controller,
- Delete,
- Get,
- HttpCode,
- Injectable,
- Module,
- Patch,
- Post,
- Put,
-)
-from nest.core.pynest_application import PyNestApp
+from nest.core.injectable import Injectable
+from nest.core.module import Module
from nest.core.pynest_container import PyNestContainer
-from nest.core.pynest_factory import PyNestFactory
diff --git a/nest/core/decorators/__init__.py b/nest/core/decorators/__init__.py
deleted file mode 100644
index 1ed7489..0000000
--- a/nest/core/decorators/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from nest.core.decorators.controller import Controller
-from nest.core.decorators.http_code import HttpCode
-from nest.core.decorators.http_method import Delete, Get, Patch, Post, Put
-from nest.core.decorators.injectable import Injectable
-from nest.core.decorators.module import Module
diff --git a/nest/core/decorators/injectable.py b/nest/core/injectable.py
similarity index 95%
rename from nest/core/decorators/injectable.py
rename to nest/core/injectable.py
index 2e00aea..2eff7d8 100644
--- a/nest/core/decorators/injectable.py
+++ b/nest/core/injectable.py
@@ -3,7 +3,7 @@
from injector import inject
from nest.common.constants import DEPENDENCIES, INJECTABLE_NAME, INJECTABLE_TOKEN
-from nest.core.decorators.utils import parse_dependencies
+from nest.core.utils import parse_dependencies
def Injectable(target_class: Optional[Type] = None, *args, **kwargs) -> Callable:
diff --git a/nest/core/decorators/module.py b/nest/core/module.py
similarity index 100%
rename from nest/core/decorators/module.py
rename to nest/core/module.py
diff --git a/nest/common/module.py b/nest/core/nest_module.py
similarity index 99%
rename from nest/common/module.py
rename to nest/core/nest_module.py
index a877eab..de4ad05 100644
--- a/nest/common/module.py
+++ b/nest/core/nest_module.py
@@ -5,7 +5,7 @@
from typing import Any, List, Type
from uuid import uuid4
-from nest.core import Module
+from nest.core.module import Module
class ModulesContainer(dict):
@@ -26,7 +26,7 @@ def has(self, token: str):
return True if self.get(token) is not None else False
-class Module:
+class NestModule:
def __init__(self, metatype: Type[object], container):
self._id = str(uuid.uuid4())
self._metatype = metatype
diff --git a/nest/core/pynest_app_context.py b/nest/core/pynest_app_context.py
index 030d627..1f289f4 100644
--- a/nest/core/pynest_app_context.py
+++ b/nest/core/pynest_app_context.py
@@ -2,7 +2,7 @@
from typing import TypeVar, Union
from nest.common.exceptions import UnknownModuleException
-from nest.common.module import Module, ModuleCompiler
+from nest.core.nest_module import NestModule, ModuleCompiler
from nest.core.pynest_container import PyNestContainer
T = TypeVar("T")
@@ -60,7 +60,7 @@ def init(self):
return self
def __init__(
- self, container: PyNestContainer, context_module: Union[Module, None] = None
+ self, container: PyNestContainer, context_module: Union[NestModule, None] = None
):
"""
Constructor for the PyNestApplicationContext.
@@ -70,7 +70,7 @@ def __init__(
context_module (Union[Module, None], optional): The initial context module of the application.
"""
self.container = container
- self.context_module: Module = context_module
+ self.context_module: NestModule = context_module
self.logger = logging.getLogger(PyNestApplicationContext.__name__)
def select_context_module(self):
diff --git a/nest/core/pynest_container.py b/nest/core/pynest_container.py
index 9e524f8..275bba3 100644
--- a/nest/core/pynest_container.py
+++ b/nest/core/pynest_container.py
@@ -10,8 +10,8 @@
NoneInjectableException,
UnknownModuleException,
)
-from nest.common.module import (
- Module,
+from nest.core.nest_module import (
+ NestModule,
ModuleCompiler,
ModuleFactory,
ModulesContainer,
@@ -95,7 +95,7 @@ def add_module(self, metaclass) -> dict:
return {"module_ref": self.modules.get(token), "inserted": False}
return {"module_ref": self.register_module(module_factory), "inserted": True}
- def register_module(self, module_factory: ModuleFactory) -> Module:
+ def register_module(self, module_factory: ModuleFactory) -> NestModule:
"""
Register a module in the container.
@@ -111,7 +111,7 @@ def register_module(self, module_factory: ModuleFactory) -> Module:
Module: The module reference that has been registered in the container.
"""
- module_ref = Module(module_factory.type, self)
+ module_ref = NestModule(module_factory.type, self)
module_ref.token = module_factory.token
self._modules[module_factory.token] = module_ref
@@ -140,7 +140,7 @@ def add_import(self, token: str):
if not self.modules.has(token):
return
module_metadata = self._modules_metadata.get(token)
- module_ref: Module = self.modules.get(token)
+ module_ref: NestModule = self.modules.get(token)
imports_mod: List[Any] = module_metadata.get("imports")
self.add_modules(imports_mod)
module_ref.add_imports(imports_mod)
@@ -158,7 +158,7 @@ def add_providers(self, providers: List[Any], module_token: str) -> None:
def add_provider(self, token: str, provider):
"""Add a provider to a module."""
- module_ref: Module = self.modules[token]
+ module_ref: NestModule = self.modules[token]
if not provider:
raise CircularDependencyException(module_ref.metatype)
@@ -200,7 +200,7 @@ def _add_controller(self, token: str, controller: TController) -> None:
"""Add a controller to a module."""
if not self.modules.has(token):
raise UnknownModuleException()
- module_ref: Module = self.modules[token]
+ module_ref: NestModule = self.modules[token]
module_ref.add_controller(controller)
if hasattr(controller, DEPENDENCIES):
for provider_name, provider_type in getattr(
@@ -228,5 +228,5 @@ def add_related_module(self, related_module, token: str) -> None:
# UNUSED: This function is currently not used but retained for potential future use.
# It retrieves a module from the container by its key.
- def get_module_by_key(self, module_key: str) -> Module:
+ def get_module_by_key(self, module_key: str) -> NestModule:
return self._modules[module_key]
diff --git a/nest/core/pynest_factory.py b/nest/core/pynest_factory.py
index 2d988ae..5015fc1 100644
--- a/nest/core/pynest_factory.py
+++ b/nest/core/pynest_factory.py
@@ -1,11 +1,6 @@
from abc import ABC, abstractmethod
from typing import Type, TypeVar
-from fastapi import FastAPI
-
-from nest.core.pynest_application import PyNestApp
-from nest.core.pynest_container import PyNestContainer
-
ModuleType = TypeVar("ModuleType")
@@ -13,37 +8,3 @@ class AbstractPyNestFactory(ABC):
@abstractmethod
def create(self, main_module: Type[ModuleType], **kwargs):
raise NotImplementedError
-
-
-class PyNestFactory(AbstractPyNestFactory):
- """Factory class for creating PyNest applications."""
-
- @staticmethod
- def create(main_module: Type[ModuleType], **kwargs) -> PyNestApp:
- """
- Create a PyNest application with the specified main module class.
-
- Args:
- main_module (ModuleType): The main module for the PyNest application.
- **kwargs: Additional keyword arguments for the FastAPI server.
-
- Returns:
- PyNestApp: The created PyNest application.
- """
- container = PyNestContainer()
- container.add_module(main_module)
- http_server = PyNestFactory._create_server(**kwargs)
- return PyNestApp(container, http_server)
-
- @staticmethod
- def _create_server(**kwargs) -> FastAPI:
- """
- Create a FastAPI server.
-
- Args:
- **kwargs: Additional keyword arguments for the FastAPI server.
-
- Returns:
- FastAPI: The created FastAPI server.
- """
- return FastAPI(**kwargs)
diff --git a/nest/core/decorators/utils.py b/nest/core/utils.py
similarity index 100%
rename from nest/core/decorators/utils.py
rename to nest/core/utils.py
diff --git a/nest/core/decorators/cli/__init__.py b/nest/database/__init__.py
similarity index 100%
rename from nest/core/decorators/cli/__init__.py
rename to nest/database/__init__.py
diff --git a/nest/core/database/base_config.py b/nest/database/base_config.py
similarity index 100%
rename from nest/core/database/base_config.py
rename to nest/database/base_config.py
diff --git a/nest/core/database/odm_config.py b/nest/database/odm_config.py
similarity index 61%
rename from nest/core/database/odm_config.py
rename to nest/database/odm_config.py
index 8dc13b2..908e8b6 100644
--- a/nest/core/database/odm_config.py
+++ b/nest/database/odm_config.py
@@ -1,4 +1,5 @@
-from nest.core.database.base_config import BaseProvider, ConfigFactoryBase
+from nest.database.base_config import BaseProvider, ConfigFactoryBase
+from urllib.parse import urlencode
class MongoDBConfig(BaseProvider):
@@ -12,17 +13,21 @@ class MongoDBConfig(BaseProvider):
password (str): The password for database authentication.
port (int): The database port number.
srv (bool): Whether to use the SRV connection string.
+ uri (str): Optional pre-built MongoDB URI.
+ **kwargs: Additional keyword arguments to include in the URI query parameters.
"""
def __init__(
self,
- host: str,
- db_name: str,
+ host: str = None,
+ db_name: str = None,
user: str = None,
password: str = None,
port: int = 27017,
srv: bool = False,
+ uri: str = None,
+ **kwargs,
):
"""
Initializes the MongoDBConfig instance.
@@ -34,22 +39,48 @@ def __init__(
password (str): The password for database authentication.
port (int): The database port number.
srv (bool): Whether to use the SRV connection string.
+ uri (str): Optional pre-built MongoDB URI.
+ **kwargs: Additional keyword arguments to include in the URI query parameters.
"""
self.srv = srv
+ self.uri = uri
+ self.kwargs = kwargs or {}
super().__init__(host, db_name, user, password, port)
def get_engine_url(self) -> str:
"""
- Returns the engine URL for the ORM.
+ Returns the engine URL for the ODM.
Returns:
str: The engine URL.
"""
+ if self.uri:
+ return self.uri
+
+ # Build the base URI
+ protocol = "mongodb+srv" if self.srv else "mongodb"
+ credentials = ""
if self.user and self.password:
- return f"mongodb{'+srv' if self.srv else ''}://{self.user}:{self.password}@{self.host}:{self.port}"
- return f"mongodb{'+srv' if self.srv else ''}://{self.host}:{self.port}"
+ credentials = f"{self.user}:{self.password}@"
+ elif self.user:
+ credentials = f"{self.user}@"
+
+ host_port = self.host or ""
+ if not self.srv and self.port:
+ host_port = f"{host_port}:{self.port}"
+
+ db_name = f"/{self.db_name}" if self.db_name else ""
+
+ # Build the query string from kwargs
+ query = ""
+ if self.kwargs:
+ query = "?" + urlencode(self.kwargs)
+
+ # Build the full URI
+ uri = f"{protocol}://{credentials}{host_port}{db_name}{query}"
+ return uri
class ConfigFactory(ConfigFactoryBase):
diff --git a/nest/core/database/odm_provider.py b/nest/database/odm_provider.py
similarity index 75%
rename from nest/core/database/odm_provider.py
rename to nest/database/odm_provider.py
index ead8d06..b082909 100644
--- a/nest/core/database/odm_provider.py
+++ b/nest/database/odm_provider.py
@@ -1,9 +1,9 @@
-from typing import List
+from typing import List, Type
from beanie import Document, init_beanie
from motor.motor_asyncio import AsyncIOMotorClient
-from nest.core.database.odm_config import ConfigFactory
+from nest.database.odm_config import ConfigFactory
class OdmProvider:
@@ -14,7 +14,7 @@ class OdmProvider:
db_type (str, optional): The type of database. Defaults to "mongodb".
config_params (dict, optional): Configuration parameters specific to the chosen database type.
Defaults to None.
- document_models (beanie.Document): a list of beanie.Document instances
+ document_models (List[Type[Document]]): A list of beanie.Document subclasses.
Attributes:
config: The configuration factory for the chosen database type.
@@ -26,34 +26,35 @@ def __init__(
self,
db_type="mongodb",
config_params: dict = None,
- document_models: List[Document] = None,
+ document_models: list[Type[Document]] = None,
):
"""
- Initializes the OrmService instance.
+ Initializes the OdmProvider instance.
Args:
db_type (str, optional): The type of database. Defaults to "mongodb".
config_params (dict, optional): Configuration parameters specific to the chosen database type.
Defaults to None.
- document_models (beanie.Document): a list of beanie.Document instances
+ document_models (List[Type[Document]]): A list of beanie.Document subclasses.
"""
-
self.config_object = ConfigFactory(db_type=db_type).get_config()
self.config = self.config_object(**config_params)
self.config_url = self.config.get_engine_url()
- self.document_models = document_models
+ self.document_models = document_models or []
async def create_all(self):
+ """
+ Initializes the Beanie ODM with the provided document models.
+ """
self.check_document_models()
client = AsyncIOMotorClient(self.config_url)
await init_beanie(
- database=client[self.config.db_name], document_models=self.document_models
+ database=client.get_default_database(), document_models=self.document_models
)
def check_document_models(self):
"""
- Checks that the document_models argument is a list of beanie.Document instances.
-
+ Checks that the document_models argument is a list of beanie.Document subclasses.
"""
if not isinstance(self.document_models, list):
raise Exception("document_models should be a list")
diff --git a/nest/core/database/orm_config.py b/nest/database/orm_config.py
similarity index 98%
rename from nest/core/database/orm_config.py
rename to nest/database/orm_config.py
index f681d86..88a1151 100644
--- a/nest/core/database/orm_config.py
+++ b/nest/database/orm_config.py
@@ -1,4 +1,4 @@
-from nest.core.database.base_config import BaseConfig, BaseProvider, ConfigFactoryBase
+from nest.database.base_config import BaseConfig, BaseProvider, ConfigFactoryBase
class PostgresConfig(BaseProvider):
diff --git a/nest/core/database/orm_provider.py b/nest/database/orm_provider.py
similarity index 97%
rename from nest/core/database/orm_provider.py
rename to nest/database/orm_provider.py
index 21b0df3..d8cc81c 100644
--- a/nest/core/database/orm_provider.py
+++ b/nest/database/orm_provider.py
@@ -6,7 +6,7 @@
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from sqlalchemy.orm import DeclarativeBase, Session, sessionmaker
-from nest.core.database.orm_config import AsyncConfigFactory, ConfigFactory
+from nest.database.orm_config import AsyncConfigFactory, ConfigFactory
class Base(DeclarativeBase):
diff --git a/nest/core/decorators/database.py b/nest/database/utils.py
similarity index 100%
rename from nest/core/decorators/database.py
rename to nest/database/utils.py
diff --git a/nest/plugins/__init__.py b/nest/plugins/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/nest/plugins/controllers/__init__.py b/nest/plugins/controllers/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/nest/plugins/modules/__init__.py b/nest/plugins/modules/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/nest/plugins/modules/auth/__init__.py b/nest/plugins/modules/auth/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/nest/plugins/modules/redis/__init__.py b/nest/plugins/modules/redis/__init__.py
deleted file mode 100644
index 013a218..0000000
--- a/nest/plugins/modules/redis/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-from nest.plugins.modules.redis.redis_controller import RedisController
-from nest.plugins.modules.redis.redis_model import RedisInput
-from nest.plugins.modules.redis.redis_module import RedisModule
-from nest.plugins.modules.redis.redis_service import RedisService
diff --git a/nest/plugins/modules/redis/redis_controller.py b/nest/plugins/modules/redis/redis_controller.py
deleted file mode 100644
index c5c4954..0000000
--- a/nest/plugins/modules/redis/redis_controller.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from nest.core import Controller, Delete, Depends, Get, Post
-from nest.plugins.modules.redis.redis_model import RedisInput
-from nest.plugins.modules.redis.redis_service import RedisService
-
-
-@Controller("redis")
-class RedisController:
-
- def __init__(self, redis_service: RedisService):
- self.redis_service = redis_service
-
- @Get("/{key}")
- def get(self, key: str):
- return self.redis_service.get(key)
-
- @Post("/")
- def set(self, redis_input: RedisInput):
- return self.redis_service.set(redis_input)
-
- @Delete("/{key}")
- def delete(self, key: str):
- return self.redis_service.delete(key)
-
- @Get("/exists/{key}")
- def exists(self, key: str):
- return self.redis_service.exists(key)
diff --git a/nest/plugins/modules/redis/redis_model.py b/nest/plugins/modules/redis/redis_model.py
deleted file mode 100644
index d852228..0000000
--- a/nest/plugins/modules/redis/redis_model.py
+++ /dev/null
@@ -1,14 +0,0 @@
-from typing import Any
-
-from pydantic import BaseModel, BaseSettings
-
-
-class RedisInput(BaseModel):
- key: str
- value: Any
-
-
-class RedisConfig(BaseSettings):
- REDIS_HOST: str = "localhost"
- REDIS_PORT: int = 6379
- REDIS_DB: int = 0
diff --git a/nest/plugins/modules/redis/redis_module.py b/nest/plugins/modules/redis/redis_module.py
deleted file mode 100644
index 95ff6ab..0000000
--- a/nest/plugins/modules/redis/redis_module.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from nest.core import Module
-from nest.plugins.modules.redis.redis_controller import RedisController
-from nest.plugins.modules.redis.redis_service import RedisService
-
-
-@Module(controllers=[RedisController], providers=[RedisService], imports=[])
-class RedisModule:
- pass
diff --git a/nest/plugins/modules/redis/redis_service.py b/nest/plugins/modules/redis/redis_service.py
deleted file mode 100644
index 8464873..0000000
--- a/nest/plugins/modules/redis/redis_service.py
+++ /dev/null
@@ -1,30 +0,0 @@
-import redis
-from fastapi import HTTPException
-
-from nest.core import Injectable
-from nest.plugins.modules.redis.redis_model import RedisConfig, RedisInput
-
-
-@Injectable()
-class RedisService:
- def __init__(self):
- self.redis_config = RedisConfig()
- self.redis_client = redis.StrictRedis(
- host=self.redis_config.REDIS_HOST,
- port=self.redis_config.REDIS_PORT,
- db=self.redis_config.REDIS_DB,
- )
-
- def set(self, redis_input: RedisInput):
- if self.exists(redis_input.key):
- raise HTTPException(status_code=400, detail="Key already exists")
- self.redis_client.set(redis_input.key, redis_input.value)
-
- def get(self, redis_key: str):
- return self.redis_client.get(redis_key)
-
- def exists(self, redis_key: str):
- return self.redis_client.exists(redis_key)
-
- def delete(self, redis_key: str):
- self.redis_client.delete(redis_key)
diff --git a/nest/plugins/services/__init__.py b/nest/plugins/services/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/nest/web/__init__.py b/nest/web/__init__.py
new file mode 100644
index 0000000..9da0344
--- /dev/null
+++ b/nest/web/__init__.py
@@ -0,0 +1,3 @@
+from nest.web.controller import Controller
+from nest.web.http_method import Delete, Get, Patch, Post, Put
+from nest.web.pynset_web_factory import PyNestWebFactory
diff --git a/nest/core/decorators/class_based_view.py b/nest/web/class_based_view.py
similarity index 95%
rename from nest/core/decorators/class_based_view.py
rename to nest/web/class_based_view.py
index a465542..e73c3cd 100644
--- a/nest/core/decorators/class_based_view.py
+++ b/nest/web/class_based_view.py
@@ -4,16 +4,24 @@
"""
import inspect
-from typing import Any, Callable, List, Type, TypeVar, Union, get_type_hints
+from typing import (
+ Any,
+ Callable,
+ ClassVar,
+ List,
+ Type,
+ TypeVar,
+ Union,
+ get_origin,
+ get_type_hints,
+)
from fastapi import APIRouter, Depends
-from pydantic.typing import is_classvar
from starlette.routing import Route, WebSocketRoute
T = TypeVar("T")
K = TypeVar("K", bound=Callable[..., Any])
-
CBV_CLASS_KEY = "__cbv_class__"
@@ -61,7 +69,7 @@ def _init_cbv(cls: Type[Any]) -> None:
]
dependency_names: List[str] = []
for name, hint in get_type_hints(cls).items():
- if is_classvar(hint):
+ if get_origin(hint) is ClassVar:
continue
parameter_kwargs = {"default": getattr(cls, name, Ellipsis)}
dependency_names.append(name)
diff --git a/nest/core/decorators/controller.py b/nest/web/controller.py
similarity index 95%
rename from nest/core/decorators/controller.py
rename to nest/web/controller.py
index 8073083..d5c2d41 100644
--- a/nest/core/decorators/controller.py
+++ b/nest/web/controller.py
@@ -2,9 +2,9 @@
from fastapi.routing import APIRouter
-from nest.core.decorators.class_based_view import class_based_view as ClassBasedView
-from nest.core.decorators.http_method import HTTPMethod
-from nest.core.decorators.utils import get_instance_variables, parse_dependencies
+from nest.core.utils import get_instance_variables, parse_dependencies
+from nest.web.class_based_view import class_based_view as ClassBasedView
+from nest.web.http_method import HTTPMethod
def Controller(prefix: Optional[str] = None, tag: Optional[str] = None):
diff --git a/nest/core/decorators/http_code.py b/nest/web/http_code.py
similarity index 100%
rename from nest/core/decorators/http_code.py
rename to nest/web/http_code.py
diff --git a/nest/core/decorators/http_method.py b/nest/web/http_method.py
similarity index 100%
rename from nest/core/decorators/http_method.py
rename to nest/web/http_method.py
diff --git a/nest/core/pynest_application.py b/nest/web/pynest_fastapi_application.py
similarity index 94%
rename from nest/core/pynest_application.py
rename to nest/web/pynest_fastapi_application.py
index 22e2669..8db6f0e 100644
--- a/nest/core/pynest_application.py
+++ b/nest/web/pynest_fastapi_application.py
@@ -2,12 +2,12 @@
from fastapi import FastAPI
-from nest.common.route_resolver import RoutesResolver
from nest.core.pynest_app_context import PyNestApplicationContext
from nest.core.pynest_container import PyNestContainer
+from nest.web.route_resolver import RoutesResolver
-class PyNestApp(PyNestApplicationContext):
+class PyNestFastapiApp(PyNestApplicationContext):
"""
PyNestApp is the main application class for the PyNest framework,
managing the container and HTTP server.
diff --git a/nest/web/pynset_web_factory.py b/nest/web/pynset_web_factory.py
new file mode 100644
index 0000000..dbf4f65
--- /dev/null
+++ b/nest/web/pynset_web_factory.py
@@ -0,0 +1,42 @@
+from abc import ABC, abstractmethod
+from typing import Type, TypeVar
+
+from fastapi import FastAPI
+
+from nest.core.pynest_container import PyNestContainer
+from nest.core.pynest_factory import AbstractPyNestFactory, ModuleType
+from nest.web.pynest_fastapi_application import PyNestFastapiApp
+
+
+class PyNestWebFactory(AbstractPyNestFactory):
+ """Factory class for creating PyNest applications."""
+
+ @staticmethod
+ def create(main_module: Type[ModuleType], **kwargs) -> PyNestFastapiApp:
+ """
+ Create a PyNest application with the specified main module class.
+
+ Args:
+ main_module (ModuleType): The main module for the PyNest application.
+ **kwargs: Additional keyword arguments for the FastAPI server.
+
+ Returns:
+ PyNestApp: The created PyNest application.
+ """
+ container = PyNestContainer()
+ container.add_module(main_module)
+ http_server = PyNestWebFactory._create_server(**kwargs)
+ return PyNestFastapiApp(container, http_server)
+
+ @staticmethod
+ def _create_server(**kwargs) -> FastAPI:
+ """
+ Create a FastAPI server.
+
+ Args:
+ **kwargs: Additional keyword arguments for the FastAPI server.
+
+ Returns:
+ FastAPI: The created FastAPI server.
+ """
+ return FastAPI(**kwargs)
diff --git a/nest/common/route_resolver.py b/nest/web/route_resolver.py
similarity index 100%
rename from nest/common/route_resolver.py
rename to nest/web/route_resolver.py
diff --git a/pyproject.toml b/pyproject.toml
index 9acd99e..ac5c5f3 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,48 +1,86 @@
[build-system]
-requires = ["setuptools>=61.0", "wheel>=0.37.0"]
-build-backend = "setuptools.build_meta"
+requires = ["poetry-core"]
+build-backend = "poetry.core.masonry.api"
-[project]
+[tool.poetry]
name = "pynest-api"
+version = "0.3.1"
description = "PyNest is a FastAPI Abstraction for building microservices, influenced by NestJS."
+authors = ["itay.dar "]
readme = "README.md"
-requires-python = ">=3.8.1"
-license = { file = "LICENSE" }
-authors = [
- { name = "Itay Dar", email = "itay2803@gmail.com" },
+homepage = "https://github.com/PythonNest/PyNest"
+documentation = "https://pythonnest.github.io/PyNest/"
+packages = [
+ { include = "nest" }
]
-dynamic = ["version"]
classifiers = [
- "Development Status :: 5 - Production/Stable",
- "Intended Audience :: Developers",
- "Operating System :: OS Independent",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
+ "Programming Language :: Python :: 3.12",
+ "Operating System :: OS Independent",
+ "License :: OSI Approved :: MIT License",
+ "Development Status :: 4 - Beta",
+ "Intended Audience :: Developers",
+ "Topic :: Software Development :: Libraries :: Python Modules",
]
-dependencies = [
- "click>=8.1.6",
- "fastapi>=0.88.0,<1.0.0",
- "python-dotenv>=1.0.0",
- "uvicorn>=0.23.1",
- "PyYAML>=6.0.1",
- "astor>=0.8.1",
- "black>=23.11.0",
- "injector>=0.20.1",
- "pydantic<2.0.0",
- "sqlalchemy == 2.0.19",
- "alembic == 1.7.5",
-]
-[tool.setuptools.dynamic]
-version = { attr = "nest.__init__.__version__" }
-[tool.pip]
-index-url = "https://pypi.org/simple"
-trusted-host = ["pypi.org", "files.pythonhosted.org"]
-[tools.black]
+[tool.poetry.dependencies]
+python = "^3.10"
+# Core dependencies
+click = "^8.1.7"
+injector = "^0.22.0"
+astor = "^0.8.1"
+pyyaml = "^6.0.2"
+black = "^24.10.0"
+
+
+# Optional dependencies
+fastapi = { version = "^0.115.4", optional = true }
+pydantic = { version = "^2.9.2", optional = true }
+uvicorn = { version = "^0.32.0", optional = true }
+sqlalchemy = { version = "^2.0.36", optional = true }
+asyncpg = { version = "^0.30.0", optional = true }
+psycopg2 = { version = "^2.9.3", optional = true }
+alembic = { version = "^1.13.3", optional = true }
+beanie = { version = "^1.27.0", optional = true }
+python-dotenv = { version = "^1.0.1", optional = true }
+greenlet = { version = "^3.1.1", optional = true }
+
+
+
+[tool.poetry.extras]
+fastapi = ["fastapi", "pydantic", "uvicorn"]
+postgres = ["sqlalchemy", "asyncpg", "psycopg2", "alembic", "greenlet", "python-dotenv"]
+mongo = ["beanie", "python-dotenv"]
+test = ["pytest"]
+
+[tool.poetry.group.build.dependencies]
+setuptools = "^75.3.0"
+wheel = "^0.44.0"
+build = "^1.2.2.post1"
+twine = "^5.1.1"
+git-changelog = "^2.5.2"
+
+[tool.poetry.group.test.dependencies]
+pytest = "^7.0.1"
+fastapi = "^0.115.4"
+sqlalchemy = "^2.0.36"
+motor = "^3.2.0"
+beanie = "^1.27.0"
+pydantic = "^2.9.2"
+python-dotenv = "^1.0.1"
+uvicorn = "^0.32.0"
+
+[tool.poetry.group.docs.dependencies]
+mkdocs-material = "^9.5.43"
+mkdocstrings-python = "^1.12.2"
+
+
+[tool.black]
force-exclude = '''
/(
| /*venv*
@@ -58,34 +96,18 @@ force-exclude = '''
)/
'''
-[project.optional-dependencies]
-test = [
- "pytest == 6.2.5",
+[tool.mypy]
+exclude = [
+ "/*venv*"
]
+ignore_missing_imports = true
-orm = [
- "sqlalchemy == 2.0.19",
- "alembic == 1.7.4",
-]
-mongo = [
- "pymongo == 3.12.0",
- "motor == 3.2.0",
- "beanie == 1.20.0",
-]
+[tool.poetry.urls]
+Homepage = "https://github.com/PythonNest/PyNest"
+Documentation = "https://pythonnest.github.io/PyNest/"
-[project.scripts]
+[tool.poetry.scripts]
pynest = "nest.cli.cli:nest_cli"
-[tool.setuptools.packages.find]
-include = ["nest*"]
-namespaces = false
-[tool.mypy]
-exclude = [
- "/*venv*"
-]
-ignore_missing_imports = true
-[project.urls]
-"Homepage" = "https://github.com/PythonNest/PyNest"
-"Documentation" = "https://pythonnest.github.io/PyNest/"
diff --git a/tests/test_core/__init__.py b/tests/test_core/__init__.py
index f5303b4..40e79ec 100644
--- a/tests/test_core/__init__.py
+++ b/tests/test_core/__init__.py
@@ -1,16 +1,9 @@
import pytest
from fastapi import FastAPI
-from nest.common.route_resolver import RoutesResolver
-from nest.core import (
- Controller,
- Get,
- Injectable,
- Module,
- PyNestContainer,
- PyNestFactory,
-)
-from nest.core.pynest_application import PyNestApp
+from nest.core import Injectable, Module, PyNestContainer
+from nest.web import Controller, Get, PyNestWebFactory
+from nest.web.route_resolver import RoutesResolver
@Injectable
@@ -45,7 +38,7 @@ def test_module():
@pytest.fixture
def test_server() -> FastAPI:
- server = PyNestFactory._create_server(
+ server = PyNestWebFactory._create_server(
title="Test Server",
description="This is a test server",
version="1.0.0",
diff --git a/tests/test_core/test_database/test_odm.py b/tests/test_core/test_database/test_odm.py
index 7b2ffb2..a935c47 100644
--- a/tests/test_core/test_database/test_odm.py
+++ b/tests/test_core/test_database/test_odm.py
@@ -1,9 +1,7 @@
-import os
-
import pytest
-from nest.core.database.odm_config import ConfigFactory, MongoDBConfig
-from nest.core.database.odm_provider import OdmProvider
+from nest.database.odm_config import MongoDBConfig
+from nest.database.odm_provider import OdmProvider
@pytest.fixture(scope="module")
@@ -36,7 +34,7 @@ def test_odm_service_definition(odm_service):
def test_odm_service_config_url(odm_service):
config_url = odm_service.config_url
- assert config_url == "mongodb://user:password@host:port"
+ assert config_url == "mongodb://user:password@host:port/db_name"
def test_mongo_config_definition(mongodb_config):
diff --git a/tests/test_core/test_database/test_orm.py b/tests/test_core/test_database/test_orm.py
index 82ddf35..e4ea55e 100644
--- a/tests/test_core/test_database/test_orm.py
+++ b/tests/test_core/test_database/test_orm.py
@@ -2,8 +2,8 @@
import pytest
-from nest.core.database.orm_config import ConfigFactory
-from nest.core.database.orm_provider import OrmProvider
+from nest.database.orm_config import ConfigFactory
+from nest.database.orm_provider import OrmProvider
@pytest.fixture(scope="module")
diff --git a/tests/test_core/test_decorators/test_controller.py b/tests/test_core/test_decorators/test_controller.py
index 0985014..dd594e7 100644
--- a/tests/test_core/test_decorators/test_controller.py
+++ b/tests/test_core/test_decorators/test_controller.py
@@ -1,6 +1,7 @@
import pytest
-from nest.core import Controller, Delete, Get, Injectable, Patch, Post, Put
+from nest.core import Injectable
+from nest.web import Controller, Delete, Get, Patch, Post, Put
@Controller(prefix="api/v1/user", tag="test")
diff --git a/tests/test_core/test_pynest_application.py b/tests/test_core/test_pynest_application.py
index df364b7..e46467a 100644
--- a/tests/test_core/test_pynest_application.py
+++ b/tests/test_core/test_pynest_application.py
@@ -1,13 +1,13 @@
import pytest
-from nest.core import PyNestApp
+from nest.web.pynest_fastapi_application import PyNestFastapiApp
from tests.test_core import test_container, test_resolver
from tests.test_core.test_pynest_factory import test_server
@pytest.fixture
def pynest_app(test_container, test_server):
- return PyNestApp(container=test_container, http_server=test_server)
+ return PyNestFastapiApp(container=test_container, http_server=test_server)
def test_is_listening_property(pynest_app):
diff --git a/tests/test_core/test_pynest_factory.py b/tests/test_core/test_pynest_factory.py
index 51ecb0f..c7cb627 100644
--- a/tests/test_core/test_pynest_factory.py
+++ b/tests/test_core/test_pynest_factory.py
@@ -1,7 +1,9 @@
import pytest
from fastapi import FastAPI
-from nest.core import PyNestFactory # Replace 'your_module' with the actual module name
+from nest.web import (
+ PyNestWebFactory,
+)
from tests.test_core import test_container, test_module, test_server
@@ -14,7 +16,7 @@ def test_create_server(test_server):
def test_e2e(test_module):
- app = PyNestFactory.create(
+ app = PyNestWebFactory.create(
test_module,
title="Test Server",
description="This is a test server",