pyapiutils 0.0.10__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.
pyapiutils/__init__.py ADDED
@@ -0,0 +1,10 @@
1
+ from .utils import Logging, ConfigUtil, RelDirs, ClientInfo, APIResponse
2
+
3
+ __all__ = ["UTILS"]
4
+
5
+ class UTILS:
6
+ Logging = Logging
7
+ ConfigUtil = ConfigUtil
8
+ ClientInfo = ClientInfo
9
+ RelDirs = RelDirs
10
+ APIResponse = APIResponse
@@ -0,0 +1,11 @@
1
+ """Docstring"""
2
+
3
+ from .config import ConfigUtil
4
+ from .infoui import ClientInfo
5
+ from .reldir import RelDirs
6
+ from .logger import Logging
7
+ from .apires import APIResponse
8
+
9
+
10
+
11
+ __all__ = ["ConfigUtil", "ClientInfo", "RelDirs", "Logging", "APIResponse"]
@@ -0,0 +1,16 @@
1
+ """Docstring"""
2
+ from typing import Any, Optional, Self
3
+ from pydantic import BaseModel
4
+
5
+ class APIResponse(BaseModel):
6
+ success: bool = True
7
+ message: str = "OK"
8
+ data: Optional[Any] = None
9
+
10
+ @classmethod
11
+ def from_res(cls, res: Any, message: Optional[str] = None) ->Self:
12
+ return cls(
13
+ success = True,
14
+ message = message or "request successful",
15
+ data = res
16
+ )
@@ -0,0 +1,50 @@
1
+ """Docstring"""
2
+ from pathlib import Path
3
+ from functools import lru_cache
4
+ from typing import Optional, Union, Type, Any
5
+ from pydantic_settings import BaseSettings, SettingsConfigDict
6
+
7
+ __all__ = ["ConfigUtil"]
8
+
9
+ class ConfigUtil:
10
+ def __init__(
11
+ self,
12
+ base: Any,
13
+ env: Optional[Union[str, Path]] = None,
14
+ secrets: Optional[Union[str, Path]] = None,
15
+ prefix: Optional[str] = None,
16
+ ):
17
+ self.base = base
18
+ self.env_path = env
19
+ self.secrets_path = secrets
20
+ self.prefix = prefix
21
+
22
+ @property
23
+ def config(self):
24
+ config = self.get_config(
25
+ self.base,
26
+ self.env_path,
27
+ self.secrets_path,
28
+ self.prefix,
29
+ )
30
+ return self.base.model_validate(config)
31
+
32
+ @classmethod
33
+ @lru_cache
34
+ def get_config(
35
+ cls,
36
+ base: Type[BaseSettings],
37
+ env: Optional[Union[str, Path]] = None,
38
+ secrets: Optional[Union[str, Path]] = None,
39
+ prefix: Optional[str] = None,
40
+ ):
41
+ class Config(base):
42
+ model_config = SettingsConfigDict(
43
+ env_prefix=prefix or "",
44
+ env_file=str(env) if env else None,
45
+ env_file_encoding="utf-8",
46
+ extra="ignore",
47
+ secrets_dir=str(secrets) if secrets else None,
48
+ )
49
+
50
+ return Config()
@@ -0,0 +1,35 @@
1
+ import user_agents
2
+ from fastapi import Request
3
+
4
+ class ClientInfo:
5
+ @staticmethod
6
+ def client_ip(request: Request) -> str:
7
+ return (
8
+ request.headers.get("CF-Connecting-IP") # Cloudflare
9
+ or request.headers.get("True-Client-IP") # Akamai / proxies
10
+ or request.headers.get("X-Forwarded-For", "").split(",")[0].strip()
11
+ or request.headers.get("X-Real-IP")
12
+ or (request.client.host if request.client else "unknown")
13
+ )
14
+
15
+ @staticmethod
16
+ def user_agent(request: Request) -> str:
17
+ """
18
+ Returns a clean parsed User-Agent string like 'Chrome 122 on Windows 10'.
19
+ """
20
+ ua_string = (
21
+ request.headers.get("X-Real-User-Agent")
22
+ or request.headers.get("X-Device-User-Agent")
23
+ or request.headers.get("X-Original-User-Agent")
24
+ or request.headers.get("User-Agent")
25
+ or "unknown"
26
+ )
27
+
28
+ ua = user_agents.parse(ua_string)
29
+
30
+ browser = f"{ua.browser.family} {ua.browser.version_string}".strip()
31
+ os = f"{ua.os.family} {ua.os.version_string}".strip()
32
+ device = ua.device.family or "Unknown Device"
33
+
34
+ # Return a clean single string
35
+ return f"{browser} on {os} ({device})"
@@ -0,0 +1,80 @@
1
+ """Docstring"""
2
+ import logging, sys
3
+
4
+ class Logging:
5
+ KAFKA_SILENT_LIST=["aiokafka"]
6
+ GAIMS_SILENT_LIST=["aiokafka", "botocore", "s3transfer", "urllib3"]
7
+ @staticmethod
8
+ def setup_basic(level=logging.INFO):
9
+ root = logging.getLogger()
10
+ if root.handlers:
11
+ root.handlers.clear()
12
+ root.setLevel(level)
13
+
14
+ formatter = logging.Formatter(
15
+ "%(asctime)s | %(levelname)s | %(name)s | %(message)s"
16
+ )
17
+
18
+ handler = logging.StreamHandler(sys.stdout)
19
+ handler.setFormatter(formatter)
20
+ handler.setLevel(level)
21
+
22
+ logging.basicConfig(
23
+ level=level,
24
+ handlers=[handler],
25
+ force=True, # override any existing config
26
+ )
27
+
28
+ @staticmethod
29
+ def setup_process(level=logging.INFO):
30
+ root = logging.getLogger()
31
+ if root.handlers:
32
+ root.handlers.clear()
33
+ root.setLevel(level)
34
+
35
+ formatter = logging.Formatter(
36
+ "%(asctime)s | %(levelname)s | %(processName)s | %(name)s | %(message)s"
37
+ )
38
+
39
+ handler = logging.StreamHandler(sys.stdout)
40
+ handler.setFormatter(formatter)
41
+ handler.setLevel(level)
42
+
43
+ logging.basicConfig(
44
+ level=level,
45
+ handlers=[handler],
46
+ force=True,
47
+ )
48
+
49
+ @staticmethod
50
+ def setup_service(service:str, level=logging.INFO):
51
+ root = logging.getLogger()
52
+ if root.handlers:
53
+ root.handlers.clear()
54
+ root.setLevel(level)
55
+
56
+ formatter = logging.Formatter(
57
+ "%(asctime)s | %(levelname)s | %(service)s | %(processName)s | %(name)s:%(lineno)d | %(message)s"
58
+ )
59
+
60
+ handler = logging.StreamHandler(sys.stdout)
61
+ handler.setFormatter(formatter)
62
+ handler.setLevel(level)
63
+
64
+ class ServiceFilter(logging.Filter):
65
+ def filter(self, record):
66
+ record.service = service
67
+ return True
68
+
69
+ handler.addFilter(ServiceFilter())
70
+
71
+ logging.basicConfig(
72
+ level=level,
73
+ handlers=[handler],
74
+ force=True,
75
+ )
76
+
77
+ @staticmethod
78
+ def silent_loglist(names: list[str], level=logging.ERROR):
79
+ for name in names:
80
+ logging.getLogger(name).setLevel(level)
@@ -0,0 +1,21 @@
1
+ from pathlib import Path
2
+
3
+ class RelDirs:
4
+ def __init__(self, path_str):
5
+ self.path = self._path(path_str)
6
+ self.dir = (
7
+ self.path
8
+ if self.path.is_dir()
9
+ else self.path.parent
10
+ )
11
+
12
+ def _path(self, path_str):
13
+ """
14
+ Doc String
15
+ """
16
+ path = Path(path_str).resolve()
17
+ cwd = Path.cwd().resolve()
18
+ try:
19
+ return path.relative_to(cwd)
20
+ except ValueError:
21
+ return path
@@ -0,0 +1,24 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyapiutils
3
+ Version: 0.0.10
4
+ Summary:
5
+ Author: sharmauksa
6
+ Author-email: sharmaumesh791@gmail.com
7
+ Requires-Python: >=3.14,<4.0
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.14
10
+ Description-Content-Type: text/markdown
11
+
12
+ # pyapiutils
13
+
14
+ **pyapiutils** is a lightweight Python library for fastapi utilities.
15
+
16
+ ## Features
17
+
18
+ - 🔐 Utilities to create alembic migration
19
+ ## Installation
20
+
21
+ You can install the package via pip:
22
+
23
+ ```bash
24
+ pip install pyapilib
@@ -0,0 +1,10 @@
1
+ pyapiutils/__init__.py,sha256=EkQkmMbWoG1faiUV77vf7TjInIcikL0popAx3eWX-qY,246
2
+ pyapiutils/utils/__init__.py,sha256=-HOhMYTiSubnFPCtIhT9JYuYETfvAtA2s8IIOCPskpI,255
3
+ pyapiutils/utils/apires.py,sha256=BAiIy3T8ZuD2prYnsKVVB_DTDbje_8JdJhDA31Bks7c,421
4
+ pyapiutils/utils/config.py,sha256=4Jxfox5qx63PGabzABP1LgRCD6anizWn-ip0TK3sM3Q,1414
5
+ pyapiutils/utils/infoui.py,sha256=yI5T4lYxKNOutbxzLBcHzMjAnfl9bld54s2bIjolc58,1299
6
+ pyapiutils/utils/logger.py,sha256=I9f9a4xpcsEMD0fIibRT0ZqkeIaPQwCt9UK9L7LsKAc,2345
7
+ pyapiutils/utils/reldir.py,sha256=jiSBC8sFJeerMckD1edIOyXxrK8o5O28s9QR1HL7B9k,522
8
+ pyapiutils-0.0.10.dist-info/METADATA,sha256=4IAUkvSPnTQDgUrNiES7yREOIVeevD0BT7UWgkWrke4,519
9
+ pyapiutils-0.0.10.dist-info/WHEEL,sha256=EGEvSphFYqXKs23-kQBeyNoJP1nrT8ZJKQoi5p5DYL8,88
10
+ pyapiutils-0.0.10.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 2.4.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any