fastbrick 0.5__py3-none-any.whl → 0.5.2__py3-none-any.whl

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.
fastbrick/__init__.py ADDED
@@ -0,0 +1,7 @@
1
+ # fastbrick/__init__.py
2
+
3
+ from .cli import cli # Import CLI functionality
4
+
5
+ # Expose CLI entry point
6
+ def main():
7
+ cli()
fastbrick/cli.py ADDED
@@ -0,0 +1,262 @@
1
+ import os
2
+ import click
3
+ from jinja2 import Template
4
+
5
+ # Default template for main.py
6
+ MAIN_TEMPLATE = """\
7
+ from fastapi import FastAPI
8
+ from middlewares.middleware import GlobalMiddleware
9
+ from settings.routing import router
10
+ from settings.database import engine, Base
11
+
12
+ # ✅ Create all tables in the database
13
+ Base.metadata.create_all(bind=engine)
14
+
15
+ app = FastAPI()
16
+
17
+ # ✅ Add Middleware
18
+ app.add_middleware(GlobalMiddleware)
19
+
20
+ # ✅ Include API routes
21
+ app.include_router(router)
22
+
23
+ @app.get("/")
24
+ def root():
25
+ return {"message": "Welcome to FastAPI Project"}
26
+ """
27
+
28
+ # Default template for new app routers
29
+ APP_ROUTER_TEMPLATE = """\
30
+ from fastapi import APIRouter
31
+
32
+ router = APIRouter()
33
+
34
+ @router.get("/")
35
+ def {{ app_name }}_home():
36
+ return {"message": "Welcome to the {{ app_name }} app"}
37
+ """
38
+
39
+ # Default template for database settings
40
+ DATABASE_TEMPLATE = """\
41
+ from sqlalchemy import create_engine, MetaData
42
+ from sqlalchemy.orm import sessionmaker, declarative_base
43
+ from settings.config import DATABASE_URL
44
+
45
+ engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
46
+ SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
47
+ Base = declarative_base()
48
+
49
+ # Dependency: Get DB Session
50
+ def get_db():
51
+ db = SessionLocal()
52
+ try:
53
+ yield db
54
+ finally:
55
+ db.close()
56
+
57
+ """
58
+
59
+ # Template for dynamic routing
60
+ ROUTING_TEMPLATE = """\
61
+ import importlib
62
+ import pkgutil
63
+ from fastapi import APIRouter
64
+ import routers
65
+
66
+ # Import custom route mappings from routes.py
67
+ from routes import app_routes
68
+
69
+ router = APIRouter()
70
+
71
+ # Dynamically import and include all routers from 'routers' package
72
+ for _, module_name, _ in pkgutil.iter_modules(routers.__path__):
73
+ module = importlib.import_module(f"routers.{module_name}")
74
+
75
+ if hasattr(module, "router"):
76
+ prefix = app_routes.get(module_name, f"/{module_name}")
77
+ router.include_router(module.router, prefix=prefix, tags=[module_name.capitalize()])
78
+ """
79
+
80
+ # routes.py template (Separate file for `app_routes`)
81
+ ROUTES_TEMPLATE = """\
82
+ # Users can modify this dictionary to change route prefixes
83
+ app_routes = {}
84
+ """
85
+
86
+ MODELS_TEMPLATE = """\
87
+ from sqlalchemy import Column, Integer, String
88
+ from settings.database import Base
89
+
90
+ class User(Base):
91
+ __tablename__ = "users"
92
+ id = Column(Integer, primary_key=True, index=True)
93
+ email = Column(String, unique=True, index=True)
94
+ hashed_password = Column(String)
95
+ """
96
+
97
+ SCHEMAS_TEMPLATE = """\
98
+ from pydantic import BaseModel
99
+
100
+ class UserBase(BaseModel):
101
+ email: str
102
+ hashed_password: str
103
+
104
+ """
105
+
106
+ MIDDLEWARE_TEMPLATE = """\
107
+ import time
108
+ import logging
109
+ from fastapi import Request, Response
110
+ from starlette.middleware.base import BaseHTTPMiddleware
111
+ from settings.config import ALLOWED_IPS
112
+
113
+ # Configure logging
114
+ logging.basicConfig(level=logging.INFO)
115
+ logger = logging.getLogger("middleware")
116
+
117
+
118
+ class GlobalMiddleware(BaseHTTPMiddleware):
119
+ async def dispatch(self, request: Request, call_next):
120
+ start_time = time.time()
121
+ client_ip = request.client.host
122
+
123
+ # ✅ Allow Only Specific IPs
124
+ if "*" not in ALLOWED_IPS and client_ip not in ALLOWED_IPS:
125
+ return Response(content="⛔ Access Denied", status_code=403)
126
+
127
+ # ⏳ Process Request
128
+ try:
129
+ response = await call_next(request)
130
+ except Exception as e:
131
+ logger.error(f"❌ Exception: {e}")
132
+ return Response(content="🚨 Internal Server Error", status_code=500)
133
+
134
+ # ⏱️ Track Request Time
135
+ process_time = time.time() - start_time
136
+ response.headers["X-Process-Time"] = str(process_time)
137
+ response.headers["X-App-Version"] = "1.0.0"
138
+
139
+ logger.info(f"✅ {request.method} {request.url} - {response.status_code} ({process_time:.4f}s)")
140
+ return response
141
+ """
142
+
143
+ CONFIG_TEMPLATE="""\
144
+ DATABASE_URL = "sqlite:///./test.db"
145
+
146
+ # Define Allowed IPs
147
+ ALLOWED_IPS = {"*"} # Set specific IPs to restrict access, or "*" to allow all
148
+ """
149
+
150
+ @click.group()
151
+ def cli():
152
+ """FastAPI Project Generator CLI"""
153
+ pass
154
+
155
+ @click.command(name="create-project")
156
+ @click.argument("name")
157
+ def create_project(name):
158
+ """Create a new FastAPI project with a clean structure."""
159
+
160
+ if os.path.exists(name):
161
+ click.echo(f"❌ Error: Project '{name}' already exists! Choose a different name.")
162
+ return
163
+
164
+ # Create project directories
165
+ os.makedirs(f"{name}/routers", exist_ok=True)
166
+ os.makedirs(f"{name}/settings", exist_ok=True)
167
+ os.makedirs(f"{name}/alembic", exist_ok=True)
168
+ os.makedirs(f"{name}/middlewares", exist_ok=True)
169
+
170
+ # Create main.py
171
+ with open(f"{name}/main.py", "w") as f:
172
+ f.write(Template(MAIN_TEMPLATE).render(project_name=name))
173
+
174
+ # Create settings/database.py
175
+ with open(f"{name}/settings/database.py", "w") as f:
176
+ f.write(DATABASE_TEMPLATE)
177
+
178
+ # Create settings/routing.py
179
+ with open(f"{name}/settings/routing.py", "w") as f:
180
+ f.write(ROUTING_TEMPLATE)
181
+
182
+ # Create settings/config.py
183
+ with open(f"{name}/settings/config.py", "w") as f:
184
+ f.write(CONFIG_TEMPLATE)
185
+
186
+ # Create middlewares/middleware.py
187
+ with open(f"{name}/middlewares/middleware.py", "w") as f:
188
+ f.write(MIDDLEWARE_TEMPLATE)
189
+
190
+ # Create models.py
191
+ with open(f"{name}/models.py", "w") as f:
192
+ f.write(MODELS_TEMPLATE)
193
+
194
+ # Create schemas.py
195
+ with open(f"{name}/schemas.py", "w") as f:
196
+ f.write(SCHEMAS_TEMPLATE)
197
+
198
+ # Create routes.py
199
+ with open(f"{name}/routes.py", "w") as f:
200
+ f.write(ROUTES_TEMPLATE)
201
+
202
+ click.echo(f"✅ FastAPI project '{name}' created successfully!")
203
+
204
+
205
+ @click.command(name="create-app")
206
+ @click.argument("name")
207
+ def create_app(name):
208
+ """Create a new FastAPI app (router) with database settings."""
209
+ app_path = f"routers/{name}.py"
210
+ settings_path = "settings/"
211
+ routing_config_path = os.path.join(settings_path, "routing.py")
212
+
213
+ if not os.path.exists("routers"):
214
+ click.echo("❌ Error: No 'routers' directory found! Are you inside a FastAPI project?")
215
+ return
216
+
217
+ if os.path.exists(app_path):
218
+ click.echo(f"❌ Error: App '{name}' already exists! Choose a different name.")
219
+ return
220
+
221
+ # Ensure settings folder exists
222
+ os.makedirs(settings_path, exist_ok=True)
223
+
224
+ # Create router file
225
+ with open(app_path, "w") as f:
226
+ f.write(Template(APP_ROUTER_TEMPLATE).render(app_name=name))
227
+
228
+ # Ensure database.py exists inside settings/
229
+ db_config_path = os.path.join(settings_path, "database.py")
230
+ if not os.path.exists(db_config_path):
231
+ with open(db_config_path, "w") as f:
232
+ f.write(DATABASE_TEMPLATE)
233
+
234
+ # Ensure routing.py exists inside settings/
235
+ if not os.path.exists(routing_config_path):
236
+ with open(routing_config_path, "w") as f:
237
+ f.write(ROUTING_TEMPLATE)
238
+
239
+ # Ensure routes.py exists outside settings/
240
+ if not os.path.exists("routes.py"):
241
+ with open("routes.py", "w") as f:
242
+ f.write(ROUTING_TEMPLATE)
243
+
244
+ # Update `settings/routing.py` with the new default prefix
245
+ with open("routes.py", "r+") as f:
246
+ content = f.read()
247
+ if "app_routes = {" in content:
248
+ new_entry = f' "{name}": "/{name}",\n'
249
+ if f'"{name}":' not in content: # Prevent duplicate entries
250
+ updated_content = content.replace("app_routes = {", f"app_routes = {{\n{new_entry}")
251
+ f.seek(0)
252
+ f.write(updated_content)
253
+ f.truncate()
254
+
255
+ click.echo(f"✅ App '{name}' created successfully")
256
+
257
+
258
+ cli.add_command(create_project)
259
+ cli.add_command(create_app)
260
+
261
+ if __name__ == "__main__":
262
+ cli()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastbrick
3
- Version: 0.5
3
+ Version: 0.5.2
4
4
  Summary: A CLI tool for generating FastAPI projects and apps
5
5
  Home-page: UNKNOWN
6
6
  Author: Sandeep Singh Negi
@@ -12,9 +12,8 @@ Classifier: License :: OSI Approved :: MIT License
12
12
  Classifier: Operating System :: OS Independent
13
13
  Requires-Python: >=3.7
14
14
  Description-Content-Type: text/markdown
15
- License-File: LICENSE
16
- Requires-Dist: click
17
15
  Requires-Dist: fastapi
16
+ Requires-Dist: click
18
17
  Requires-Dist: jinja2
19
18
 
20
19
  # FastBrick 🚀
@@ -0,0 +1,8 @@
1
+ fastbrick/__init__.py,sha256=h9MsX7cxacJFEKVrHA4M6XwqDkmuVNJ9KAtJ6HRv1rw,122
2
+ fastbrick/cli.py,sha256=-G5Rg7oxfmgDY36ygs8JlD4a5uQajw-LbSFkJrGVJlU,7605
3
+ fastbrick-0.5.2.dist-info/LICENSE,sha256=VueWmlho5XxqjRpByo5KlMuWT7T-_AjQOVeiXRad66o,244
4
+ fastbrick-0.5.2.dist-info/METADATA,sha256=biaDZV93EgLmpq5q48YTxLUyorRan1eqiwiCMwKuTPg,1729
5
+ fastbrick-0.5.2.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
6
+ fastbrick-0.5.2.dist-info/entry_points.txt,sha256=1jus0gebTrhse91bDFTBPKzoVgu5pwNTjZAr-uLcfbA,46
7
+ fastbrick-0.5.2.dist-info/top_level.txt,sha256=wP0Z3gRwVZj2qAQ1WHAvQtmRwCjEFFUe-lKKijnnf-Y,10
8
+ fastbrick-0.5.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.37.1)
2
+ Generator: bdist_wheel (0.45.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ fastbrick = fastbrick:main
3
+
@@ -0,0 +1 @@
1
+ fastbrick
@@ -1,6 +0,0 @@
1
- fastbrick-0.5.dist-info/LICENSE,sha256=VueWmlho5XxqjRpByo5KlMuWT7T-_AjQOVeiXRad66o,244
2
- fastbrick-0.5.dist-info/METADATA,sha256=OF9uXjjH_6oa7p_DGuVU_XTXwTCFFlwGuP0kZV3aWo0,1749
3
- fastbrick-0.5.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
4
- fastbrick-0.5.dist-info/entry_points.txt,sha256=E25qyIpsqpZCjdza4bncHZhd7tmQwWqnWaz8eTz5luE,45
5
- fastbrick-0.5.dist-info/top_level.txt,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
6
- fastbrick-0.5.dist-info/RECORD,,
@@ -1,3 +0,0 @@
1
- [console_scripts]
2
- fastbrick = fastbrick:cli
3
-
@@ -1 +0,0 @@
1
-