Repository: TechWithDunamix/Nexios (language: python)

Issue:
merge



Discussion / hints:

Fix patch:
diff --git a/nexio/cli/__init__.py b/nexio/cli/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/nexio/cli/create_project.py b/nexio/cli/create_project.py
new file mode 100644
index 0000000..c559739
--- /dev/null
+++ b/nexio/cli/create_project.py
@@ -0,0 +1,107 @@
+import os
+
+def create_project_structure(project_name):
+    # Create the base project directory
+    os.makedirs(project_name, exist_ok=True)
+    os.makedirs(f"{project_name}/app", exist_ok=True)
+    os.makedirs(f"{project_name}/config", exist_ok=True)
+    os.makedirs(f"{project_name}/middlewares", exist_ok=True)
+    os.makedirs(f"{project_name}/migrations", exist_ok=True)
+
+    # Create the files within the app directory
+    create_file(f"{project_name}/app/app.py", app_code())
+    create_file(f"{project_name}/config/config.py", config_code())
+    create_file(f"{project_name}/config/database.py", database_code())
+    create_file(f"{project_name}/middlewares/middleware.py", middleware_code())
+    create_file(f"{project_name}/migrations/__init__.py", '')  # placeholder for migrations
+
+    print(f"Project structure for '{project_name}' created successfully!")
+
+def create_file(file_path, content):
+    with open(file_path, "w") as file:
+        file.write(content)
+
+def app_code():
+    return '''
+import uvicorn
+from nexio.http.request import Request
+from nexio.application import NexioHTTPApp
+from nexio.routers import Routes, Router
+from nexio.http.response import NexioResponse
+from nexio.middlewares.base import BaseMiddleware
+from nexio.config.settings import BaseConfig
+from nexio.sessions.middlewares import SessionMiddleware
+from nexio.middlewares.common import CommonMiddleware
+from nexio.middleware.logging import ErrorHandlerMiddleware
+
+# Import database connection from the config
+from config.database import connect_db, disconnect_db
+
+# App Setup
+app = NexioHTTPApp(config=BaseConfig())
+
+# Middleware
+app.add_middleware(BaseMiddleware())
+app.add_middleware(SessionMiddleware())
+app.add_middleware(CommonMiddleware())
+app.add_middleware(ErrorHandlerMiddleware())
+
+@app.on_startup
+async def on_startup():
+    await connect_db()
+
+@app.on_shutdown
+async def on_shutdown():
+    await disconnect_db()
+
+# Routes
+async def welcome(request: Request, response: NexioResponse):
+    return response.json({"message": "Welcome to Nexio! 😀"})
+
+r = Router()
+r.add_route(Routes("/", welcome))
+app.mount_router(r)
+
+if __name__ == "__main__":
+    uvicorn.run(app, host="127.0.0.1", port=8000)
+'''
+
+def config_code():
+    return '''
+class BaseConfig:
+    SECRET_KEY = "your_secret_key"
+
+TORTOISE_ORM = {
+    "connections": {
+        "default": "sqlite://db.sqlite3"
+    },
+    "apps": {
+        "models": {
+            "models": ["nexio.sessions.models"], 
+            "default_connection": "default",
+        },
+    },
+}
+'''
+
+def database_code():
+    return '''
+from tortoise import Tortoise
+import os
+
+async def connect_db():
+    db_path = os.path.join(os.path.dirname(__file__), "db.sqlite3")
+    await Tortoise.init(db_url=f"sqlite:///{db_path}", modules={"models": ["nexio.sessions.models"]})
+    await Tortoise.generate_schemas()
+
+async def disconnect_db():
+    await Tortoise.close_connections()
+'''
+
+def middleware_code():
+    return '''
+class BaseMiddleware:
+    async def process_request(self, request, response):
+        # Handle the request here
+        pass
+'''
diff --git a/nexio/cli/main.py b/nexio/cli/main.py
new file mode 100644
index 0000000..6bbfb7a
--- /dev/null
+++ b/nexio/cli/main.py
@@ -0,0 +1,20 @@
+import argparse
+from mypackage.create_project import create_project_structure
+
+def main():
+    parser = argparse.ArgumentParser(prog="mypackage")
+    subparsers = parser.add_subparsers(dest="command")
+    
+    # 'create' subcommand
+    create_parser = subparsers.add_parser('create', help="Create a new Nexio project")
+    create_parser.add_argument('project_name', type=str, help="The name of the project to create")
+    
+    args = parser.parse_args()
+    
+    if args.command == "create":
+        create_project_structure(args.project_name)
+    else:
+        parser.print_help()
+
+if __name__ == "__main__":
+    main()
diff --git a/nexio/middlewares/__pycache__/logging.cpython-312.pyc b/nexio/middlewares/__pycache__/logging.cpython-312.pyc
index 9e51b67..89a708a 100644
Binary files a/nexio/middlewares/__pycache__/logging.cpython-312.pyc and b/nexio/middlewares/__pycache__/logging.cpython-312.pyc differ
diff --git a/nexio/middlewares/logging.py b/nexio/middlewares/logging.py
index e0a5e49..beb5442 100644
--- a/nexio/middlewares/logging.py
+++ b/nexio/middlewares/logging.py
@@ -1,65 +1,62 @@
-import logging
-import time
 import traceback
+import logging
+import typing
 from nexio.http.request import Request
-from nexio.http.response import Response,NexioResponse
+from nexio.http.response import NexioResponse
 from .base import BaseMiddleware
-# Set up advanced logging
-logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
+# Setting up a logger for middleware
 logger = logging.getLogger(__name__)
+logger.setLevel(logging.ERROR)
+# You can also configure more advanced logging handlers (e.g., logging to a file, database, or external service).
 
-# Function to log exceptions
-def log_exception(exception: Exception):
-    logger.error("An error occurred: %s", exception)
-    logger.error("Traceback: %s", traceback.format_exc())
+class ErrorHandlerMiddleware(BaseMiddleware):
+    """
+    A middleware class for handling errors globally within the application.
+    This class processes requests and responses, capturing errors and logging them.
+    """
 
-# Logging middleware
-async def logging_middleware(request: Request, response: Response, nex):
-    start_time = time.time()  # Start time to track request processing duration
-    try:
-        # Log the incoming request
-        logger.info(f"Received {request.method} request for {request.url.path}")
-        logger.debug(f"Request headers: {request.headers}")
-        logger.debug(f"Request query params: {request.query_params}")
-        if request.body:
-            logger.debug(f"Request body: {await request.body()}")
-        
-        # Process the request
-        await nex()
+    def __init__(self, *args, **kwargs) -> None:
+        super().__init__(*args, **kwargs)
+        # Any additional initialization can be done here
+        self.error_status_code = 500
+        self.error_message = "An unexpected error occurred"
 
-        # Log the outgoing response
-        logger.info(f"Response status: {response.status_code}")
-        logger.debug(f"Response headers: {response.headers}")
-        if response.body:
-            logger.debug(f"Response body: {response.body.decode()}")
-        
-        # Log the time taken for the request
-        duration = time.time() - start_time
-        logger.info(f"Request processing time: {duration:.2f} seconds")
+    async def process_request(self, request: Request, response: NexioResponse) -> None:
+        """
+        Process the request before passing it along to the next middleware.
+        We can add logging or any preprocessing before the request reaches the main handler.
+        """
+        pass
 
-    except Exception as e:
-        # Log the exception if one occurs
-        log_exception(e)
+    async def process_response(self, request: Request, response: NexioResponse) -> None:
+        """
+        Process the response after the request has been handled by the main application or other middleware.
+        This is where we can log success responses or handle any post-processing.
+        """
+        pass
 
-        # Optionally, set a custom error response or let the default error handler handle it
-        response.status_code = 500
-        response.body = b"Internal Server Error"
-        logger.error(f"Error occurred while processing the request: {e}")
+    async def __call__(self, request: Request, response: NexioResponse, next_middleware: typing.Callable) -> NexioResponse:
+        """
+        The core method of the middleware, which processes the request, handles the error, and processes the response.
+        """
+        try:
+            # Let the next middleware or route handler process the request
+            response = await next_middleware()
+        except Exception as error:
+            # Capture and log the exception details
+            self._log_error(traceback.format_exc())
 
+            # Modify the response object to reflect an error
+            return  response.send("Server error",status_code=500)
+            
 
-# Example usage of custom middleware
-class LoggingMiddleware(BaseMiddleware):
-    """
-    Example middleware that logs request and response details.
-    """
-    
-    async def process_request(self, request: Request, response: NexioResponse) -> None:
-        print(f"Processing request to: {request.url.path}")
-    
-    async def process_response(self, request: Request, response: NexioResponse) -> NexioResponse:
-        print(f"Processing response from: {request.url.path}")
         return response
-    
-    async def process_exception(self, request: Request, response: NexioResponse, exc: Exception) -> NexioResponse:
-        print(f"Error processing {request.url.path}: {str(exc)}")
-        return await super().process_exception(request, response, exc)
\ No newline at end of file
+
+    def _log_error(self, error: Exception) -> None:
+        """
+        A helper method to log the error details in a structured and configurable way.
+        This can be expanded to log to files, external monitoring services, etc.
+        """
+        # Log the error with traceback for full context
+        logger.error(f"Unhandled exception: {str(error)}")
+        logger.debug("Error traceback: %s", traceback.format_exc())
diff --git a/setup.py b/setup.py
index 8fe1dd1..60c097a 100644
--- a/setup.py
+++ b/setup.py
@@ -19,4 +19,9 @@
         "Operating System :: OS Independent",
     ],
     python_requires=">=3.8",
+    entry_points={
+        'console_scripts': [
+            'nexio=nexio.cli.main:main',
+        ],
+    },
 )


Test patch:
diff --git a/__pycache__/test.cpython-312.pyc b/__pycache__/test.cpython-312.pyc
index 8b86750..d16142d 100644
Binary files a/__pycache__/test.cpython-312.pyc and b/__pycache__/test.cpython-312.pyc differ
diff --git a/test.py b/test.py
index c5b83c3..2b92f4e 100644
--- a/test.py
+++ b/test.py
@@ -21,6 +21,7 @@
 from nexio.validator.descriptor import FieldDescriptor
 from nexio.validator.fields import StringField,IntegerField,BooleanField,ChoiceField,FileField
 from nexio.http.parsers import UploadedFile
+from nexio.middlewares.logging import ErrorHandlerMiddleware
 # from tests import User
 
 TORTOISE_ORM = {
@@ -66,6 +67,7 @@ async def home_handler(request: Request, response :NexioResponse, **kwargs):
     files = await request.files
     # print("file is ",type(files['b']) == UploadedFile)
     b = await a(data, files)
+    print(request.headers['Origin'])
     if not b.is_valid():
         return response.json(b.errors)
     
@@ -154,7 +156,7 @@ async def lifespan():
 app.add_middleware(ErrorHandler)
 app.add_middleware(SessionMiddleware())
 app.add_middleware(CommonMiddleware())
-
+app.add_middleware(ErrorHandlerMiddleware())
 # app.add_middleware(LoggingMiddleware)