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.
Files changed (156) hide show
  1. example/__init__.py +0 -0
  2. example/conf.py +35 -0
  3. example/main.py +24 -0
  4. example/models/__init__.py +0 -0
  5. example/permissions.py +6 -0
  6. example/pure_flask_example.py +65 -0
  7. example/rate_limit_load.py +10 -0
  8. example/redis_repository.py +22 -0
  9. example/routes/__init__.py +0 -0
  10. example/routes/api_some.py +335 -0
  11. example/sockets/__init__.py +0 -0
  12. example/sockets/on_connect.py +16 -0
  13. example/sockets/on_disconnect.py +14 -0
  14. example/sockets/on_json.py +10 -0
  15. example/sockets/on_message.py +13 -0
  16. example/sockets/on_open.py +16 -0
  17. example/workers/__init__.py +0 -0
  18. example/workers/worker.py +28 -0
  19. ul_api_utils/__init__.py +0 -0
  20. ul_api_utils/access/__init__.py +122 -0
  21. ul_api_utils/api_resource/__init__.py +0 -0
  22. ul_api_utils/api_resource/api_request.py +105 -0
  23. ul_api_utils/api_resource/api_resource.py +414 -0
  24. ul_api_utils/api_resource/api_resource_config.py +20 -0
  25. ul_api_utils/api_resource/api_resource_error_handling.py +21 -0
  26. ul_api_utils/api_resource/api_resource_fn_typing.py +356 -0
  27. ul_api_utils/api_resource/api_resource_type.py +16 -0
  28. ul_api_utils/api_resource/api_response.py +300 -0
  29. ul_api_utils/api_resource/api_response_db.py +26 -0
  30. ul_api_utils/api_resource/api_response_payload_alias.py +25 -0
  31. ul_api_utils/api_resource/db_types.py +9 -0
  32. ul_api_utils/api_resource/signature_check.py +41 -0
  33. ul_api_utils/commands/__init__.py +0 -0
  34. ul_api_utils/commands/cmd_enc_keys.py +172 -0
  35. ul_api_utils/commands/cmd_gen_api_user_token.py +77 -0
  36. ul_api_utils/commands/cmd_gen_new_api_user.py +106 -0
  37. ul_api_utils/commands/cmd_generate_api_docs.py +181 -0
  38. ul_api_utils/commands/cmd_start.py +110 -0
  39. ul_api_utils/commands/cmd_worker_start.py +76 -0
  40. ul_api_utils/commands/start/__init__.py +0 -0
  41. ul_api_utils/commands/start/gunicorn.conf.local.py +0 -0
  42. ul_api_utils/commands/start/gunicorn.conf.py +26 -0
  43. ul_api_utils/commands/start/wsgi.py +22 -0
  44. ul_api_utils/conf/ul-debugger-main.js +1 -0
  45. ul_api_utils/conf/ul-debugger-ui.js +1 -0
  46. ul_api_utils/conf.py +70 -0
  47. ul_api_utils/const.py +78 -0
  48. ul_api_utils/debug/__init__.py +0 -0
  49. ul_api_utils/debug/debugger.py +119 -0
  50. ul_api_utils/debug/malloc.py +93 -0
  51. ul_api_utils/debug/stat.py +444 -0
  52. ul_api_utils/encrypt/__init__.py +0 -0
  53. ul_api_utils/encrypt/encrypt_decrypt_abstract.py +15 -0
  54. ul_api_utils/encrypt/encrypt_decrypt_aes_xtea.py +59 -0
  55. ul_api_utils/errors.py +200 -0
  56. ul_api_utils/internal_api/__init__.py +0 -0
  57. ul_api_utils/internal_api/__tests__/__init__.py +0 -0
  58. ul_api_utils/internal_api/__tests__/internal_api.py +29 -0
  59. ul_api_utils/internal_api/__tests__/internal_api_content_type.py +22 -0
  60. ul_api_utils/internal_api/internal_api.py +369 -0
  61. ul_api_utils/internal_api/internal_api_check_context.py +42 -0
  62. ul_api_utils/internal_api/internal_api_error.py +17 -0
  63. ul_api_utils/internal_api/internal_api_response.py +296 -0
  64. ul_api_utils/main.py +29 -0
  65. ul_api_utils/modules/__init__.py +0 -0
  66. ul_api_utils/modules/__tests__/__init__.py +0 -0
  67. ul_api_utils/modules/__tests__/test_api_sdk_jwt.py +195 -0
  68. ul_api_utils/modules/api_sdk.py +555 -0
  69. ul_api_utils/modules/api_sdk_config.py +63 -0
  70. ul_api_utils/modules/api_sdk_jwt.py +377 -0
  71. ul_api_utils/modules/intermediate_state.py +34 -0
  72. ul_api_utils/modules/worker_context.py +35 -0
  73. ul_api_utils/modules/worker_sdk.py +109 -0
  74. ul_api_utils/modules/worker_sdk_config.py +13 -0
  75. ul_api_utils/py.typed +0 -0
  76. ul_api_utils/resources/__init__.py +0 -0
  77. ul_api_utils/resources/caching.py +196 -0
  78. ul_api_utils/resources/debugger_scripts.py +97 -0
  79. ul_api_utils/resources/health_check/__init__.py +0 -0
  80. ul_api_utils/resources/health_check/const.py +2 -0
  81. ul_api_utils/resources/health_check/health_check.py +439 -0
  82. ul_api_utils/resources/health_check/health_check_template.py +64 -0
  83. ul_api_utils/resources/health_check/resource.py +97 -0
  84. ul_api_utils/resources/not_implemented.py +25 -0
  85. ul_api_utils/resources/permissions.py +29 -0
  86. ul_api_utils/resources/rate_limitter.py +84 -0
  87. ul_api_utils/resources/socketio.py +55 -0
  88. ul_api_utils/resources/swagger.py +119 -0
  89. ul_api_utils/resources/web_forms/__init__.py +0 -0
  90. ul_api_utils/resources/web_forms/custom_fields/__init__.py +0 -0
  91. ul_api_utils/resources/web_forms/custom_fields/custom_checkbox_select.py +5 -0
  92. ul_api_utils/resources/web_forms/custom_widgets/__init__.py +0 -0
  93. ul_api_utils/resources/web_forms/custom_widgets/custom_select_widget.py +86 -0
  94. ul_api_utils/resources/web_forms/custom_widgets/custom_text_input_widget.py +42 -0
  95. ul_api_utils/resources/web_forms/uni_form.py +75 -0
  96. ul_api_utils/sentry.py +52 -0
  97. ul_api_utils/utils/__init__.py +0 -0
  98. ul_api_utils/utils/__tests__/__init__.py +0 -0
  99. ul_api_utils/utils/__tests__/api_path_version.py +16 -0
  100. ul_api_utils/utils/__tests__/unwrap_typing.py +67 -0
  101. ul_api_utils/utils/api_encoding.py +51 -0
  102. ul_api_utils/utils/api_format.py +61 -0
  103. ul_api_utils/utils/api_method.py +55 -0
  104. ul_api_utils/utils/api_pagination.py +58 -0
  105. ul_api_utils/utils/api_path_version.py +60 -0
  106. ul_api_utils/utils/api_request_info.py +6 -0
  107. ul_api_utils/utils/avro.py +131 -0
  108. ul_api_utils/utils/broker_topics_message_count.py +47 -0
  109. ul_api_utils/utils/cached_per_request.py +23 -0
  110. ul_api_utils/utils/colors.py +31 -0
  111. ul_api_utils/utils/constants.py +7 -0
  112. ul_api_utils/utils/decode_base64.py +9 -0
  113. ul_api_utils/utils/deprecated.py +19 -0
  114. ul_api_utils/utils/flags.py +29 -0
  115. ul_api_utils/utils/flask_swagger_generator/__init__.py +0 -0
  116. ul_api_utils/utils/flask_swagger_generator/conf.py +4 -0
  117. ul_api_utils/utils/flask_swagger_generator/exceptions.py +7 -0
  118. ul_api_utils/utils/flask_swagger_generator/specifiers/__init__.py +0 -0
  119. ul_api_utils/utils/flask_swagger_generator/specifiers/swagger_models.py +57 -0
  120. ul_api_utils/utils/flask_swagger_generator/specifiers/swagger_specifier.py +48 -0
  121. ul_api_utils/utils/flask_swagger_generator/specifiers/swagger_three_specifier.py +777 -0
  122. ul_api_utils/utils/flask_swagger_generator/specifiers/swagger_version.py +40 -0
  123. ul_api_utils/utils/flask_swagger_generator/utils/__init__.py +0 -0
  124. ul_api_utils/utils/flask_swagger_generator/utils/input_type.py +77 -0
  125. ul_api_utils/utils/flask_swagger_generator/utils/parameter_type.py +51 -0
  126. ul_api_utils/utils/flask_swagger_generator/utils/replace_in_dict.py +18 -0
  127. ul_api_utils/utils/flask_swagger_generator/utils/request_type.py +52 -0
  128. ul_api_utils/utils/flask_swagger_generator/utils/schema_type.py +15 -0
  129. ul_api_utils/utils/flask_swagger_generator/utils/security_type.py +39 -0
  130. ul_api_utils/utils/imports.py +16 -0
  131. ul_api_utils/utils/instance_checks.py +16 -0
  132. ul_api_utils/utils/jinja/__init__.py +0 -0
  133. ul_api_utils/utils/jinja/t_url_for.py +19 -0
  134. ul_api_utils/utils/jinja/to_pretty_json.py +11 -0
  135. ul_api_utils/utils/json_encoder.py +126 -0
  136. ul_api_utils/utils/load_modules.py +15 -0
  137. ul_api_utils/utils/memory_db/__init__.py +0 -0
  138. ul_api_utils/utils/memory_db/__tests__/__init__.py +0 -0
  139. ul_api_utils/utils/memory_db/errors.py +8 -0
  140. ul_api_utils/utils/memory_db/repository.py +102 -0
  141. ul_api_utils/utils/token_check.py +14 -0
  142. ul_api_utils/utils/token_check_through_request.py +16 -0
  143. ul_api_utils/utils/unwrap_typing.py +117 -0
  144. ul_api_utils/utils/uuid_converter.py +22 -0
  145. ul_api_utils/validators/__init__.py +0 -0
  146. ul_api_utils/validators/__tests__/__init__.py +0 -0
  147. ul_api_utils/validators/__tests__/test_custom_fields.py +32 -0
  148. ul_api_utils/validators/custom_fields.py +66 -0
  149. ul_api_utils/validators/validate_empty_object.py +10 -0
  150. ul_api_utils/validators/validate_uuid.py +11 -0
  151. ul_api_utils-9.3.0.dist-info/LICENSE +21 -0
  152. ul_api_utils-9.3.0.dist-info/METADATA +279 -0
  153. ul_api_utils-9.3.0.dist-info/RECORD +156 -0
  154. ul_api_utils-9.3.0.dist-info/WHEEL +5 -0
  155. ul_api_utils-9.3.0.dist-info/entry_points.txt +2 -0
  156. 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,10 @@
1
+ import requests
2
+
3
+
4
+ max_lim = 10000
5
+
6
+
7
+ for i in range(max_lim):
8
+ resp = requests.get('http://localhost:5001/api/v1/example-send-temp-file')
9
+ print(f'{i}/{max_lim} = {resp.status_code}') # noqa
10
+ resp.raise_for_status()
@@ -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,10 @@
1
+ from typing import Any
2
+
3
+ from flask_socketio import send # type: ignore
4
+
5
+ from example.conf import sdk
6
+
7
+
8
+ @sdk.socket.on('json')
9
+ def handle_json(json: dict[str, Any]) -> None:
10
+ send(json, json=True)
@@ -0,0 +1,13 @@
1
+ import logging
2
+ from typing import Any
3
+
4
+ from example.conf import sdk
5
+
6
+
7
+ logger = logging.getLogger(__name__)
8
+
9
+
10
+ @sdk.socket.on('message')
11
+ def handle_message(data: Any) -> None:
12
+ logger.info('received message: ')
13
+ logger.info(data)
@@ -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
File without changes