wappa 0.1.5__py3-none-any.whl → 0.1.7__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.

Potentially problematic release.


This version of wappa might be problematic. Click here for more details.

Files changed (50) hide show
  1. wappa/__init__.py +13 -69
  2. wappa/cli/examples/init/.gitignore +69 -0
  3. wappa/cli/examples/init/pyproject.toml +7 -0
  4. wappa/cli/examples/json_cache_example/.gitignore +69 -0
  5. wappa/cli/examples/json_cache_example/README.md +190 -0
  6. wappa/cli/examples/openai_transcript/.gitignore +10 -0
  7. wappa/cli/examples/openai_transcript/README.md +0 -0
  8. wappa/cli/examples/redis_cache_example/.gitignore +69 -0
  9. wappa/cli/examples/redis_cache_example/README.md +0 -0
  10. wappa/cli/examples/simple_echo_example/.gitignore +69 -0
  11. wappa/cli/examples/simple_echo_example/.python-version +1 -0
  12. wappa/cli/examples/simple_echo_example/README.md +0 -0
  13. wappa/cli/examples/simple_echo_example/pyproject.toml +9 -0
  14. wappa/cli/examples/wappa_full_example/.dockerignore +171 -0
  15. wappa/cli/examples/wappa_full_example/.gitignore +10 -0
  16. wappa/cli/examples/wappa_full_example/Dockerfile +85 -0
  17. wappa/cli/examples/wappa_full_example/RAILWAY_DEPLOYMENT.md +366 -0
  18. wappa/cli/examples/wappa_full_example/README.md +322 -0
  19. wappa/cli/examples/wappa_full_example/docker-compose.yml +170 -0
  20. wappa/cli/examples/wappa_full_example/nginx.conf +177 -0
  21. wappa/cli/examples/wappa_full_example/railway.toml +30 -0
  22. wappa/cli/main.py +346 -22
  23. wappa/cli/templates/__init__.py.template +0 -0
  24. wappa/cli/templates/env.template +37 -0
  25. wappa/cli/templates/gitignore.template +165 -0
  26. wappa/cli/templates/main.py.template +8 -0
  27. wappa/cli/templates/master_event.py.template +8 -0
  28. wappa/core/__init__.py +86 -3
  29. wappa/core/plugins/wappa_core_plugin.py +15 -5
  30. wappa/database/__init__.py +16 -4
  31. wappa/domain/interfaces/media_interface.py +57 -3
  32. wappa/domain/models/media_result.py +43 -0
  33. wappa/messaging/__init__.py +53 -3
  34. wappa/messaging/whatsapp/handlers/whatsapp_media_handler.py +112 -4
  35. wappa/models/__init__.py +103 -0
  36. wappa/persistence/__init__.py +55 -0
  37. wappa/webhooks/__init__.py +53 -4
  38. wappa/webhooks/whatsapp/__init__.py +57 -3
  39. wappa/webhooks/whatsapp/status_models.py +10 -0
  40. {wappa-0.1.5.dist-info → wappa-0.1.7.dist-info}/METADATA +7 -25
  41. {wappa-0.1.5.dist-info → wappa-0.1.7.dist-info}/RECORD +44 -23
  42. wappa/domain/interfaces/webhooks/__init__.py +0 -1
  43. wappa/persistence/json/handlers/__init__.py +0 -1
  44. wappa/persistence/json/handlers/utils/__init__.py +0 -1
  45. wappa/persistence/memory/handlers/__init__.py +0 -1
  46. wappa/persistence/memory/handlers/utils/__init__.py +0 -1
  47. wappa/schemas/webhooks/__init__.py +0 -3
  48. {wappa-0.1.5.dist-info → wappa-0.1.7.dist-info}/WHEEL +0 -0
  49. {wappa-0.1.5.dist-info → wappa-0.1.7.dist-info}/entry_points.txt +0 -0
  50. {wappa-0.1.5.dist-info → wappa-0.1.7.dist-info}/licenses/LICENSE +0 -0
wappa/cli/main.py CHANGED
@@ -5,40 +5,192 @@ Provides clean command-line interface for development and production workflows.
5
5
  """
6
6
 
7
7
  import os
8
+ import shutil
8
9
  import subprocess
9
10
  import sys
10
11
  from pathlib import Path
11
12
 
12
13
  import typer
14
+ from rich.console import Console
15
+ from rich.table import Table
13
16
 
14
17
  app = typer.Typer(help="Wappa WhatsApp Business Framework CLI")
18
+ console = Console()
19
+
20
+ # Example projects metadata
21
+ EXAMPLES = {
22
+ "init": {
23
+ "name": "Basic Project",
24
+ "description": "Minimal Wappa project with basic message handling",
25
+ "features": ["Message handling", "Mark as read", "Basic response"],
26
+ "complexity": "🟢 Beginner",
27
+ },
28
+ "simple_echo_example": {
29
+ "name": "Simple Echo Bot",
30
+ "description": "Echoes all incoming messages with acknowledgment",
31
+ "features": ["Message echo", "Media handling", "Clean architecture"],
32
+ "complexity": "🟢 Beginner",
33
+ },
34
+ "json_cache_example": {
35
+ "name": "JSON Cache Demo",
36
+ "description": "File-based caching with user management and state handling",
37
+ "features": ["JSON caching", "User management", "State handling", "Statistics"],
38
+ "complexity": "🟡 Intermediate",
39
+ },
40
+ "redis_cache_example": {
41
+ "name": "Redis Cache Demo",
42
+ "description": "Redis-powered caching with advanced state management",
43
+ "features": [
44
+ "Redis caching",
45
+ "Advanced state",
46
+ "Performance monitoring",
47
+ "Cache statistics",
48
+ ],
49
+ "complexity": "🟡 Intermediate",
50
+ },
51
+ "openai_transcript": {
52
+ "name": "OpenAI Transcription",
53
+ "description": "Voice message transcription using OpenAI Whisper API",
54
+ "features": ["Audio processing", "OpenAI integration", "Voice transcription"],
55
+ "complexity": "🟡 Intermediate",
56
+ },
57
+ "wappa_full_example": {
58
+ "name": "Full-Featured Bot",
59
+ "description": "Complete WhatsApp bot with all features and deployment configs",
60
+ "features": [
61
+ "All message types",
62
+ "Media handling",
63
+ "Interactive components",
64
+ "Docker deployment",
65
+ ],
66
+ "complexity": "🔴 Advanced",
67
+ },
68
+ }
69
+
70
+
71
+ def _get_template_content(template_name: str) -> str:
72
+ """
73
+ Load template content from the templates directory.
74
+
75
+ Args:
76
+ template_name: Name of the template file (e.g., 'main.py.template')
77
+
78
+ Returns:
79
+ Template content as string
80
+ """
81
+ template_dir = Path(__file__).parent / "templates"
82
+ template_path = template_dir / template_name
83
+
84
+ if not template_path.exists():
85
+ typer.echo(f"❌ Template not found: {template_name}", err=True)
86
+ raise typer.Exit(1)
87
+
88
+ return template_path.read_text()
89
+
90
+
91
+ def _initialize_project(directory: str) -> None:
92
+ """
93
+ Initialize a new Wappa project in the specified directory.
94
+
95
+ Args:
96
+ directory: Target directory for project initialization
97
+ """
98
+ project_path = Path(directory).resolve()
99
+
100
+ # Check if directory exists, create if it doesn't
101
+ if directory != "." and not project_path.exists():
102
+ try:
103
+ project_path.mkdir(parents=True, exist_ok=True)
104
+ typer.echo(f"📁 Created directory: {project_path}")
105
+ except Exception as e:
106
+ typer.echo(f"❌ Failed to create directory {project_path}: {e}", err=True)
107
+ raise typer.Exit(1)
108
+
109
+ # Check if directory is empty (except for hidden files and common files like pyproject.toml)
110
+ existing_files = [
111
+ f
112
+ for f in project_path.iterdir()
113
+ if not f.name.startswith(".")
114
+ and f.name not in ["pyproject.toml", "uv.lock", "README.md"]
115
+ ]
116
+
117
+ if existing_files:
118
+ typer.echo(f"⚠️ Directory {project_path} is not empty:", err=True)
119
+ typer.echo(f" Found: {[f.name for f in existing_files]}", err=True)
120
+
121
+ if not typer.confirm("Continue anyway?"):
122
+ typer.echo("❌ Project initialization cancelled")
123
+ raise typer.Exit(1)
124
+
125
+ typer.echo(f"🚀 Initializing Wappa project in: {project_path}")
126
+
127
+ try:
128
+ # Create directory structure
129
+ (project_path / "app").mkdir(exist_ok=True)
130
+ (project_path / "scores").mkdir(exist_ok=True)
131
+
132
+ typer.echo("📁 Created directory structure")
133
+
134
+ # Create files from templates
135
+ templates_to_create = {
136
+ "app/__init__.py": "__init__.py.template",
137
+ "app/main.py": "main.py.template",
138
+ "app/master_event.py": "master_event.py.template",
139
+ "scores/__init__.py": "__init__.py.template",
140
+ ".gitignore": "gitignore.template",
141
+ ".env": "env.template",
142
+ }
143
+
144
+ for file_path, template_name in templates_to_create.items():
145
+ full_path = project_path / file_path
146
+ template_content = _get_template_content(template_name)
147
+
148
+ full_path.write_text(template_content)
149
+ typer.echo(f"📝 Created: {file_path}")
150
+
151
+ typer.echo()
152
+ typer.echo("✅ Wappa project initialized successfully!")
153
+ typer.echo()
154
+ typer.echo("📋 Next steps:")
155
+ typer.echo("1. Add your WhatsApp credentials to .env file")
156
+ typer.echo("2. Install dependencies: uv sync")
157
+ typer.echo("3. Start development: uv run wappa dev app/main.py")
158
+ typer.echo()
159
+ typer.echo("🔧 Required environment variables (.env file):")
160
+ typer.echo(" WP_ACCESS_TOKEN=your_access_token")
161
+ typer.echo(" WP_PHONE_ID=your_phone_id")
162
+ typer.echo(" WP_BID=your_business_id")
163
+
164
+ except Exception as e:
165
+ typer.echo(f"❌ Failed to initialize project: {e}", err=True)
166
+ raise typer.Exit(1)
15
167
 
16
168
 
17
169
  def _resolve_module_name(file_path: str) -> tuple[str, Path]:
18
170
  """
19
171
  Convert a file path to a Python module name and working directory.
20
-
172
+
21
173
  Handles both flat and nested project structures:
22
174
  main.py -> ("main", Path("."))
23
175
  app/main.py -> ("app.main", Path(".")) # Use dotted import from project root
24
176
  examples/redis_demo/main.py -> ("examples.redis_demo.main", Path("."))
25
-
177
+
26
178
  Returns:
27
179
  tuple[str, Path]: (module_name, working_directory)
28
180
  """
29
181
  # Convert to Path object for better handling
30
182
  path = Path(file_path)
31
-
183
+
32
184
  # Always use current directory as working dir and create dotted module name
33
185
  working_dir = Path(".")
34
-
186
+
35
187
  # Convert path to dotted module name (remove .py extension)
36
188
  if path.suffix == ".py":
37
189
  path = path.with_suffix("")
38
-
190
+
39
191
  # Convert path separators to dots for Python import
40
192
  module_name = str(path).replace(os.path.sep, ".")
41
-
193
+
42
194
  return module_name, working_dir
43
195
 
44
196
 
@@ -83,7 +235,7 @@ def dev(
83
235
  str(port),
84
236
  ]
85
237
 
86
- typer.echo(f"🚀 Starting Wappa development server...")
238
+ typer.echo("🚀 Starting Wappa development server...")
87
239
  typer.echo(f"📡 Import: {working_dir / module_name}:{app_var}.asgi")
88
240
  typer.echo(f"🌐 Server: http://{host}:{port}")
89
241
  typer.echo(f"📝 Docs: http://{host}:{port}/docs")
@@ -114,7 +266,7 @@ def dev(
114
266
 
115
267
 
116
268
  @app.command()
117
- def run(
269
+ def prod(
118
270
  file_path: str = typer.Argument(
119
271
  ..., help="Path to your Python file (e.g., main.py)"
120
272
  ),
@@ -131,8 +283,8 @@ def run(
131
283
  Run production server (no auto-reload).
132
284
 
133
285
  Examples:
134
- wappa run main.py
135
- wappa run main.py --workers 4 --port 8080
286
+ wappa prod main.py
287
+ wappa prod main.py --workers 4 --port 8080
136
288
  """
137
289
  # Validate file exists
138
290
  if not Path(file_path).exists():
@@ -157,7 +309,7 @@ def run(
157
309
  str(workers),
158
310
  ]
159
311
 
160
- typer.echo(f"🚀 Starting Wappa production server...")
312
+ typer.echo("🚀 Starting Wappa production server...")
161
313
  typer.echo(f"📡 Import: {working_dir / module_name}:{app_var}.asgi")
162
314
  typer.echo(f"🌐 Server: http://{host}:{port}")
163
315
  typer.echo(f"👥 Workers: {workers}")
@@ -183,23 +335,195 @@ def run(
183
335
 
184
336
  @app.command()
185
337
  def init(
186
- project_name: str = typer.Argument(..., help="Project name"),
187
- template: str = typer.Option(
188
- "basic", "--template", "-t", help="Project template (basic, redis)"
338
+ directory: str = typer.Argument(
339
+ ".", help="Directory to initialize (default: current directory)"
189
340
  ),
190
341
  ):
191
342
  """
192
- Initialize a new Wappa project (coming soon).
343
+ Initialize a new Wappa project.
344
+
345
+ Creates a basic Wappa project structure with:
346
+ - app/ directory with main.py and master_event.py
347
+ - scores/ directory (empty)
348
+ - .gitignore file
349
+ - .env template file
193
350
 
194
351
  Examples:
195
- wappa init my-whatsapp-bot
196
- wappa init my-bot --template redis
352
+ wappa init # Initialize in current directory
353
+ wappa init my-bot # Initialize in ./my-bot/ directory
197
354
  """
198
- typer.echo("🚧 Project initialization coming soon!")
199
- typer.echo(f"Project: {project_name}")
200
- typer.echo(f"Template: {template}")
201
- typer.echo()
202
- typer.echo("For now, check out the examples directory for project templates.")
355
+ _initialize_project(directory)
356
+
357
+
358
+ @app.command()
359
+ def examples(
360
+ directory: str = typer.Argument(
361
+ ".", help="Directory to copy example to (default: current directory)"
362
+ ),
363
+ ):
364
+ """
365
+ Browse and copy Wappa example projects.
366
+
367
+ Interactive menu to select from various example projects:
368
+ - Basic project template
369
+ - Echo bot example
370
+ - JSON cache demo
371
+ - Redis cache demo
372
+ - OpenAI transcription
373
+ - Full-featured bot
374
+
375
+ Examples:
376
+ wappa examples # Show examples menu
377
+ wappa examples my-bot # Copy to ./my-bot/ directory
378
+ """
379
+ _show_examples_menu(directory)
380
+
381
+
382
+ def _show_examples_menu(target_directory: str) -> None:
383
+ """
384
+ Display interactive examples menu and handle selection.
385
+
386
+ Args:
387
+ target_directory: Directory to copy the selected example to
388
+ """
389
+ console.print("\n🚀 [bold blue]Wappa Example Projects[/bold blue]")
390
+ console.print("Choose an example to copy to your project:\n")
391
+
392
+ # Create examples table
393
+ table = Table(show_header=True, header_style="bold cyan")
394
+ table.add_column("#", style="dim", width=3)
395
+ table.add_column("Name", style="bold")
396
+ table.add_column("Description", style="white")
397
+ table.add_column("Complexity", style="green")
398
+ table.add_column("Key Features", style="yellow")
399
+
400
+ example_keys = list(EXAMPLES.keys())
401
+ for i, (key, example) in enumerate(EXAMPLES.items(), 1):
402
+ features_text = ", ".join(example["features"][:3]) # Show first 3 features
403
+ if len(example["features"]) > 3:
404
+ features_text += "..."
405
+
406
+ table.add_row(
407
+ str(i),
408
+ example["name"],
409
+ example["description"],
410
+ example["complexity"],
411
+ features_text,
412
+ )
413
+
414
+ console.print(table)
415
+ console.print("\n")
416
+
417
+ # Get user selection
418
+ while True:
419
+ try:
420
+ choice = typer.prompt("Enter your choice (1-6) or 'q' to quit")
421
+
422
+ if choice.lower() == "q":
423
+ console.print("👋 Goodbye!")
424
+ raise typer.Exit(0)
425
+
426
+ choice_num = int(choice)
427
+ if 1 <= choice_num <= len(example_keys):
428
+ selected_key = example_keys[choice_num - 1]
429
+ selected_example = EXAMPLES[selected_key]
430
+
431
+ console.print(f"\n✨ Selected: [bold]{selected_example['name']}[/bold]")
432
+ console.print(f"📝 Description: {selected_example['description']}")
433
+ console.print(f"🎯 Features: {', '.join(selected_example['features'])}")
434
+ console.print(f"📊 Complexity: {selected_example['complexity']}")
435
+
436
+ if typer.confirm(f"\nCopy this example to '{target_directory}'?"):
437
+ _copy_example(selected_key, target_directory)
438
+ break
439
+ else:
440
+ console.print("Selection cancelled. Choose another example:\n")
441
+ continue
442
+
443
+ else:
444
+ console.print(
445
+ f"❌ Invalid choice. Please enter a number between 1 and {len(example_keys)}"
446
+ )
447
+
448
+ except ValueError:
449
+ console.print("❌ Invalid input. Please enter a number or 'q' to quit")
450
+ except KeyboardInterrupt:
451
+ console.print("\n👋 Goodbye!")
452
+ raise typer.Exit(0)
453
+
454
+
455
+ def _copy_example(example_key: str, target_directory: str) -> None:
456
+ """
457
+ Copy selected example to target directory.
458
+
459
+ Args:
460
+ example_key: Key of the example to copy
461
+ target_directory: Directory to copy to
462
+ """
463
+ examples_dir = Path(__file__).parent / "examples"
464
+ source_path = examples_dir / example_key
465
+ target_path = Path(target_directory).resolve()
466
+
467
+ if not source_path.exists():
468
+ console.print(f"❌ Example '{example_key}' not found in {examples_dir}")
469
+ raise typer.Exit(1)
470
+
471
+ try:
472
+ # Create target directory if it doesn't exist
473
+ if target_directory != "." and not target_path.exists():
474
+ target_path.mkdir(parents=True, exist_ok=True)
475
+ console.print(f"📁 Created directory: {target_path}")
476
+
477
+ # Check if target directory is empty (except for standard files)
478
+ if target_path.exists():
479
+ existing_files = [
480
+ f
481
+ for f in target_path.iterdir()
482
+ if not f.name.startswith(".")
483
+ and f.name not in ["pyproject.toml", "uv.lock", "README.md"]
484
+ ]
485
+
486
+ if existing_files:
487
+ console.print(f"⚠️ Directory {target_path} is not empty:")
488
+ console.print(f" Found: {[f.name for f in existing_files]}")
489
+
490
+ if not typer.confirm("Continue anyway?"):
491
+ console.print("❌ Example copy cancelled")
492
+ raise typer.Exit(0)
493
+
494
+ console.print(f"🚀 Copying {EXAMPLES[example_key]['name']} to {target_path}")
495
+
496
+ # Copy all files from the example
497
+ for item in source_path.iterdir():
498
+ if item.is_file():
499
+ shutil.copy2(item, target_path / item.name)
500
+ console.print(f"📝 Copied: {item.name}")
501
+ elif item.is_dir():
502
+ shutil.copytree(item, target_path / item.name, dirs_exist_ok=True)
503
+ console.print(f"📁 Copied: {item.name}/")
504
+
505
+ console.print("\n✅ Example copied successfully!")
506
+ console.print("\n📋 Next steps:")
507
+ console.print("1. Navigate to the project directory")
508
+ console.print("2. Install dependencies: uv sync")
509
+ console.print("3. Add your WhatsApp credentials to .env file (if not present)")
510
+ console.print("4. Start development: uv run wappa dev app/main.py")
511
+
512
+ # Show example-specific instructions
513
+ if example_key == "redis_cache_example":
514
+ console.print("\n🔧 Redis-specific setup:")
515
+ console.print(" - Install and start Redis server")
516
+ console.print(" - Add REDIS_URL to .env file")
517
+ elif example_key == "openai_transcript":
518
+ console.print("\n🔧 OpenAI-specific setup:")
519
+ console.print(" - Add OPENAI_API_KEY to .env file")
520
+ console.print(" - Ensure audio file handling is configured")
521
+
522
+ console.print("\n📖 Check the README.md for detailed setup instructions")
523
+
524
+ except Exception as e:
525
+ console.print(f"❌ Failed to copy example: {e}")
526
+ raise typer.Exit(1)
203
527
 
204
528
 
205
529
  if __name__ == "__main__":
File without changes
@@ -0,0 +1,37 @@
1
+ # WhatsApp Business API Configuration
2
+
3
+ # General Configuration
4
+ PORT=8000
5
+ TIME_ZONE=America/Bogota
6
+
7
+ # DEBUG or INFO or WARNING or ERROR or CRITICAL
8
+ LOG_LEVEL=INFO
9
+ LOG_DIR=./logs
10
+
11
+ ## Environment DEV or PROD
12
+ ENVIRONMENT=DEV
13
+
14
+ # WhatsApp Graph API
15
+ BASE_URL=https://graph.facebook.com/
16
+ API_VERSION=v23.0
17
+
18
+ # Get these values from your WhatsApp Business API setup
19
+
20
+ # WhatsApp Access Token (required)
21
+ WP_ACCESS_TOKEN=
22
+
23
+ # WhatsApp Phone Number ID (required)
24
+ WP_PHONE_ID=
25
+
26
+ # WhatsApp Business ID (required)
27
+ WP_BID=
28
+
29
+ # Webhook Configuration
30
+ WHATSAPP_WEBHOOK_VERIFY_TOKEN=
31
+
32
+ # Redis Configuration (Optional - uncomment to enable Redis persistence)
33
+ REDIS_URL=redis://localhost:6379/
34
+ REDIS_MAX_CONNECTIONS=64
35
+
36
+ # Optional: AI Tools
37
+ OPENAI_API_KEY=
@@ -0,0 +1,165 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # poetry
98
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102
+ #poetry.lock
103
+
104
+ # pdm
105
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106
+ #pdm.lock
107
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108
+ # in version control.
109
+ # https://pdm.fming.dev/#use-with-ide
110
+ .pdm.toml
111
+
112
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113
+ __pypackages__/
114
+
115
+ # Celery stuff
116
+ celerybeat-schedule
117
+ celerybeat.pid
118
+
119
+ # SageMath parsed files
120
+ *.sage.py
121
+
122
+ # Environments
123
+ .env
124
+ .venv
125
+ env/
126
+ venv/
127
+ ENV/
128
+ env.bak/
129
+ venv.bak/
130
+
131
+ # Spyder project settings
132
+ .spyderproject
133
+ .spyproject
134
+
135
+ # Rope project settings
136
+ .ropeproject
137
+
138
+ # mkdocs documentation
139
+ /site
140
+
141
+ # mypy
142
+ .mypy_cache/
143
+ .dmypy.json
144
+ dmypy.json
145
+
146
+ # Pyre type checker
147
+ .pyre/
148
+
149
+ # pytype static type analyzer
150
+ .pytype/
151
+
152
+ # Cython debug symbols
153
+ cython_debug/
154
+
155
+ # PyCharm
156
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157
+ # be added to the global gitignore or merged into this project gitignore. For a PyCharm
158
+ # project, it is recommended to exclude everything except .idea/modules.xml and
159
+ # .idea/*.iml files. A simple way to do this is with the IDEA_IGNORE=1 environment variable.
160
+ .idea/
161
+
162
+ # Wappa-specific
163
+ logs/
164
+ cache/
165
+ *.log
@@ -0,0 +1,8 @@
1
+ from wappa import Wappa
2
+ from .master_event import MasterEventHandler
3
+
4
+ app = Wappa()
5
+ app.set_event_handler(MasterEventHandler())
6
+
7
+ if __name__ == "__main__":
8
+ app.run()
@@ -0,0 +1,8 @@
1
+ from wappa import WappaEventHandler
2
+ from wappa.webhooks import IncomingMessageWebhook
3
+
4
+ class MasterEventHandler(WappaEventHandler):
5
+
6
+ async def process_message(self, webhook: IncomingMessageWebhook):
7
+ await self.messenger.mark_as_read(webhook.message.message_id, webhook.user.user_id)
8
+ await self.messenger.send_text("Wappa App ready", webhook.user.user_id)