ul-api-utils 9.3.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.
- example/__init__.py +0 -0
- example/conf.py +35 -0
- example/main.py +24 -0
- example/models/__init__.py +0 -0
- example/permissions.py +6 -0
- example/pure_flask_example.py +65 -0
- example/rate_limit_load.py +10 -0
- example/redis_repository.py +22 -0
- example/routes/__init__.py +0 -0
- example/routes/api_some.py +335 -0
- example/sockets/__init__.py +0 -0
- example/sockets/on_connect.py +16 -0
- example/sockets/on_disconnect.py +14 -0
- example/sockets/on_json.py +10 -0
- example/sockets/on_message.py +13 -0
- example/sockets/on_open.py +16 -0
- example/workers/__init__.py +0 -0
- example/workers/worker.py +28 -0
- ul_api_utils/__init__.py +0 -0
- ul_api_utils/access/__init__.py +122 -0
- ul_api_utils/api_resource/__init__.py +0 -0
- ul_api_utils/api_resource/api_request.py +105 -0
- ul_api_utils/api_resource/api_resource.py +414 -0
- ul_api_utils/api_resource/api_resource_config.py +20 -0
- ul_api_utils/api_resource/api_resource_error_handling.py +21 -0
- ul_api_utils/api_resource/api_resource_fn_typing.py +356 -0
- ul_api_utils/api_resource/api_resource_type.py +16 -0
- ul_api_utils/api_resource/api_response.py +300 -0
- ul_api_utils/api_resource/api_response_db.py +26 -0
- ul_api_utils/api_resource/api_response_payload_alias.py +25 -0
- ul_api_utils/api_resource/db_types.py +9 -0
- ul_api_utils/api_resource/signature_check.py +41 -0
- ul_api_utils/commands/__init__.py +0 -0
- ul_api_utils/commands/cmd_enc_keys.py +172 -0
- ul_api_utils/commands/cmd_gen_api_user_token.py +77 -0
- ul_api_utils/commands/cmd_gen_new_api_user.py +106 -0
- ul_api_utils/commands/cmd_generate_api_docs.py +181 -0
- ul_api_utils/commands/cmd_start.py +110 -0
- ul_api_utils/commands/cmd_worker_start.py +76 -0
- ul_api_utils/commands/start/__init__.py +0 -0
- ul_api_utils/commands/start/gunicorn.conf.local.py +0 -0
- ul_api_utils/commands/start/gunicorn.conf.py +26 -0
- ul_api_utils/commands/start/wsgi.py +22 -0
- ul_api_utils/conf/ul-debugger-main.js +1 -0
- ul_api_utils/conf/ul-debugger-ui.js +1 -0
- ul_api_utils/conf.py +70 -0
- ul_api_utils/const.py +78 -0
- ul_api_utils/debug/__init__.py +0 -0
- ul_api_utils/debug/debugger.py +119 -0
- ul_api_utils/debug/malloc.py +93 -0
- ul_api_utils/debug/stat.py +444 -0
- ul_api_utils/encrypt/__init__.py +0 -0
- ul_api_utils/encrypt/encrypt_decrypt_abstract.py +15 -0
- ul_api_utils/encrypt/encrypt_decrypt_aes_xtea.py +59 -0
- ul_api_utils/errors.py +200 -0
- ul_api_utils/internal_api/__init__.py +0 -0
- ul_api_utils/internal_api/__tests__/__init__.py +0 -0
- ul_api_utils/internal_api/__tests__/internal_api.py +29 -0
- ul_api_utils/internal_api/__tests__/internal_api_content_type.py +22 -0
- ul_api_utils/internal_api/internal_api.py +369 -0
- ul_api_utils/internal_api/internal_api_check_context.py +42 -0
- ul_api_utils/internal_api/internal_api_error.py +17 -0
- ul_api_utils/internal_api/internal_api_response.py +296 -0
- ul_api_utils/main.py +29 -0
- ul_api_utils/modules/__init__.py +0 -0
- ul_api_utils/modules/__tests__/__init__.py +0 -0
- ul_api_utils/modules/__tests__/test_api_sdk_jwt.py +195 -0
- ul_api_utils/modules/api_sdk.py +555 -0
- ul_api_utils/modules/api_sdk_config.py +63 -0
- ul_api_utils/modules/api_sdk_jwt.py +377 -0
- ul_api_utils/modules/intermediate_state.py +34 -0
- ul_api_utils/modules/worker_context.py +35 -0
- ul_api_utils/modules/worker_sdk.py +109 -0
- ul_api_utils/modules/worker_sdk_config.py +13 -0
- ul_api_utils/py.typed +0 -0
- ul_api_utils/resources/__init__.py +0 -0
- ul_api_utils/resources/caching.py +196 -0
- ul_api_utils/resources/debugger_scripts.py +97 -0
- ul_api_utils/resources/health_check/__init__.py +0 -0
- ul_api_utils/resources/health_check/const.py +2 -0
- ul_api_utils/resources/health_check/health_check.py +439 -0
- ul_api_utils/resources/health_check/health_check_template.py +64 -0
- ul_api_utils/resources/health_check/resource.py +97 -0
- ul_api_utils/resources/not_implemented.py +25 -0
- ul_api_utils/resources/permissions.py +29 -0
- ul_api_utils/resources/rate_limitter.py +84 -0
- ul_api_utils/resources/socketio.py +55 -0
- ul_api_utils/resources/swagger.py +119 -0
- ul_api_utils/resources/web_forms/__init__.py +0 -0
- ul_api_utils/resources/web_forms/custom_fields/__init__.py +0 -0
- ul_api_utils/resources/web_forms/custom_fields/custom_checkbox_select.py +5 -0
- ul_api_utils/resources/web_forms/custom_widgets/__init__.py +0 -0
- ul_api_utils/resources/web_forms/custom_widgets/custom_select_widget.py +86 -0
- ul_api_utils/resources/web_forms/custom_widgets/custom_text_input_widget.py +42 -0
- ul_api_utils/resources/web_forms/uni_form.py +75 -0
- ul_api_utils/sentry.py +52 -0
- ul_api_utils/utils/__init__.py +0 -0
- ul_api_utils/utils/__tests__/__init__.py +0 -0
- ul_api_utils/utils/__tests__/api_path_version.py +16 -0
- ul_api_utils/utils/__tests__/unwrap_typing.py +67 -0
- ul_api_utils/utils/api_encoding.py +51 -0
- ul_api_utils/utils/api_format.py +61 -0
- ul_api_utils/utils/api_method.py +55 -0
- ul_api_utils/utils/api_pagination.py +58 -0
- ul_api_utils/utils/api_path_version.py +60 -0
- ul_api_utils/utils/api_request_info.py +6 -0
- ul_api_utils/utils/avro.py +131 -0
- ul_api_utils/utils/broker_topics_message_count.py +47 -0
- ul_api_utils/utils/cached_per_request.py +23 -0
- ul_api_utils/utils/colors.py +31 -0
- ul_api_utils/utils/constants.py +7 -0
- ul_api_utils/utils/decode_base64.py +9 -0
- ul_api_utils/utils/deprecated.py +19 -0
- ul_api_utils/utils/flags.py +29 -0
- ul_api_utils/utils/flask_swagger_generator/__init__.py +0 -0
- ul_api_utils/utils/flask_swagger_generator/conf.py +4 -0
- ul_api_utils/utils/flask_swagger_generator/exceptions.py +7 -0
- ul_api_utils/utils/flask_swagger_generator/specifiers/__init__.py +0 -0
- ul_api_utils/utils/flask_swagger_generator/specifiers/swagger_models.py +57 -0
- ul_api_utils/utils/flask_swagger_generator/specifiers/swagger_specifier.py +48 -0
- ul_api_utils/utils/flask_swagger_generator/specifiers/swagger_three_specifier.py +777 -0
- ul_api_utils/utils/flask_swagger_generator/specifiers/swagger_version.py +40 -0
- ul_api_utils/utils/flask_swagger_generator/utils/__init__.py +0 -0
- ul_api_utils/utils/flask_swagger_generator/utils/input_type.py +77 -0
- ul_api_utils/utils/flask_swagger_generator/utils/parameter_type.py +51 -0
- ul_api_utils/utils/flask_swagger_generator/utils/replace_in_dict.py +18 -0
- ul_api_utils/utils/flask_swagger_generator/utils/request_type.py +52 -0
- ul_api_utils/utils/flask_swagger_generator/utils/schema_type.py +15 -0
- ul_api_utils/utils/flask_swagger_generator/utils/security_type.py +39 -0
- ul_api_utils/utils/imports.py +16 -0
- ul_api_utils/utils/instance_checks.py +16 -0
- ul_api_utils/utils/jinja/__init__.py +0 -0
- ul_api_utils/utils/jinja/t_url_for.py +19 -0
- ul_api_utils/utils/jinja/to_pretty_json.py +11 -0
- ul_api_utils/utils/json_encoder.py +126 -0
- ul_api_utils/utils/load_modules.py +15 -0
- ul_api_utils/utils/memory_db/__init__.py +0 -0
- ul_api_utils/utils/memory_db/__tests__/__init__.py +0 -0
- ul_api_utils/utils/memory_db/errors.py +8 -0
- ul_api_utils/utils/memory_db/repository.py +102 -0
- ul_api_utils/utils/token_check.py +14 -0
- ul_api_utils/utils/token_check_through_request.py +16 -0
- ul_api_utils/utils/unwrap_typing.py +117 -0
- ul_api_utils/utils/uuid_converter.py +22 -0
- ul_api_utils/validators/__init__.py +0 -0
- ul_api_utils/validators/__tests__/__init__.py +0 -0
- ul_api_utils/validators/__tests__/test_custom_fields.py +32 -0
- ul_api_utils/validators/custom_fields.py +66 -0
- ul_api_utils/validators/validate_empty_object.py +10 -0
- ul_api_utils/validators/validate_uuid.py +11 -0
- ul_api_utils-9.3.0.dist-info/LICENSE +21 -0
- ul_api_utils-9.3.0.dist-info/METADATA +279 -0
- ul_api_utils-9.3.0.dist-info/RECORD +156 -0
- ul_api_utils-9.3.0.dist-info/WHEEL +5 -0
- ul_api_utils-9.3.0.dist-info/entry_points.txt +2 -0
- ul_api_utils-9.3.0.dist-info/top_level.txt +2 -0
example/__init__.py
ADDED
|
File without changes
|
example/conf.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
from ul_db_utils.modules.postgres_modules.db import DbConfig
|
|
4
|
+
|
|
5
|
+
from ul_api_utils.modules.api_sdk import ApiSdk
|
|
6
|
+
from ul_api_utils.modules.api_sdk_config import ApiSdkConfig, ApiSdkIdentifyTypeEnum, \
|
|
7
|
+
ApiSdkFlaskDebuggingPluginsEnabled
|
|
8
|
+
from example.permissions import permissions
|
|
9
|
+
from ul_api_utils.resources.socketio import SocketIOConfigType, SocketIOConfig
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
sdk = ApiSdk(ApiSdkConfig(
|
|
13
|
+
socket_config=SocketIOConfig(
|
|
14
|
+
app_type=SocketIOConfigType.EXTERNAL_PROCESS,
|
|
15
|
+
message_queue='redis://localhost:16379',
|
|
16
|
+
logs_enabled=True,
|
|
17
|
+
engineio_logs_enabled=False,
|
|
18
|
+
),
|
|
19
|
+
service_name='example_service',
|
|
20
|
+
permissions=permissions,
|
|
21
|
+
cache_storage_uri='redis://localhost:16379',
|
|
22
|
+
cache_default_ttl=60,
|
|
23
|
+
rate_limit_storage_uri='redis://localhost:16379',
|
|
24
|
+
rate_limit_identify=ApiSdkIdentifyTypeEnum.JWT_USER_ID,
|
|
25
|
+
flask_debugging_plugins=ApiSdkFlaskDebuggingPluginsEnabled(
|
|
26
|
+
flask_monitoring_dashboard=True,
|
|
27
|
+
),
|
|
28
|
+
web_error_template='error.html.jinja2',
|
|
29
|
+
))
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
fake_models_dir = os.path.join(os.path.dirname(__file__), 'models')
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
db_config = DbConfig(uri='postgresql://admin:admin@localhost:45432/example', models_path=fake_models_dir)
|
example/main.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# from gevent import monkey
|
|
2
|
+
#
|
|
3
|
+
# monkey.patch_all()
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# UNCOMMENT THIS IN CASE YOU'RE TESTING GEVENT WORKERS WITH SOCKET.IO
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
|
|
10
|
+
if int(os.environ.get('PROFILE_MEM', '0')):
|
|
11
|
+
from ul_api_utils.debug.malloc import trace_malloc
|
|
12
|
+
|
|
13
|
+
with trace_malloc(show_all=True):
|
|
14
|
+
from example.conf import sdk, db_config
|
|
15
|
+
|
|
16
|
+
flask_app = sdk.init_with_flask(__name__, db_config=db_config)
|
|
17
|
+
else:
|
|
18
|
+
from example.conf import sdk, db_config
|
|
19
|
+
|
|
20
|
+
flask_app = sdk.init_with_flask(__name__, db_config=db_config)
|
|
21
|
+
|
|
22
|
+
__all__ = (
|
|
23
|
+
'flask_app',
|
|
24
|
+
)
|
|
File without changes
|
example/permissions.py
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
from ul_api_utils.access import PermissionRegistry
|
|
2
|
+
|
|
3
|
+
permissions = PermissionRegistry('example-debug-log', 111, 222)
|
|
4
|
+
|
|
5
|
+
SOME_PERMISSION = permissions.add('SOME', 1, 'Param pam Pam', 'test')
|
|
6
|
+
SOME_PERMISSION2 = permissions.add('SOME2', 2, 'Param pam Pam2', 'test', flags='123,234')
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# import os.path
|
|
2
|
+
# from tempfile import NamedTemporaryFile
|
|
3
|
+
#
|
|
4
|
+
# from flask import Flask, send_file, after_this_request, Response
|
|
5
|
+
#
|
|
6
|
+
# app = Flask(__name__)
|
|
7
|
+
#
|
|
8
|
+
#
|
|
9
|
+
# files = []
|
|
10
|
+
#
|
|
11
|
+
#
|
|
12
|
+
# # def _clean_files():
|
|
13
|
+
# # print('_clean_files')
|
|
14
|
+
# #
|
|
15
|
+
# #
|
|
16
|
+
# # @app.after_request
|
|
17
|
+
# # def _after(resp):
|
|
18
|
+
# # print('_after', resp)
|
|
19
|
+
# # return resp
|
|
20
|
+
# #
|
|
21
|
+
# #
|
|
22
|
+
# # def _after_this(resp):
|
|
23
|
+
# # print('_after_this', resp)
|
|
24
|
+
# # return resp
|
|
25
|
+
#
|
|
26
|
+
#
|
|
27
|
+
# @app.route('/test')
|
|
28
|
+
# def donwload_test():
|
|
29
|
+
# resp = Response("some")
|
|
30
|
+
#
|
|
31
|
+
# after_this_request(_after_this)
|
|
32
|
+
# resp.call_on_close(_clean_files)
|
|
33
|
+
#
|
|
34
|
+
# return resp, 200
|
|
35
|
+
#
|
|
36
|
+
#
|
|
37
|
+
# # @app.teardown_request
|
|
38
|
+
# # def _teardown(exc):
|
|
39
|
+
# # print('_teardown', str(exc))
|
|
40
|
+
#
|
|
41
|
+
#
|
|
42
|
+
# @app.route('/test-file')
|
|
43
|
+
# def donwload_test_file():
|
|
44
|
+
# f = NamedTemporaryFile()
|
|
45
|
+
# for ff in files:
|
|
46
|
+
# print(f'{ff} = {os.path.exists(ff)}')
|
|
47
|
+
# files.append(str(f.name))
|
|
48
|
+
# # f.seek(0)
|
|
49
|
+
# f.write(b'test\n')
|
|
50
|
+
# f.write(b'test\n')
|
|
51
|
+
# f.write(b'test\n')
|
|
52
|
+
# f.write(b'test\n')
|
|
53
|
+
#
|
|
54
|
+
# with open(f.name, 'w+t') as ff:
|
|
55
|
+
# ff.write('SOME\n')
|
|
56
|
+
# ff.write('SOME\n')
|
|
57
|
+
# ff.write('SOME\n')
|
|
58
|
+
# ff.write('SOME\n')
|
|
59
|
+
#
|
|
60
|
+
# resp = send_file(f, mimetype='application/javascript')
|
|
61
|
+
#
|
|
62
|
+
# # after_this_request(_after_this)
|
|
63
|
+
# # resp.call_on_close(_clean_files)
|
|
64
|
+
#
|
|
65
|
+
# return resp
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
import redis
|
|
4
|
+
from pydantic import BaseModel, UUID4
|
|
5
|
+
from uuid import uuid4
|
|
6
|
+
from ul_api_utils.utils.memory_db.repository import BaseMemoryDbRepository
|
|
7
|
+
|
|
8
|
+
redis_client: Any = redis.StrictRedis.from_url("redis://172.19.0.2:6379")
|
|
9
|
+
redis_db = BaseMemoryDbRepository(redis_client=redis_client)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Person(BaseModel):
|
|
13
|
+
id: UUID4
|
|
14
|
+
name: str = 'Slava'
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
slava = Person(id=uuid4())
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
redis_db['slava'] = 35
|
|
21
|
+
value = redis_db['slava', Person]
|
|
22
|
+
value2 = redis_db.get('slava', default=1)
|
|
File without changes
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from enum import IntEnum, Enum
|
|
3
|
+
from time import sleep
|
|
4
|
+
from datetime import datetime, timedelta
|
|
5
|
+
from typing import List, Optional, Tuple
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
from flask import jsonify
|
|
9
|
+
from pydantic import BaseModel
|
|
10
|
+
from ul_db_utils.modules.postgres_modules.db import db
|
|
11
|
+
from werkzeug import Response as BaseResponse
|
|
12
|
+
from example.conf import sdk
|
|
13
|
+
from example.permissions import SOME_PERMISSION, SOME_PERMISSION2
|
|
14
|
+
from ul_api_utils.api_resource.api_request import ApiRequestQuery
|
|
15
|
+
from ul_api_utils.api_resource.api_resource import ApiResource
|
|
16
|
+
from ul_api_utils.api_resource.api_resource_config import ApiResourceConfig
|
|
17
|
+
from ul_api_utils.api_resource.api_response import FileApiResponse, JsonApiResponsePayload, JsonApiResponse, \
|
|
18
|
+
AnyJsonApiResponse, ProxyJsonApiResponse, HtmlApiResponse, EmptyJsonApiResponse
|
|
19
|
+
from ul_api_utils.errors import Server5XXInternalApiError, NoResultFoundApiError, Client4XXInternalApiError
|
|
20
|
+
from ul_api_utils.internal_api.internal_api import InternalApi
|
|
21
|
+
from ul_api_utils.utils.api_encoding import ApiEncoding
|
|
22
|
+
from ul_api_utils.resources.health_check.health_check import HealthCheckContext
|
|
23
|
+
from ul_api_utils.validators.custom_fields import QueryParamsSeparatedList
|
|
24
|
+
|
|
25
|
+
internal_api = InternalApi(
|
|
26
|
+
entry_point='http://localhost:5000',
|
|
27
|
+
default_auth_token='',
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
internal_api_another_service = InternalApi(
|
|
31
|
+
entry_point='http://localhost:5000',
|
|
32
|
+
default_auth_token='',
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
internal_api_gzip = InternalApi(
|
|
36
|
+
entry_point='http://localhost:5000',
|
|
37
|
+
default_auth_token='',
|
|
38
|
+
force_encoding=ApiEncoding.GZIP,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class RespObject(JsonApiResponsePayload):
|
|
43
|
+
now: datetime
|
|
44
|
+
notes: str = ''
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class Eeenum(IntEnum):
|
|
48
|
+
one = 1
|
|
49
|
+
two = 2
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class SomeBody(BaseModel):
|
|
53
|
+
seconds: float
|
|
54
|
+
eenum: Optional[Eeenum] = None
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class Some2Query(ApiRequestQuery):
|
|
58
|
+
sleep: float = 0.4
|
|
59
|
+
some: QueryParamsSeparatedList[str] = '' # type: ignore
|
|
60
|
+
eenum: Optional[Eeenum]
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
logger = logging.getLogger(__name__)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@sdk.rest_api('POST', '/example-resource-simple', access=sdk.ACCESS_PUBLIC)
|
|
67
|
+
@sdk.cache_api('REFRESH', 'example')
|
|
68
|
+
def some5(api_resource: ApiResource, body: SomeBody) -> JsonApiResponse[List[RespObject]]:
|
|
69
|
+
"""
|
|
70
|
+
The API returns user details for a given username.
|
|
71
|
+
The API can be invoked using *curl* like below:
|
|
72
|
+
```
|
|
73
|
+
curl --header accept: application/json -u username:password http://localhost:8080/api/v2/user/jhondoe
|
|
74
|
+
```
|
|
75
|
+
**Sample Output**
|
|
76
|
+
```
|
|
77
|
+
{
|
|
78
|
+
"id": 2,
|
|
79
|
+
"username": "jhondoe"
|
|
80
|
+
"email": "jhon.doe@mail.com"
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
"""
|
|
84
|
+
return api_resource.response_ok([
|
|
85
|
+
RespObject(now=datetime.now() + timedelta(seconds=body.seconds)),
|
|
86
|
+
RespObject(now=datetime.now() + timedelta(seconds=body.seconds * 2)),
|
|
87
|
+
], 2)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class Eennum(Enum):
|
|
91
|
+
one = 'one'
|
|
92
|
+
two = 'two'
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class Some7Query(ApiRequestQuery):
|
|
96
|
+
need_redirect: int
|
|
97
|
+
eenum: Optional[Eeenum]
|
|
98
|
+
eennum: Optional[Eennum]
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@sdk.rest_api('POST', '/example-resource-simple-any', access=sdk.ACCESS_PUBLIC)
|
|
102
|
+
@sdk.cache_api('READ', 'example')
|
|
103
|
+
def some9(api_resource: ApiResource) -> AnyJsonApiResponse:
|
|
104
|
+
return api_resource.response_ok([RespObject(now=datetime.now(), notes="some9")], 1)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@sdk.rest_api('POST', '/example-resource-simple-any-private', access=SOME_PERMISSION)
|
|
108
|
+
def some9private(api_resource: ApiResource) -> AnyJsonApiResponse:
|
|
109
|
+
return api_resource.response_ok([RespObject(now=datetime.now(), notes="some9")], 1)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@sdk.rest_api('POST', '/example-resource-simple-any-private2222', access=SOME_PERMISSION2)
|
|
113
|
+
def some9private2222(api_resource: ApiResource) -> AnyJsonApiResponse:
|
|
114
|
+
return api_resource.response_ok([RespObject(now=datetime.now(), notes="some9")], 1)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@sdk.rest_api('POST', '/example-resource-simple-proxy', access=sdk.ACCESS_PUBLIC)
|
|
118
|
+
def some8(api_resource: ApiResource) -> JsonApiResponse[List[RespObject]]:
|
|
119
|
+
return api_resource.response_ok([RespObject(now=datetime.now(), notes="some8")], 1)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@sdk.rest_api('POST', '/example-resource-simple-redirect-or-json', access=sdk.ACCESS_PUBLIC)
|
|
123
|
+
def some7(api_resource: ApiResource, query: Some7Query) -> JsonApiResponse[List[RespObject]]:
|
|
124
|
+
if query.need_redirect > 0:
|
|
125
|
+
return api_resource.response_redirect(sdk.url_for('some8')) # type: ignore
|
|
126
|
+
return api_resource.response_ok([RespObject(now=datetime.now(), notes="some7")], 1)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@sdk.rest_api('GET', '/example-resource-simple-proxy', access=sdk.ACCESS_PUBLIC)
|
|
130
|
+
def some6(api_resource: ApiResource) -> ProxyJsonApiResponse[List[RespObject]]: # type: ignore
|
|
131
|
+
res = internal_api.request_post('/example-resource-simple-any', json={'seconds': 123}).typed(List[RespObject]).check()
|
|
132
|
+
assert res.payload[0].now is not None
|
|
133
|
+
|
|
134
|
+
return api_resource.response_proxy(res)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@sdk.rest_api('GET', '/example-limiter', access=sdk.ACCESS_PUBLIC)
|
|
138
|
+
def some6limit(api_resource: ApiResource) -> JsonApiResponse[List[RespObject]]:
|
|
139
|
+
return api_resource.response_ok([
|
|
140
|
+
RespObject(now=datetime.now() + timedelta(seconds=4)),
|
|
141
|
+
RespObject(now=datetime.now() + timedelta(seconds=5 * 2)),
|
|
142
|
+
], 2)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@sdk.rest_api('POST', '/example-resource-simple-list', access=sdk.ACCESS_PUBLIC)
|
|
146
|
+
def some4(api_resource: ApiResource, body: List[SomeBody]) -> JsonApiResponse[List[RespObject]]:
|
|
147
|
+
return api_resource.response_ok([
|
|
148
|
+
RespObject(now=datetime.now() + timedelta(seconds=body[0].seconds)),
|
|
149
|
+
RespObject(now=datetime.now() + timedelta(seconds=body[0].seconds * 2)),
|
|
150
|
+
], 2)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
@sdk.rest_api('POST', '/example-resource-simple-list-err', access=sdk.ACCESS_PUBLIC)
|
|
154
|
+
def some4err(api_resource: ApiResource, body: List[SomeBody]) -> JsonApiResponse[List[RespObject]]:
|
|
155
|
+
raise ValueError('some error')
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@sdk.rest_api('GET', '/example-resource-simple-not-found', access=sdk.ACCESS_PUBLIC)
|
|
159
|
+
def some5err(api_resource: ApiResource) -> JsonApiResponse[List[RespObject]]:
|
|
160
|
+
raise NoResultFoundApiError()
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
@sdk.health_check()
|
|
164
|
+
def health_check(context: HealthCheckContext) -> None:
|
|
165
|
+
def function_raises_error_example() -> None:
|
|
166
|
+
raise TypeError('blabla')
|
|
167
|
+
|
|
168
|
+
context.add_step("Function_raises_error_example", function_raises_error_example)
|
|
169
|
+
context.check_database_connection_exists()
|
|
170
|
+
context.check_internal_api_route(
|
|
171
|
+
internal_api,
|
|
172
|
+
"Check Example with 1 second sleep",
|
|
173
|
+
'/example-resource-for-loong-sleep',
|
|
174
|
+
q={'sleep': 1},
|
|
175
|
+
)
|
|
176
|
+
context.check_internal_api_route(
|
|
177
|
+
internal_api,
|
|
178
|
+
"Check another example",
|
|
179
|
+
'/example-resource-empty',
|
|
180
|
+
)
|
|
181
|
+
context.check_internal_api_health(internal_api_another_service, "SELF_API")
|
|
182
|
+
# context.check_message_queues_health(
|
|
183
|
+
# uni,
|
|
184
|
+
# override_limits = {
|
|
185
|
+
# "some_queue_name": HealthCheckMessageQueueRange(ok=2, warn=100),
|
|
186
|
+
# }
|
|
187
|
+
# )
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
@sdk.rest_api('GET', '/example-resource', access=sdk.ACCESS_PUBLIC)
|
|
191
|
+
@sdk.cache_api('READ', ('example', 'resource', 'simple'))
|
|
192
|
+
def some3(api_resource: ApiResource) -> JsonApiResponse[RespObject]:
|
|
193
|
+
api_resource.logger.info('some 1')
|
|
194
|
+
sleep(0.1)
|
|
195
|
+
sess = db.session()
|
|
196
|
+
sess.execute('SELECT * FROM information_schema.tables WHERE table_schema = \'pg_catalog\' LIMIT 4;')
|
|
197
|
+
api_resource.logger.info('some 2')
|
|
198
|
+
internal_api.request_get('/example-resource-for-loong-sleep', q={"sleep": 0.1}).check()
|
|
199
|
+
api_resource.logger.info('some 3')
|
|
200
|
+
internal_api.request_post('/example-resource-simple', q={"sleep": 0.1}, json={"seconds": 123}).check()
|
|
201
|
+
api_resource.logger.info('some 4')
|
|
202
|
+
internal_api.request_post('/example-resource-simple-list', q={"sleep": 0.1}, json=[{"seconds": 123}]).check()
|
|
203
|
+
api_resource.logger.info('some 5')
|
|
204
|
+
internal_api.request_post('/example-resource-simple-proxy', q={"sleep": 0.1}, json={"seconds": 123}).check()
|
|
205
|
+
api_resource.logger.info('some 6')
|
|
206
|
+
internal_api.request_post('/example-resource-simple-any', q={"sleep": 0.1}, json={"seconds": 123}).check()
|
|
207
|
+
api_resource.logger.info('some 7')
|
|
208
|
+
internal_api.request_post('/example-resource-simple-redirect-or-json', q={"need_redirect": 3}, json={"seconds": 123}).check()
|
|
209
|
+
api_resource.logger.info('some 8')
|
|
210
|
+
internal_api.request_post('/example-resource-simple-redirect-or-json', q={"need_redirect": -3}, json={"seconds": 123}).check()
|
|
211
|
+
api_resource.logger.info('some 9')
|
|
212
|
+
sess.execute('SELECT * FROM information_schema.tables LIMIT 4;')
|
|
213
|
+
api_resource.logger.info('some 10')
|
|
214
|
+
return api_resource.response_ok(RespObject(now=datetime.now()))
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
@sdk.html_view(('GET', 'OPTIONS'), '/example-resource-for-loong-sleep', access=sdk.ACCESS_PUBLIC)
|
|
218
|
+
def some2html(api_resource: ApiResource, query: Some2Query) -> HtmlApiResponse:
|
|
219
|
+
raise NoResultFoundApiError()
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
@sdk.rest_api('GET', '/example-resource-for-loong-sleep', access=sdk.ACCESS_PUBLIC)
|
|
223
|
+
@sdk.cache_api('READ', ('example', 'resource', 'simple'))
|
|
224
|
+
def some2(api_resource: ApiResource, query: Some2Query) -> JsonApiResponse[RespObject]:
|
|
225
|
+
sess = db.session()
|
|
226
|
+
sess.execute('SELECT * FROM information_schema.tables LIMIT 3;')
|
|
227
|
+
sleep(query.sleep)
|
|
228
|
+
sess.execute('SELECT * FROM information_schema.tables LIMIT 3;')
|
|
229
|
+
return api_resource.response_ok(RespObject(now=datetime.now()))
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
@sdk.rest_api('GET', '/example-resource-empty', access=sdk.ACCESS_PUBLIC)
|
|
233
|
+
@sdk.cache_api('READ', ('example', 'resource'))
|
|
234
|
+
def some1(api_resource: ApiResource) -> JsonApiResponse[RespObject]:
|
|
235
|
+
return api_resource.response_ok(RespObject(now=datetime.now()))
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def test_override(res: Tuple[BaseResponse, int]) -> Tuple[BaseResponse, int]:
|
|
239
|
+
return jsonify({'this is test': 'test'}), 500
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
@sdk.rest_api('GET', '/example-resource-override', access=sdk.ACCESS_PUBLIC, config=ApiResourceConfig(override_flask_response=test_override))
|
|
243
|
+
def override(api_resource: ApiResource) -> JsonApiResponse[RespObject]:
|
|
244
|
+
return api_resource.response_ok(RespObject(now=datetime.now()))
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
@sdk.rest_api('GET', '/example-resource-empty', access=sdk.ACCESS_PUBLIC)
|
|
248
|
+
def empty_resp_test(api_resource: ApiResource) -> EmptyJsonApiResponse:
|
|
249
|
+
return api_resource.response_empty_ok()
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
@sdk.rest_api('POST', '/example-resource-empty-check', access=sdk.ACCESS_PUBLIC)
|
|
253
|
+
def empty_resp_req_test(api_resource: ApiResource) -> EmptyJsonApiResponse:
|
|
254
|
+
internal_api.request_get('/example-resource-empty').check()
|
|
255
|
+
return api_resource.response_empty_ok()
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
@sdk.rest_api('POST', '/example-resource-empty-gzip', access=sdk.ACCESS_PUBLIC)
|
|
259
|
+
def some12(api_resource: ApiResource, body: List[SomeBody]) -> JsonApiResponse[RespObject]:
|
|
260
|
+
sess = db.session()
|
|
261
|
+
sess.execute('SELECT * FROM information_schema.tables LIMIT 3;')
|
|
262
|
+
sleep(body[0].seconds)
|
|
263
|
+
return api_resource.response_ok(RespObject(now=datetime.now()))
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
@sdk.html_view(('GET', 'POST'), '/', access=sdk.ACCESS_PUBLIC)
|
|
267
|
+
@sdk.cache_api('READ', 'some')
|
|
268
|
+
def view_home(api_resource: ApiResource, body: Optional[List[SomeBody]]) -> HtmlApiResponse:
|
|
269
|
+
sleep(0.02)
|
|
270
|
+
sess = db.session()
|
|
271
|
+
|
|
272
|
+
resp = internal_api.request_get('/example-resource-simple-not-found')
|
|
273
|
+
try:
|
|
274
|
+
resp.check()
|
|
275
|
+
except Client4XXInternalApiError:
|
|
276
|
+
pass
|
|
277
|
+
|
|
278
|
+
sess.execute('SELECT * FROM information_schema.tables LIMIT 100;')
|
|
279
|
+
res = internal_api.request_get('/example-resource-empty').check()
|
|
280
|
+
res2 = internal_api_gzip.request_post('/example-resource-empty-gzip', json=[{"seconds": 0.7} for i in range(1000)]).check()
|
|
281
|
+
|
|
282
|
+
assert isinstance(res.payload_raw, dict)
|
|
283
|
+
assert isinstance(res2.payload_raw, dict)
|
|
284
|
+
assert res.payload_raw['now'] is not None
|
|
285
|
+
sess.execute('SELECT * FROM information_schema.tables LIMIT 100;')
|
|
286
|
+
sleep(0.3)
|
|
287
|
+
|
|
288
|
+
try:
|
|
289
|
+
internal_api.request_get('/example-resource').check()
|
|
290
|
+
except Server5XXInternalApiError:
|
|
291
|
+
pass
|
|
292
|
+
|
|
293
|
+
try:
|
|
294
|
+
internal_api.request_get('/example-resource-override').check()
|
|
295
|
+
except Server5XXInternalApiError:
|
|
296
|
+
pass
|
|
297
|
+
|
|
298
|
+
resp = internal_api.request_get('/example-resource-for-405')
|
|
299
|
+
try:
|
|
300
|
+
resp.check()
|
|
301
|
+
except Server5XXInternalApiError:
|
|
302
|
+
pass
|
|
303
|
+
|
|
304
|
+
sess.execute('SELECT * FROM information_schema.tables LIMIT 100;')
|
|
305
|
+
try:
|
|
306
|
+
internal_api.request_get('/example-resource-for-loong-sleep', q={"sleep": 0.4, "some": "1,2,3"}).check()
|
|
307
|
+
except Server5XXInternalApiError:
|
|
308
|
+
pass
|
|
309
|
+
sess.execute('SELECT * FROM information_schema.tables LIMIT 100;')
|
|
310
|
+
internal_api.request_get('/example-resource-for-loong-sleep', q={"sleep": 0.2, "some": "1,2,3"}).check()
|
|
311
|
+
try:
|
|
312
|
+
internal_api.request_post('/example-resource-simple-list-err', q={"sleep": 0.1}, json=[{"seconds": 123}]).check()
|
|
313
|
+
except Server5XXInternalApiError:
|
|
314
|
+
pass
|
|
315
|
+
|
|
316
|
+
internal_api.request_get('/permissions').check()
|
|
317
|
+
|
|
318
|
+
sleep(0.02)
|
|
319
|
+
return api_resource.response_template('home.html.jinja2')
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
@sdk.file_download('GET', '/example-send-temp-file', access=sdk.ACCESS_PUBLIC)
|
|
323
|
+
def somefile(api_resource: ApiResource) -> FileApiResponse:
|
|
324
|
+
fn = api_resource.mk_tmp_file()
|
|
325
|
+
|
|
326
|
+
with open(fn, 'wt') as f:
|
|
327
|
+
for i in range(1000_000):
|
|
328
|
+
f.write(f'test {i}\n')
|
|
329
|
+
|
|
330
|
+
return api_resource.response_file_ok(
|
|
331
|
+
path_or_file=fn,
|
|
332
|
+
mimetype='text/plain',
|
|
333
|
+
as_attachment=True,
|
|
334
|
+
attachment_filename='import_devices_log.txt',
|
|
335
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from flask import request
|
|
4
|
+
from flask_socketio import emit # type: ignore
|
|
5
|
+
|
|
6
|
+
from example.conf import sdk
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@sdk.socket.on('connect')
|
|
13
|
+
def handle_connect() -> None:
|
|
14
|
+
logger.info("Connected!")
|
|
15
|
+
logger.info("SESSION INFO: " + str(request.sid)) # type: ignore
|
|
16
|
+
emit('message', {"data1": 1, "data": 2}, room=request.sid, broadcast=True) # type: ignore
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from flask import request
|
|
4
|
+
|
|
5
|
+
from example.conf import sdk
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@sdk.socket.on('disconnect')
|
|
12
|
+
def disconnect() -> None:
|
|
13
|
+
logger.info("Client disconnected!")
|
|
14
|
+
logger.info("SESSION INFO: " + str(request.sid)) # type: ignore
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from flask import request
|
|
4
|
+
from flask_socketio import emit # type: ignore
|
|
5
|
+
|
|
6
|
+
from example.conf import sdk
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@sdk.socket.on('open')
|
|
13
|
+
def handle_open() -> None:
|
|
14
|
+
logger.info("Connected!")
|
|
15
|
+
logger.info("SESSION INFO: " + str(request.sid)) # type: ignore
|
|
16
|
+
emit('message', {"data1": 1, "data": 2}, room=request.sid, broadcast=True) # type: ignore
|
|
File without changes
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from ul_unipipeline.message.uni_message import UniMessage
|
|
2
|
+
from ul_unipipeline.worker.uni_worker import UniWorker
|
|
3
|
+
from ul_unipipeline.worker.uni_worker_consumer_message import UniWorkerConsumerMessage
|
|
4
|
+
|
|
5
|
+
from ul_api_utils.modules.worker_context import WorkerContext
|
|
6
|
+
from ul_api_utils.modules.worker_sdk import WorkerSdk
|
|
7
|
+
from ul_api_utils.modules.worker_sdk_config import WorkerSdkConfig
|
|
8
|
+
from ul_api_utils.resources.socketio import SocketIOConfig, SocketIOConfigType
|
|
9
|
+
|
|
10
|
+
initialized_worker = WorkerSdk(WorkerSdkConfig(
|
|
11
|
+
socket_config=SocketIOConfig(
|
|
12
|
+
app_type=SocketIOConfigType.EXTERNAL_PROCESS,
|
|
13
|
+
message_queue='redis://localhost:16379',
|
|
14
|
+
logs_enabled=True,
|
|
15
|
+
engineio_logs_enabled=False,
|
|
16
|
+
),
|
|
17
|
+
))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Msg(UniMessage):
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class HttpNbfiParserWorker(UniWorker[Msg, None]):
|
|
25
|
+
|
|
26
|
+
@initialized_worker.handle_message() # type: ignore
|
|
27
|
+
def handle_message(self, ctx: WorkerContext, message: UniWorkerConsumerMessage[Msg]) -> None:
|
|
28
|
+
pass
|
ul_api_utils/__init__.py
ADDED
|
File without changes
|