From f9b7c80b981542b4d0d1e9b81c7abb0cfea6caef Mon Sep 17 00:00:00 2001
From: ItayTheDar
Date: Mon, 17 Jul 2023 07:18:00 +0300
Subject: [PATCH 01/16] add license tag
---
README.md | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 0487b0f..5132b2a 100644
--- a/README.md
+++ b/README.md
@@ -11,9 +11,12 @@
+
+
+
-# PyNest - Description
+# Description
PyNest is designed to help structure your APIs in an intuitive, easy to understand, and enjoyable way.
From 04563495f98c156fb22a262d5af1c85d974b9a6a Mon Sep 17 00:00:00 2001
From: ItayTheDar
Date: Wed, 19 Jul 2023 19:29:45 +0300
Subject: [PATCH 02/16] add support in ODM
---
nest/core/database/base_orm.py | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/nest/core/database/base_orm.py b/nest/core/database/base_orm.py
index f07f2ad..e5a545e 100644
--- a/nest/core/database/base_orm.py
+++ b/nest/core/database/base_orm.py
@@ -68,3 +68,15 @@ def get_db(self) -> Session:
return session()
except Exception as e:
raise e
+
+
+class MongoService:
+
+ def __init__(self, config_params: dict = None):
+ self.config = ConfigFactory(db_type="mongodb").get_config()
+ self.config_url = self.config(**config_params).get_engine_url()
+
+
+
+
+
From 0102176fe9a254514e345b713658c6461f8b4c7c Mon Sep 17 00:00:00 2001
From: ItayTheDar
Date: Sun, 23 Jul 2023 00:40:54 +0300
Subject: [PATCH 03/16] change the src type in module creation
---
nest/cli/click_handlers.py | 33 +++++++++++++++++++++++++++++++--
1 file changed, 31 insertions(+), 2 deletions(-)
diff --git a/nest/cli/click_handlers.py b/nest/cli/click_handlers.py
index 80d5644..11ac9ed 100644
--- a/nest/cli/click_handlers.py
+++ b/nest/cli/click_handlers.py
@@ -380,6 +380,32 @@ def get_module_end_index(lines, modules_start_index):
return modules_end_index
+def append_module_to_app(path_to_app_py: Path, new_module: str, db_type: str):
+ """
+ Append a module import statement to the app.py file.
+
+ Args:
+ path_to_app_py (Path): The path to the app.py file.
+ new_module (str): The name of the new module to import.
+ db_type (str): The type of database to use.
+
+ return new_import, capitalized_new_module
+
+ Returns:
+ None
+ """
+ split_new_module = new_module.split("_")
+ capitalized_new_module = "".join([word.capitalize() for word in split_new_module])
+
+ lines, _ = append_import(path_to_app_py, new_module, db_type)
+ # Find the line index where the modules list starts
+ modules_start_index = next(
+ (i for i, line in enumerate(lines) if "modules=[" in line),
+ len(lines) - 1, # If modules list not found, append the new module at the end
+ )
+ return modules_end_index
+
+
def append_module_to_app(path_to_app_py: Path, new_module: str, db_type: str):
"""
Append a module import statement to the app.py file.
@@ -408,6 +434,9 @@ def append_module_to_app(path_to_app_py: Path, new_module: str, db_type: str):
# Find the line index where the modules list ends
modules_end_index = get_module_end_index(lines, modules_start_index)
+ # Find the line index where the modules list ends
+ modules_end_index = get_module_end_index(lines, modules_start_index)
+
# Insert the new module before the closing bracket or at the end of the file
new_lines = (
lines[:modules_end_index]
@@ -467,10 +496,10 @@ def create_nest_module(name: str):
├── module_name_entity.py
├── module_name_module.py
"""
- src_path = Path("/Users/itayd/PycharmProjects/testMongo") / "src"
+ src_path = Path(find_target_folder(os.getcwd(), "src"))
+
if name in [x.name for x in src_path.iterdir()]:
raise Exception(f"module {name} already exists")
- # src_path = Path(find_target_folder(os.getcwd(), "src"))
if not src_path:
raise Exception("src folder not found")
From 99e07847c5bf9a34183a1ec5b1ee0cf97dfd64fd Mon Sep 17 00:00:00 2001
From: ItayTheDar
Date: Sun, 23 Jul 2023 14:33:57 +0300
Subject: [PATCH 04/16] bump version. make requierments granular update readme
badges remove deprecated `InferringRouter`
---
README.md | 22 +++++++++++++---------
nest/core/decorators/controller.py | 4 ++--
pyproject.toml | 20 ++++++--------------
3 files changed, 21 insertions(+), 25 deletions(-)
diff --git a/README.md b/README.md
index 5132b2a..0edaba8 100644
--- a/README.md
+++ b/README.md
@@ -5,17 +5,21 @@
PyNest is a Python framework built on top of FastAPI that follows the modular architecture of NestJS
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
# Description
PyNest is designed to help structure your APIs in an intuitive, easy to understand, and enjoyable way.
diff --git a/nest/core/decorators/controller.py b/nest/core/decorators/controller.py
index 44cc904..16a5f98 100644
--- a/nest/core/decorators/controller.py
+++ b/nest/core/decorators/controller.py
@@ -1,5 +1,5 @@
from fastapi_utils.cbv import _cbv as ClassBasedView
-from fastapi_utils.inferring_router import InferringRouter
+from fastapi.routing import APIRouter
def Controller(tag: str = None, prefix: str = None):
@@ -21,7 +21,7 @@ def Controller(tag: str = None, prefix: str = None):
prefix = prefix[:-1]
def wrapper(cls):
- router = InferringRouter(tags=[tag] if tag else None)
+ router = APIRouter(tags=[tag] if tag else None)
for name, method in cls.__dict__.items():
if callable(method) and hasattr(method, "method"):
diff --git a/pyproject.toml b/pyproject.toml
index f9866eb..eb8fe41 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -17,26 +17,18 @@ classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"Operating System :: OS Independent",
- "Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
]
dependencies = [
- "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",
+ "click==8.1.6",
+ "fastapi==0.100.0",
+ "fastapi-utils==0.3.0",
+ "pydantic==2.0.3",
"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",
+ "SQLAlchemy==2.0.19",
+ "uvicorn==0.23.1",
]
[tool.setuptools.dynamic]
From 244a22a883e88256ea60fd11be49220ca34855c9 Mon Sep 17 00:00:00 2001
From: ItayTheDar
Date: Sun, 23 Jul 2023 14:51:18 +0300
Subject: [PATCH 05/16] unbump version.
---
pyproject.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyproject.toml b/pyproject.toml
index eb8fe41..dbef19a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -24,7 +24,7 @@ classifiers = [
dependencies = [
"click==8.1.6",
"fastapi==0.100.0",
- "fastapi-utils==0.3.0",
+ "fastapi-utils==0.2.1",
"pydantic==2.0.3",
"python-dotenv==1.0.0",
"SQLAlchemy==2.0.19",
From de25b625bc8c365343cf919bdebcdcb79c1c667a Mon Sep 17 00:00:00 2001
From: ItayTheDar
Date: Sun, 23 Jul 2023 23:44:46 +0300
Subject: [PATCH 06/16] remove pydatinc since it's a deps
---
pyproject.toml | 1 -
1 file changed, 1 deletion(-)
diff --git a/pyproject.toml b/pyproject.toml
index dbef19a..4562971 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -25,7 +25,6 @@ dependencies = [
"click==8.1.6",
"fastapi==0.100.0",
"fastapi-utils==0.2.1",
- "pydantic==2.0.3",
"python-dotenv==1.0.0",
"SQLAlchemy==2.0.19",
"uvicorn==0.23.1",
From edb4305ab290a07d4d7af3651712d80ea5c5c3db Mon Sep 17 00:00:00 2001
From: ItayTheDar
Date: Sun, 23 Jul 2023 23:51:44 +0300
Subject: [PATCH 07/16] remove fastapi-utils and use only the single file that
create the abstract class based view
---
nest/core/decorators/controller.py | 2 +-
nest/core/decorators/helpers.py | 84 ++++++++++++++++++++++++++++++
pyproject.toml | 1 -
3 files changed, 85 insertions(+), 2 deletions(-)
create mode 100644 nest/core/decorators/helpers.py
diff --git a/nest/core/decorators/controller.py b/nest/core/decorators/controller.py
index 16a5f98..f9fb57c 100644
--- a/nest/core/decorators/controller.py
+++ b/nest/core/decorators/controller.py
@@ -1,5 +1,5 @@
-from fastapi_utils.cbv import _cbv as ClassBasedView
from fastapi.routing import APIRouter
+from nest.core.decorators.helpers import class_based_view as ClassBasedView
def Controller(tag: str = None, prefix: str = None):
diff --git a/nest/core/decorators/helpers.py b/nest/core/decorators/helpers.py
new file mode 100644
index 0000000..f67eaf2
--- /dev/null
+++ b/nest/core/decorators/helpers.py
@@ -0,0 +1,84 @@
+import inspect
+from typing import Any, Callable, List, Type, TypeVar, Union, get_type_hints
+
+from fastapi import APIRouter, Depends
+from pydantic.typing import is_classvar
+from starlette.routing import Route, WebSocketRoute
+
+T = TypeVar("T")
+
+CBV_CLASS_KEY = "__cbv_class__"
+
+
+def class_based_view(router: APIRouter, cls: Type[T]) -> Type[T]:
+ """
+ Replaces any methods of the provided class `cls` that are endpoints of routes in `router` with updated
+ function calls that will properly inject an instance of `cls`.
+ """
+ _init_cbv(cls)
+ cbv_router = APIRouter()
+ function_members = inspect.getmembers(cls, inspect.isfunction)
+ functions_set = set(func for _, func in function_members)
+ cbv_routes = [
+ route
+ for route in router.routes
+ if isinstance(route, (Route, WebSocketRoute)) and route.endpoint in functions_set
+ ]
+ for route in cbv_routes:
+ router.routes.remove(route)
+ _update_cbv_route_endpoint_signature(cls, route)
+ cbv_router.routes.append(route)
+ router.include_router(cbv_router)
+ return cls
+
+
+def _init_cbv(cls: Type[Any]) -> None:
+ """
+ Idempotently modifies the provided `cls`, performing the following modifications:
+ * The `__init__` function is updated to set any class-annotated dependencies as instance attributes
+ * The `__signature__` attribute is updated to indicate to FastAPI what arguments should be passed to the initializer
+ """
+ if getattr(cls, CBV_CLASS_KEY, False): # pragma: no cover
+ return # Already initialized
+ old_init: Callable[..., Any] = cls.__init__
+ old_signature = inspect.signature(old_init)
+ old_parameters = list(old_signature.parameters.values())[1:] # drop `self` parameter
+ new_parameters = [
+ x for x in old_parameters if x.kind not in (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD)
+ ]
+ dependency_names: List[str] = []
+ for name, hint in get_type_hints(cls).items():
+ if is_classvar(hint):
+ continue
+ parameter_kwargs = {"default": getattr(cls, name, Ellipsis)}
+ dependency_names.append(name)
+ new_parameters.append(
+ inspect.Parameter(name=name, kind=inspect.Parameter.KEYWORD_ONLY, annotation=hint, **parameter_kwargs)
+ )
+ new_signature = old_signature.replace(parameters=new_parameters)
+
+ def new_init(self: Any, *args: Any, **kwargs: Any) -> None:
+ for dep_name in dependency_names:
+ dep_value = kwargs.pop(dep_name)
+ setattr(self, dep_name, dep_value)
+ old_init(self, *args, **kwargs)
+
+ setattr(cls, "__signature__", new_signature)
+ setattr(cls, "__init__", new_init)
+ setattr(cls, CBV_CLASS_KEY, True)
+
+
+def _update_cbv_route_endpoint_signature(cls: Type[Any], route: Union[Route, WebSocketRoute]) -> None:
+ """
+ Fixes the endpoint signature for a cbv route to ensure FastAPI performs dependency injection properly.
+ """
+ old_endpoint = route.endpoint
+ old_signature = inspect.signature(old_endpoint)
+ old_parameters: List[inspect.Parameter] = list(old_signature.parameters.values())
+ old_first_parameter = old_parameters[0]
+ new_first_parameter = old_first_parameter.replace(default=Depends(cls))
+ new_parameters = [new_first_parameter] + [
+ parameter.replace(kind=inspect.Parameter.KEYWORD_ONLY) for parameter in old_parameters[1:]
+ ]
+ new_signature = old_signature.replace(parameters=new_parameters)
+ setattr(route.endpoint, "__signature__", new_signature)
diff --git a/pyproject.toml b/pyproject.toml
index 4562971..587464c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -24,7 +24,6 @@ classifiers = [
dependencies = [
"click==8.1.6",
"fastapi==0.100.0",
- "fastapi-utils==0.2.1",
"python-dotenv==1.0.0",
"SQLAlchemy==2.0.19",
"uvicorn==0.23.1",
From 9b501b34d8dbedccb384ee6cef889f6f6e043b18 Mon Sep 17 00:00:00 2001
From: ItayTheDar
Date: Sun, 23 Jul 2023 23:53:15 +0300
Subject: [PATCH 08/16] remove fastapi-utils and use only the single file that
create the abstract class based view
---
nest/core/decorators/helpers.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/nest/core/decorators/helpers.py b/nest/core/decorators/helpers.py
index f67eaf2..e5fa78d 100644
--- a/nest/core/decorators/helpers.py
+++ b/nest/core/decorators/helpers.py
@@ -1,3 +1,9 @@
+'''
+Credit: FastAPI-Utils
+Source: https://github.com/dmontagu/fastapi-utils/blob/master/fastapi_utils/cbv.py
+'''
+
+
import inspect
from typing import Any, Callable, List, Type, TypeVar, Union, get_type_hints
From b7dba03585faddbeb8ecddcb141646a76591d5cd Mon Sep 17 00:00:00 2001
From: ItayTheDar
Date: Mon, 24 Jul 2023 07:00:26 +0300
Subject: [PATCH 09/16] fix pydantic error
---
pyproject.toml | 1 +
1 file changed, 1 insertion(+)
diff --git a/pyproject.toml b/pyproject.toml
index 587464c..50e2ff8 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -27,6 +27,7 @@ dependencies = [
"python-dotenv==1.0.0",
"SQLAlchemy==2.0.19",
"uvicorn==0.23.1",
+ "pydantic==1.8.2",
]
[tool.setuptools.dynamic]
From 64f328e05b70a1fd88087ee896ffe1cd712148a9 Mon Sep 17 00:00:00 2001
From: ItayTheDar
Date: Mon, 24 Jul 2023 07:05:58 +0300
Subject: [PATCH 10/16] fix pydantic error
---
pyproject.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyproject.toml b/pyproject.toml
index 50e2ff8..aa56a8a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -23,7 +23,7 @@ classifiers = [
]
dependencies = [
"click==8.1.6",
- "fastapi==0.100.0",
+ "fastapi==0.95.1",
"python-dotenv==1.0.0",
"SQLAlchemy==2.0.19",
"uvicorn==0.23.1",
From ecf089d8b4d0dc5d908edfe7db819f96f28ace18 Mon Sep 17 00:00:00 2001
From: ItayTheDar
Date: Tue, 25 Jul 2023 17:49:34 +0300
Subject: [PATCH 11/16] fix pydantic error
---
pyproject.toml | 1 -
1 file changed, 1 deletion(-)
diff --git a/pyproject.toml b/pyproject.toml
index aa56a8a..c1970c8 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -27,7 +27,6 @@ dependencies = [
"python-dotenv==1.0.0",
"SQLAlchemy==2.0.19",
"uvicorn==0.23.1",
- "pydantic==1.8.2",
]
[tool.setuptools.dynamic]
From 424875b99f885e7e15fd5fcc2ff67a5dd46800b8 Mon Sep 17 00:00:00 2001
From: ItayTheDar
Date: Tue, 25 Jul 2023 20:42:04 +0300
Subject: [PATCH 12/16] add user name and password for odm config object for
better security
---
nest/core/database/base_odm.py | 14 +++++---------
nest/core/database/base_orm.py | 12 ------------
nest/core/database/config.py | 17 ++++++++---------
nest/core/database/odm_config.py | 14 +++++++++++---
4 files changed, 24 insertions(+), 33 deletions(-)
diff --git a/nest/core/database/base_odm.py b/nest/core/database/base_odm.py
index b4caa01..81cc365 100644
--- a/nest/core/database/base_odm.py
+++ b/nest/core/database/base_odm.py
@@ -18,10 +18,8 @@ class OdmService:
document_models (beanie.Document): a list of beanie.Document instances
Attributes:
- Base: The declarative base class for defining ORM models.
config: The configuration factory for the chosen database type.
config_url: The URL generated from the database configuration parameters.
- client: The Motor client for database connection.
"""
@@ -53,13 +51,11 @@ def check_document_models(self):
"""
Checks that the document_models argument is a list of beanie.Document instances.
- Args:
- document_models (beanie.Document): a list of beanie.Document instances
"""
if not isinstance(self.document_models, list):
raise Exception("document_models should be a list")
- # for document_model in self.document_models:
- # if not isinstance(document_model, Document):
- # raise Exception(
- # "Each item in document_models should be an instance of beanie.Document"
- # )
+ for document_model in self.document_models:
+ if not issubclass(document_model, Document):
+ raise Exception(
+ "Each item in document_models should be a subclass of beanie.Document"
+ )
diff --git a/nest/core/database/base_orm.py b/nest/core/database/base_orm.py
index e5a545e..f07f2ad 100644
--- a/nest/core/database/base_orm.py
+++ b/nest/core/database/base_orm.py
@@ -68,15 +68,3 @@ def get_db(self) -> Session:
return session()
except Exception as e:
raise e
-
-
-class MongoService:
-
- def __init__(self, config_params: dict = None):
- self.config = ConfigFactory(db_type="mongodb").get_config()
- self.config_url = self.config(**config_params).get_engine_url()
-
-
-
-
-
diff --git a/nest/core/database/config.py b/nest/core/database/config.py
index aa7bcb0..77bb799 100644
--- a/nest/core/database/config.py
+++ b/nest/core/database/config.py
@@ -34,7 +34,7 @@ def get_config(self):
assert self.db_type, "db_type is required"
-class BaseOdmConfig:
+class BaseConfig:
"""
Base abstract class for ODM (Object-Document Mapping) configurations.
@@ -52,18 +52,13 @@ def get_engine_url(self) -> str:
pass
-class BaseProvider(BaseOdmConfig):
+class BaseProvider(BaseConfig):
"""
- Base class for ODM providers that implement the BaseOdmConfig interface.
-
- Args:
- host (str): The database host.
- db_name (str): The name of the database.
- port (int): The database port number.
+ Base class for Objets Mapping providers that implement the BaseConfig interface.
"""
- def __init__(self, host: str, db_name: str, port: int):
+ def __init__(self, host: str, db_name: str, port: int, user: str, password: str):
"""
Initializes the BaseOdmProvider instance.
@@ -71,11 +66,15 @@ def __init__(self, host: str, db_name: str, port: int):
host (str): The database host.
db_name (str): The name of the database.
port (int): The database port number.
+ user (str): The username for database authentication.
+ password (str): The password for database authentication.
"""
self.host = host
self.db_name = db_name
self.port = port
+ self.user = user
+ self.password = password
def get_engine_url(self) -> str:
"""
diff --git a/nest/core/database/odm_config.py b/nest/core/database/odm_config.py
index 163baa0..6e13043 100644
--- a/nest/core/database/odm_config.py
+++ b/nest/core/database/odm_config.py
@@ -1,4 +1,4 @@
-from nest.core.database.config import BaseOdmConfig, ConfigFactoryBase, BaseProvider
+from nest.core.database.config import ConfigFactoryBase, BaseProvider
class MongoDBConfig(BaseProvider):
@@ -15,7 +15,15 @@ class MongoDBConfig(BaseProvider):
"""
- def __init__(self, host: str, db_name: str, port: int = 27017, srv: bool = False):
+ def __init__(
+ self,
+ host: str,
+ db_name: str,
+ port: int = 27017,
+ user: str = None,
+ password: str = None,
+ srv: bool = False
+ ):
"""
Initializes the MongoDBConfig instance.
@@ -29,7 +37,7 @@ def __init__(self, host: str, db_name: str, port: int = 27017, srv: bool = False
"""
self.srv = srv
- super().__init__(host, db_name, port)
+ super().__init__(host, db_name, port, user, password)
def get_engine_url(self) -> str:
"""
From fe1265a1f548309f976bf4c0bbef92fff27d1f5d Mon Sep 17 00:00:00 2001
From: ItayTheDar
Date: Fri, 28 Jul 2023 07:11:59 +0300
Subject: [PATCH 13/16] fix orm misconfiguration. add more unit test to verify
databases urls
---
nest/common/templates/orm_config.py | 2 +
nest/core/database/config.py | 4 +-
nest/core/database/odm_config.py | 6 +-
nest/core/database/orm_config.py | 2 +-
nest/core/decorators/controller.py | 4 +-
tests/test_core/test_database/test_odm.py | 23 +++--
tests/test_core/test_database/test_orm.py | 103 ++++++++++++++++------
7 files changed, 105 insertions(+), 39 deletions(-)
diff --git a/nest/common/templates/orm_config.py b/nest/common/templates/orm_config.py
index ee8f6d7..6715f17 100644
--- a/nest/common/templates/orm_config.py
+++ b/nest/common/templates/orm_config.py
@@ -55,6 +55,8 @@ def generate_orm_config(db_type: str):
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]
diff --git a/nest/core/database/config.py b/nest/core/database/config.py
index 77bb799..32a1707 100644
--- a/nest/core/database/config.py
+++ b/nest/core/database/config.py
@@ -58,7 +58,7 @@ class BaseProvider(BaseConfig):
"""
- def __init__(self, host: str, db_name: str, port: int, user: str, password: str):
+ def __init__(self, host: str, db_name: str, user: str, password: str, port: int):
"""
Initializes the BaseOdmProvider instance.
@@ -72,9 +72,9 @@ def __init__(self, host: str, db_name: str, port: int, user: str, password: str)
"""
self.host = host
self.db_name = db_name
- self.port = port
self.user = user
self.password = password
+ self.port = port
def get_engine_url(self) -> str:
"""
diff --git a/nest/core/database/odm_config.py b/nest/core/database/odm_config.py
index 6e13043..b2f79d1 100644
--- a/nest/core/database/odm_config.py
+++ b/nest/core/database/odm_config.py
@@ -19,9 +19,9 @@ def __init__(
self,
host: str,
db_name: str,
- port: int = 27017,
user: str = None,
password: str = None,
+ port: int = 27017,
srv: bool = False
):
"""
@@ -37,7 +37,7 @@ def __init__(
"""
self.srv = srv
- super().__init__(host, db_name, port, user, password)
+ super().__init__(host, db_name, user, password, port)
def get_engine_url(self) -> str:
"""
@@ -47,7 +47,7 @@ def get_engine_url(self) -> str:
str: The engine URL.
"""
- return f"mongodb{'+srv' if self.srv else ''}://{self.host}:{self.port}"
+ return f"mongodb{'+srv' if self.srv else ''}://{self.user}:{self.password}@{self.host}:{self.port}"
class ConfigFactory(ConfigFactoryBase):
diff --git a/nest/core/database/orm_config.py b/nest/core/database/orm_config.py
index 946986b..9a452a4 100644
--- a/nest/core/database/orm_config.py
+++ b/nest/core/database/orm_config.py
@@ -76,7 +76,7 @@ def get_engine_url(self) -> str:
str: The engine URL.
"""
- return f"mysql+mysqlconnector://{self.user}:{self.password}@{self.host}"
+ return f"mysql+mysqlconnector://{self.user}:{self.password}@{self.host}:{self.port}/{self.db_name}"
class SQLiteConfig(BaseConfig):
diff --git a/nest/core/decorators/controller.py b/nest/core/decorators/controller.py
index f9fb57c..d5d3912 100644
--- a/nest/core/decorators/controller.py
+++ b/nest/core/decorators/controller.py
@@ -70,10 +70,10 @@ def wrapper(cls):
else:
raise Exception("Invalid method")
- def get_router():
+ def get_router() -> APIRouter:
"""
Returns:
- InferringRouter: The router associated with the controller.
+ APIRouter: The router associated with the controller.
"""
return router
diff --git a/tests/test_core/test_database/test_odm.py b/tests/test_core/test_database/test_odm.py
index 66c65c9..67284be 100644
--- a/tests/test_core/test_database/test_odm.py
+++ b/tests/test_core/test_database/test_odm.py
@@ -14,9 +14,11 @@ def odm_service():
return OdmService(
db_type="mongodb",
config_params={
- "db_name": "test",
- "host": "test",
- "port": "test",
+ "db_name": "db_name",
+ "host": "host",
+ "user": "user",
+ "password": "password",
+ "port": "port",
},
document_models=[],
)
@@ -24,7 +26,13 @@ def odm_service():
@pytest.fixture(scope="module")
def mongodb_config():
- return MongoDBConfig("test", "test", "test")
+ return MongoDBConfig(
+ db_name="db_name"
+ , host="host"
+ , user="user"
+ , password="password"
+ , port="port"
+ )
def test_odm_service_definition(odm_service):
@@ -35,4 +43,9 @@ 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://test:test"
+ assert config_url == "mongodb://user:password@host:port"
+
+
+def test_mongo_config_definition(mongodb_config):
+ assert mongodb_config
+ assert mongodb_config.get_engine_url
diff --git a/tests/test_core/test_database/test_orm.py b/tests/test_core/test_database/test_orm.py
index b9582e1..86f3225 100644
--- a/tests/test_core/test_database/test_orm.py
+++ b/tests/test_core/test_database/test_orm.py
@@ -2,49 +2,100 @@
import pytest
from nest.core.database.orm_config import (
- ConfigFactory,
- SQLiteConfig,
- PostgresConfig,
- MySQLConfig,
+ ConfigFactory
)
from nest.core.database.base_orm import OrmService
@pytest.fixture(scope="module")
-def orm_service():
- return OrmService(
- db_type="sqlite",
- config_params=dict(db_name=os.getenv("SQLITE_DB_NAME", "default_nest_db")),
- )
+def config_factory():
+ return ConfigFactory
-@pytest.fixture(scope="module")
-def sqlite_config():
- return SQLiteConfig("test")
+def test_config_factory_definition(config_factory):
+ assert config_factory
+ assert config_factory.get_config
@pytest.fixture(scope="module")
-def postgres_config():
- return PostgresConfig("test", "test", "test", "test", "test")
+def sqlite_config_factory(config_factory):
+ config = config_factory(db_type="sqlite").get_config()
+ params = dict(db_name=os.getenv("SQLITE_DB_NAME", "default_nest_db"))
+ return config(**params)
@pytest.fixture(scope="module")
-def mysql_config():
- return MySQLConfig("test", "test", "test", "test", "test")
+def postgres_config_factory(config_factory):
+ config = config_factory(db_type="postgresql").get_config()
+ params = dict(
+ db_name=os.getenv("POSTGRES_DB_NAME", "default_nest_db"),
+ host=os.getenv("POSTGRES_HOST", "localhost"),
+ user=os.getenv("POSTGRES_USER", "postgres"),
+ password=os.getenv("POSTGRES_PASSWORD", "postgres"),
+ port=os.getenv("POSTGRES_PORT", "5432"),
+ )
+ return config(**params)
-def test_orm_service_definition(orm_service):
- assert orm_service.Base
- assert orm_service.config
- assert orm_service.config_url
- assert orm_service.engine
+@pytest.fixture(scope="module")
+def mysql_config_factory(config_factory):
+ config = config_factory(db_type="mysql").get_config()
+ params = dict(
+ db_name=os.getenv("MYSQL_DB_NAME", "default_nest_db"),
+ host=os.getenv("MYSQL_HOST", "localhost"),
+ user=os.getenv("MYSQL_USER", "root"),
+ password=os.getenv("MYSQL_PASSWORD", "root"),
+ port=os.getenv("MYSQL_PORT", "3306"),
+ )
+ return config(**params)
-def test_orm_service_config_url(orm_service):
- config_url = orm_service.config_url
+def test_sqlite_url(sqlite_config_factory):
+ config_url = sqlite_config_factory.get_engine_url()
assert config_url == "sqlite:///default_nest_db.db"
-def test_orm_service_engine(orm_service):
- engine = orm_service.engine
- assert engine
+def test_postgres_url(postgres_config_factory):
+ config_url = postgres_config_factory.get_engine_url()
+ assert config_url == "postgresql+psycopg2://postgres:postgres@localhost:5432/default_nest_db"
+
+
+def test_mysql_url(mysql_config_factory):
+ config_url = mysql_config_factory.get_engine_url()
+ assert config_url == "mysql+mysqlconnector://root:root@localhost:3306/default_nest_db"
+
+
+@pytest.fixture(scope="module")
+def sqlite_orm_service():
+ return OrmService(
+ db_type="sqlite",
+ config_params=dict(db_name=os.getenv("SQLITE_DB_NAME", "default_nest_db")),
+ )
+
+
+@pytest.fixture(scope="module")
+def postgres_orm_service():
+ return OrmService(
+ db_type="postgresql",
+ config_params=dict(
+ db_name=os.getenv("POSTGRES_DB_NAME", "default_nest_db"),
+ host=os.getenv("POSTGRES_HOST", "localhost"),
+ user=os.getenv("POSTGRES_USER", "postgres"),
+ password=os.getenv("POSTGRES_PASSWORD", "postgres"),
+ port=os.getenv("POSTGRES_PORT", "5432"),
+ ),
+ )
+
+
+@pytest.fixture(scope="module")
+def mysql_orm_service():
+ return OrmService(
+ db_type="mysql",
+ config_params=dict(
+ db_name=os.getenv("MYSQL_DB_NAME", "default_nest_db"),
+ host=os.getenv("MYSQL_HOST", "localhost"),
+ user=os.getenv("MYSQL_USER", "root"),
+ password=os.getenv("MYSQL_PASSWORD", "root"),
+ port=os.getenv("MYSQL_PORT", "3306"),
+ ),
+ )
From 7a3eb02f5f62381a7a87e17a5e9421fffd2515cd Mon Sep 17 00:00:00 2001
From: ItayTheDar
Date: Fri, 28 Jul 2023 07:12:41 +0300
Subject: [PATCH 14/16] remove empty file
---
nest/common/common.py | 0
1 file changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 nest/common/common.py
diff --git a/nest/common/common.py b/nest/common/common.py
deleted file mode 100644
index e69de29..0000000
From 3fa413de326efbf59487e1abbff6dcc94e3688ef Mon Sep 17 00:00:00 2001
From: ItayTheDar
Date: Fri, 28 Jul 2023 07:17:08 +0300
Subject: [PATCH 15/16] add return in inner controller function add restriction
to mongodb in creating new module
---
nest/cli/click_handlers.py | 3 ++-
nest/core/decorators/controller.py | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/nest/cli/click_handlers.py b/nest/cli/click_handlers.py
index 11ac9ed..3af6ea1 100644
--- a/nest/cli/click_handlers.py
+++ b/nest/cli/click_handlers.py
@@ -507,7 +507,8 @@ def create_nest_module(name: str):
if not config_file.exists():
raise Exception("orm_config.py file not found")
db_type = get_db_type(config_file)
- add_document_to_odm_config(config_file, name, db_type)
+ if db_type == "mongodb":
+ add_document_to_odm_config(config_file, name, db_type)
module_path = src_path / name
create_folder(module_path)
create_file(module_path / "__init__.py", "")
diff --git a/nest/core/decorators/controller.py b/nest/core/decorators/controller.py
index d5d3912..62fcf30 100644
--- a/nest/core/decorators/controller.py
+++ b/nest/core/decorators/controller.py
@@ -20,7 +20,7 @@ def Controller(tag: str = None, prefix: str = None):
if prefix.endswith("/"):
prefix = prefix[:-1]
- def wrapper(cls):
+ def wrapper(cls) -> ClassBasedView:
router = APIRouter(tags=[tag] if tag else None)
for name, method in cls.__dict__.items():
From 374cd5325ac36a1a436ae7718db578c60f230e65 Mon Sep 17 00:00:00 2001
From: ItayTheDar
Date: Wed, 2 Aug 2023 08:11:32 +0300
Subject: [PATCH 16/16] change requirements_dev.txt
---
.github/workflows/tests.yaml | 2 +-
nest/common/templates/app.py | 2 +-
requirements_dev.txt => requirements-dev.txt | 0
3 files changed, 2 insertions(+), 2 deletions(-)
rename requirements_dev.txt => requirements-dev.txt (100%)
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index acc4250..ffe3d69 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -21,5 +21,5 @@ jobs:
- name: Run tests
run: |
- pip install -r requirements_dev.txt
+ pip install -r requirements-dev.txt
pytest tests
\ No newline at end of file
diff --git a/nest/common/templates/app.py b/nest/common/templates/app.py
index 1e3fbbd..cf2d59f 100644
--- a/nest/common/templates/app.py
+++ b/nest/common/templates/app.py
@@ -14,4 +14,4 @@ def generate_app(db_type: str):
@app.on_event("startup")
async def startup():
{'await config.create_all()' if db_type == 'mongodb' else 'config.create_all()'}
-"""
\ No newline at end of file
+"""
diff --git a/requirements_dev.txt b/requirements-dev.txt
similarity index 100%
rename from requirements_dev.txt
rename to requirements-dev.txt