amen-cli 0.1.0__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.
amen/__init__.py ADDED
@@ -0,0 +1,25 @@
1
+ """AMEN CLI - Python Web Framework Scaffolding Tool"""
2
+ __version__ = "0.1.0"
3
+ __author__ = "Tanaka Chinengundu"
4
+
5
+ __description__ = "A composer-inspired Python Web Framework Scaffolding Tool"
6
+ __license__ = "Modified MIT with Attribution Requirements"
7
+ __copyright__ = "Copyright (c) 2025 Tanaka Chinengundu"
8
+ __email__ = "tanakah30@gmail.com"
9
+ __url__ = "https://github.com/taqsblaze/amen-cli"
10
+ __docs__ = "https://github.com/taqsblaze/amen-cli/#readme"
11
+ __python_requires__ = ">=3.7"
12
+
13
+ SUPPORTED_FRAMEWORKS = {
14
+ "flask": {"version": ">=2.0.0", "port": 5000},
15
+ "fastapi": {"version": ">=0.68.0", "port": 8000}
16
+ }
17
+
18
+ # Package status
19
+ __status__ = "Development"
20
+ __maintainer__ = "Tanaka Chinengundu"
21
+ __credits__ = ["Tanaka Chinengundu"]
22
+
23
+ # Feature flags
24
+ ENABLE_LOGGING = True
25
+ DEBUG_MODE = True
amen/cli.py ADDED
@@ -0,0 +1,230 @@
1
+ import os
2
+ import sys
3
+ import subprocess
4
+ import venv
5
+ from pathlib import Path
6
+
7
+ import click
8
+ import questionary
9
+ from rich.console import Console
10
+ from rich.panel import Panel
11
+ from rich.progress import Progress, SpinnerColumn, TextColumn
12
+
13
+ from .frameworks import FRAMEWORKS
14
+ from .templates import TemplateManager
15
+
16
+ console = Console()
17
+
18
+ VALID_FRAMEWORKS = ['flask', 'fastapi', 'bottle', 'pyramid']
19
+ VALID_PROJECT_TYPES = ['webapp', 'api']
20
+
21
+ def create_project(path, framework, project_type):
22
+ """
23
+ Create a new project with the specified framework and type.
24
+
25
+ Args:
26
+ path (str): Project directory path
27
+ framework (str): Web framework to use
28
+ project_type (str): Type of project (webapp/api)
29
+ """
30
+ if framework not in VALID_FRAMEWORKS:
31
+ raise ValueError(f"Invalid framework. Choose from: {VALID_FRAMEWORKS}")
32
+
33
+ if project_type not in VALID_PROJECT_TYPES:
34
+ raise ValueError(f"Invalid project type. Choose from: {VALID_PROJECT_TYPES}")
35
+
36
+ # Create project directory
37
+ os.makedirs(path, exist_ok=True)
38
+
39
+ # Create basic structure
40
+ os.makedirs(os.path.join(path, "app"), exist_ok=True)
41
+ os.makedirs(os.path.join(path, "app", "templates"), exist_ok=True)
42
+ os.makedirs(os.path.join(path, "app", "static"), exist_ok=True)
43
+
44
+ # Create empty files
45
+ open(os.path.join(path, "requirements.txt"), 'a').close()
46
+ open(os.path.join(path, "README.md"), 'a').close()
47
+
48
+ class AmenCLI:
49
+ def __init__(self):
50
+ self.template_manager = TemplateManager()
51
+
52
+ def welcome_banner(self):
53
+ """Display welcome banner"""
54
+ console.print(Panel.fit(
55
+ """AMEN: composer-inspired Python Web Framework Scaffolding
56
+ Create your web applications with ease!
57
+ By [bold magenta]Tanaka Chinengundu[/bold magenta]
58
+ [bold blue]
59
+ """,
60
+ border_style="magenta"
61
+ ))
62
+ console.print()
63
+
64
+ def select_framework(self) -> str:
65
+ """Interactive framework selection"""
66
+ frameworks = list(FRAMEWORKS.keys())
67
+
68
+ choice = questionary.select(
69
+ "🚀 Select a web framework:",
70
+ choices=[
71
+ questionary.Choice(f"{FRAMEWORKS[fw]['name']} - {FRAMEWORKS[fw]['description']}", fw)
72
+ for fw in frameworks
73
+ ]
74
+ ).ask()
75
+
76
+ return choice
77
+
78
+ def select_app_type(self) -> str:
79
+ """Select application type"""
80
+ return questionary.select(
81
+ "🏗️ What type of application?",
82
+ choices=[
83
+ questionary.Choice("Full Web Application (with frontend)", "webapp"),
84
+ questionary.Choice("API Only", "api"),
85
+ ]
86
+ ).ask()
87
+
88
+ def get_app_name(self) -> str:
89
+ """Get application name"""
90
+ return questionary.text(
91
+ "📝 Enter your application name:",
92
+ validate=lambda x: len(x.strip()) > 0 or "Application name cannot be empty"
93
+ ).ask().strip()
94
+
95
+ def create_virtual_environment(self, app_path: Path) -> bool:
96
+ """Create virtual environment"""
97
+ venv_path = app_path / "venv"
98
+
99
+ try:
100
+ with Progress(
101
+ SpinnerColumn(),
102
+ TextColumn("[progress.description]{task.description}"),
103
+ console=console,
104
+ ) as progress:
105
+ task = progress.add_task("Creating virtual environment...", total=None)
106
+ venv.create(venv_path, with_pip=True)
107
+ progress.update(task, description="✅ Virtual environment created")
108
+
109
+ return True
110
+ except Exception as e:
111
+ console.print(f"❌ Error creating virtual environment: {e}", style="red")
112
+ return False
113
+
114
+ def install_framework(self, app_path: Path, framework: str) -> bool:
115
+ """Install selected framework in virtual environment"""
116
+ venv_path = app_path / "venv"
117
+
118
+ # Determine pip path based on OS
119
+ if sys.platform == "win32":
120
+ pip_path = venv_path / "Scripts" / "pip"
121
+ else:
122
+ pip_path = venv_path / "bin" / "pip"
123
+
124
+ framework_info = FRAMEWORKS[framework]
125
+ packages = framework_info['packages']
126
+
127
+ try:
128
+ with Progress(
129
+ SpinnerColumn(),
130
+ TextColumn("[progress.description]{task.description}"),
131
+ console=console,
132
+ ) as progress:
133
+ task = progress.add_task(f"Installing {framework_info['name']}...", total=None)
134
+
135
+ for package in packages:
136
+ subprocess.run([
137
+ str(pip_path), "install", package
138
+ ], check=True, capture_output=True)
139
+
140
+ progress.update(task, description=f"✅ {framework_info['name']} installed")
141
+
142
+ return True
143
+ except subprocess.CalledProcessError as e:
144
+ console.print(f"❌ Error installing {framework_info['name']}: {e}", style="red")
145
+ return False
146
+
147
+ def create_app(self):
148
+ """Main app creation flow"""
149
+ self.welcome_banner()
150
+
151
+ # Get user choices
152
+ framework = self.select_framework()
153
+ if not framework:
154
+ console.print("❌ No framework selected. Exiting.", style="red")
155
+ return
156
+
157
+ app_type = self.select_app_type()
158
+ if not app_type:
159
+ console.print("❌ No application type selected. Exiting.", style="red")
160
+ return
161
+
162
+ app_name = self.get_app_name()
163
+ if not app_name:
164
+ console.print("❌ No application name provided. Exiting.", style="red")
165
+ return
166
+
167
+ # Create application directory
168
+ app_path = Path.cwd() / app_name
169
+
170
+ if app_path.exists():
171
+ overwrite = questionary.confirm(
172
+ f"Directory '{app_name}' already exists. Overwrite?"
173
+ ).ask()
174
+
175
+ if not overwrite:
176
+ console.print("❌ Operation cancelled.", style="yellow")
177
+ return
178
+
179
+ import shutil
180
+ shutil.rmtree(app_path)
181
+
182
+ app_path.mkdir()
183
+ console.print(f"📁 Created directory: {app_path}", style="green")
184
+
185
+ # Create virtual environment
186
+ if not self.create_virtual_environment(app_path):
187
+ return
188
+
189
+ # Install framework
190
+ if not self.install_framework(app_path, framework):
191
+ return
192
+
193
+ # Generate project structure
194
+ with Progress(
195
+ SpinnerColumn(),
196
+ TextColumn("[progress.description]{task.description}"),
197
+ console=console,
198
+ ) as progress:
199
+ task = progress.add_task("Generating project structure...", total=None)
200
+ self.template_manager.generate_structure(app_path, framework, app_type, app_name)
201
+ progress.update(task, description="✅ Project structure generated")
202
+
203
+ # Success message
204
+ console.print(Panel(
205
+ f"""🎉 Successfully created '{app_name}'!
206
+
207
+ 📁 Next Steps:
208
+ 1. cd {app_name}
209
+ 2. source venv/bin/activate (Linux/Mac) or venv\\Scripts\\activate (Windows)
210
+ 3. python run.py
211
+
212
+ Your app will be running at http://localhost:{FRAMEWORKS[framework]['default_port']}
213
+ """.strip(),
214
+ title="🎊 Project Created Successfully!",
215
+ border_style="green"
216
+ ))
217
+
218
+ @click.group()
219
+ def main():
220
+ """Amen - composer-inspired Python web framework scaffolding tool"""
221
+ pass
222
+
223
+ @main.command()
224
+ def create():
225
+ """Create a new web application"""
226
+ cli = AmenCLI()
227
+ cli.create_app()
228
+
229
+ if __name__ == "__main__":
230
+ main()
amen/frameworks.py ADDED
@@ -0,0 +1,46 @@
1
+ """Framework configurations and metadata"""
2
+
3
+ FRAMEWORKS = {
4
+ 'flask': {
5
+ 'name': 'Flask',
6
+ 'description': 'Lightweight WSGI web application framework',
7
+ 'packages': ['flask', 'flask-cors', 'python-dotenv'],
8
+ 'default_port': 5000,
9
+ 'entry_file': 'app.py',
10
+ },
11
+ # 'django': {
12
+ # 'name': 'Django',
13
+ # 'description': 'High-level Python web framework',
14
+ # 'packages': ['django', 'django-cors-headers', 'python-dotenv'],
15
+ # 'default_port': 8000,
16
+ # 'entry_file': 'manage.py',
17
+ # },
18
+ 'fastapi': {
19
+ 'name': 'FastAPI',
20
+ 'description': 'Modern, fast web framework for building APIs',
21
+ 'packages': ['fastapi', 'uvicorn[standard]', 'python-dotenv'],
22
+ 'default_port': 8000,
23
+ 'entry_file': 'main.py',
24
+ },
25
+ # 'bottle': {
26
+ # 'name': 'Bottle',
27
+ # 'description': 'Fast, simple micro web framework',
28
+ # 'packages': ['bottle', 'python-dotenv'],
29
+ # 'default_port': 8080,
30
+ # 'entry_file': 'app.py',
31
+ # },
32
+ # 'pyramid': {
33
+ # 'name': 'Pyramid',
34
+ # 'description': 'Flexible, open source web framework',
35
+ # 'packages': ['pyramid', 'waitress', 'python-dotenv'],
36
+ # 'default_port': 6543,
37
+ # 'entry_file': 'app.py',
38
+ # },
39
+ # 'django-hotsauce': {
40
+ # 'name': 'Django Hotsauce',
41
+ # 'description': 'Django-based rapid development framework',
42
+ # 'packages': ['django', 'django-hotsauce', 'python-dotenv'],
43
+ # 'default_port': 8000,
44
+ # 'entry_file': 'manage.py',
45
+ # }
46
+ }
@@ -0,0 +1,3 @@
1
+ from .manager import TemplateManager
2
+
3
+ __all__ = ['TemplateManager']
@@ -0,0 +1,617 @@
1
+ """Template management for different frameworks"""
2
+
3
+ import os
4
+ from pathlib import Path
5
+ from ..frameworks import FRAMEWORKS
6
+
7
+ class TemplateManager:
8
+ def _write_file(self, path: Path, content: str):
9
+ """Helper method to write files with UTF-8 encoding"""
10
+ # Ensure parent directory exists
11
+ path.parent.mkdir(parents=True, exist_ok=True)
12
+ path.write_text(content, encoding='utf-8')
13
+
14
+ def generate_structure(self, app_path: Path, framework: str, app_type: str, app_name: str):
15
+ """Generate project structure based on framework and app type"""
16
+
17
+ # Create all necessary directories
18
+ (app_path / "app").mkdir(exist_ok=True)
19
+ (app_path / "app" / "templates").mkdir(exist_ok=True)
20
+ (app_path / "app" / "static").mkdir(exist_ok=True)
21
+ (app_path / "app" / "static" / "css").mkdir(exist_ok=True)
22
+ (app_path / "app" / "static" / "js").mkdir(exist_ok=True)
23
+ (app_path / "tests").mkdir(exist_ok=True) # Create tests directory
24
+
25
+ # Generate framework-specific files
26
+ if framework == 'flask':
27
+ self._generate_flask_files(app_path, app_type, app_name)
28
+ elif framework == 'fastapi':
29
+ self._generate_fastapi_files(app_path, app_type, app_name)
30
+ # Add other frameworks as needed
31
+
32
+ # Generate common files
33
+ self._generate_common_files(app_path, framework, app_name, app_type)
34
+
35
+ def _generate_flask_files(self, app_path: Path, app_type: str, app_name: str):
36
+ """Generate Flask files"""
37
+ app_content = f"""from flask import Flask, render_template, jsonify
38
+ from flask_cors import CORS
39
+ from dotenv import load_dotenv
40
+ import os
41
+
42
+ load_dotenv()
43
+
44
+ app = Flask(__name__)
45
+ CORS(app)
46
+
47
+ app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', 'dev-secret-key')
48
+
49
+ @app.route('/')
50
+ def index():
51
+ {"return render_template('index.html', title='" + app_name + "')" if app_type == 'webapp' else "return jsonify({'message': 'Welcome to " + app_name + " API!'})"}
52
+
53
+ @app.route('/health')
54
+ def health():
55
+ return jsonify({{'status': 'healthy', 'service': '{app_name}'}})
56
+
57
+ if __name__ == '__main__':
58
+ app.run(host='0.0.0.0', port=int(os.getenv('PORT', 5000)), debug=True)
59
+ """
60
+ self._write_file(app_path / "app" / "app.py", app_content)
61
+ self._write_file(app_path / "run.py", "from app.app import app\n\nif __name__ == '__main__':\n app.run()")
62
+
63
+ if app_type == 'webapp':
64
+ self._generate_html_template(app_path, app_name)
65
+
66
+ def _generate_fastapi_files(self, app_path: Path, app_type: str, app_name: str):
67
+ """Generate FastAPI files"""
68
+ main_content = f"""from fastapi import FastAPI, Request
69
+ from fastapi.middleware.cors import CORSMiddleware
70
+ {"from fastapi.templating import Jinja2Templates" if app_type == 'webapp' else ""}
71
+ {"from fastapi.staticfiles import StaticFiles" if app_type == 'webapp' else ""}
72
+ from dotenv import load_dotenv
73
+ import os
74
+
75
+ load_dotenv()
76
+
77
+ app = FastAPI(title="{app_name}")
78
+
79
+ app.add_middleware(
80
+ CORSMiddleware,
81
+ allow_origins=["*"],
82
+ allow_credentials=True,
83
+ allow_methods=["*"],
84
+ allow_headers=["*"],
85
+ )
86
+
87
+ {"app.mount('/static', StaticFiles(directory='app/static'), name='static')" if app_type == 'webapp' else ""}
88
+ {"templates = Jinja2Templates(directory='app/templates')" if app_type == 'webapp' else ""}
89
+
90
+ @app.get("/")
91
+ async def root({"request: Request" if app_type == 'webapp' else ""}):
92
+ {"return templates.TemplateResponse('index.html', {'request': request, 'title': '" + app_name + "'})" if app_type == 'webapp' else 'return {"message": "Welcome to ' + app_name + ' API!"}'}
93
+
94
+ @app.get("/health")
95
+ async def health():
96
+ return {{"status": "healthy", "service": "{app_name}"}}
97
+
98
+ if __name__ == "__main__":
99
+ import uvicorn
100
+ uvicorn.run(app, host="0.0.0.0", port=8000)
101
+ """
102
+ self._write_file(app_path / "app" / "main.py", main_content)
103
+ self._write_file(app_path / "run.py", "import uvicorn\nfrom app.main import app\n\nif __name__ == '__main__':\n uvicorn.run(app, host='0.0.0.0', port=8000)")
104
+
105
+ if app_type == 'webapp':
106
+ self._generate_html_template(app_path, app_name)
107
+
108
+ def _generate_html_template(self, app_path: Path, app_name: str):
109
+ """Generate HTML template"""
110
+ template_content = f"""<!DOCTYPE html>
111
+ <html lang="en">
112
+ <head>
113
+ <meta charset="UTF-8">
114
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
115
+ <title>{app_name}</title>
116
+ <link rel="stylesheet" href="/static/css/style.css">
117
+ </head>
118
+ <body>
119
+ <div class="container">
120
+ <h1>Welcome to {app_name}!</h1>
121
+ <p>Your application is running successfully.</p>
122
+ </div>
123
+ <script src="/static/js/app.js"></script>
124
+ </body>
125
+ </html>"""
126
+ self._write_file(app_path / "app" / "templates" / "index.html", template_content)
127
+
128
+ def _generate_common_files(self, app_path: Path, framework: str, app_name: str, app_type: str):
129
+ """Generate common files for all projects"""
130
+
131
+ # requirements.txt
132
+ framework_info = FRAMEWORKS[framework]
133
+ requirements = "\n".join(framework_info['packages'])
134
+ self._write_file(app_path / "requirements.txt", requirements)
135
+
136
+ # .env
137
+ env_content = f"""SECRET_KEY=your-secret-key-here
138
+ DEBUG=True
139
+ PORT={framework_info['default_port']}
140
+ """
141
+ self._write_file(app_path / ".env", env_content)
142
+
143
+ # README.md
144
+ readme_content = f"""# {app_name}
145
+
146
+ A web application built with {framework_info['name']}.
147
+
148
+ ## Quick Start
149
+
150
+ 1. Activate virtual environment:
151
+ ```bash
152
+ source venv/bin/activate # Linux/Mac
153
+ venv\\Scripts\\activate # Windows
154
+ 3. **Install dependencies** (if not already installed)
155
+ ```bash
156
+ pip install -r requirements.txt
157
+ ```
158
+
159
+ 4. **Set up environment variables**
160
+ ```bash
161
+ cp .env.example .env
162
+ # Edit .env file with your configuration
163
+ ```
164
+
165
+ 5. **Run the application**
166
+ ```bash
167
+ python run.py
168
+ ```
169
+
170
+ Your application will be available at `http://localhost:{framework_info['default_port']}`
171
+
172
+ ## 📁 Project Structure
173
+
174
+ ```
175
+ {app_name}/
176
+ ├── venv/ # Virtual environment
177
+ ├── app/ # Main application code
178
+ │ ├── __init__.py
179
+ │ ├── {framework_info['entry_file']} # Main application file
180
+ │ ├── templates/ # HTML templates (if web app)
181
+ │ └── static/ # Static files (CSS, JS, images)
182
+ │ ├── css/
183
+ │ └── js/
184
+ ├── tests/ # Test files
185
+ ├── docs/ # Documentation
186
+ ├── requirements.txt # Python dependencies
187
+ ├── .env # Environment variables (local)
188
+ ├── .env.example # Environment variables template
189
+ ├── .gitignore # Git ignore rules
190
+ ├── run.py # Application runner
191
+ └── README.md # This file
192
+ ```
193
+
194
+ ## 🛠️ Development
195
+
196
+ ### Framework: {FRAMEWORKS[framework]['name']}
197
+ {FRAMEWORKS[framework]['description']}
198
+
199
+ ### Application Type: {"Full Web Application" if app_type == 'webapp' else "API Only"}
200
+
201
+ ### Available Endpoints
202
+ - `GET /` - {"Main page" if app_type == 'webapp' else "API welcome message"}
203
+ - `GET /health` - Health check endpoint
204
+
205
+ ### Adding New Routes
206
+
207
+ #### {FRAMEWORKS[framework]['name']} specific instructions:
208
+ '''
209
+
210
+ # Add framework-specific route examples
211
+ if framework == 'flask':
212
+ readme_content += '''
213
+ ```python
214
+ from flask import Flask
215
+
216
+ @app.route('/new-route')
217
+ def new_route():
218
+ return 'Hello from new route!'
219
+ ```
220
+ '''
221
+ elif framework == 'fastapi':
222
+ readme_content += '''
223
+ ```python
224
+ from fastapi import FastAPI
225
+
226
+ @app.get("/new-route")
227
+ async def new_route():
228
+ return {{"message": "Hello from new route!"}}
229
+ ```
230
+ '''
231
+ elif framework == 'django':
232
+ readme_content += '''
233
+ 1. Add to `app/urls.py`:
234
+ ```python
235
+ path('new-route/', views.new_route, name='new_route'),
236
+ ```
237
+
238
+ 2. Add to `app/views.py`:
239
+ ```python
240
+ def new_route(request):
241
+ return JsonResponse({{'message': 'Hello from new route!'}})
242
+ ```
243
+ '''
244
+ elif framework == 'bottle':
245
+ readme_content += '''
246
+ ```python
247
+ @app.route('/new-route')
248
+ def new_route():
249
+ return {{'message': 'Hello from new route!'}}
250
+ ```
251
+ '''
252
+ elif framework == 'pyramid':
253
+ readme_content += '''
254
+ 1. Add route in `main()`:
255
+ ```python
256
+ config.add_route('new_route', '/new-route')
257
+ ```
258
+
259
+ 2. Add view function:
260
+ ```python
261
+ @view_config(route_name='new_route', renderer='json')
262
+ def new_route_view(request):
263
+ return {{'message': 'Hello from new route!'}}
264
+ ```
265
+ """
266
+
267
+ readme_content += f"""
268
+
269
+ ## 🧪 Testing
270
+
271
+ Run tests with:
272
+ ```bash
273
+ pytest tests/
274
+ ```
275
+
276
+ ## 📦 Deployment
277
+
278
+ ### Environment Variables
279
+ Make sure to set these in production:
280
+ - `SECRET_KEY`: A secure secret key
281
+ - `DEBUG`: Set to `False` in production
282
+ - `PORT`: Port number for the application
283
+
284
+ ### Docker (Optional)
285
+ Create a `Dockerfile`:
286
+ ```dockerfile
287
+ FROM python:3.9-slim
288
+
289
+ WORKDIR /app
290
+
291
+ COPY requirements.txt .`
292
+ RUN pip install -r requirements.txt
293
+
294
+ COPY . .
295
+
296
+ EXPOSE {framework_info['default_port']}
297
+
298
+ CMD ["python", "run.py"]
299
+ ```
300
+
301
+ ## 🤝 Contributing
302
+
303
+ 1. Fork the repository
304
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
305
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
306
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
307
+ 5. Open a Pull Request
308
+
309
+ ## 📄 License
310
+
311
+ This project is licensed under the MIT License.
312
+
313
+ ## 🙏 Acknowledgments
314
+
315
+ - Built with [Amen CLI](https://github.com/your-username/amen-cli)
316
+ - Powered by {FRAMEWORKS[framework]['name']}
317
+
318
+ ---
319
+
320
+ Happy coding! 🎉
321
+ """
322
+
323
+ self._write_file(app_path / "README.md", readme_content)
324
+
325
+ # Generate CSS
326
+ css_content = """/* Reset and Base Styles */
327
+ * {
328
+ margin: 0;
329
+ padding: 0;
330
+ box-sizing: border-box;
331
+ }
332
+
333
+ body {
334
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
335
+ line-height: 1.6;
336
+ color: #333;
337
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
338
+ min-height: 100vh;
339
+ }
340
+
341
+ .container {
342
+ max-width: 1200px;
343
+ margin: 0 auto;
344
+ padding: 2rem;
345
+ }
346
+
347
+ /* Header */
348
+ header {
349
+ text-align: center;
350
+ margin-bottom: 3rem;
351
+ color: white;
352
+ }
353
+
354
+ header h1 {
355
+ font-size: 3rem;
356
+ font-weight: 700;
357
+ margin-bottom: 0.5rem;
358
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
359
+ }
360
+
361
+ .subtitle {
362
+ font-size: 1.2rem;
363
+ opacity: 0.9;
364
+ font-weight: 300;
365
+ }
366
+
367
+ /* Hero Section */
368
+ .hero {
369
+ background: white;
370
+ padding: 3rem;
371
+ border-radius: 15px;
372
+ box-shadow: 0 20px 40px rgba(0,0,0,0.1);
373
+ text-align: center;
374
+ margin-bottom: 3rem;
375
+ }
376
+
377
+ .hero h2 {
378
+ color: #667eea;
379
+ font-size: 2rem;
380
+ margin-bottom: 1rem;
381
+ }
382
+
383
+ .hero p {
384
+ font-size: 1.1rem;
385
+ color: #666;
386
+ }
387
+
388
+ /* Features Grid */
389
+ .features {
390
+ display: grid;
391
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
392
+ gap: 2rem;
393
+ margin-bottom: 3rem;
394
+ }
395
+
396
+ .feature {
397
+ background: white;
398
+ padding: 2rem;
399
+ border-radius: 10px;
400
+ box-shadow: 0 10px 25px rgba(0,0,0,0.1);
401
+ transition: transform 0.3s ease, box-shadow 0.3s ease;
402
+ }
403
+
404
+ .feature:hover {
405
+ transform: translateY(-5px);
406
+ box-shadow: 0 15px 35px rgba(0,0,0,0.15);
407
+ }
408
+
409
+ .feature h3 {
410
+ color: #667eea;
411
+ font-size: 1.3rem;
412
+ margin-bottom: 1rem;
413
+ }
414
+
415
+ .feature p {
416
+ color: #666;
417
+ font-size: 1rem;
418
+ }
419
+
420
+ /* Footer */
421
+ footer {
422
+ text-align: center;
423
+ color: white;
424
+ opacity: 0.8;
425
+ padding: 2rem 0;
426
+ }
427
+
428
+ /* Responsive Design */
429
+ @media (max-width: 768px) {
430
+ .container {
431
+ padding: 1rem;
432
+ }
433
+
434
+ header h1 {
435
+ font-size: 2rem;
436
+ }
437
+
438
+ .hero {
439
+ padding: 2rem;
440
+ }
441
+
442
+ .hero h2 {
443
+ font-size: 1.5rem;
444
+ }
445
+
446
+ .features {
447
+ grid-template-columns: 1fr;
448
+ gap: 1rem;
449
+ }
450
+
451
+ .feature {
452
+ padding: 1.5rem;
453
+ }
454
+ }
455
+
456
+ /* Animation */
457
+ @keyframes fadeInUp {
458
+ from {
459
+ opacity: 0;
460
+ transform: translateY(30px);
461
+ }
462
+ to {
463
+ opacity: 1;
464
+ transform: translateY(0);
465
+ }
466
+ }
467
+
468
+ .hero, .feature {
469
+ animation: fadeInUp 0.6s ease-out;
470
+ }
471
+
472
+ .feature:nth-child(2) {
473
+ animation-delay: 0.1s;
474
+ }
475
+
476
+ .feature:nth-child(3) {
477
+ animation-delay: 0.2s;
478
+ }
479
+ """
480
+
481
+ self._write_file(app_path / "app" / "static" / "css" / "style.css", css_content)
482
+
483
+ # Generate JavaScript
484
+ js_content = """// Main application JavaScript
485
+ document.addEventListener('DOMContentLoaded', function() {
486
+ console.log('Application loaded successfully!');
487
+
488
+ // Add smooth scrolling for anchor links
489
+ const links = document.querySelectorAll('a[href^="#"]');
490
+ links.forEach(link => {
491
+ link.addEventListener('click', function(e) {
492
+ e.preventDefault();
493
+ const target = document.querySelector(this.getAttribute('href'));
494
+ if (target) {
495
+ target.scrollIntoView({
496
+ behavior: 'smooth',
497
+ block: 'start'
498
+ });
499
+ }
500
+ });
501
+ });
502
+
503
+ // Add click animation to features
504
+ const features = document.querySelectorAll('.feature');
505
+ features.forEach(feature => {
506
+ feature.addEventListener('click', function() {
507
+ this.style.transform = 'scale(0.98)';
508
+ setTimeout(() => {
509
+ this.style.transform = '';
510
+ }, 150);
511
+ });
512
+ });
513
+
514
+ // Health check function (example API call)
515
+ async function checkHealth() {
516
+ try {
517
+ const response = await fetch('/health');
518
+ const data = await response.json();
519
+ console.log('Health check:', data);
520
+ } catch (error) {
521
+ console.error('Health check failed:', error);
522
+ }
523
+ }
524
+
525
+ // Uncomment to perform health check on load
526
+ // checkHealth();
527
+ });
528
+
529
+ // Utility functions
530
+ const utils = {
531
+ // Format date
532
+ formatDate: (date) => {
533
+ return new Intl.DateTimeFormat('en-US', {
534
+ year: 'numeric',
535
+ month: 'long',
536
+ day: 'numeric'
537
+ }).format(date);
538
+ },
539
+
540
+ // Debounce function
541
+ debounce: (func, wait) => {
542
+ let timeout;
543
+ return function executedFunction(...args) {
544
+ const later = () => {
545
+ clearTimeout(timeout);
546
+ func(...args);
547
+ };
548
+ clearTimeout(timeout);
549
+ timeout = setTimeout(later, wait);
550
+ };
551
+ },
552
+
553
+ // Show notification (you can integrate with a toast library)
554
+ showNotification: (message, type = 'info') => {
555
+ console.log(`[${type.toUpperCase()}] ${message}`);
556
+ // Implement your notification system here
557
+ }
558
+ };
559
+
560
+ // Export for use in other scripts
561
+ window.AppUtils = utils;
562
+ """
563
+ self._write_file(app_path / "app" / "static" / "js" / "app.js", js_content)
564
+
565
+ # Generate test files
566
+ test_content = f"""import pytest
567
+ import sys
568
+ import os
569
+
570
+ # Add the app directory to the Python path
571
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'app'))
572
+
573
+ def test_basic_functionality():
574
+ '''Test basic functionality'''
575
+ assert True # Replace with actual tests
576
+
577
+ class Test{app_name.replace('-', '').replace('_', '').title()}:
578
+ '''Test class for {app_name}'''
579
+
580
+ def test_app_creation(self):
581
+ '''Test application creation'''
582
+ # Add your app-specific tests here
583
+ pass
584
+
585
+ def test_health_endpoint(self):
586
+ '''Test health endpoint'''
587
+ # Add health endpoint test
588
+ pass
589
+ """
590
+ # Add more tests as needed
591
+
592
+
593
+ self._write_file(app_path / "tests" / "__init__.py", "")
594
+ self._write_file(app_path / "tests" / f"test_{app_name.replace('-', '_')}.py", test_content)
595
+
596
+ # Generate pytest configuration
597
+ pytest_ini = """
598
+ [tool:pytest]
599
+ testpaths = tests
600
+ python_files = test_*.py
601
+ python_functions = test_*
602
+ python_classes = Test*
603
+ addopts = -v --tb=short
604
+ """
605
+
606
+ self._write_file(app_path / "pytest.ini", pytest_ini)
607
+
608
+ self._write_file(app_path / "pytest.ini", pytest_ini)
609
+
610
+ # MANIFEST.in - for including non-Python files in the package
611
+ MANIFEST_IN = """
612
+ include README.md
613
+ include LICENSE
614
+ recursive-include amen/templates *.py *.html *.css *.js *.md
615
+ recursive-exclude * __pycache__
616
+ recursive-exclude * *.py[co]
617
+ """
@@ -0,0 +1,189 @@
1
+ Metadata-Version: 2.4
2
+ Name: amen-cli
3
+ Version: 0.1.0
4
+ Summary: composer-inspired Python web framework scaffolding tool
5
+ Home-page: https://github.com/taqsblaze/amen-cli
6
+ Author: Tanaka Chinengundu
7
+ Author-email: tanakah30@gmail.com
8
+ Project-URL: Bug Reports, https://github.com/taqsblaze/amen-cli/issues
9
+ Project-URL: Source, https://github.com/taqsblaze/amen-cli
10
+ Project-URL: Documentation, https://github.com/taqsblaze/amen-cli#readme
11
+ Keywords: python,web-framework,cli,scaffold,amen,composer,laravel,flask,django,fastapi,bottle,pyramid
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Requires-Python: >=3.11
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: click>=8.0.0
23
+ Requires-Dist: rich>=12.0.0
24
+ Requires-Dist: questionary>=1.10.0
25
+ Requires-Dist: virtualenv>=20.0.0
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=6.0.0; extra == "dev"
28
+ Requires-Dist: pytest-cov>=2.0.0; extra == "dev"
29
+ Requires-Dist: black>=21.0.0; extra == "dev"
30
+ Requires-Dist: flake8>=3.9.0; extra == "dev"
31
+ Requires-Dist: mypy>=0.900; extra == "dev"
32
+ Dynamic: author
33
+ Dynamic: author-email
34
+ Dynamic: classifier
35
+ Dynamic: description
36
+ Dynamic: description-content-type
37
+ Dynamic: home-page
38
+ Dynamic: keywords
39
+ Dynamic: license-file
40
+ Dynamic: project-url
41
+ Dynamic: provides-extra
42
+ Dynamic: requires-dist
43
+ Dynamic: requires-python
44
+ Dynamic: summary
45
+
46
+ # 🚀 AMEN CLI ![icon](https://raw.githubusercontent.com/TaqsBlaze/amen-cli/refs/heads/main/image/icon.png)
47
+ A composer-inspired Python Web Framework Scaffolding Tool that helps you create web applications with ease!
48
+
49
+ ## ✨ Features
50
+
51
+ - 🎯 Interactive project setup wizard
52
+ - 🔧 Multiple framework support:
53
+ - Flask - Lightweight WSGI framework
54
+ - FastAPI - Modern, fast API framework
55
+ - Bottle - Simple micro web framework 🚧
56
+ - Pyramid - Flexible web framework 🚧
57
+ - 🎨 Project templates for both web apps and APIs
58
+ - 🔄 Automatic virtual environment setup
59
+ - 📦 Dependency management
60
+ - 🏗️ Structured project scaffolding
61
+
62
+ ## 🛠️ Installation
63
+
64
+ ```bash
65
+ pip install amen-cli
66
+ ```
67
+
68
+ ## 📖 Usage
69
+
70
+ ```bash
71
+ # Create a new project
72
+ amen create
73
+
74
+ # Follow the interactive prompts to:
75
+ # 1. Select a framework
76
+ # 2. Choose application type (webapp/api)
77
+ # 3. Name your project
78
+ ```
79
+
80
+ ## 🌟 Project Structure
81
+
82
+ When you create a project, AMEN generates:
83
+
84
+ ```
85
+ your-app/
86
+ ├── venv/ # Virtual environment
87
+ ├── app/ # Main application code
88
+ │ ├── templates/ # HTML templates (webapp)
89
+ │ └── static/ # Static files
90
+ │ ├── css/ # Stylesheets
91
+ │ └── js/ # JavaScript files
92
+ ├── tests/ # Test directory
93
+ ├── requirements.txt # Python dependencies
94
+ ├── .env # Environment variables
95
+ └── README.md # Project documentation
96
+ ```
97
+
98
+ ## 🎯 Supported Frameworks
99
+
100
+ | Framework | Description | Default Port | Status |
101
+ |-----------|-------------|--------------|--------|
102
+ | Flask | Lightweight WSGI web framework | 5000 | ✅ |
103
+ | FastAPI | Modern, fast web framework | 8000 | ✅ |
104
+ | Django | High-level Python web framework | 8000 | ❌ |
105
+ | Bottle | Fast, simple micro framework | 8080 | 🚧 |
106
+ | Pyramid | Flexible web framework | 6543 | 🚧 |
107
+
108
+ ## Work in Progress
109
+ Currently implementing support for additional web frameworks:
110
+
111
+ - **Bottle**: Integration in development
112
+ - **Pyramid**: Initial implementation phase
113
+
114
+ These frameworks will enable:
115
+ - Route mapping and handling
116
+ - Request/response processing
117
+ - Middleware integration
118
+ - Template rendering support
119
+
120
+ Check back for updates or follow the project's issues for implementation progress. Contributions are welcome!
121
+
122
+ > Note: For now, please use our stable implementations for Flask or FastAPI.
123
+ ## 🚗 Quick Start
124
+
125
+ ```bash
126
+ # Install AMEN CLI
127
+ pip install amen-cli
128
+
129
+ # Create a new project
130
+ amen create
131
+
132
+ # Follow the interactive prompts
133
+
134
+ # Navigate to your project
135
+ cd your-project-name
136
+
137
+ # Activate virtual environment
138
+ source venv/bin/activate # Linux/Mac
139
+ venv\Scripts\activate # Windows
140
+
141
+ # Run your application
142
+ python run.py
143
+ ```
144
+
145
+ ## 🔧 Development
146
+
147
+ ```bash
148
+ # Clone the repository
149
+ git clone https://github.com/taqsblaze/amen-cli.git
150
+
151
+ # Install for development and testing
152
+ pip install -e .
153
+ pip install pytest pytest-cov
154
+
155
+ # Run tests
156
+ pytest
157
+
158
+ # Run tests with coverage
159
+ pytest
160
+ ```
161
+
162
+ ## 🤝 Contributing
163
+
164
+ Contributions are welcome! Here's how:
165
+
166
+ 1. Fork the repository
167
+ 2. Create your feature branch: `git checkout -b feature/amazing-feature`
168
+ 3. Make your changes
169
+ 4. Push to the branch: `git push origin feature/amazing-feature`
170
+ 5. Open a Pull Request
171
+
172
+ ## 📝 License
173
+
174
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
175
+
176
+ ## 👥 Contact & Support
177
+
178
+ - 🌐 [GitHub Repository](https://github.com/taqsblaze/amen-cli)
179
+ - 🐛 [Issue Tracker](https://github.com/taqsblaze/amen-cli/issues)
180
+ - 📧 [Send Email](mailto:tanakah30@gmail.com)
181
+
182
+ ## ⭐ Credits
183
+
184
+ Created by [Tanaka Chinengundu](https://www.linkedin.com/in/taqsblaze)
185
+ Inspired by Laravel's elegant development experience
186
+
187
+ ---
188
+
189
+ Made with ❤️ by Tanaka Chinengundu
@@ -0,0 +1,11 @@
1
+ amen/__init__.py,sha256=7gWg66LLzl97AIWrsnSq0Y3OpGIWqQzkKLzwnuNr8LQ,810
2
+ amen/cli.py,sha256=BNeXzW2gjhLFx554WK_zZZOwQfJF30zVGLbeixq3pNE,7952
3
+ amen/frameworks.py,sha256=uarXCHkZgMwf9sfY9r2wim3rk8sNBwW7j8Cy8On3N7s,1624
4
+ amen/templates/__init__.py,sha256=2MvacuUyKD4x1-YnByMDi_hq90rH8wkNh0sKvUhhOAw,69
5
+ amen/templates/manager.py,sha256=PaGqpWivfet8DoV5UTMzS9A0XEwwXK9k7iD6DtOQ2kg,16958
6
+ amen_cli-0.1.0.dist-info/licenses/LICENSE,sha256=3A9c5OOecf_0logHhGvw85x-VtpTFPti1I1GBEJTkQk,2532
7
+ amen_cli-0.1.0.dist-info/METADATA,sha256=L8VJTDNIiXFTDpNi2y8c1SjqyECLMmq01jYDz9LaQek,5619
8
+ amen_cli-0.1.0.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
9
+ amen_cli-0.1.0.dist-info/entry_points.txt,sha256=US5E6fz5OI2kAwqz-zqBB7M-LeeQANqVlEvpx5a0yo4,39
10
+ amen_cli-0.1.0.dist-info/top_level.txt,sha256=Ot0LsWWgOO3jySIhly8qjAYj2sTASmVdbvE1LtBasdg,5
11
+ amen_cli-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.8.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ amen = amen.cli:main
@@ -0,0 +1,43 @@
1
+ Modified MIT License with Attribution Requirements
2
+
3
+ Copyright (c) 2024 Tanaka Chinengundu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, subject to the following conditions:
10
+
11
+ 1. The above copyright notice, this permission notice, and the following attribution
12
+ requirements shall be included in all copies or substantial portions of the Software.
13
+
14
+ 2. Attribution Requirements:
15
+ a. All copies or substantial portions of the Software must retain clear and visible
16
+ attribution to the original author, Tanaka Chinengundu.
17
+ b. The original author's name (Tanaka Chinengundu) must not be removed, modified,
18
+ or obscured in any derivative works or modifications of the Software.
19
+ c. Any modifications or derivative works must clearly indicate that changes have
20
+ been made from the original Software and must not imply endorsement by the
21
+ original author.
22
+
23
+ 3. Liability and Responsibility:
24
+ a. The original author shall not be held responsible or liable for any damages,
25
+ losses, or consequences arising from the use, misuse, or failure of the Software,
26
+ whether in its original or modified form.
27
+ b. Users and modifiers of the Software assume all risks associated with its use,
28
+ including but not limited to data loss, system failure, or other damages.
29
+ c. Any modifications made to the Software are the sole responsibility of the modifier,
30
+ and the original author bears no responsibility for derivative works.
31
+
32
+ 4. Additional Restrictions:
33
+ a. The Software may not be used in any way that implies endorsement by the original author.
34
+ b. The Software may not be used for illegal or malicious purposes.
35
+ c. Users must notify end users if they are using a modified version of the Software.
36
+
37
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
39
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
40
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
42
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
43
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ amen