stackmate 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.
stackmate/__init__.py ADDED
@@ -0,0 +1,24 @@
1
+ """
2
+ StackMate: A Full-Stack Development Toolkit for Python.
3
+ """
4
+
5
+ __version__ = "0.1.0"
6
+ __author__ = "Sudhakar K"
7
+
8
+ from stackmate.auth import AuthManager
9
+ from stackmate.db_helper import DBHelper
10
+ from stackmate.error_handler import APIResponse, ErrorCode
11
+ from stackmate.logger import AppLogger
12
+ from stackmate.utils import generate_uuid, get_timestamp
13
+ from stackmate.validator import PayloadValidator
14
+
15
+ __all__ = [
16
+ "AuthManager",
17
+ "DBHelper",
18
+ "APIResponse",
19
+ "ErrorCode",
20
+ "AppLogger",
21
+ "generate_uuid",
22
+ "get_timestamp",
23
+ "PayloadValidator",
24
+ ]
stackmate/auth.py ADDED
@@ -0,0 +1,82 @@
1
+ """
2
+ JWT and token management utilities for StackMate.
3
+ """
4
+
5
+ from datetime import datetime, timedelta, timezone
6
+ from typing import Any, Dict, Optional, Union
7
+
8
+ import jwt
9
+
10
+
11
+ class AuthManager:
12
+ """
13
+ Manager for creating and verifying JWT tokens.
14
+ """
15
+
16
+ def __init__(
17
+ self,
18
+ secret_key: str,
19
+ algorithm: str = "HS256",
20
+ expires_delta: int = 60,
21
+ ):
22
+ """
23
+ Initializes the Auth Manager.
24
+
25
+ Args:
26
+ secret_key (str): Secret key for encoding/decoding.
27
+ algorithm (str): JWT algorithm. Defaults to HS256.
28
+ expires_delta (int): Expiry time in minutes. Defaults to 60.
29
+ """
30
+ self.secret_key = secret_key
31
+ self.algorithm = algorithm
32
+ self.expires_delta = expires_delta
33
+
34
+ def create_token(self, data: Dict[str, Any]) -> str:
35
+ """
36
+ Creates a JWT token.
37
+
38
+ Args:
39
+ data (Dict): The payload to include.
40
+
41
+ Returns:
42
+ str: Encoded JWT token.
43
+ """
44
+ to_encode = data.copy()
45
+ expire = datetime.now(timezone.utc) + timedelta(minutes=self.expires_delta)
46
+ to_encode.update({"exp": expire})
47
+ return jwt.encode(to_encode, self.secret_key, algorithm=self.algorithm)
48
+
49
+ def verify_token(self, token: str) -> Optional[Dict[str, Any]]:
50
+ """
51
+ Verifies and decodes a JWT token.
52
+
53
+ Args:
54
+ token (str): The JWT string.
55
+
56
+ Returns:
57
+ Optional[Dict]: The decoded payload if valid, None otherwise.
58
+ """
59
+ try:
60
+ return jwt.decode(token, self.secret_key, algorithms=[self.algorithm])
61
+ except (jwt.ExpiredSignatureError, jwt.InvalidTokenError):
62
+ return None
63
+
64
+ def decode_token(self, token: str) -> Optional[Dict[str, Any]]:
65
+ """
66
+ Decodes a token without verifying expiry (for debug/extraction).
67
+
68
+ Args:
69
+ token (str): The JWT string.
70
+
71
+ Returns:
72
+ Optional[Dict]: The decoded payload.
73
+ """
74
+ try:
75
+ return jwt.decode(
76
+ token,
77
+ self.secret_key,
78
+ algorithms=[self.algorithm],
79
+ options={"verify_exp": False},
80
+ )
81
+ except Exception:
82
+ return None
stackmate/db_helper.py ADDED
@@ -0,0 +1,94 @@
1
+ """
2
+ Database utility helpers for StackMate.
3
+ Simulates a generic CRUD interface.
4
+ """
5
+
6
+ from typing import Any, Dict, List, Optional, Union
7
+
8
+
9
+ class DBHelper:
10
+ """
11
+ Generic Database Helper for CRUD operations.
12
+ Acts as an abstraction layer (Mocked for demonstration).
13
+ """
14
+
15
+ def __init__(self, connection_string: str = "mock://localhost"):
16
+ """
17
+ Initializes the DB helper.
18
+
19
+ Args:
20
+ connection_string (str): Database connection URI.
21
+ """
22
+ self.connection_string = connection_string
23
+ # In a real app, you'd initialize a pool or client here
24
+ self._mock_db: List[Dict[str, Any]] = []
25
+
26
+ def create(self, table: str, data: Dict[str, Any]) -> Dict[str, Any]:
27
+ """
28
+ Inserts a new record into the "table".
29
+
30
+ Args:
31
+ table (str): Target table/collection name.
32
+ data (Dict): Record content.
33
+
34
+ Returns:
35
+ Dict: The created record.
36
+ """
37
+ # Mock implementation
38
+ record = {"id": len(self._mock_db) + 1, "table": table, **data}
39
+ self._mock_db.append(record)
40
+ return record
41
+
42
+ def read(self, table: str, filters: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
43
+ """
44
+ Retrieves records from the "table" based on filters.
45
+
46
+ Args:
47
+ table (str): Target table name.
48
+ filters (Dict): Query filters.
49
+
50
+ Returns:
51
+ List[Dict]: List of matching records.
52
+ """
53
+ results = [r for r in self._mock_db if r["table"] == table]
54
+ if filters:
55
+ for key, value in filters.items():
56
+ results = [r for r in results if r.get(key) == value]
57
+ return results
58
+
59
+ def update(
60
+ self, table: str, record_id: int, updates: Dict[str, Any]
61
+ ) -> Optional[Dict[str, Any]]:
62
+ """
63
+ Updates an existing record.
64
+
65
+ Args:
66
+ table (str): Target table name.
67
+ record_id (int): ID of the record to update.
68
+ updates (Dict): Field-value updates.
69
+
70
+ Returns:
71
+ Optional[Dict]: The updated record if found.
72
+ """
73
+ for record in self._mock_db:
74
+ if record["table"] == table and record["id"] == record_id:
75
+ record.update(updates)
76
+ return record
77
+ return None
78
+
79
+ def delete(self, table: str, record_id: int) -> bool:
80
+ """
81
+ Deletes a record.
82
+
83
+ Args:
84
+ table (str): Target table name.
85
+ record_id (int): ID of the record.
86
+
87
+ Returns:
88
+ bool: True if deleted, False if not found.
89
+ """
90
+ for i, record in enumerate(self._mock_db):
91
+ if record["table"] == table and record["id"] == record_id:
92
+ del self._mock_db[i]
93
+ return True
94
+ return False
@@ -0,0 +1,73 @@
1
+ """
2
+ Unified error handling and structured API responses for StackMate.
3
+ """
4
+
5
+ from enum import Enum
6
+ from typing import Any, Dict, Optional, Union
7
+
8
+
9
+ class ErrorCode(str, Enum):
10
+ """Enumeration of standard error codes."""
11
+
12
+ SUCCESS = "SUCCESS"
13
+ VALIDATION_ERROR = "VALIDATION_ERROR"
14
+ AUTHENTICATION_ERROR = "AUTHENTICATION_ERROR"
15
+ NOT_FOUND = "NOT_FOUND"
16
+ DATABASE_ERROR = "DATABASE_ERROR"
17
+ INTERNAL_SERVER_ERROR = "INTERNAL_SERVER_ERROR"
18
+
19
+
20
+ class APIResponse:
21
+ """Class to handle structured API responses."""
22
+
23
+ @staticmethod
24
+ def success(
25
+ data: Any = None,
26
+ message: str = "Operation successful",
27
+ status_code: int = 200,
28
+ ) -> Dict[str, Any]:
29
+ """
30
+ Generates a successful API response.
31
+
32
+ Args:
33
+ data (Any): The payload to return.
34
+ message (str): A message for the user.
35
+ status_code (int): HTTP status code.
36
+
37
+ Returns:
38
+ Dict[str, Any]: Structured success response.
39
+ """
40
+ return {
41
+ "success": True,
42
+ "message": message,
43
+ "data": data,
44
+ "error_code": ErrorCode.SUCCESS,
45
+ "status_code": status_code,
46
+ }
47
+
48
+ @staticmethod
49
+ def failure(
50
+ message: str,
51
+ error_code: ErrorCode = ErrorCode.INTERNAL_SERVER_ERROR,
52
+ data: Any = None,
53
+ status_code: int = 500,
54
+ ) -> Dict[str, Any]:
55
+ """
56
+ Generates a failed API response.
57
+
58
+ Args:
59
+ message (str): Error message.
60
+ error_code (ErrorCode): Standardized error code.
61
+ data (Any): Optional additional error context.
62
+ status_code (int): HTTP status code.
63
+
64
+ Returns:
65
+ Dict[str, Any]: Structured failure response.
66
+ """
67
+ return {
68
+ "success": False,
69
+ "message": message,
70
+ "data": data,
71
+ "error_code": error_code,
72
+ "status_code": status_code,
73
+ }
stackmate/logger.py ADDED
@@ -0,0 +1,96 @@
1
+ """
2
+ Request/Response logging utilities for StackMate.
3
+ """
4
+
5
+ import json
6
+ import logging
7
+ import time
8
+ from typing import Any, Dict, Optional
9
+
10
+ from stackmate.utils import get_timestamp, parse_latency
11
+
12
+
13
+ class AppLogger:
14
+ """
15
+ Standard logger for API requests and responses.
16
+ """
17
+
18
+ def __init__(self, name: str = "StackMate", level: int = logging.INFO):
19
+ """
20
+ Initializes the logger.
21
+
22
+ Args:
23
+ name (str): Name of the logger.
24
+ level (int): Logging level.
25
+ """
26
+ self.logger = logging.getLogger(name)
27
+ handler = logging.StreamHandler()
28
+ formatter = logging.Formatter(
29
+ "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
30
+ )
31
+ handler.setFormatter(formatter)
32
+ if not self.logger.handlers:
33
+ self.logger.addHandler(handler)
34
+ self.logger.setLevel(level)
35
+
36
+ def log_request(self, method: str, url: str, payload: Optional[Dict[str, Any]] = None) -> float:
37
+ """
38
+ Logs an incoming API request.
39
+
40
+ Args:
41
+ method (str): HTTP method (GET, POST, etc.).
42
+ url (str): Target URL.
43
+ payload (Dict): Request body.
44
+
45
+ Returns:
46
+ float: The start time of the request.
47
+ """
48
+ start_time = time.time()
49
+ log_data = {
50
+ "timestamp": get_timestamp(),
51
+ "type": "REQUEST",
52
+ "method": method,
53
+ "url": url,
54
+ "payload": payload,
55
+ }
56
+ self.logger.info("Request: %s", json.dumps(log_data))
57
+ return start_time
58
+
59
+ def log_response(
60
+ self,
61
+ method: str,
62
+ url: str,
63
+ status_code: int,
64
+ start_time: float,
65
+ response_data: Optional[Any] = None,
66
+ ) -> None:
67
+ """
68
+ Logs an API response with latency calculation.
69
+
70
+ Args:
71
+ method (str): HTTP method.
72
+ url (str): Target URL.
73
+ status_code (int): HTTP status code.
74
+ start_time (float): The timestamp when the request started.
75
+ response_data (Any): The response content.
76
+ """
77
+ end_time = time.time()
78
+ latency = parse_latency(start_time, end_time)
79
+ log_data = {
80
+ "timestamp": get_timestamp(),
81
+ "type": "RESPONSE",
82
+ "method": method,
83
+ "url": url,
84
+ "status": status_code,
85
+ "latency": latency,
86
+ "data": response_data,
87
+ }
88
+ self.logger.info("Response: %s", json.dumps(log_data))
89
+
90
+ def error(self, message: str, exc_info: bool = True) -> None:
91
+ """Logs an error message."""
92
+ self.logger.error(message, exc_info=exc_info)
93
+
94
+ def info(self, message: str) -> None:
95
+ """Logs an info message."""
96
+ self.logger.info(message)
stackmate/utils.py ADDED
@@ -0,0 +1,62 @@
1
+ """
2
+ Miscellaneous helper functions for StackMate.
3
+ """
4
+
5
+ import uuid
6
+ from datetime import datetime, timezone
7
+ from typing import Any, Dict, Optional
8
+
9
+
10
+ def generate_uuid() -> str:
11
+ """
12
+ Generates a unique UUID v4 string.
13
+
14
+ Returns:
15
+ str: A unique UUID.
16
+ """
17
+ return str(uuid.uuid4())
18
+
19
+
20
+ def get_timestamp(utc: bool = True) -> str:
21
+ """
22
+ Returns the current timestamp in ISO format.
23
+
24
+ Args:
25
+ utc (bool): Whether to use UTC time. Defaults to True.
26
+
27
+ Returns:
28
+ str: ISO formatted timestamp.
29
+ """
30
+ if utc:
31
+ return datetime.now(timezone.utc).isoformat()
32
+ return datetime.now().isoformat()
33
+
34
+
35
+ def format_response_data(data: Any) -> Dict[str, Any]:
36
+ """
37
+ Helper to ensure data is in a dictionary format for JSON responses.
38
+
39
+ Args:
40
+ data (Any): Input data.
41
+
42
+ Returns:
43
+ Dict[str, Any]: Formatted data.
44
+ """
45
+ if isinstance(data, dict):
46
+ return data
47
+ return {"result": data}
48
+
49
+
50
+ def parse_latency(start_time: float, end_time: float) -> str:
51
+ """
52
+ Calculates latency and returns it as a formatted string.
53
+
54
+ Args:
55
+ start_time (float): Execution start time.
56
+ end_time (float): Execution end time.
57
+
58
+ Returns:
59
+ str: Latency in milliseconds (e.g., "120ms").
60
+ """
61
+ duration = (end_time - start_time) * 1000
62
+ return f"{duration:.2f}ms"
stackmate/validator.py ADDED
@@ -0,0 +1,66 @@
1
+ """
2
+ API payload validation utilities for StackMate.
3
+ """
4
+
5
+ from typing import Any, Dict, List, Optional, Type, Union
6
+
7
+
8
+ class PayloadValidator:
9
+ """
10
+ Validates API request payloads against required fields and types.
11
+ """
12
+
13
+ @staticmethod
14
+ def validate(
15
+ payload: Dict[str, Any],
16
+ schema: Dict[str, Type],
17
+ required_fields: Optional[List[str]] = None,
18
+ ) -> List[str]:
19
+ """
20
+ Validates the payload against a schema.
21
+
22
+ Args:
23
+ payload (Dict): The data to validate.
24
+ schema (Dict): A mapping of field names to expected types.
25
+ required_fields (List): A list of fields that must be present.
26
+
27
+ Returns:
28
+ List[str]: A list of error messages. Empty if valid.
29
+ """
30
+ errors = []
31
+ required = required_fields or []
32
+
33
+ # Check for missing required fields
34
+ for field in required:
35
+ if field not in payload:
36
+ errors.append(f"Field '{field}' is required.")
37
+
38
+ # Check types for present fields
39
+ for field, value in payload.items():
40
+ if field in schema:
41
+ expected_type = schema[field]
42
+ if not isinstance(value, expected_type):
43
+ errors.append(
44
+ f"Field '{field}' must be of type {expected_type.__name__}, "
45
+ f"got {type(value).__name__}."
46
+ )
47
+ elif field not in schema and required_fields is not None:
48
+ # Optionally handle unexpected fields if schema is strict
49
+ # For now, we allow them unless we want strict validation
50
+ pass
51
+
52
+ return errors
53
+
54
+ @staticmethod
55
+ def is_valid(
56
+ payload: Dict[str, Any],
57
+ schema: Dict[str, Type],
58
+ required_fields: Optional[List[str]] = None,
59
+ ) -> bool:
60
+ """
61
+ Shortcut to check if a payload is valid.
62
+
63
+ Returns:
64
+ bool: True if valid, False otherwise.
65
+ """
66
+ return len(PayloadValidator.validate(payload, schema, required_fields)) == 0
@@ -0,0 +1,74 @@
1
+ Metadata-Version: 2.4
2
+ Name: stackmate
3
+ Version: 0.1.0
4
+ Summary: A Full-Stack Development Toolkit for Python developers.
5
+ Author-email: Sudhakar K <sudhakark4227@gmail.com>
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Operating System :: OS Independent
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
11
+ Requires-Python: >=3.8
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: PyJWT>=2.8.0
15
+ Requires-Dist: pydantic>=2.0.0
16
+ Provides-Extra: dev
17
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
18
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
19
+ Requires-Dist: black>=23.0.0; extra == "dev"
20
+ Requires-Dist: isort>=5.12.0; extra == "dev"
21
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
22
+ Dynamic: license-file
23
+
24
+ # StackMate
25
+
26
+ **StackMate** is a production-ready Full-Stack Development Toolkit for Python developers. It provides essential utilities for building robust APIs, managing authentication, handling errors, and simplifying database operations.
27
+
28
+ ## Features
29
+
30
+ - **Logger**: Structured request/response logging with latency tracking.
31
+ - **Validator**: API payload validation using type hints and schema checks.
32
+ - **DB Helper**: Generic CRUD utilities for SQL/NoSQL databases.
33
+ - **Auth**: Secure JWT token management (creation and verification).
34
+ - **Error Handler**: Standardized API response formatting.
35
+ - **Utils**: Common helper functions (UUIDs, timestamps, etc.).
36
+
37
+ ## Installation
38
+
39
+ ```bash
40
+ pip install stackmate
41
+ ```
42
+
43
+ ## Quick Start
44
+
45
+ ```python
46
+ from stackmate.logger import AppLogger
47
+ from stackmate.auth import AuthManager
48
+
49
+ # Initialize components
50
+ logger = AppLogger("my-app")
51
+ auth = AuthManager(secret_key="your-secret-key")
52
+
53
+ # Use them in your application
54
+ token = auth.create_token({"user_id": 123})
55
+ ```
56
+
57
+ ## Project Structure
58
+
59
+ ```text
60
+ stackmate/
61
+ ├── stackmate/ # Core library files
62
+ ├── examples/ # Example usage scripts
63
+ ├── tests/ # Unit tests
64
+ ├── pyproject.toml # Build configuration
65
+ └── README.md # Project documentation
66
+ ```
67
+
68
+ ## Author
69
+
70
+ - **Sudhakar K** - [sudhakark4227@gmail.com](mailto:sudhakark4227@gmail.com)
71
+
72
+ ## License
73
+
74
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,12 @@
1
+ stackmate/__init__.py,sha256=IPfrLdFHIHgHB_4V3X3Hn-TqtCk6Dwm9lzAj1s452ak,591
2
+ stackmate/auth.py,sha256=B4tOtpXXxp1Ce017HLLgmSaRNAe03OF8FR1rG5vG384,2344
3
+ stackmate/db_helper.py,sha256=KpCXNCxl_8iXsNcdRUcstoZUJgDwhukK4laSL3BOpaY,2912
4
+ stackmate/error_handler.py,sha256=XYat-D9mlmUhcVCCUewsQYG2o7YOUW5zANPU2KD3w9I,2038
5
+ stackmate/logger.py,sha256=ya3nV6KA9RfIZ3uV2pvStchirMryO_SxCd5eOycy1L4,2876
6
+ stackmate/utils.py,sha256=COtTHEKU2t7IyBE5oB_-vC9KcM0O_gMQr5dG_UQglVo,1419
7
+ stackmate/validator.py,sha256=HcizDceTYQJYb29fwGs6HARauHa35LMikOhgdScJ6yc,2151
8
+ stackmate-0.1.0.dist-info/licenses/LICENSE,sha256=mpx1EG96iVtm54Ttxu_r5k9cj9Q6vjiozWO-n3UMTLM,1088
9
+ stackmate-0.1.0.dist-info/METADATA,sha256=_wNFezIWN-Wxj48wzVsMfMDxtJtEXcPw3Kxa_RgnjUA,2421
10
+ stackmate-0.1.0.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
11
+ stackmate-0.1.0.dist-info/top_level.txt,sha256=mV9VScpq-qTtrQJk9bHvvmQ-2L93_y25D4SeAB6t1CE,10
12
+ stackmate-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sudhakar K
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, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ stackmate