socialseed-e2e 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.
- socialseed_e2e/__init__.py +51 -0
- socialseed_e2e/__version__.py +21 -0
- socialseed_e2e/cli.py +611 -0
- socialseed_e2e/core/__init__.py +35 -0
- socialseed_e2e/core/base_page.py +839 -0
- socialseed_e2e/core/check_deps.py +43 -0
- socialseed_e2e/core/config.py +119 -0
- socialseed_e2e/core/config_loader.py +604 -0
- socialseed_e2e/core/headers.py +20 -0
- socialseed_e2e/core/interfaces.py +22 -0
- socialseed_e2e/core/loaders.py +51 -0
- socialseed_e2e/core/models.py +24 -0
- socialseed_e2e/core/test_orchestrator.py +84 -0
- socialseed_e2e/services/__init__.py +9 -0
- socialseed_e2e/templates/__init__.py +32 -0
- socialseed_e2e/templates/config.py.template +20 -0
- socialseed_e2e/templates/data_schema.py.template +116 -0
- socialseed_e2e/templates/e2e.conf.template +20 -0
- socialseed_e2e/templates/service_page.py.template +83 -0
- socialseed_e2e/templates/test_module.py.template +46 -0
- socialseed_e2e/utils/__init__.py +44 -0
- socialseed_e2e/utils/template_engine.py +246 -0
- socialseed_e2e/utils/validators.py +588 -0
- socialseed_e2e-0.1.0.dist-info/METADATA +333 -0
- socialseed_e2e-0.1.0.dist-info/RECORD +29 -0
- socialseed_e2e-0.1.0.dist-info/WHEEL +5 -0
- socialseed_e2e-0.1.0.dist-info/entry_points.txt +3 -0
- socialseed_e2e-0.1.0.dist-info/licenses/LICENSE +21 -0
- socialseed_e2e-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from typing import Any, Dict, Optional, Protocol, runtime_checkable
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ServiceConfig(BaseModel):
|
|
7
|
+
"""Configuration for a specific service."""
|
|
8
|
+
|
|
9
|
+
name: str
|
|
10
|
+
base_url: str
|
|
11
|
+
default_headers: Dict[str, str] = Field(default_factory=dict)
|
|
12
|
+
timeout: int = 30000
|
|
13
|
+
extra: Dict[str, Any] = Field(default_factory=dict)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TestContext(BaseModel):
|
|
17
|
+
"""Generic context for test execution."""
|
|
18
|
+
|
|
19
|
+
env: str = "dev"
|
|
20
|
+
services: Dict[str, ServiceConfig] = Field(default_factory=dict)
|
|
21
|
+
metadata: Dict[str, Any] = Field(default_factory=dict)
|
|
22
|
+
|
|
23
|
+
def get_service(self, name: str) -> Optional[ServiceConfig]:
|
|
24
|
+
return self.services.get(name)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import importlib.util
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
import pytest
|
|
9
|
+
except ImportError:
|
|
10
|
+
pytest = None
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
from socialseed_e2e.core.loaders import ModuleLoader
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TestOrchestrator:
|
|
17
|
+
"""
|
|
18
|
+
Orchestrates dynamic loading and execution of test modules.
|
|
19
|
+
Auto-discovers modules in services/*/modules/ and runs them.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(
|
|
23
|
+
self, root_dir: Optional[str] = None, services_path: str = "verify_services/e2e/services"
|
|
24
|
+
):
|
|
25
|
+
# Default to the directory containing the 'verify_services' folder or current working directory
|
|
26
|
+
self.root_dir = Path(root_dir) if root_dir else Path(os.getcwd())
|
|
27
|
+
self.services_dir = self.root_dir / services_path
|
|
28
|
+
self.loader = ModuleLoader()
|
|
29
|
+
self.modules: Dict[str, List[Callable]] = {}
|
|
30
|
+
|
|
31
|
+
def discover_modules(self):
|
|
32
|
+
"""Discover all test modules in services directories using dynamic file loading."""
|
|
33
|
+
if not self.services_dir.exists():
|
|
34
|
+
print(f"Warning: Services directory not found at {self.services_dir}")
|
|
35
|
+
return
|
|
36
|
+
|
|
37
|
+
for service_dir in self.services_dir.iterdir():
|
|
38
|
+
if service_dir.is_dir():
|
|
39
|
+
modules_dir = service_dir / "modules"
|
|
40
|
+
if modules_dir.exists():
|
|
41
|
+
service_name = service_dir.name
|
|
42
|
+
self.modules[service_name] = self.loader.discover_runnables(modules_dir)
|
|
43
|
+
|
|
44
|
+
def run_service_tests(self, service_name: str, context: Any):
|
|
45
|
+
"""Run all modules for a specific service."""
|
|
46
|
+
if service_name not in self.modules:
|
|
47
|
+
raise ValueError(
|
|
48
|
+
f"Service {service_name} not found or has no modules discovered at {self.services_dir}"
|
|
49
|
+
)
|
|
50
|
+
for run_func in self.modules[service_name]:
|
|
51
|
+
run_func(context)
|
|
52
|
+
|
|
53
|
+
def run_all_tests(self, context_factory: Callable[[], Any]):
|
|
54
|
+
"""Run all discovered tests with a context factory."""
|
|
55
|
+
for service_name, modules in self.modules.items():
|
|
56
|
+
context = context_factory()
|
|
57
|
+
try:
|
|
58
|
+
for run_func in modules:
|
|
59
|
+
run_func(context)
|
|
60
|
+
print(f"✓ {service_name} tests passed")
|
|
61
|
+
except Exception as e:
|
|
62
|
+
print(f"✗ {service_name} tests failed: {e}")
|
|
63
|
+
raise
|
|
64
|
+
finally:
|
|
65
|
+
if hasattr(context, "teardown"):
|
|
66
|
+
context.teardown()
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# Pytest integration
|
|
70
|
+
def pytest_configure(config):
|
|
71
|
+
"""Hook to set up orchestrator for pytest."""
|
|
72
|
+
if pytest:
|
|
73
|
+
# Configuration can be passed via environment variables
|
|
74
|
+
root = os.getenv("E2E_ROOT_DIR")
|
|
75
|
+
spath = os.getenv("E2E_SERVICES_PATH", "verify_services/e2e/services")
|
|
76
|
+
config.orchestrator = TestOrchestrator(root_dir=root, services_path=spath)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def pytest_collection_modifyitems(config, items):
|
|
80
|
+
"""Modify test collection to include dynamic modules."""
|
|
81
|
+
if pytest:
|
|
82
|
+
orchestrator = getattr(config, "orchestrator", None)
|
|
83
|
+
if orchestrator:
|
|
84
|
+
orchestrator.discover_modules()
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# E2E Testing Framework - Services
|
|
2
|
+
# ==================================
|
|
3
|
+
#
|
|
4
|
+
# This package contains service-specific test implementations.
|
|
5
|
+
# Each service has its own directory with:
|
|
6
|
+
# - config.py: Service configuration
|
|
7
|
+
# - data_schema.py: Pydantic models
|
|
8
|
+
# - {service}_page.py: Page object
|
|
9
|
+
# - modules/: Test modules
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Templates for code scaffolding.
|
|
2
|
+
|
|
3
|
+
This package contains template files used by the TemplateEngine
|
|
4
|
+
to generate code files and project scaffolding.
|
|
5
|
+
|
|
6
|
+
Available Templates:
|
|
7
|
+
- e2e.conf.template: Default configuration file
|
|
8
|
+
- service_page.py.template: Service page class
|
|
9
|
+
- test_module.py.template: Test module structure
|
|
10
|
+
- data_schema.py.template: Data transfer objects
|
|
11
|
+
- config.py.template: Service configuration loader
|
|
12
|
+
|
|
13
|
+
Usage:
|
|
14
|
+
Templates are loaded and rendered by the TemplateEngine class
|
|
15
|
+
in socialseed_e2e.utils.template_engine.
|
|
16
|
+
|
|
17
|
+
Example:
|
|
18
|
+
from socialseed_e2e.utils import TemplateEngine
|
|
19
|
+
|
|
20
|
+
engine = TemplateEngine()
|
|
21
|
+
content = engine.render('service_page.py', {
|
|
22
|
+
'service_name': 'users-api',
|
|
23
|
+
'class_name': 'UsersApi'
|
|
24
|
+
})
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
|
|
29
|
+
# Get the templates directory
|
|
30
|
+
TEMPLATES_DIR = Path(__file__).parent
|
|
31
|
+
|
|
32
|
+
__all__ = ["TEMPLATES_DIR"]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Configuration loader for ${service_name}.
|
|
2
|
+
|
|
3
|
+
This module provides configuration loading specific to the ${service_name} service.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from socialseed_e2e.core.config_loader import ApiConfigLoader, ServiceConfig
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_${snake_case_name}_config() -> ServiceConfig:
|
|
10
|
+
"""Get configuration for ${service_name} service.
|
|
11
|
+
|
|
12
|
+
Returns:
|
|
13
|
+
ServiceConfig: Configuration object for the service
|
|
14
|
+
|
|
15
|
+
Raises:
|
|
16
|
+
ConfigError: If configuration cannot be loaded
|
|
17
|
+
"""
|
|
18
|
+
loader = ApiConfigLoader()
|
|
19
|
+
config = loader.load()
|
|
20
|
+
return config.services["${service_name}"]
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""Data schema and DTOs for ${service_name}.
|
|
2
|
+
|
|
3
|
+
This module defines data transfer objects, validators, and constants
|
|
4
|
+
for the ${service_name} service.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Optional, List
|
|
8
|
+
from pydantic import BaseModel, Field, validator
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ${class_name}DTO(BaseModel):
|
|
12
|
+
"""Data Transfer Object for ${service_name} entities.
|
|
13
|
+
|
|
14
|
+
Attributes:
|
|
15
|
+
id: Unique identifier
|
|
16
|
+
name: Entity name
|
|
17
|
+
description: Entity description
|
|
18
|
+
created_at: Creation timestamp
|
|
19
|
+
updated_at: Last update timestamp
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
id: Optional[str] = Field(None, description="Unique identifier")
|
|
23
|
+
name: str = Field(..., description="Entity name", min_length=1, max_length=100)
|
|
24
|
+
description: Optional[str] = Field(None, description="Entity description", max_length=500)
|
|
25
|
+
created_at: Optional[str] = Field(None, description="Creation timestamp (ISO format)")
|
|
26
|
+
updated_at: Optional[str] = Field(None, description="Last update timestamp (ISO format)")
|
|
27
|
+
|
|
28
|
+
@validator('name')
|
|
29
|
+
def name_must_not_be_empty(cls, v):
|
|
30
|
+
"""Validate that name is not empty or whitespace."""
|
|
31
|
+
if not v or not v.strip():
|
|
32
|
+
raise ValueError('Name cannot be empty')
|
|
33
|
+
return v.strip()
|
|
34
|
+
|
|
35
|
+
class Config:
|
|
36
|
+
"""Pydantic configuration."""
|
|
37
|
+
json_schema_extra = {
|
|
38
|
+
"example": {
|
|
39
|
+
"id": "123e4567-e89b-12d3-a456-426614174000",
|
|
40
|
+
"name": "Example Entity",
|
|
41
|
+
"description": "This is an example entity",
|
|
42
|
+
"created_at": "2025-01-31T12:00:00Z",
|
|
43
|
+
"updated_at": "2025-01-31T12:00:00Z"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class ${class_name}CreateDTO(BaseModel):
|
|
49
|
+
"""DTO for creating new ${service_name} entities.
|
|
50
|
+
|
|
51
|
+
Attributes:
|
|
52
|
+
name: Entity name (required)
|
|
53
|
+
description: Entity description (optional)
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
name: str = Field(..., description="Entity name", min_length=1, max_length=100)
|
|
57
|
+
description: Optional[str] = Field(None, description="Entity description", max_length=500)
|
|
58
|
+
|
|
59
|
+
@validator('name')
|
|
60
|
+
def name_must_not_be_empty(cls, v):
|
|
61
|
+
"""Validate that name is not empty or whitespace."""
|
|
62
|
+
if not v or not v.strip():
|
|
63
|
+
raise ValueError('Name cannot be empty')
|
|
64
|
+
return v.strip()
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class ${class_name}UpdateDTO(BaseModel):
|
|
68
|
+
"""DTO for updating existing ${service_name} entities.
|
|
69
|
+
|
|
70
|
+
Attributes:
|
|
71
|
+
name: Entity name (optional)
|
|
72
|
+
description: Entity description (optional)
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
name: Optional[str] = Field(None, description="Entity name", min_length=1, max_length=100)
|
|
76
|
+
description: Optional[str] = Field(None, description="Entity description", max_length=500)
|
|
77
|
+
|
|
78
|
+
@validator('name')
|
|
79
|
+
def name_must_not_be_empty_if_provided(cls, v):
|
|
80
|
+
"""Validate that name is not empty if provided."""
|
|
81
|
+
if v is not None and not v.strip():
|
|
82
|
+
raise ValueError('Name cannot be empty')
|
|
83
|
+
return v.strip() if v else v
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class ${class_name}ListResponse(BaseModel):
|
|
87
|
+
"""DTO for paginated list response.
|
|
88
|
+
|
|
89
|
+
Attributes:
|
|
90
|
+
items: List of entities
|
|
91
|
+
total: Total number of entities
|
|
92
|
+
page: Current page number
|
|
93
|
+
page_size: Number of items per page
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
items: List[${class_name}DTO] = Field(default_factory=list)
|
|
97
|
+
total: int = Field(0, ge=0)
|
|
98
|
+
page: int = Field(1, ge=1)
|
|
99
|
+
page_size: int = Field(10, ge=1, le=100)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# Constants for ${service_name} service
|
|
103
|
+
${constants}
|
|
104
|
+
|
|
105
|
+
# Validation patterns
|
|
106
|
+
VALIDATION_PATTERNS = {
|
|
107
|
+
"uuid": r'^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$',
|
|
108
|
+
"iso_timestamp": r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})?$',
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# Default values
|
|
112
|
+
DEFAULTS = {
|
|
113
|
+
"page_size": 10,
|
|
114
|
+
"timeout": 5000,
|
|
115
|
+
"max_retries": 3,
|
|
116
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Configuración E2E para socialseed-e2e
|
|
2
|
+
# Documentación: https://github.com/daironpf/socialseed-e2e
|
|
3
|
+
|
|
4
|
+
general:
|
|
5
|
+
# Entorno de ejecución (dev, staging, production)
|
|
6
|
+
environment: ${environment}
|
|
7
|
+
|
|
8
|
+
# Timeout global para requests en milisegundos
|
|
9
|
+
timeout: ${timeout}
|
|
10
|
+
|
|
11
|
+
# User agent para requests HTTP
|
|
12
|
+
user_agent: "${user_agent}"
|
|
13
|
+
|
|
14
|
+
# Modo verbose para debugging
|
|
15
|
+
verbose: ${verbose}
|
|
16
|
+
|
|
17
|
+
# Configuración de servicios
|
|
18
|
+
# Define cada servicio a testear
|
|
19
|
+
services:
|
|
20
|
+
${services_config}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""Página de servicio para ${service_name}.
|
|
2
|
+
|
|
3
|
+
Este módulo define la clase de página para interactuar con el servicio ${service_name}.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Optional
|
|
7
|
+
from playwright.sync_api import APIResponse
|
|
8
|
+
|
|
9
|
+
from socialseed_e2e.core.base_page import BasePage
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ${class_name}Page(BasePage):
|
|
13
|
+
"""Página de servicio para ${service_name}.
|
|
14
|
+
|
|
15
|
+
Gestiona el estado compartido entre módulos de test.
|
|
16
|
+
|
|
17
|
+
Attributes:
|
|
18
|
+
current_entity: Entidad actualmente seleccionada
|
|
19
|
+
auth_token: Token de autenticación
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, playwright=None, base_url: Optional[str] = None):
|
|
23
|
+
"""Inicializa la página de servicio.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
playwright: Instancia de Playwright
|
|
27
|
+
base_url: URL base del servicio (opcional)
|
|
28
|
+
"""
|
|
29
|
+
# Cargar configuración desde e2e.conf
|
|
30
|
+
from .config import get_${snake_case_name}_config
|
|
31
|
+
config = get_${snake_case_name}_config()
|
|
32
|
+
|
|
33
|
+
url = base_url or config.base_url
|
|
34
|
+
super().__init__(url, playwright, default_headers=config.default_headers)
|
|
35
|
+
|
|
36
|
+
# Estado compartido entre módulos
|
|
37
|
+
self.current_entity: Optional[dict] = None
|
|
38
|
+
self.auth_token: Optional[str] = None
|
|
39
|
+
|
|
40
|
+
def get_entity(self, entity_id: str) -> APIResponse:
|
|
41
|
+
"""Obtener entidad por ID.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
entity_id: ID de la entidad
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
APIResponse: Respuesta HTTP
|
|
48
|
+
"""
|
|
49
|
+
return self.get(f"/${endpoint_prefix}/{entity_id}")
|
|
50
|
+
|
|
51
|
+
def create_entity(self, data: dict) -> APIResponse:
|
|
52
|
+
"""Crear nueva entidad.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
data: Datos de la entidad a crear
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
APIResponse: Respuesta HTTP
|
|
59
|
+
"""
|
|
60
|
+
return self.post("/${endpoint_prefix}", json=data)
|
|
61
|
+
|
|
62
|
+
def update_entity(self, entity_id: str, data: dict) -> APIResponse:
|
|
63
|
+
"""Actualizar entidad existente.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
entity_id: ID de la entidad
|
|
67
|
+
data: Datos a actualizar
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
APIResponse: Respuesta HTTP
|
|
71
|
+
"""
|
|
72
|
+
return self.put(f"/${endpoint_prefix}/{entity_id}", json=data)
|
|
73
|
+
|
|
74
|
+
def delete_entity(self, entity_id: str) -> APIResponse:
|
|
75
|
+
"""Eliminar entidad.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
entity_id: ID de la entidad
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
APIResponse: Respuesta HTTP
|
|
82
|
+
"""
|
|
83
|
+
return self.delete(f"/${endpoint_prefix}/{entity_id}")
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Test module for ${test_name} flow.
|
|
2
|
+
|
|
3
|
+
This module implements the test flow for ${test_description}.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from playwright.sync_api import APIResponse
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from ..${snake_case_service}_page import ${class_name}Page
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def run(${snake_case_service}: '${class_name}Page') -> APIResponse:
|
|
14
|
+
"""Execute ${test_name} test flow.
|
|
15
|
+
|
|
16
|
+
This test validates the ${test_description} functionality.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
${snake_case_service}: Instance of ${class_name}Page
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
APIResponse: HTTP response from the API
|
|
23
|
+
|
|
24
|
+
Raises:
|
|
25
|
+
AssertionError: If test assertions fail
|
|
26
|
+
"""
|
|
27
|
+
print(f"Running ${test_name} test...")
|
|
28
|
+
|
|
29
|
+
# Arrange: Setup test data and preconditions
|
|
30
|
+
# TODO: Add test data setup here
|
|
31
|
+
|
|
32
|
+
# Act: Execute the operation being tested
|
|
33
|
+
# TODO: Add API call here
|
|
34
|
+
# response = ${snake_case_service}.get("/${endpoint}")
|
|
35
|
+
|
|
36
|
+
# Assert: Verify the results
|
|
37
|
+
# TODO: Add assertions here
|
|
38
|
+
# assert response.ok, f"Expected success, got {response.status}"
|
|
39
|
+
# data = response.json()
|
|
40
|
+
# assert "expected_field" in data
|
|
41
|
+
|
|
42
|
+
# Store state for subsequent tests (optional)
|
|
43
|
+
# ${snake_case_service}.current_entity = data
|
|
44
|
+
|
|
45
|
+
print(f"✓ ${test_name} test completed successfully")
|
|
46
|
+
return response
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Utility functions for socialseed-e2e."""
|
|
2
|
+
|
|
3
|
+
from .template_engine import TemplateEngine, to_camel_case, to_class_name, to_snake_case
|
|
4
|
+
from .validators import (
|
|
5
|
+
ValidationError,
|
|
6
|
+
validate_base_url,
|
|
7
|
+
validate_dict,
|
|
8
|
+
validate_email,
|
|
9
|
+
validate_integer,
|
|
10
|
+
validate_json_response,
|
|
11
|
+
validate_list,
|
|
12
|
+
validate_pagination_response,
|
|
13
|
+
validate_port,
|
|
14
|
+
validate_service_name,
|
|
15
|
+
validate_status_code,
|
|
16
|
+
validate_string,
|
|
17
|
+
validate_timeout,
|
|
18
|
+
validate_url,
|
|
19
|
+
validate_uuid,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
# Template engine
|
|
24
|
+
"TemplateEngine",
|
|
25
|
+
"to_class_name",
|
|
26
|
+
"to_snake_case",
|
|
27
|
+
"to_camel_case",
|
|
28
|
+
# Validators
|
|
29
|
+
"ValidationError",
|
|
30
|
+
"validate_url",
|
|
31
|
+
"validate_base_url",
|
|
32
|
+
"validate_port",
|
|
33
|
+
"validate_timeout",
|
|
34
|
+
"validate_service_name",
|
|
35
|
+
"validate_string",
|
|
36
|
+
"validate_integer",
|
|
37
|
+
"validate_email",
|
|
38
|
+
"validate_uuid",
|
|
39
|
+
"validate_status_code",
|
|
40
|
+
"validate_json_response",
|
|
41
|
+
"validate_pagination_response",
|
|
42
|
+
"validate_list",
|
|
43
|
+
"validate_dict",
|
|
44
|
+
]
|