fastlib-py 0.2.0__tar.gz → 0.2.1__tar.gz

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.
Files changed (84) hide show
  1. {fastlib_py-0.2.0/fastlib_py.egg-info → fastlib_py-0.2.1}/PKG-INFO +1 -1
  2. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/cache/__init__.py +1 -1
  3. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/cache/disk_cache.py +2 -2
  4. fastlib_py-0.2.0/fastlib/cache/cache_manager.py → fastlib_py-0.2.1/fastlib/cache/manager.py +4 -3
  5. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/cache/redis_cache.py +6 -7
  6. fastlib_py-0.2.1/fastlib/config/base.py +17 -0
  7. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/config/utils.py +0 -2
  8. fastlib_py-0.2.1/fastlib/i18n/manager.py +96 -0
  9. fastlib_py-0.2.1/fastlib/i18n/messages.py +88 -0
  10. fastlib_py-0.2.1/fastlib/i18n/utils.py +86 -0
  11. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/logging/config.py +9 -0
  12. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/mapper/impl/base_mapper_impl.py +1 -1
  13. fastlib_py-0.2.1/fastlib/middleware/__init__.py +7 -0
  14. fastlib_py-0.2.1/fastlib/middleware/i18n.py +57 -0
  15. fastlib_py-0.2.0/fastlib/middleware/jwt_middleware.py → fastlib_py-0.2.1/fastlib/middleware/jwt.py +1 -1
  16. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/model/base_model.py +2 -2
  17. {fastlib_py-0.2.0 → fastlib_py-0.2.1/fastlib_py.egg-info}/PKG-INFO +1 -1
  18. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib_py.egg-info/SOURCES.txt +11 -10
  19. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/pyproject.toml +1 -1
  20. fastlib_py-0.2.0/fastlib/config/base.py +0 -6
  21. fastlib_py-0.2.0/fastlib/i18n/i18n_context.py +0 -215
  22. fastlib_py-0.2.0/fastlib/i18n/i18n_messages.py +0 -99
  23. fastlib_py-0.2.0/fastlib/i18n/i18n_util.py +0 -233
  24. fastlib_py-0.2.0/fastlib/middleware/__init__.py +0 -7
  25. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/LICENSE +0 -0
  26. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/README.md +0 -0
  27. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/__init__.py +0 -0
  28. /fastlib_py-0.2.0/fastlib/cache/base_cache.py → /fastlib_py-0.2.1/fastlib/cache/base.py +0 -0
  29. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/config/__init__.py +0 -0
  30. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/config/database_config.py +0 -0
  31. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/config/loader.py +0 -0
  32. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/config/manager.py +0 -0
  33. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/config/registry.py +0 -0
  34. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/config/security_config.py +0 -0
  35. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/config/server_config.py +0 -0
  36. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/constant/__init__.py +0 -0
  37. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/constant/constant.py +0 -0
  38. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/context/__init__.py +0 -0
  39. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/context/contextvars.py +0 -0
  40. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/enums/__init__.py +0 -0
  41. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/enums/base_error_code.py +0 -0
  42. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/enums/enum.py +0 -0
  43. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/exception/__init__.py +0 -0
  44. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/exception/custom_exception.py +0 -0
  45. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/exception/exception_handler.py +0 -0
  46. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/exception/exception_manager.py +0 -0
  47. /fastlib_py-0.2.0/fastlib/i18n/i18n_types.py → /fastlib_py-0.2.1/fastlib/i18n/types.py +0 -0
  48. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/logging/__init__.py +0 -0
  49. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/logging/handlers.py +0 -0
  50. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/mapper/__init__.py +0 -0
  51. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/mapper/base_mapper.py +0 -0
  52. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/mapper/impl/__init__.py +0 -0
  53. /fastlib_py-0.2.0/fastlib/middleware/db_session_middleware.py → /fastlib_py-0.2.1/fastlib/middleware/db_session.py +0 -0
  54. /fastlib_py-0.2.0/fastlib/middleware/log_middleware.py → /fastlib_py-0.2.1/fastlib/middleware/log.py +0 -0
  55. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/migrate/migrate.py +0 -0
  56. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/model/__init__.py +0 -0
  57. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/openapi/__init__.py +0 -0
  58. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/openapi/offline.py +0 -0
  59. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/router/__init__.py +0 -0
  60. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/router/router_v1.py +0 -0
  61. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/schema/__init__.py +0 -0
  62. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/schema/response.py +0 -0
  63. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/schema/schema.py +0 -0
  64. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/security/__init__.py +0 -0
  65. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/security/security.py +0 -0
  66. /fastlib_py-0.2.0/fastlib/utils/security_util.py → /fastlib_py-0.2.1/fastlib/security/utils.py +0 -0
  67. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/service/__init__.py +0 -0
  68. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/service/base_service.py +0 -0
  69. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/service/impl/__init__.py +0 -0
  70. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/service/impl/base_service_impl.py +0 -0
  71. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/session/__init__.py +0 -0
  72. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/session/db_engine.py +0 -0
  73. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/session/db_session.py +0 -0
  74. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/utils/__init__.py +0 -0
  75. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/utils/excel_util.py +0 -0
  76. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/utils/file_util.py +0 -0
  77. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/utils/http_util.py +0 -0
  78. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/utils/ip_util.py +0 -0
  79. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/utils/snowflake_util.py +0 -0
  80. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib/utils/str_util.py +0 -0
  81. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib_py.egg-info/dependency_links.txt +0 -0
  82. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib_py.egg-info/requires.txt +0 -0
  83. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/fastlib_py.egg-info/top_level.txt +0 -0
  84. {fastlib_py-0.2.0 → fastlib_py-0.2.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastlib-py
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: Fastlib, high performance, easy to use, fast to code, ready for production
5
5
  Author-email: tyvekZhang <tyvekzhang@gmail.com>
6
6
  Maintainer-email: tyvekZhang <tyvekzhang@gmail.com>
@@ -1,6 +1,6 @@
1
1
  """Provides a unified cache client based on configuration."""
2
2
 
3
- from .cache_manager import get_cache_client
3
+ from .manager import get_cache_client
4
4
 
5
5
  __all__ = [
6
6
  get_cache_client,
@@ -5,11 +5,11 @@ import json
5
5
  import threading
6
6
  import time
7
7
  from contextlib import asynccontextmanager
8
- from typing import Any, Optional, list
8
+ from typing import Any, Optional
9
9
 
10
10
  import diskcache
11
11
 
12
- from fastlib.cache.base_cache import Cache, CacheError
12
+ from fastlib.cache.base import Cache, CacheError
13
13
 
14
14
 
15
15
  class PageCache(Cache):
@@ -1,8 +1,8 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  """Cache Client manager to instantiate the appropriate cache client"""
3
3
 
4
- from fastlib.cache.base_cache import Cache
5
- from fastlib.cache.redis_cache import RedisManager
4
+ from fastlib.cache.base import Cache
5
+
6
6
  from fastlib.config.manager import ConfigManager
7
7
 
8
8
 
@@ -12,7 +12,8 @@ async def get_cache_client() -> Cache:
12
12
  Returns:
13
13
  Cache: Redis client if Redis is enabled in config, otherwise returns page cache.
14
14
  """
15
-
15
+ from fastlib.cache.redis_cache import RedisManager
16
+
16
17
  config = ConfigManager.get_database_config()
17
18
  if config.enable_redis:
18
19
  from fastlib.cache.redis_cache import RedisCache
@@ -5,17 +5,18 @@ import asyncio
5
5
  import time
6
6
  import uuid
7
7
  from contextlib import asynccontextmanager
8
- from typing import Any, Optional, list
8
+ from typing import Any, Optional
9
9
 
10
10
  from loguru import logger
11
11
 
12
- from fastlib.cache.base_cache import Cache, CacheError
12
+ from fastlib import ConfigManager
13
+ from fastlib.cache.base import Cache, CacheError
13
14
 
14
15
  try:
15
16
  import redis.asyncio as redis
16
17
  from redis.exceptions import RedisError
17
18
  except ModuleNotFoundError:
18
- logger.error(
19
+ logger.warning(
19
20
  "Cannot find redis module, please install it via `uv add redis[hiredis] and then uv remove diskcache`"
20
21
  )
21
22
  redis = None
@@ -25,8 +26,6 @@ except Exception:
25
26
  redis = None
26
27
  RedisError = Exception
27
28
 
28
- from fastlib.config.manager import load_config
29
-
30
29
 
31
30
  class RedisCache(Cache):
32
31
  def __init__(self, redis_client):
@@ -347,9 +346,9 @@ class RedisManager:
347
346
  if cls._instance is None:
348
347
  async with cls._lock:
349
348
  if cls._connection_pool is None:
350
- database = load_config().database
349
+ database_config = ConfigManager.get_database_config()
351
350
  cls._connection_pool = redis.ConnectionPool.from_url(
352
- f"redis://:{database.cache_pass}@{database.cache_host}:{database.cache_port}/{database.db_num}",
351
+ f"redis://:{database_config.cache_pass}@{database_config.cache_host}:{database_config.cache_port}/{database_config.db_num}",
353
352
  decode_responses=True,
354
353
  )
355
354
  if cls._instance is None:
@@ -0,0 +1,17 @@
1
+ # SPDX-License-Identifier: MIT
2
+ """Base configuration classes."""
3
+
4
+ from abc import ABC, abstractmethod
5
+
6
+
7
+ class BaseConfig(ABC):
8
+ """Base class for all configuration classes."""
9
+
10
+ @abstractmethod
11
+ def __str__(self) -> str:
12
+ """Return string representation of the configuration.
13
+
14
+ Returns:
15
+ str: String representation of the configuration instance.
16
+ """
17
+ pass
@@ -1,5 +1,4 @@
1
1
  # SPDX-License-Identifier: MIT
2
-
3
2
  """Configuration module util"""
4
3
 
5
4
  import configparser
@@ -60,7 +59,6 @@ class ProjectInfo:
60
59
  path = Path(file_util.find_project_root()) / "pyproject.toml"
61
60
  else:
62
61
  path = Path(pyproject_path)
63
- print(f"{path}")
64
62
  if not path.exists():
65
63
  raise FileNotFoundError(f"{pyproject_path} does not exist")
66
64
 
@@ -0,0 +1,96 @@
1
+ """
2
+ Internationalization context manager
3
+ """
4
+
5
+ import contextvars
6
+ import functools
7
+ from typing import Any, Callable, TypeVar, Awaitable
8
+ from fastlib.i18n.types import Language
9
+
10
+ _language_context = contextvars.ContextVar("language", default=Language.ENGLISH)
11
+
12
+ F = TypeVar("F", bound=Callable[..., Any])
13
+
14
+
15
+ def set_language(language: Language) -> None:
16
+ """Set current language"""
17
+ _language_context.set(language)
18
+
19
+
20
+ def get_language() -> Language:
21
+ """Get current language"""
22
+ return _language_context.get()
23
+
24
+
25
+ def get_language_code() -> str:
26
+ """Get current language code, e.g. 'en', 'zh'"""
27
+ return get_language().value
28
+
29
+
30
+ def reset_language() -> None:
31
+ """Reset language to default"""
32
+ _language_context.set(Language.ENGLISH)
33
+
34
+
35
+ def is_language(language: Language) -> bool:
36
+ """Check if current language matches"""
37
+ return get_language() == language
38
+
39
+
40
+ class I18nContext:
41
+ """Context manager to temporarily switch language"""
42
+
43
+ def __init__(self, language: Language):
44
+ self.language = language
45
+ self._token: contextvars.Token | None = None
46
+
47
+ def __enter__(self):
48
+ self._token = _language_context.set(self.language)
49
+ return self
50
+
51
+ def __exit__(self, exc_type, exc_val, exc_tb):
52
+ if self._token is not None:
53
+ _language_context.reset(self._token)
54
+
55
+
56
+ def with_language(language: Language) -> I18nContext:
57
+ """Helper to create context manager"""
58
+ return I18nContext(language)
59
+
60
+
61
+ def _language_context_decorator(
62
+ language: Language, is_async: bool = False
63
+ ) -> Callable[[F], F]:
64
+ """Internal generator for sync/async language context decorators"""
65
+
66
+ def decorator(func: F) -> F:
67
+ if is_async:
68
+
69
+ @functools.wraps(func)
70
+ async def async_wrapper(*args: Any, **kwargs: Any) -> Any:
71
+ with I18nContext(language):
72
+ return await func(*args, **kwargs)
73
+
74
+ return async_wrapper
75
+ else:
76
+
77
+ @functools.wraps(func)
78
+ def wrapper(*args: Any, **kwargs: Any) -> Any:
79
+ with I18nContext(language):
80
+ return func(*args, **kwargs)
81
+
82
+ return wrapper
83
+
84
+ return decorator
85
+
86
+
87
+ def language_context(language: Language) -> Callable[[F], F]:
88
+ """Decorator: run a sync function within a language context"""
89
+ return _language_context_decorator(language, is_async=False)
90
+
91
+
92
+ def async_language_context(
93
+ language: Language,
94
+ ) -> Callable[[Callable[..., Awaitable[Any]]], Callable[..., Awaitable[Any]]]:
95
+ """Decorator: run an async function within a language context"""
96
+ return _language_context_decorator(language, is_async=True)
@@ -0,0 +1,88 @@
1
+ import json
2
+ from pathlib import Path
3
+ from typing import List, Optional, Union
4
+ from fastlib.constant.constant import RESOURCE_DIR
5
+ from fastlib.i18n.types import Language
6
+
7
+ # Default i18n directory (assumed to be in the same directory as this file)
8
+ DEFAULT_BASE_DIR = Path(RESOURCE_DIR) / "i18n"
9
+
10
+ # Global cache for translation data
11
+ TRANSLATIONS = {
12
+ "zh": {"debug": {"test_message": "这是一条调试测试消息"}},
13
+ "en": {"debug": {"test_message": "This is a debug test message"}},
14
+ }
15
+
16
+
17
+ def load_translations(base_dirs: Union[Path, List[Path], None] = None):
18
+ """Load multilingual translation files from multiple directories.
19
+
20
+ Args:
21
+ base_dirs: Single directory path or list of directory paths for translation files.
22
+ If not provided, uses the default DEFAULT_BASE_DIR.
23
+
24
+ File structure requirements:
25
+ Each directory should follow: base_dir/{lang}/{namespace}.json
26
+ Example: i18n/zh/error.json
27
+
28
+ Note: Later directories will override translations from earlier directories
29
+ if the same language and namespace exist.
30
+ """
31
+ if base_dirs is None:
32
+ base_dirs = [DEFAULT_BASE_DIR]
33
+ elif isinstance(base_dirs, Path):
34
+ base_dirs = [base_dirs]
35
+
36
+ for base_dir in base_dirs:
37
+ if not base_dir.exists():
38
+ continue # Skip if directory doesn't exist
39
+
40
+ for lang in [Language.CHINESE, Language.ENGLISH]:
41
+ lang_dir = base_dir / lang.value
42
+ if not lang_dir.exists():
43
+ continue # Skip if language directory doesn't exist
44
+
45
+ # Initialize language dict if not exists
46
+ if lang.value not in TRANSLATIONS:
47
+ TRANSLATIONS[lang.value] = {}
48
+
49
+ for file in lang_dir.glob("*.json"):
50
+ namespace = (
51
+ file.stem
52
+ ) # Determine message_type from filename, e.g., error, success
53
+ with open(file, "r", encoding="utf-8") as f:
54
+ translations_data = json.load(f)
55
+
56
+ # Merge with existing namespace data or create new
57
+ if namespace in TRANSLATIONS[lang.value]:
58
+ TRANSLATIONS[lang.value][namespace].update(translations_data)
59
+ else:
60
+ TRANSLATIONS[lang.value][namespace] = translations_data
61
+
62
+
63
+ def get_message(message_type: str, key: str, language: Language) -> str:
64
+ """Get translated message for given type, key and language.
65
+
66
+ Args:
67
+ message_type: Namespace/category of the message (e.g., 'error', 'success')
68
+ key: Message identifier key
69
+ language: Target language
70
+
71
+ Returns:
72
+ Translated message or fallback to default language if not found
73
+ """
74
+ default_language = Language.CHINESE.value
75
+
76
+ # Try to get message from requested language
77
+ lang_dict = TRANSLATIONS.get(language.value, {})
78
+ msg = lang_dict.get(message_type, {}).get(key)
79
+
80
+ if msg:
81
+ return msg
82
+
83
+ # Fallback to default language
84
+ return (
85
+ TRANSLATIONS.get(default_language, {})
86
+ .get(message_type, {})
87
+ .get(key, f"Unknown {message_type} message: {key}")
88
+ )
@@ -0,0 +1,86 @@
1
+ """
2
+ Internationalization utilities
3
+ """
4
+
5
+ from typing import Any, Optional
6
+
7
+ from .manager import I18nContext
8
+ from .messages import get_message
9
+ from .types import Language
10
+
11
+ # Default language
12
+ DEFAULT_LANGUAGE = Language.ENGLISH
13
+
14
+ # Language alias mapping
15
+ LANGUAGE_MAPPING = {
16
+ "zh": Language.CHINESE,
17
+ "zh_cn": Language.CHINESE,
18
+ "en": Language.ENGLISH,
19
+ "en_us": Language.ENGLISH,
20
+ }
21
+
22
+ # --- Helpers ---
23
+
24
+
25
+ def _resolve_language(language: Optional[Language]) -> Language:
26
+ """Return given language or current context default"""
27
+ return language or I18nContext.get_language()
28
+
29
+
30
+ # --- Core utilities ---
31
+
32
+
33
+ def parse_language(language_str: Optional[str]) -> Language:
34
+ """Parse string like 'zh-CN', 'en-US' to Language enum"""
35
+ if not language_str:
36
+ return DEFAULT_LANGUAGE
37
+ return LANGUAGE_MAPPING.get(
38
+ language_str.lower().replace("-", "_"), DEFAULT_LANGUAGE
39
+ )
40
+
41
+
42
+ def get_localized_message(
43
+ category: str, key: str, language: Optional[Language] = None
44
+ ) -> str:
45
+ """Get localized message by category ('error', 'success', 'business')"""
46
+ lang = _resolve_language(language)
47
+ return get_message(category, key, lang)
48
+
49
+
50
+ def get_error_message(key: str, language: Optional[Language] = None) -> str:
51
+ return get_localized_message("error", key, language)
52
+
53
+
54
+ def get_success_message(key: str, language: Optional[Language] = None) -> str:
55
+ return get_localized_message("success", key, language)
56
+
57
+
58
+ def create_error_response(
59
+ error_key: str,
60
+ language: Optional[Language] = None,
61
+ details: Optional[str] = None,
62
+ error_code: int = 400,
63
+ ) -> dict[str, Any]:
64
+ lang = _resolve_language(language)
65
+ error = {
66
+ "code": error_code,
67
+ "message": get_error_message(error_key, lang),
68
+ "language": lang.value,
69
+ }
70
+ if details:
71
+ error["details"] = details
72
+ return {"success": False, "error": error}
73
+
74
+
75
+ def create_success_response(
76
+ data: Any,
77
+ language: Optional[Language] = None,
78
+ message_key: str = "search_success",
79
+ ) -> dict[str, Any]:
80
+ lang = _resolve_language(language)
81
+ return {
82
+ "success": True,
83
+ "data": data,
84
+ "message": get_success_message(message_key, lang),
85
+ "language": lang.value,
86
+ }
@@ -64,3 +64,12 @@ class LogConfig(BaseConfig):
64
64
  def error_log_file_pattern(self) -> str:
65
65
  """Returns the error log file pattern with timestamp."""
66
66
  return f"{{time:{self.time_format}}}_error_{self.app_name}.log"
67
+
68
+ def __str__(self) -> str:
69
+ """
70
+ Returns a string representation of the database configuration.
71
+
72
+ Returns:
73
+ A string representation of the DatabaseConfig instance.
74
+ """
75
+ return f"{self.__class__.__name__}({self.__dict__})"
@@ -11,7 +11,7 @@ from sqlmodel.ext.asyncio.session import AsyncSession
11
11
  from fastlib.constant import FilterOperators, constant
12
12
  from fastlib.enums import SortEnum
13
13
  from fastlib.mapper.base_mapper import BaseMapper
14
- from fastlib.middleware.db_session_middleware import db
14
+ from fastlib.middleware.db_session import db
15
15
  from fastlib.schema import SortItem
16
16
 
17
17
  IDType = TypeVar("IDType", int, str)
@@ -0,0 +1,7 @@
1
+ """Export middleware symbols."""
2
+
3
+ from .db_session import SQLAlchemyMiddleware, db
4
+ from .jwt import jwt_middleware
5
+ from .log import log_requests
6
+
7
+ __all__ = [SQLAlchemyMiddleware, jwt_middleware, log_requests, db]
@@ -0,0 +1,57 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from starlette.middleware.base import BaseHTTPMiddleware
3
+
4
+ from fastlib.i18n.types import Language
5
+
6
+
7
+ class I18nMiddleware(BaseHTTPMiddleware):
8
+ """
9
+ Middleware for automatic language detection and setting based on HTTP headers.
10
+
11
+ This middleware inspects the Accept-Language header from incoming requests
12
+ and sets the appropriate language in the request state for use throughout
13
+ the application.
14
+
15
+ The language preference is stored in request.state.language and can be
16
+ accessed in route handlers and other middleware.
17
+
18
+ Example:
19
+ ```python
20
+ from fastapi import FastAPI, Request
21
+
22
+ app = FastAPI()
23
+ app.add_middleware(I18nMiddleware)
24
+
25
+ @app.get("/")
26
+ async def root(request: Request):
27
+ language = request.state.language
28
+ return {"language": language.value}
29
+ ```
30
+
31
+ Note:
32
+ Currently supports only English and Chinese. Defaults to English
33
+ if the Accept-Language header is not present or unrecognized.
34
+ """
35
+
36
+ async def dispatch(self, request, call_next):
37
+ """
38
+ Process the request and set the language based on Accept-Language header.
39
+
40
+ Args:
41
+ request: The incoming HTTP request
42
+ call_next: The next middleware or route handler in the chain
43
+
44
+ Returns:
45
+ The HTTP response from the next handler
46
+ """
47
+ # Get language preference from request headers
48
+ accept_lang = request.headers.get("Accept-Language", "en")
49
+
50
+ # Set the language for current request
51
+ if accept_lang.startswith("en"):
52
+ request.state.language = Language.ENGLISH
53
+ else:
54
+ request.state.language = Language.CHINESE
55
+
56
+ response = await call_next(request)
57
+ return response
@@ -6,12 +6,12 @@ import http
6
6
  from fastapi import Request
7
7
  from jwt.exceptions import PyJWTError
8
8
  from loguru import logger
9
- from src.main.app.enums.auth_error_code import AuthErrorCode
10
9
  from starlette.responses import JSONResponse
11
10
 
12
11
  from fastlib import ConfigManager, constant, security
13
12
  from fastlib.context.contextvars import current_user_id
14
13
  from fastlib.enums.enum import MediaTypeEnum
14
+ from fastlib.enums import AuthErrorCode
15
15
  from fastlib.schema import UserCredential
16
16
 
17
17
  # Load configuration
@@ -47,12 +47,12 @@ class ModelExt(_SQLModel):
47
47
  Create time and update time for a model, can be automatically generated
48
48
  """
49
49
 
50
- create_time: Optional[datetime] = Field(
50
+ create_at: Optional[datetime] = Field(
51
51
  sa_type=DateTime,
52
52
  default_factory=datetime.utcnow,
53
53
  sa_column_kwargs={"comment": "创建时间"},
54
54
  )
55
- update_time: Optional[datetime] = Field(
55
+ update_at: Optional[datetime] = Field(
56
56
  sa_type=DateTime,
57
57
  default_factory=datetime.utcnow,
58
58
  sa_column_kwargs={
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastlib-py
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: Fastlib, high performance, easy to use, fast to code, ready for production
5
5
  Author-email: tyvekZhang <tyvekzhang@gmail.com>
6
6
  Maintainer-email: tyvekZhang <tyvekzhang@gmail.com>
@@ -3,9 +3,9 @@ README.md
3
3
  pyproject.toml
4
4
  fastlib/__init__.py
5
5
  fastlib/cache/__init__.py
6
- fastlib/cache/base_cache.py
7
- fastlib/cache/cache_manager.py
6
+ fastlib/cache/base.py
8
7
  fastlib/cache/disk_cache.py
8
+ fastlib/cache/manager.py
9
9
  fastlib/cache/redis_cache.py
10
10
  fastlib/config/__init__.py
11
11
  fastlib/config/base.py
@@ -27,10 +27,10 @@ fastlib/exception/__init__.py
27
27
  fastlib/exception/custom_exception.py
28
28
  fastlib/exception/exception_handler.py
29
29
  fastlib/exception/exception_manager.py
30
- fastlib/i18n/i18n_context.py
31
- fastlib/i18n/i18n_messages.py
32
- fastlib/i18n/i18n_types.py
33
- fastlib/i18n/i18n_util.py
30
+ fastlib/i18n/manager.py
31
+ fastlib/i18n/messages.py
32
+ fastlib/i18n/types.py
33
+ fastlib/i18n/utils.py
34
34
  fastlib/logging/__init__.py
35
35
  fastlib/logging/config.py
36
36
  fastlib/logging/handlers.py
@@ -39,9 +39,10 @@ fastlib/mapper/base_mapper.py
39
39
  fastlib/mapper/impl/__init__.py
40
40
  fastlib/mapper/impl/base_mapper_impl.py
41
41
  fastlib/middleware/__init__.py
42
- fastlib/middleware/db_session_middleware.py
43
- fastlib/middleware/jwt_middleware.py
44
- fastlib/middleware/log_middleware.py
42
+ fastlib/middleware/db_session.py
43
+ fastlib/middleware/i18n.py
44
+ fastlib/middleware/jwt.py
45
+ fastlib/middleware/log.py
45
46
  fastlib/migrate/migrate.py
46
47
  fastlib/model/__init__.py
47
48
  fastlib/model/base_model.py
@@ -54,6 +55,7 @@ fastlib/schema/response.py
54
55
  fastlib/schema/schema.py
55
56
  fastlib/security/__init__.py
56
57
  fastlib/security/security.py
58
+ fastlib/security/utils.py
57
59
  fastlib/service/__init__.py
58
60
  fastlib/service/base_service.py
59
61
  fastlib/service/impl/__init__.py
@@ -66,7 +68,6 @@ fastlib/utils/excel_util.py
66
68
  fastlib/utils/file_util.py
67
69
  fastlib/utils/http_util.py
68
70
  fastlib/utils/ip_util.py
69
- fastlib/utils/security_util.py
70
71
  fastlib/utils/snowflake_util.py
71
72
  fastlib/utils/str_util.py
72
73
  fastlib_py.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fastlib-py"
3
- version = "0.2.0"
3
+ version = "0.2.1"
4
4
  description = "Fastlib, high performance, easy to use, fast to code, ready for production"
5
5
  readme = "README.md"
6
6
  keywords = [
@@ -1,6 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- """Base configuration classes."""
3
-
4
-
5
- class BaseConfig:
6
- """Base class for all configuration classes."""