valerius-flow 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,28 @@
1
+ Metadata-Version: 2.4
2
+ Name: valerius_flow
3
+ Version: 0.1.0
4
+ Summary: A Django-inspired API framework
5
+ Author-email: Joao Goncalves <you@email.com>
6
+ License: MIT
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Python :: 3 :: Only
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Framework :: Django
12
+ Classifier: Intended Audience :: Developers
13
+ Requires-Python: >=3.8
14
+ Description-Content-Type: text/markdown
15
+ Requires-Dist: webob
16
+ Requires-Dist: parse
17
+ Requires-Dist: python-dotenv
18
+ Requires-Dist: gunicorn
19
+
20
+ # Valerius
21
+
22
+ A Django-inspired API framework.
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ pip install valerius
28
+ ```
@@ -0,0 +1,9 @@
1
+ # Valerius
2
+
3
+ A Django-inspired API framework.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install valerius
9
+ ```
@@ -0,0 +1,27 @@
1
+ [project]
2
+ name = "valerius_flow"
3
+ version = "0.1.0"
4
+ description = "A Django-inspired API framework"
5
+ readme = "README.md"
6
+ requires-python = ">=3.8"
7
+ license = { text = "MIT" }
8
+
9
+ authors = [
10
+ { name = "Joao Goncalves", email = "you@email.com" }
11
+ ]
12
+
13
+ classifiers = [
14
+ "Programming Language :: Python :: 3",
15
+ "Programming Language :: Python :: 3 :: Only",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Operating System :: OS Independent",
18
+ "Framework :: Django",
19
+ "Intended Audience :: Developers"
20
+ ]
21
+
22
+ dependencies = [
23
+ "webob",
24
+ "parse",
25
+ "python-dotenv",
26
+ "gunicorn"
27
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
@@ -0,0 +1,132 @@
1
+ import os
2
+ import sys
3
+
4
+
5
+ def start_app():
6
+ if len(sys.argv) < 3:
7
+ print("Usage: valerius startapp <app_name>")
8
+ return
9
+
10
+ app_name = sys.argv[2]
11
+ class_name = app_name.capitalize()
12
+
13
+ # Templates for the new app
14
+ handlers_content = """class {class_name}Resource:
15
+ def get(self, req, resp):
16
+ resp.text = {{"message": "Welcome to the {app_name} app!"}}
17
+ """
18
+
19
+ routes_content = """from .handlers import {class_name}Resource
20
+
21
+ routes = [
22
+ ("/{app_name}", {class_name}Resource),
23
+ ]
24
+ """
25
+
26
+ # Create directory and files
27
+ os.makedirs(app_name, exist_ok=True)
28
+
29
+ # Create __init__.py so it's a package
30
+ with open(os.path.join(app_name, "__init__.py"), "w") as f:
31
+ f.write("")
32
+
33
+ with open(os.path.join(app_name, "handlers.py"), "w") as f:
34
+ f.write(handlers_content.format(class_name=class_name, app_name=app_name))
35
+
36
+ with open(os.path.join(app_name, "routes.py"), "w") as f:
37
+ f.write(routes_content.format(class_name=class_name, app_name=app_name))
38
+
39
+ settings_path = "config/settings/base.py"
40
+
41
+ if os.path.exists(settings_path):
42
+ with open(settings_path, "r") as f:
43
+ lines = f.readlines()
44
+
45
+ with open(settings_path, "w") as f:
46
+ for line in lines:
47
+ f.write(line)
48
+ # Find the INSTALLED_APPS list and inject the new app
49
+ if "INSTALLED_APPS = [" in line:
50
+ f.write(f" '{app_name}.routes',\n")
51
+
52
+ print(f"Registered '{app_name}.routes' in settings.py")
53
+ else:
54
+ print(f"Next: Add '{app_name}.routes' to INSTALLED_APPS manually.")
55
+
56
+
57
+ def start_project():
58
+ if len(sys.argv) < 3:
59
+ print("Usage: valerius startproject <project_name>")
60
+ return
61
+
62
+ project_name = sys.argv[2]
63
+
64
+ app_content = """from valerius.framework import App
65
+
66
+ app = App(settings_module='config.settings.base')
67
+ """
68
+
69
+ settings_content = """INSTALLED_APPS = []
70
+
71
+ MIDDLEWARE = [
72
+ 'valerius.middlewares.logger.LoggerMiddleware',
73
+ 'valerius.middlewares.json.JsonErrorMiddleware',
74
+ ]
75
+ """
76
+
77
+ manage_content = """import sys
78
+ import os
79
+ from valerius.management import create_app
80
+
81
+ def main():
82
+ if len(sys.argv) < 2:
83
+ print("Usage: python manage.py [run|startapp]")
84
+ return
85
+
86
+ command = sys.argv[1]
87
+
88
+ if command == "run":
89
+ # We assume the user's entry file is named app.py
90
+ os.system("gunicorn app:app --reload")
91
+
92
+ elif command == "startapp":
93
+ if len(sys.argv) > 2:
94
+ create_app(sys.argv[2])
95
+ else:
96
+ print("Error: Please provide an app name.")
97
+
98
+ else:
99
+ print(f"Unknown command: {command}")
100
+
101
+ if __name__ == "__main__":
102
+ main()
103
+ """
104
+
105
+ files = {
106
+ "app.py": app_content,
107
+ "config/__init__.py": "",
108
+ "config/settings/__init__.py": "",
109
+ "config/settings/base.py": settings_content,
110
+ "manage.py": manage_content,
111
+ "requirements/base.txt": "valerius\ngunicorn",
112
+ "env/.env": "DEBUG=True"
113
+ }
114
+
115
+ # Create directory and files
116
+ os.makedirs(project_name, exist_ok=True)
117
+
118
+ for relative_path, content in files.items():
119
+ # 1. Join project folder + relative path
120
+ full_path = os.path.join(project_name, relative_path)
121
+
122
+ # 2. Extract the directory portion (e.g., 'my_project/config/settings')
123
+ directory = os.path.dirname(full_path)
124
+
125
+ # 3. Create the directories if they don't exist
126
+ if directory:
127
+ os.makedirs(directory, exist_ok=True)
128
+
129
+ with open(full_path, "w") as f:
130
+ f.write(content)
131
+
132
+ print(f"Project '{project_name}' created successfully!")
@@ -0,0 +1,102 @@
1
+ import json
2
+ import inspect
3
+ import importlib
4
+ from parse import parse
5
+ from webob import Request, Response
6
+
7
+
8
+ class App:
9
+ def __init__(self, settings_module=None):
10
+ self.routes = {}
11
+ self.middleware_classes = []
12
+
13
+ if settings_module:
14
+ self.settings = importlib.import_module(settings_module)
15
+ self.register_apps()
16
+
17
+ def load_settings(self, settings_module):
18
+ settings = importlib.import_module(settings_module)
19
+ self.settings = settings
20
+ middleware_paths = getattr(settings, "MIDDLEWARE", [])
21
+
22
+ for path in middleware_paths:
23
+ self.add_middleware_from_path(path)
24
+
25
+ def add_middleware_from_path(self, path):
26
+ module_path, class_name = path.rsplit(".", 1)
27
+ module = importlib.import_module(module_path)
28
+ middleware_cls = getattr(module, class_name)
29
+ self.middleware_classes.append(middleware_cls)
30
+
31
+ def register_apps(self):
32
+ apps = getattr(self.settings, "INSTALLED_APPS", [])
33
+
34
+ for app_path in apps:
35
+ module = importlib.import_module(app_path)
36
+ app_routes = getattr(module, "routes", [])
37
+
38
+ for path, handler in app_routes:
39
+ self.add_route(path, handler)
40
+
41
+ def add_route(self, path, handler):
42
+ assert path not in self.routes, f"Route {path} already exists."
43
+ self.routes[path] = handler
44
+
45
+ def __call__(self, environ, start_response):
46
+ app = self.handle_request_wsgi
47
+
48
+ for middleware in reversed(self.middleware_classes):
49
+ app = middleware(app)
50
+
51
+ return app(environ, start_response)
52
+
53
+ def handle_request_wsgi(self, environ, start_response):
54
+ request = Request(environ)
55
+ response = self.handle_request(request)
56
+ return response(environ, start_response)
57
+
58
+ def default_response(self, response):
59
+ response.status_code = 404
60
+ response.text = "Not found."
61
+
62
+ def route(self, path):
63
+ assert path not in self.routes, "Such route already exists."
64
+
65
+ def wrapper(handler):
66
+ self.routes[path] = handler
67
+ return handler
68
+
69
+ return wrapper
70
+
71
+ def find_handler(self, request_path):
72
+ for path, handler in self.routes.items():
73
+ parse_result = parse(path, request_path)
74
+
75
+ if parse_result is not None:
76
+ return handler, parse_result.named
77
+
78
+ return None, None
79
+
80
+ def handle_request(self, request):
81
+ response = Response()
82
+ handler, kwargs = self.find_handler(request_path=request.path)
83
+
84
+ if handler is not None:
85
+ if inspect.isclass(handler):
86
+ handler_instance = handler()
87
+ handler = getattr(handler_instance, request.method.lower(), None)
88
+
89
+ if handler is None:
90
+ response.status_code = 405
91
+ response.text = "Method not allowed."
92
+ return response
93
+
94
+ handler(request, response, **kwargs)
95
+
96
+ if hasattr(response, 'json_body'):
97
+ response.body = json.dumps(response.json_body).encode()
98
+ response.content_type = "application/json"
99
+ else:
100
+ self.default_response(response)
101
+
102
+ return response
@@ -0,0 +1,19 @@
1
+ import os
2
+
3
+
4
+ def create_app(app_name):
5
+ class_name = app_name.capitalize()
6
+ os.makedirs(app_name, exist_ok=True)
7
+
8
+ app_files = {
9
+ "__init__.py": "",
10
+ "models.py": f"class {class_name}(object):\n pass\n",
11
+ "handlers.py": f"class {class_name}Resource:\n def get(self, req, resp):\n resp.json = {{'message': 'Hello from {app_name}'}}\n",
12
+ "router.py": f"from .handlers import {class_name}Resource\n\nroutes = [\n ('/{app_name}', {class_name}Resource),\n]\n"
13
+ }
14
+
15
+ for filename, content in app_files.items():
16
+ with open(os.path.join(app_name, filename), "w") as f:
17
+ f.write(content)
18
+
19
+ print(f"App '{app_name}' created and registered!")
@@ -0,0 +1,19 @@
1
+ from webob import Response
2
+
3
+
4
+ class JsonErrorMiddleware:
5
+ def __init__(self, app):
6
+ self.app = app
7
+
8
+ def __call__(self, environ, start_response):
9
+ try:
10
+ return self.app(environ, start_response)
11
+ except Exception as e:
12
+ response = Response()
13
+ response.status_code = 500
14
+ response.json_body = {
15
+ "error": "Internal Server Error",
16
+ "message": str(e)
17
+ }
18
+ response.content_type = "application/json"
19
+ return response(environ, start_response)
@@ -0,0 +1,20 @@
1
+ from datetime import datetime
2
+
3
+
4
+ class LoggerMiddleware:
5
+ def __init__(self, app):
6
+ self.app = app
7
+
8
+ def __call__(self, environ, start_response):
9
+ # 1. Logic BEFORE the request hits the API
10
+ start_time = datetime.now()
11
+ method = environ.get('REQUEST_METHOD')
12
+ path = environ.get('PATH_INFO')
13
+
14
+ # 2. Pass the request to the main API (or the next middleware)
15
+ response = self.app(environ, start_response)
16
+
17
+ # 3. Logic AFTER the response is generated
18
+ duration = datetime.now() - start_time
19
+
20
+ return response
@@ -0,0 +1,28 @@
1
+ Metadata-Version: 2.4
2
+ Name: valerius_flow
3
+ Version: 0.1.0
4
+ Summary: A Django-inspired API framework
5
+ Author-email: Joao Goncalves <you@email.com>
6
+ License: MIT
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Python :: 3 :: Only
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Framework :: Django
12
+ Classifier: Intended Audience :: Developers
13
+ Requires-Python: >=3.8
14
+ Description-Content-Type: text/markdown
15
+ Requires-Dist: webob
16
+ Requires-Dist: parse
17
+ Requires-Dist: python-dotenv
18
+ Requires-Dist: gunicorn
19
+
20
+ # Valerius
21
+
22
+ A Django-inspired API framework.
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ pip install valerius
28
+ ```
@@ -0,0 +1,13 @@
1
+ README.md
2
+ pyproject.toml
3
+ valerius/__init__.py
4
+ valerius/cli.py
5
+ valerius/framework.py
6
+ valerius/management.py
7
+ valerius/middlewares/json.py
8
+ valerius/middlewares/logger.py
9
+ valerius_flow.egg-info/PKG-INFO
10
+ valerius_flow.egg-info/SOURCES.txt
11
+ valerius_flow.egg-info/dependency_links.txt
12
+ valerius_flow.egg-info/requires.txt
13
+ valerius_flow.egg-info/top_level.txt
@@ -0,0 +1,4 @@
1
+ webob
2
+ parse
3
+ python-dotenv
4
+ gunicorn