fastapi-rtk 0.2.27__py3-none-any.whl → 1.0.13__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.
- fastapi_rtk/__init__.py +39 -35
- fastapi_rtk/_version.py +1 -0
- fastapi_rtk/api/model_rest_api.py +476 -221
- fastapi_rtk/auth/auth.py +0 -9
- fastapi_rtk/backends/generic/__init__.py +6 -0
- fastapi_rtk/backends/generic/column.py +21 -12
- fastapi_rtk/backends/generic/db.py +42 -7
- fastapi_rtk/backends/generic/filters.py +21 -16
- fastapi_rtk/backends/generic/interface.py +14 -8
- fastapi_rtk/backends/generic/model.py +19 -11
- fastapi_rtk/backends/sqla/__init__.py +1 -0
- fastapi_rtk/backends/sqla/db.py +77 -17
- fastapi_rtk/backends/sqla/extensions/audit/audit.py +401 -189
- fastapi_rtk/backends/sqla/extensions/geoalchemy2/filters.py +15 -12
- fastapi_rtk/backends/sqla/filters.py +50 -21
- fastapi_rtk/backends/sqla/interface.py +96 -34
- fastapi_rtk/backends/sqla/model.py +56 -39
- fastapi_rtk/bases/__init__.py +20 -0
- fastapi_rtk/bases/db.py +94 -7
- fastapi_rtk/bases/file_manager.py +47 -3
- fastapi_rtk/bases/filter.py +22 -0
- fastapi_rtk/bases/interface.py +49 -5
- fastapi_rtk/bases/model.py +3 -0
- fastapi_rtk/bases/session.py +2 -0
- fastapi_rtk/cli/cli.py +62 -9
- fastapi_rtk/cli/commands/__init__.py +23 -0
- fastapi_rtk/cli/{db.py → commands/db/__init__.py} +107 -50
- fastapi_rtk/cli/{templates → commands/db/templates}/fastapi/env.py +2 -3
- fastapi_rtk/cli/{templates → commands/db/templates}/fastapi-multidb/env.py +10 -9
- fastapi_rtk/cli/{templates → commands/db/templates}/fastapi-multidb/script.py.mako +3 -1
- fastapi_rtk/cli/{export.py → commands/export.py} +12 -10
- fastapi_rtk/cli/{security.py → commands/security.py} +73 -7
- fastapi_rtk/cli/commands/translate.py +299 -0
- fastapi_rtk/cli/decorators.py +9 -4
- fastapi_rtk/cli/utils.py +46 -0
- fastapi_rtk/config.py +41 -1
- fastapi_rtk/const.py +29 -1
- fastapi_rtk/db.py +76 -40
- fastapi_rtk/decorators.py +1 -1
- fastapi_rtk/dependencies.py +134 -62
- fastapi_rtk/exceptions.py +51 -1
- fastapi_rtk/fastapi_react_toolkit.py +186 -171
- fastapi_rtk/file_managers/file_manager.py +8 -6
- fastapi_rtk/file_managers/s3_file_manager.py +69 -33
- fastapi_rtk/globals.py +22 -12
- fastapi_rtk/lang/__init__.py +3 -0
- fastapi_rtk/lang/babel/__init__.py +4 -0
- fastapi_rtk/lang/babel/cli.py +40 -0
- fastapi_rtk/lang/babel/config.py +17 -0
- fastapi_rtk/lang/babel.cfg +1 -0
- fastapi_rtk/lang/lazy_text.py +120 -0
- fastapi_rtk/lang/messages.pot +238 -0
- fastapi_rtk/lang/translations/de/LC_MESSAGES/messages.mo +0 -0
- fastapi_rtk/lang/translations/de/LC_MESSAGES/messages.po +248 -0
- fastapi_rtk/lang/translations/en/LC_MESSAGES/messages.mo +0 -0
- fastapi_rtk/lang/translations/en/LC_MESSAGES/messages.po +244 -0
- fastapi_rtk/manager.py +355 -37
- fastapi_rtk/mixins.py +12 -0
- fastapi_rtk/routers.py +208 -72
- fastapi_rtk/schemas.py +142 -39
- fastapi_rtk/security/sqla/apis.py +39 -13
- fastapi_rtk/security/sqla/models.py +8 -23
- fastapi_rtk/security/sqla/security_manager.py +369 -11
- fastapi_rtk/setting.py +446 -88
- fastapi_rtk/types.py +94 -27
- fastapi_rtk/utils/__init__.py +8 -0
- fastapi_rtk/utils/async_task_runner.py +286 -61
- fastapi_rtk/utils/csv_json_converter.py +243 -40
- fastapi_rtk/utils/hooks.py +34 -0
- fastapi_rtk/utils/merge_schema.py +3 -3
- fastapi_rtk/utils/multiple_async_contexts.py +21 -0
- fastapi_rtk/utils/pydantic.py +46 -1
- fastapi_rtk/utils/run_utils.py +31 -1
- fastapi_rtk/utils/self_dependencies.py +1 -1
- fastapi_rtk/utils/use_default_when_none.py +1 -1
- fastapi_rtk/version.py +6 -1
- fastapi_rtk-1.0.13.dist-info/METADATA +28 -0
- fastapi_rtk-1.0.13.dist-info/RECORD +133 -0
- {fastapi_rtk-0.2.27.dist-info → fastapi_rtk-1.0.13.dist-info}/WHEEL +1 -2
- fastapi_rtk/backends/gremlinpython/__init__.py +0 -108
- fastapi_rtk/backends/gremlinpython/column.py +0 -208
- fastapi_rtk/backends/gremlinpython/db.py +0 -228
- fastapi_rtk/backends/gremlinpython/exceptions.py +0 -34
- fastapi_rtk/backends/gremlinpython/filters.py +0 -461
- fastapi_rtk/backends/gremlinpython/interface.py +0 -734
- fastapi_rtk/backends/gremlinpython/model.py +0 -364
- fastapi_rtk/backends/gremlinpython/session.py +0 -23
- fastapi_rtk/cli/commands.py +0 -295
- fastapi_rtk-0.2.27.dist-info/METADATA +0 -23
- fastapi_rtk-0.2.27.dist-info/RECORD +0 -126
- fastapi_rtk-0.2.27.dist-info/top_level.txt +0 -1
- /fastapi_rtk/cli/{templates → commands/db/templates}/fastapi/README +0 -0
- /fastapi_rtk/cli/{templates → commands/db/templates}/fastapi/alembic.ini.mako +0 -0
- /fastapi_rtk/cli/{templates → commands/db/templates}/fastapi/script.py.mako +0 -0
- /fastapi_rtk/cli/{templates → commands/db/templates}/fastapi-multidb/README +0 -0
- /fastapi_rtk/cli/{templates → commands/db/templates}/fastapi-multidb/alembic.ini.mako +0 -0
- {fastapi_rtk-0.2.27.dist-info → fastapi_rtk-1.0.13.dist-info}/entry_points.txt +0 -0
- {fastapi_rtk-0.2.27.dist-info → fastapi_rtk-1.0.13.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
|
|
1
3
|
from ..bases.file_manager import AbstractFileManager
|
|
2
4
|
from ..const import logger
|
|
5
|
+
from ..utils import smart_run
|
|
3
6
|
|
|
4
7
|
__all__ = ["S3FileManager"]
|
|
5
8
|
|
|
@@ -11,20 +14,58 @@ class S3FileManager(AbstractFileManager):
|
|
|
11
14
|
|
|
12
15
|
def __init__(
|
|
13
16
|
self,
|
|
14
|
-
base_path=None,
|
|
15
|
-
allowed_extensions=None,
|
|
16
|
-
namegen=None,
|
|
17
|
-
permission=None,
|
|
18
|
-
bucket_name=None,
|
|
19
|
-
bucket_subfolder=None,
|
|
20
|
-
access_key=None,
|
|
21
|
-
secret_key=None,
|
|
17
|
+
base_path: str | None = None,
|
|
18
|
+
allowed_extensions: list[str] | None = None,
|
|
19
|
+
namegen: typing.Callable[[str], str] | None = None,
|
|
20
|
+
permission: int | None = None,
|
|
21
|
+
bucket_name: str | None = None,
|
|
22
|
+
bucket_subfolder: str | None = None,
|
|
23
|
+
access_key: str | None = None,
|
|
24
|
+
secret_key: str | None = None,
|
|
25
|
+
open_params: dict[str, typing.Any] | None = None,
|
|
26
|
+
boto3_client: typing.Any | None = None,
|
|
22
27
|
):
|
|
28
|
+
"""
|
|
29
|
+
Initializes the S3FileManager.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
base_path (str | None, optional): URL path to the S3 bucket. Defaults to None.
|
|
33
|
+
allowed_extensions (list[str] | None, optional): Allowed file extensions. Defaults to None.
|
|
34
|
+
namegen (typing.Callable[[str], str] | None, optional): Callable for generating file names. Defaults to None.
|
|
35
|
+
permission (int | None, optional): File permission settings. Defaults to None.
|
|
36
|
+
bucket_name (str | None, optional): Name of the S3 bucket. Defaults to None.
|
|
37
|
+
bucket_subfolder (str | None, optional): Subfolder within the S3 bucket. Defaults to None.
|
|
38
|
+
access_key (str | None, optional): AWS access key. Needed for default boto3 client in order to delete files. Defaults to None.
|
|
39
|
+
secret_key (str | None, optional): AWS secret key. Needed for default boto3 client in order to delete files. Defaults to None.
|
|
40
|
+
open_params (dict[str, typing.Any] | None, optional): Parameters for opening files. Defaults to None.
|
|
41
|
+
boto3_client (typing.Any | None, optional): Boto3 client instance. If None, a new client will be created. Defaults to None.
|
|
42
|
+
Raises:
|
|
43
|
+
ImportError: If required libraries are not installed.
|
|
44
|
+
"""
|
|
23
45
|
super().__init__(base_path, allowed_extensions, namegen, permission)
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
import boto3
|
|
49
|
+
import smart_open
|
|
50
|
+
|
|
51
|
+
self.smart_open = smart_open
|
|
52
|
+
self.boto3 = boto3
|
|
53
|
+
except ImportError:
|
|
54
|
+
raise ImportError(
|
|
55
|
+
"smart_open is required for S3FileManager. "
|
|
56
|
+
"Please install it with 'pip install smart_open[s3]'."
|
|
57
|
+
)
|
|
58
|
+
|
|
24
59
|
self.bucket_name = bucket_name
|
|
25
60
|
self.bucket_subfolder = bucket_subfolder
|
|
26
61
|
self.access_key = access_key
|
|
27
62
|
self.secret_key = secret_key
|
|
63
|
+
self.open_params = open_params or {}
|
|
64
|
+
self.boto3_client = boto3_client or self.boto3.client(
|
|
65
|
+
"s3",
|
|
66
|
+
aws_access_key_id=self.access_key,
|
|
67
|
+
aws_secret_access_key=self.secret_key,
|
|
68
|
+
)
|
|
28
69
|
|
|
29
70
|
if not self.bucket_name:
|
|
30
71
|
logger.warning(
|
|
@@ -38,48 +79,41 @@ class S3FileManager(AbstractFileManager):
|
|
|
38
79
|
"Files may not be able to be deleted"
|
|
39
80
|
)
|
|
40
81
|
|
|
41
|
-
try:
|
|
42
|
-
import boto3
|
|
43
|
-
import smart_open
|
|
44
|
-
|
|
45
|
-
self.smart_open = smart_open
|
|
46
|
-
self.boto3 = boto3
|
|
47
|
-
except ImportError:
|
|
48
|
-
raise ImportError(
|
|
49
|
-
"smart_open is required for S3FileManager. "
|
|
50
|
-
"Please install it with 'pip install smart_open[s3]'."
|
|
51
|
-
)
|
|
52
|
-
|
|
53
82
|
def get_path(self, filename):
|
|
54
83
|
return self.base_path + "/" + filename
|
|
55
84
|
|
|
56
85
|
def get_file(self, filename):
|
|
57
|
-
with self.smart_open.open(
|
|
86
|
+
with self.smart_open.open(
|
|
87
|
+
self.get_path(filename), "rb", **self.open_params
|
|
88
|
+
) as f:
|
|
58
89
|
return f.read()
|
|
59
90
|
|
|
60
91
|
async def stream_file(self, filename):
|
|
61
|
-
with self.smart_open.open(
|
|
62
|
-
|
|
92
|
+
with self.smart_open.open(
|
|
93
|
+
self.get_path(filename), "rb", **self.open_params
|
|
94
|
+
) as f:
|
|
95
|
+
while chunk := await smart_run(f.read, 8192):
|
|
63
96
|
yield chunk
|
|
64
97
|
|
|
65
98
|
def save_file(self, file_data, filename):
|
|
66
|
-
|
|
99
|
+
path = self.get_path(filename)
|
|
100
|
+
with self.smart_open.open(path, "wb", **self.open_params) as f:
|
|
67
101
|
f.write(file_data.file.read())
|
|
102
|
+
return path
|
|
68
103
|
|
|
69
104
|
def save_content_to_file(self, content, filename):
|
|
70
|
-
|
|
105
|
+
path = self.get_path(filename)
|
|
106
|
+
with self.smart_open.open(path, "wb", **self.open_params) as f:
|
|
71
107
|
f.write(content)
|
|
108
|
+
return path
|
|
72
109
|
|
|
73
110
|
def delete_file(self, filename):
|
|
74
111
|
path = self.get_path(filename)
|
|
75
112
|
try:
|
|
76
|
-
self.smart_open.open(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
aws_secret_access_key=self.secret_key,
|
|
81
|
-
)
|
|
82
|
-
s3.delete_object(
|
|
113
|
+
self.smart_open.open(
|
|
114
|
+
path, "rb", **self.open_params
|
|
115
|
+
).close() # Check if file exists
|
|
116
|
+
self.boto3_client.delete_object(
|
|
83
117
|
Bucket=self.bucket_name,
|
|
84
118
|
Key=f"{self.bucket_subfolder}/{filename}"
|
|
85
119
|
if self.bucket_subfolder
|
|
@@ -91,7 +125,7 @@ class S3FileManager(AbstractFileManager):
|
|
|
91
125
|
def file_exists(self, filename):
|
|
92
126
|
path = self.get_path(filename)
|
|
93
127
|
try:
|
|
94
|
-
with self.smart_open.open(path, "rb"):
|
|
128
|
+
with self.smart_open.open(path, "rb", **self.open_params):
|
|
95
129
|
return True
|
|
96
130
|
except FileNotFoundError:
|
|
97
131
|
return False
|
|
@@ -105,6 +139,8 @@ class S3FileManager(AbstractFileManager):
|
|
|
105
139
|
else subfolder,
|
|
106
140
|
access_key=self.access_key,
|
|
107
141
|
secret_key=self.secret_key,
|
|
142
|
+
open_params=self.open_params,
|
|
143
|
+
boto3_client=self.boto3_client,
|
|
108
144
|
*args,
|
|
109
145
|
**kwargs,
|
|
110
146
|
)
|
fastapi_rtk/globals.py
CHANGED
|
@@ -52,8 +52,6 @@ from .const import (
|
|
|
52
52
|
BEARER_STRATEGY_CONFIG,
|
|
53
53
|
COOKIE_CONFIG,
|
|
54
54
|
COOKIE_STRATEGY_CONFIG,
|
|
55
|
-
DEFAULT_ADMIN_ROLE,
|
|
56
|
-
DEFAULT_PUBLIC_ROLE,
|
|
57
55
|
)
|
|
58
56
|
from .utils import lazy, lazy_import
|
|
59
57
|
|
|
@@ -85,14 +83,6 @@ class Globals:
|
|
|
85
83
|
"""
|
|
86
84
|
The configuration settings for the FastAPI React Toolkit.
|
|
87
85
|
"""
|
|
88
|
-
admin_role: str
|
|
89
|
-
"""
|
|
90
|
-
The role key for the admin role. Default is `"Admin"`.
|
|
91
|
-
"""
|
|
92
|
-
public_role: str
|
|
93
|
-
"""
|
|
94
|
-
The role key for the public role. Default is `"Public"`.
|
|
95
|
-
"""
|
|
96
86
|
is_migrate: bool
|
|
97
87
|
"""
|
|
98
88
|
A boolean value to indicate if the application is in migration mode. `True` when you are running a command from `fastapi-rtk` CLI.
|
|
@@ -105,6 +95,10 @@ class Globals:
|
|
|
105
95
|
"""
|
|
106
96
|
The background tasks object to add tasks to be executed after the response is sent. It will be `None` when not used in a request context.
|
|
107
97
|
"""
|
|
98
|
+
request: Request
|
|
99
|
+
"""
|
|
100
|
+
The current request object. It will be `None` when not used in a request context.
|
|
101
|
+
"""
|
|
108
102
|
file_manager: "AbstractFileManager"
|
|
109
103
|
"""
|
|
110
104
|
The file manager object to manage files in the application. Defaults to `FileManager` from `fastapi_rtk.file_managers.file_manager`.
|
|
@@ -119,6 +113,24 @@ class Globals:
|
|
|
119
113
|
object.__setattr__(self, "_vars", {})
|
|
120
114
|
object.__setattr__(self, "_defaults", {})
|
|
121
115
|
|
|
116
|
+
@property
|
|
117
|
+
def admin_role(self):
|
|
118
|
+
"""
|
|
119
|
+
The role key for the admin role. Default is `"Admin"`.
|
|
120
|
+
"""
|
|
121
|
+
from .setting import Setting
|
|
122
|
+
|
|
123
|
+
return Setting.AUTH_ROLE_ADMIN
|
|
124
|
+
|
|
125
|
+
@property
|
|
126
|
+
def public_role(self):
|
|
127
|
+
"""
|
|
128
|
+
The role key for the public role. Default is `"Public"`.
|
|
129
|
+
"""
|
|
130
|
+
from .setting import Setting
|
|
131
|
+
|
|
132
|
+
return Setting.AUTH_ROLE_PUBLIC
|
|
133
|
+
|
|
122
134
|
def set_default(self, name: str, default: Any) -> None:
|
|
123
135
|
"""Set a default value for a variable."""
|
|
124
136
|
|
|
@@ -236,8 +248,6 @@ g.set_default(
|
|
|
236
248
|
"auth", lazy_import("fastapi_rtk.auth", lambda mod: mod.AuthConfigurator())
|
|
237
249
|
)
|
|
238
250
|
g.set_default("config", Config())
|
|
239
|
-
g.set_default("admin_role", DEFAULT_ADMIN_ROLE)
|
|
240
|
-
g.set_default("public_role", DEFAULT_PUBLIC_ROLE)
|
|
241
251
|
g.set_default("is_migrate", False)
|
|
242
252
|
g.set_default("sensitive_data", {"User": ["password", "hashed_password"]})
|
|
243
253
|
g.set_default(
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from subprocess import run
|
|
2
|
+
|
|
3
|
+
import fastapi_babel
|
|
4
|
+
|
|
5
|
+
__all__ = ["FastAPIRTKBabelCLI"]
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FastAPIRTKBabelCLI(fastapi_babel.BabelCli):
|
|
9
|
+
"""
|
|
10
|
+
Subclass of `fastapi_babel.BabelCli`.
|
|
11
|
+
|
|
12
|
+
- Modified `extract` method to handle custom keywords.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def extract(self, watch_dir, keywords: str | None = None):
|
|
16
|
+
"""
|
|
17
|
+
Modified version of the default `extract` method to handle custom keywords too.
|
|
18
|
+
|
|
19
|
+
extract all messages that annotated using gettext/_
|
|
20
|
+
in the specified directory.
|
|
21
|
+
|
|
22
|
+
for first time will create messages.pot file into the root
|
|
23
|
+
directory.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
watch_dir (str): directory to extract messages.
|
|
27
|
+
keywords (str | None): custom keywords to extract separated by space.
|
|
28
|
+
"""
|
|
29
|
+
args = [
|
|
30
|
+
self.__module_name__,
|
|
31
|
+
"extract",
|
|
32
|
+
"-F",
|
|
33
|
+
self.babel.config.BABEL_CONFIG_FILE,
|
|
34
|
+
"-o",
|
|
35
|
+
self.babel.config.BABEL_MESSAGE_POT_FILE,
|
|
36
|
+
]
|
|
37
|
+
if keywords:
|
|
38
|
+
args.extend(["-k", keywords])
|
|
39
|
+
args.append(watch_dir)
|
|
40
|
+
run(args)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
import fastapi_babel
|
|
4
|
+
|
|
5
|
+
__all__ = ["FastAPIRTKBabelConfigs"]
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FastAPIRTKBabelConfigs(fastapi_babel.BabelConfigs):
|
|
9
|
+
"""
|
|
10
|
+
Subclass of `fastapi_babel.BabelConfigs`.
|
|
11
|
+
|
|
12
|
+
- Modified `ROOT_DIR` to not use its parent directory.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __post_init__(self):
|
|
16
|
+
self.ROOT_DIR = os.path.join(self.ROOT_DIR, "dummy")
|
|
17
|
+
return super().__post_init__()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[python: **/*.py]
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import fastapi_babel
|
|
2
|
+
|
|
3
|
+
from ..utils import lazy, use_default_when_none
|
|
4
|
+
|
|
5
|
+
__all__ = ["lazy_text", "translate", "_"]
|
|
6
|
+
|
|
7
|
+
logger = None
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class lazy_text(lazy[str]):
|
|
11
|
+
"""
|
|
12
|
+
Lazily translates a message using FastAPI Babel.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, message: str, *args, **kwargs):
|
|
16
|
+
"""
|
|
17
|
+
Initializes a lazy_text instance that lazily translates the given message.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
message (str): the message to be translated.
|
|
21
|
+
*args: positional arguments to format the message.
|
|
22
|
+
**kwargs: keyword arguments to format the message.
|
|
23
|
+
"""
|
|
24
|
+
super().__init__(
|
|
25
|
+
lambda: translate(message).format(*args, **kwargs),
|
|
26
|
+
cache=False,
|
|
27
|
+
only_instance=True,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def _(cls, message: str, *args, **kwargs):
|
|
32
|
+
"""
|
|
33
|
+
Class method to create a lazy_text instance that can be automatically found by `pybabel extract`.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
message (str): the message to be translated.
|
|
37
|
+
*args: positional arguments to format the message.
|
|
38
|
+
**kwargs: keyword arguments to format the message.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
lazy_text: an instance of lazy_text that will lazily translate the message.
|
|
42
|
+
"""
|
|
43
|
+
return cls(message, *args, **kwargs)
|
|
44
|
+
|
|
45
|
+
def __repr__(self):
|
|
46
|
+
"""
|
|
47
|
+
When reading it as a string, it should return the formatted message.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
str: the formatted message.
|
|
51
|
+
"""
|
|
52
|
+
return self.__call__()
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def translate(
|
|
56
|
+
message: str, *args, ensure_context=False, use_settings_translations=True, **kwargs
|
|
57
|
+
):
|
|
58
|
+
"""
|
|
59
|
+
Translates a message using FastAPI Babel.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
message (str): the message to be translated.
|
|
63
|
+
*args: positional arguments to format the message.
|
|
64
|
+
ensure_context (bool): Whether to ensure the context is already set to know which language to use. If false, it will return the message as is if the translation is not found. Defaults to False.
|
|
65
|
+
use_translations (bool): Whether to use the translations defined in `Setting.TRANSLATIONS` as a fallback if the translation is not found. Defaults to True.
|
|
66
|
+
**kwargs: keyword arguments to format the message.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
str: the translated message.
|
|
70
|
+
"""
|
|
71
|
+
try:
|
|
72
|
+
translated_message = fastapi_babel._(message)
|
|
73
|
+
if translated_message == message and use_settings_translations:
|
|
74
|
+
translated_message = use_default_when_none(
|
|
75
|
+
_use_settings_translations(message), message
|
|
76
|
+
)
|
|
77
|
+
return translated_message.format(*args, **kwargs)
|
|
78
|
+
except LookupError as e:
|
|
79
|
+
if not ensure_context:
|
|
80
|
+
from ..globals import g
|
|
81
|
+
|
|
82
|
+
if g.current_app and g.current_app.started:
|
|
83
|
+
global logger
|
|
84
|
+
if not logger:
|
|
85
|
+
from ..const import logger as base_logger
|
|
86
|
+
|
|
87
|
+
logger = base_logger.getChild("lang")
|
|
88
|
+
|
|
89
|
+
logger.warning(
|
|
90
|
+
f"Translation not found for '{message}'. Returning the original message."
|
|
91
|
+
)
|
|
92
|
+
return message.format(*args, **kwargs)
|
|
93
|
+
raise e
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _use_settings_translations(message: str):
|
|
97
|
+
"""
|
|
98
|
+
Use translations defined in `Setting.TRANSLATIONS` as a fallback if the translation is not found.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
message (str): The original message to translate.
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
str | None: The translated message, or None if no translation is found.
|
|
105
|
+
"""
|
|
106
|
+
from ..globals import g
|
|
107
|
+
from ..setting import Setting
|
|
108
|
+
|
|
109
|
+
if Setting.TRANSLATIONS and g.request:
|
|
110
|
+
try:
|
|
111
|
+
translated_message = Setting.TRANSLATIONS.get(
|
|
112
|
+
g.request.state.babel.locale, {}
|
|
113
|
+
).get(message)
|
|
114
|
+
if translated_message:
|
|
115
|
+
return translated_message
|
|
116
|
+
except Exception:
|
|
117
|
+
pass
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
_ = translate # Alias for convenience
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# Translations template for PROJECT.
|
|
2
|
+
# Copyright (C) 2025 ORGANIZATION
|
|
3
|
+
# This file is distributed under the same license as the PROJECT project.
|
|
4
|
+
# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.
|
|
5
|
+
#
|
|
6
|
+
#, fuzzy
|
|
7
|
+
msgid ""
|
|
8
|
+
msgstr ""
|
|
9
|
+
"Project-Id-Version: PROJECT VERSION\n"
|
|
10
|
+
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
|
11
|
+
"POT-Creation-Date: 2025-10-30 10:07+0100\n"
|
|
12
|
+
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
|
13
|
+
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
|
14
|
+
"Language-Team: LANGUAGE <LL@li.org>\n"
|
|
15
|
+
"MIME-Version: 1.0\n"
|
|
16
|
+
"Content-Type: text/plain; charset=utf-8\n"
|
|
17
|
+
"Content-Transfer-Encoding: 8bit\n"
|
|
18
|
+
"Generated-By: Babel 2.17.0\n"
|
|
19
|
+
|
|
20
|
+
#: fastapi_rtk/schemas.py:419
|
|
21
|
+
msgid "Columns must be a list"
|
|
22
|
+
msgstr ""
|
|
23
|
+
|
|
24
|
+
#: fastapi_rtk/schemas.py:429
|
|
25
|
+
msgid "Invalid columns: Not a valid JSON string"
|
|
26
|
+
msgstr ""
|
|
27
|
+
|
|
28
|
+
#: fastapi_rtk/schemas.py:452
|
|
29
|
+
msgid "Both 'order_column' and 'order_direction' must be filled or empty"
|
|
30
|
+
msgstr ""
|
|
31
|
+
|
|
32
|
+
#: fastapi_rtk/schemas.py:470
|
|
33
|
+
msgid "Filters must be a list"
|
|
34
|
+
msgstr ""
|
|
35
|
+
|
|
36
|
+
#: fastapi_rtk/schemas.py:485
|
|
37
|
+
msgid "Filter must be an object"
|
|
38
|
+
msgstr ""
|
|
39
|
+
|
|
40
|
+
#: fastapi_rtk/schemas.py:495
|
|
41
|
+
msgid "Invalid filters: Not a valid JSON string"
|
|
42
|
+
msgstr ""
|
|
43
|
+
|
|
44
|
+
#: fastapi_rtk/schemas.py:520
|
|
45
|
+
msgid "Opr Filters must be a list"
|
|
46
|
+
msgstr ""
|
|
47
|
+
|
|
48
|
+
#: fastapi_rtk/schemas.py:535
|
|
49
|
+
msgid "Opr Filter must be an object"
|
|
50
|
+
msgstr ""
|
|
51
|
+
|
|
52
|
+
#: fastapi_rtk/schemas.py:545
|
|
53
|
+
msgid "Invalid opr_filters: Not a valid JSON string"
|
|
54
|
+
msgstr ""
|
|
55
|
+
|
|
56
|
+
#: fastapi_rtk/api/model_rest_api.py:476
|
|
57
|
+
#, python-brace-format
|
|
58
|
+
msgid "List {ModelName}"
|
|
59
|
+
msgstr ""
|
|
60
|
+
|
|
61
|
+
#: fastapi_rtk/api/model_rest_api.py:485
|
|
62
|
+
#, python-brace-format
|
|
63
|
+
msgid "Show {ModelName}"
|
|
64
|
+
msgstr ""
|
|
65
|
+
|
|
66
|
+
#: fastapi_rtk/api/model_rest_api.py:494
|
|
67
|
+
#, python-brace-format
|
|
68
|
+
msgid "Add {ModelName}"
|
|
69
|
+
msgstr ""
|
|
70
|
+
|
|
71
|
+
#: fastapi_rtk/api/model_rest_api.py:503
|
|
72
|
+
#, python-brace-format
|
|
73
|
+
msgid "Edit {ModelName}"
|
|
74
|
+
msgstr ""
|
|
75
|
+
|
|
76
|
+
#: fastapi_rtk/api/model_rest_api.py:1395
|
|
77
|
+
msgid "OK"
|
|
78
|
+
msgstr ""
|
|
79
|
+
|
|
80
|
+
#: fastapi_rtk/api/model_rest_api.py:2411
|
|
81
|
+
#: fastapi_rtk/api/model_rest_api.py:2810
|
|
82
|
+
#, python-brace-format
|
|
83
|
+
msgid "Number of items in '{column}' does not match the number of items found."
|
|
84
|
+
msgstr ""
|
|
85
|
+
|
|
86
|
+
#: fastapi_rtk/api/model_rest_api.py:2432
|
|
87
|
+
#, python-brace-format
|
|
88
|
+
msgid "Could not find related item for column '{column}'"
|
|
89
|
+
msgstr ""
|
|
90
|
+
|
|
91
|
+
#: fastapi_rtk/api/model_rest_api.py:2464
|
|
92
|
+
#, python-brace-format
|
|
93
|
+
msgid "File type from '{filename}' is not allowed."
|
|
94
|
+
msgstr ""
|
|
95
|
+
|
|
96
|
+
#: fastapi_rtk/api/model_rest_api.py:2872
|
|
97
|
+
#, python-brace-format
|
|
98
|
+
msgid "Invalid column: {column}"
|
|
99
|
+
msgstr ""
|
|
100
|
+
|
|
101
|
+
#: fastapi_rtk/api/model_rest_api.py:2882
|
|
102
|
+
#, python-brace-format
|
|
103
|
+
msgid "Invalid filter: {column}"
|
|
104
|
+
msgstr ""
|
|
105
|
+
|
|
106
|
+
#: fastapi_rtk/backends/generic/db.py:66 fastapi_rtk/backends/sqla/db.py:163
|
|
107
|
+
#, python-brace-format
|
|
108
|
+
msgid "Invalid filter operator: {operator}"
|
|
109
|
+
msgstr ""
|
|
110
|
+
|
|
111
|
+
#: fastapi_rtk/backends/generic/db.py:90 fastapi_rtk/backends/sqla/db.py:194
|
|
112
|
+
#, python-brace-format
|
|
113
|
+
msgid "Invalid opr_filter operator: {operator}"
|
|
114
|
+
msgstr ""
|
|
115
|
+
|
|
116
|
+
#: fastapi_rtk/backends/generic/filters.py:81
|
|
117
|
+
#: fastapi_rtk/backends/sqla/filters.py:243
|
|
118
|
+
msgid "Text contains"
|
|
119
|
+
msgstr ""
|
|
120
|
+
|
|
121
|
+
#: fastapi_rtk/backends/generic/filters.py:89
|
|
122
|
+
#: fastapi_rtk/backends/sqla/filters.py:259
|
|
123
|
+
msgid "Equal to"
|
|
124
|
+
msgstr ""
|
|
125
|
+
|
|
126
|
+
#: fastapi_rtk/backends/generic/filters.py:117
|
|
127
|
+
#: fastapi_rtk/backends/sqla/filters.py:277
|
|
128
|
+
msgid "Starts with"
|
|
129
|
+
msgstr ""
|
|
130
|
+
|
|
131
|
+
#: fastapi_rtk/backends/generic/filters.py:126
|
|
132
|
+
#: fastapi_rtk/backends/sqla/filters.py:286
|
|
133
|
+
msgid "Not Starts with"
|
|
134
|
+
msgstr ""
|
|
135
|
+
|
|
136
|
+
#: fastapi_rtk/backends/generic/filters.py:135
|
|
137
|
+
#: fastapi_rtk/backends/sqla/filters.py:295
|
|
138
|
+
msgid "Ends with"
|
|
139
|
+
msgstr ""
|
|
140
|
+
|
|
141
|
+
#: fastapi_rtk/backends/generic/filters.py:144
|
|
142
|
+
#: fastapi_rtk/backends/sqla/filters.py:304
|
|
143
|
+
msgid "Not Ends with"
|
|
144
|
+
msgstr ""
|
|
145
|
+
|
|
146
|
+
#: fastapi_rtk/backends/generic/filters.py:153
|
|
147
|
+
#: fastapi_rtk/backends/sqla/filters.py:313
|
|
148
|
+
msgid "Contains"
|
|
149
|
+
msgstr ""
|
|
150
|
+
|
|
151
|
+
#: fastapi_rtk/backends/generic/filters.py:162
|
|
152
|
+
msgid "Contains (insensitive)"
|
|
153
|
+
msgstr ""
|
|
154
|
+
|
|
155
|
+
#: fastapi_rtk/backends/generic/filters.py:171
|
|
156
|
+
#: fastapi_rtk/backends/sqla/filters.py:322
|
|
157
|
+
msgid "Not Contains"
|
|
158
|
+
msgstr ""
|
|
159
|
+
|
|
160
|
+
#: fastapi_rtk/backends/generic/filters.py:180
|
|
161
|
+
#: fastapi_rtk/backends/sqla/filters.py:331
|
|
162
|
+
msgid "Greater than"
|
|
163
|
+
msgstr ""
|
|
164
|
+
|
|
165
|
+
#: fastapi_rtk/backends/generic/filters.py:189
|
|
166
|
+
#: fastapi_rtk/backends/sqla/filters.py:340
|
|
167
|
+
msgid "Smaller than"
|
|
168
|
+
msgstr ""
|
|
169
|
+
|
|
170
|
+
#: fastapi_rtk/backends/generic/filters.py:198
|
|
171
|
+
#: fastapi_rtk/backends/sqla/filters.py:349
|
|
172
|
+
msgid "Greater equal"
|
|
173
|
+
msgstr ""
|
|
174
|
+
|
|
175
|
+
#: fastapi_rtk/backends/generic/filters.py:207
|
|
176
|
+
#: fastapi_rtk/backends/sqla/filters.py:358
|
|
177
|
+
msgid "Smaller equal"
|
|
178
|
+
msgstr ""
|
|
179
|
+
|
|
180
|
+
#: fastapi_rtk/backends/generic/filters.py:216
|
|
181
|
+
#: fastapi_rtk/backends/sqla/filters.py:367
|
|
182
|
+
msgid "One of"
|
|
183
|
+
msgstr ""
|
|
184
|
+
|
|
185
|
+
#: fastapi_rtk/backends/generic/filters.py:225
|
|
186
|
+
#: fastapi_rtk/backends/sqla/filters.py:470
|
|
187
|
+
msgid "Global Filter"
|
|
188
|
+
msgstr ""
|
|
189
|
+
|
|
190
|
+
#: fastapi_rtk/backends/sqla/filters.py:268
|
|
191
|
+
msgid "Not equal to"
|
|
192
|
+
msgstr ""
|
|
193
|
+
|
|
194
|
+
#: fastapi_rtk/backends/sqla/filters.py:376
|
|
195
|
+
msgid "Between"
|
|
196
|
+
msgstr ""
|
|
197
|
+
|
|
198
|
+
#: fastapi_rtk/backends/sqla/filters.py:389
|
|
199
|
+
msgid "Between filter requires 2 values"
|
|
200
|
+
msgstr ""
|
|
201
|
+
|
|
202
|
+
#: fastapi_rtk/backends/sqla/filters.py:434
|
|
203
|
+
msgid "In"
|
|
204
|
+
msgstr ""
|
|
205
|
+
|
|
206
|
+
#: fastapi_rtk/backends/sqla/filters.py:452
|
|
207
|
+
msgid "Not In"
|
|
208
|
+
msgstr ""
|
|
209
|
+
|
|
210
|
+
#: fastapi_rtk/backends/sqla/extensions/geoalchemy2/filters.py:83
|
|
211
|
+
msgid "Intersects"
|
|
212
|
+
msgstr ""
|
|
213
|
+
|
|
214
|
+
#: fastapi_rtk/backends/sqla/extensions/geoalchemy2/filters.py:93
|
|
215
|
+
msgid "Not Intersects"
|
|
216
|
+
msgstr ""
|
|
217
|
+
|
|
218
|
+
#: fastapi_rtk/backends/sqla/extensions/geoalchemy2/filters.py:103
|
|
219
|
+
msgid "Overlaps"
|
|
220
|
+
msgstr ""
|
|
221
|
+
|
|
222
|
+
#: fastapi_rtk/backends/sqla/extensions/geoalchemy2/filters.py:113
|
|
223
|
+
msgid "Not Overlaps"
|
|
224
|
+
msgstr ""
|
|
225
|
+
|
|
226
|
+
#: fastapi_rtk/bases/db.py:463
|
|
227
|
+
#, python-brace-format
|
|
228
|
+
msgid "Invalid ID: {id}, expected {count} values"
|
|
229
|
+
msgstr ""
|
|
230
|
+
|
|
231
|
+
#: fastapi_rtk/bases/db.py:476
|
|
232
|
+
msgid "Invalid ID"
|
|
233
|
+
msgstr ""
|
|
234
|
+
|
|
235
|
+
#: fastapi_rtk/security/sqla/apis.py:299
|
|
236
|
+
msgid "User updated successfully."
|
|
237
|
+
msgstr ""
|
|
238
|
+
|
|
Binary file
|