UncountablePythonSDK 0.0.179__py3-none-any.whl → 0.0.181__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.
- examples/integration-server/jobs/materials_auto/example_http.py +6 -6
- examples/integration-server/jobs/materials_auto/example_instrument.py +3 -4
- examples/integration-server/pyproject.toml +141 -141
- examples/stream_dataset_measurements.py +196 -0
- pkgs/argument_parser/__init__.py +7 -1
- pkgs/argument_parser/cached_parser.py +69 -2
- pkgs/argument_parser/parser_inner.py +23 -2
- pkgs/filesystem_utils/__init__.py +2 -2
- pkgs/filesystem_utils/_blob_session.py +5 -5
- pkgs/filesystem_utils/_file_share_session.py +5 -5
- pkgs/filesystem_utils/_gdrive_session.py +8 -8
- pkgs/filesystem_utils/_local_session.py +4 -4
- pkgs/filesystem_utils/_s3_session.py +4 -4
- pkgs/filesystem_utils/_sftp_session.py +4 -4
- pkgs/filesystem_utils/file_type_utils.py +1 -1
- pkgs/serialization/__init__.py +1 -0
- pkgs/serialization/usage.py +17 -0
- pkgs/serialization/yaml.py +2 -1
- pkgs/serialization_util/__init__.py +2 -0
- pkgs/serialization_util/convert_to_snakecase.py +9 -1
- pkgs/serialization_util/dataclasses.py +2 -1
- pkgs/type_spec/__main__.py +4 -0
- pkgs/type_spec/actions_registry/__main__.py +2 -1
- pkgs/type_spec/actions_registry/emit_python.py +9 -0
- pkgs/type_spec/actions_registry/emit_typescript.py +12 -0
- pkgs/type_spec/builder.py +251 -38
- pkgs/type_spec/config.py +42 -2
- pkgs/type_spec/cross_output_links.py +1 -2
- pkgs/type_spec/emit_io_ts.py +3 -0
- pkgs/type_spec/emit_open_api.py +57 -52
- pkgs/type_spec/emit_python.py +40 -21
- pkgs/type_spec/emit_scss.py +42 -0
- pkgs/type_spec/emit_typescript_util.py +41 -11
- pkgs/type_spec/load_types.py +9 -2
- pkgs/type_spec/parts/base.ts.prepart +7 -0
- pkgs/type_spec/type_info/emit_type_info.py +19 -6
- pkgs/type_spec/ui_entry_actions/generate_ui_entry_actions.py +6 -6
- pkgs/type_spec/util.py +1 -2
- pkgs/type_spec/value_spec/__init__.py +6 -1
- pkgs/type_spec/value_spec/__main__.py +8 -7
- uncountable/core/client.py +1 -2
- uncountable/core/environment.py +4 -0
- uncountable/core/file_upload.py +2 -1
- uncountable/core/query/builder.py +8 -4
- uncountable/integration/cli.py +1 -1
- uncountable/integration/db/connect.py +4 -0
- uncountable/integration/db/session.py +1 -1
- uncountable/integration/executors/generic_upload_executor.py +4 -2
- uncountable/integration/executors/script_executor.py +2 -1
- uncountable/integration/http_server/types.py +12 -0
- uncountable/integration/queue_runner/command_server/command_client.py +8 -8
- uncountable/integration/queue_runner/command_server/command_server.py +3 -6
- uncountable/integration/queue_runner/datastore/__init__.py +1 -0
- uncountable/integration/queue_runner/job_process.py +78 -0
- uncountable/integration/queue_runner/job_runner.py +168 -0
- uncountable/integration/queue_runner/job_scheduler.py +19 -2
- uncountable/integration/queue_runner/queue_runner.py +9 -2
- uncountable/integration/queue_runner/worker.py +3 -152
- uncountable/integration/scheduler.py +41 -19
- uncountable/integration/secret_retrieval/basic_secret.py +1 -2
- uncountable/integration/server.py +8 -1
- uncountable/integration/telemetry.py +3 -3
- uncountable/integration/webhook_server/admin_auth.py +38 -0
- uncountable/integration/webhook_server/admin_routes.py +49 -0
- uncountable/integration/webhook_server/entrypoint.py +2 -0
- uncountable/types/__init__.py +12 -0
- uncountable/types/api/condition_parameters/upsert_condition_match.py +1 -1
- uncountable/types/api/ml/__init__.py +1 -0
- uncountable/types/api/ml/get_analyze_results.py +56 -0
- uncountable/types/api/ml/get_suggest_results.py +69 -0
- uncountable/types/api/ml/submit_async_job.py +231 -0
- uncountable/types/api/notebooks/get_notebook_content.py +2 -1
- uncountable/types/api/recipes/get_recipes_data.py +1 -0
- uncountable/types/api/time_series/__init__.py +1 -0
- uncountable/types/api/time_series/ingest_dataset_measurements.py +45 -0
- uncountable/types/async_batch_processor.py +39 -1
- uncountable/types/async_batch_t.py +1 -0
- uncountable/types/client_base.py +65 -1
- uncountable/types/curves_t.py +4 -2
- uncountable/types/dataset_measurements.py +10 -0
- uncountable/types/dataset_measurements_t.py +60 -0
- uncountable/types/entity_t.py +25 -1
- uncountable/types/ml_reports.py +15 -0
- uncountable/types/ml_reports_t.py +138 -0
- uncountable/types/specs.py +4 -0
- uncountable/types/specs_t.py +50 -0
- {uncountablepythonsdk-0.0.179.dist-info → uncountablepythonsdk-0.0.181.dist-info}/METADATA +1 -1
- {uncountablepythonsdk-0.0.179.dist-info → uncountablepythonsdk-0.0.181.dist-info}/RECORD +90 -73
- {uncountablepythonsdk-0.0.179.dist-info → uncountablepythonsdk-0.0.181.dist-info}/WHEEL +1 -1
- {uncountablepythonsdk-0.0.179.dist-info → uncountablepythonsdk-0.0.181.dist-info}/top_level.txt +0 -0
|
@@ -23,9 +23,9 @@ class HttpExample(CustomHttpJob):
|
|
|
23
23
|
@staticmethod
|
|
24
24
|
def validate_request(
|
|
25
25
|
*,
|
|
26
|
-
request: GenericHttpRequest, #
|
|
27
|
-
job_definition: job_definition_t.HttpJobDefinitionBase, #
|
|
28
|
-
profile_meta: job_definition_t.ProfileMetadata, #
|
|
26
|
+
request: GenericHttpRequest, # ruff:ignore[unused-static-method-argument]
|
|
27
|
+
job_definition: job_definition_t.HttpJobDefinitionBase, # ruff:ignore[unused-static-method-argument]
|
|
28
|
+
profile_meta: job_definition_t.ProfileMetadata, # ruff:ignore[unused-static-method-argument]
|
|
29
29
|
) -> None:
|
|
30
30
|
if (
|
|
31
31
|
CustomHttpJob.get_validated_oauth_request_user_id(
|
|
@@ -40,8 +40,8 @@ class HttpExample(CustomHttpJob):
|
|
|
40
40
|
@staticmethod
|
|
41
41
|
def handle_request(
|
|
42
42
|
*,
|
|
43
|
-
request: GenericHttpRequest, #
|
|
44
|
-
job_definition: job_definition_t.HttpJobDefinitionBase, #
|
|
45
|
-
profile_meta: job_definition_t.ProfileMetadata, #
|
|
43
|
+
request: GenericHttpRequest, # ruff:ignore[unused-static-method-argument]
|
|
44
|
+
job_definition: job_definition_t.HttpJobDefinitionBase, # ruff:ignore[unused-static-method-argument]
|
|
45
|
+
profile_meta: job_definition_t.ProfileMetadata, # ruff:ignore[unused-static-method-argument]
|
|
46
46
|
) -> GenericHttpResponse:
|
|
47
47
|
return GenericHttpResponse(response="OK", status_code=200)
|
|
@@ -84,10 +84,9 @@ class InstrumentExample(WebhookJob[InstrumentPayload]):
|
|
|
84
84
|
num_users = len(message.user_ids)
|
|
85
85
|
if num_users <= 1:
|
|
86
86
|
break
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
)
|
|
87
|
+
args.logger.log_info(
|
|
88
|
+
f"Session still open, {num_users} users in room."
|
|
89
|
+
)
|
|
91
90
|
case _:
|
|
92
91
|
args.logger.log_info("Session still open...")
|
|
93
92
|
continue
|
|
@@ -9,7 +9,7 @@ dependencies = [
|
|
|
9
9
|
"ruff == 0.*",
|
|
10
10
|
"openpyxl == 3.*",
|
|
11
11
|
"more_itertools ==11.*",
|
|
12
|
-
"types-paramiko ==5.0.0.
|
|
12
|
+
"types-paramiko ==5.0.0.20260724",
|
|
13
13
|
"types-openpyxl == 3.*",
|
|
14
14
|
"types-pytz ==2026.*",
|
|
15
15
|
"types-requests == 2.*",
|
|
@@ -17,7 +17,7 @@ dependencies = [
|
|
|
17
17
|
"pandas-stubs",
|
|
18
18
|
"xlrd == 2.*",
|
|
19
19
|
"msgspec ==0.21.*",
|
|
20
|
-
"websockets==
|
|
20
|
+
"websockets==17.0",
|
|
21
21
|
]
|
|
22
22
|
|
|
23
23
|
[tool.mypy]
|
|
@@ -49,156 +49,156 @@ exclude = [
|
|
|
49
49
|
preview = true
|
|
50
50
|
lint.select = ['ALL']
|
|
51
51
|
lint.ignore = [
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
52
|
+
"builtin-variable-shadowing", # Variable shadows python built-in. Nice to have
|
|
53
|
+
"builtin-argument-shadowing", # Variable shadows python built-in. Nice to have
|
|
54
|
+
"builtin-attribute-shadowing", # Class attribute shadows python built-in. Nice to have
|
|
55
55
|
"ANN", # Missing type annotations. Skip in favor of mypy
|
|
56
56
|
"ARG", # Unused arguments. Skip
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
57
|
+
"mutable-argument-default", # Do not use mutable data structures for argument defaults. Priority.
|
|
58
|
+
"function-uses-loop-variable", # Function doesn't bind loop variable. Priority
|
|
59
|
+
"raise-without-from-inside-except", # Exception handling raise from. Skip
|
|
60
60
|
"BLE", # Blind exception. Should Add
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"
|
|
61
|
+
"unnecessary-generator-set", # Unecessary generator. Skip
|
|
62
|
+
"unnecessary-list-comprehension-set", # Unnecessary list comprehension. Skip
|
|
63
|
+
"unnecessary-literal-set", # Unnecessary list. rewrite as set. Skip
|
|
64
|
+
"unnecessary-collection-call", # Unnecessary dict call. Skip
|
|
65
|
+
"unnecessary-comprehension", # Unnecessary list comprehension. Skip
|
|
66
|
+
"unnecessary-map", # Unnecessary use of map. Should Add
|
|
67
|
+
"missing-trailing-comma", # Trailing comma. Too opinionated. Skip
|
|
68
68
|
"CPY", # Copyright notices. Skip
|
|
69
69
|
"D", # Docstrings. Skip
|
|
70
70
|
"DOC", # Docstrings. Skip
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
"
|
|
71
|
+
"call-datetime-without-tzinfo", # Missing tzinfo. Should add
|
|
72
|
+
"call-datetime-today", # Use of today instead of now. Should add
|
|
73
|
+
"call-datetime-utcnow", # Use of utcnow not allowed. Should add
|
|
74
|
+
"call-datetime-utcfromtimestamp", # Use of utcfrom timestamp not allowed. Should add
|
|
75
|
+
"call-datetime-now-without-tzinfo", # now without tz not allowed. Should add
|
|
76
|
+
"call-datetime-fromtimestamp", # use of from timestamp without tz not allowed. Should add
|
|
77
|
+
"call-datetime-strptime-without-zone", # replace timezone after strptime. Should add
|
|
78
|
+
"call-date-today", # Use of today not allowed. Should add
|
|
79
|
+
"line-too-long", # Line length. Skip
|
|
80
|
+
"raw-string-in-exception", # exception must not use a string literal. skip
|
|
81
|
+
"f-string-in-exception", # exception must not use an f string. skip
|
|
82
|
+
"dot-format-in-exception", # exception must not use a format string. skip
|
|
83
83
|
"ERA", # Rules around commented code. Skip
|
|
84
|
-
"
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
"
|
|
94
|
-
"
|
|
95
|
-
"
|
|
96
|
-
"
|
|
97
|
-
"
|
|
98
|
-
"
|
|
99
|
-
"
|
|
100
|
-
"
|
|
101
|
-
"
|
|
102
|
-
"
|
|
103
|
-
"
|
|
104
|
-
"
|
|
105
|
-
"
|
|
106
|
-
"
|
|
107
|
-
"
|
|
108
|
-
"
|
|
109
|
-
"
|
|
110
|
-
"
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
"
|
|
114
|
-
"
|
|
115
|
-
"
|
|
116
|
-
"
|
|
117
|
-
"
|
|
118
|
-
"
|
|
119
|
-
"
|
|
120
|
-
"
|
|
121
|
-
"
|
|
122
|
-
"
|
|
123
|
-
"
|
|
124
|
-
"
|
|
125
|
-
"
|
|
126
|
-
"
|
|
127
|
-
"
|
|
128
|
-
"
|
|
129
|
-
"
|
|
130
|
-
"
|
|
131
|
-
"
|
|
132
|
-
"
|
|
133
|
-
"
|
|
134
|
-
"
|
|
135
|
-
"
|
|
136
|
-
"
|
|
137
|
-
"
|
|
138
|
-
"
|
|
139
|
-
"
|
|
140
|
-
"
|
|
141
|
-
"
|
|
142
|
-
"
|
|
143
|
-
"
|
|
144
|
-
"
|
|
145
|
-
"
|
|
146
|
-
"
|
|
147
|
-
"
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
"
|
|
84
|
+
"shebang-missing-executable-file", # Executable files need shebang. Skip
|
|
85
|
+
"unused-variable", # TEMPORARY DISABLE TO CLEAR UP BUILD. Unused variables. Prioritize.
|
|
86
|
+
"boolean-type-hint-positional-argument", # boolean positional args. Skip
|
|
87
|
+
"boolean-default-value-positional-argument", # boolean default positional. Skip
|
|
88
|
+
"boolean-positional-value-in-call", # boolean positional. Skip
|
|
89
|
+
"line-contains-fixme", # Fixme comment. Skip
|
|
90
|
+
"line-contains-todo", # todo comment. Skip
|
|
91
|
+
"line-contains-hack", # hack comment. Skip
|
|
92
|
+
"static-join-to-f-string", # Use F-String instead of join. Should Add
|
|
93
|
+
"read-whole-file", # replace read function. Skip
|
|
94
|
+
"write-whole-file", # opinionated file opening. Skip
|
|
95
|
+
"repeated-append", # extend vs append. Skip
|
|
96
|
+
"reimplemented-operator", # opinionated rules about lambdas. skip
|
|
97
|
+
"reimplemented-starmap", # starmap vs generator. Skip
|
|
98
|
+
"logging-f-string", # avoid f strings in log statements. Should add
|
|
99
|
+
"implicit-namespace-package", # implicit imports. use __init__. Skip
|
|
100
|
+
"single-line-implicit-string-concatenation", # rule conflicts with formatter. Skip
|
|
101
|
+
"explicit-string-concatenation", # Explicitly concatenated string should be implicitly concatenated. Skip
|
|
102
|
+
"invalid-class-name", # class name case. Skip
|
|
103
|
+
"invalid-function-name", # function name lower case. Skip
|
|
104
|
+
"invalid-argument-name", # argument name lower cas. Skip
|
|
105
|
+
"invalid-first-argument-name-for-class-method", # cls_ first variable. Should add
|
|
106
|
+
"non-lowercase-variable-in-function", # lower case variable. Skip
|
|
107
|
+
"lowercase-imported-as-non-lowercase", # case consistency on import. Skip
|
|
108
|
+
"mixed-case-variable-in-class-scope", # mix casing, skip
|
|
109
|
+
"camelcase-imported-as-acronym", # don't use acronym. Should add
|
|
110
|
+
"error-suffix-on-exception-name", # exception override should be named with error. should add
|
|
111
|
+
"invalid-module-name", # module naming. Should add
|
|
112
|
+
"pandas-use-of-inplace-argument", # avoid inplace. Skip
|
|
113
|
+
"pandas-use-of-dot-not-null", # .notna. Should add
|
|
114
|
+
"pandas-use-of-dot-pivot-or-unstack", # .pivottable. Should add
|
|
115
|
+
"pandas-use-of-dot-values", # use .to_numpy. Skip
|
|
116
|
+
"pandas-use-of-pd-merge", # use .merge. Should add
|
|
117
|
+
"try-except-in-loop", # avoid try except in loop. Skip
|
|
118
|
+
"manual-list-comprehension", # use list comprehension. Skip
|
|
119
|
+
"manual-list-copy", # use list.copy. Skip
|
|
120
|
+
"manual-dict-comprehension", # use dictionary comprehension. Skip
|
|
121
|
+
"suspicious-eval-usage", # avoid eval. Should add
|
|
122
|
+
"blanket-type-ignore", # ignore specific rules. Skip
|
|
123
|
+
"blanket-noqa", # ignore specific rules. Skip
|
|
124
|
+
"useless-import-alias", # import alias doesn't rename. Skip
|
|
125
|
+
"import-outside-top-level", # import at top level. Skip
|
|
126
|
+
"compare-to-empty-string", # falsy empty string. Skip
|
|
127
|
+
"comparison-with-itself", # self comparison. Skip
|
|
128
|
+
"manual-from-import", # alias import. Skip
|
|
129
|
+
"too-many-return-statements", # too many return statements. Skip
|
|
130
|
+
"too-many-branches", # too many branches. Skip
|
|
131
|
+
"too-many-arguments", # too many arguments. Skip
|
|
132
|
+
"too-many-statements", # too many statements. Skip
|
|
133
|
+
"too-many-boolean-expressions", # too many expressions. Skip
|
|
134
|
+
"too-many-positional-arguments", # too many positional arguments. Skip
|
|
135
|
+
"repeated-equality-comparison", # multiple comparisons. Skip
|
|
136
|
+
"magic-value-comparison", # magic values. skip
|
|
137
|
+
"collapsible-else-if", # use elif instead of else if. skip
|
|
138
|
+
"non-augmented-assignment", # use augmented assignment. confuses strings, wait for fix. skip
|
|
139
|
+
"literal-membership", # use a set literal for membership test. skip
|
|
140
|
+
"no-self-use", # method inference. skip
|
|
141
|
+
"unnecessary-lambda", # inline lambda. skip
|
|
142
|
+
"useless-else-on-loop", # else without break. skip
|
|
143
|
+
"global-variable-not-assigned", # global withotu assignment. consider
|
|
144
|
+
"global-statement", # discourage global. skip
|
|
145
|
+
"subprocess-run-without-check", # subprocess run without check arg. skip
|
|
146
|
+
"unspecified-encoding", # open without encoding. skip
|
|
147
|
+
"redefined-loop-name", # for loop variable overwritten. skip
|
|
148
|
+
"pytest-fixture-incorrect-parentheses-style", # change ficture decorator. should add
|
|
149
|
+
"pytest-raises-too-broad", # use more specific raises decorator. should add
|
|
150
|
+
"pytest-composite-assertion", # break down complex assertsions. skip
|
|
151
151
|
"PTH", # enforces new python path library usage. skip
|
|
152
|
-
"
|
|
153
|
-
"
|
|
152
|
+
"unnecessary-literal-union", # turn union of literals to just literal with multiple. should add
|
|
153
|
+
"redundant-numeric-union", # use float instead of int | float. should remove floats
|
|
154
154
|
"RET", # enforces return semantics. break up and re-evaluate later
|
|
155
|
-
"
|
|
156
|
-
"
|
|
157
|
-
"
|
|
158
|
-
"
|
|
159
|
-
"
|
|
160
|
-
"
|
|
161
|
-
"
|
|
155
|
+
"unnecessary-paren-on-raise-exception", # unnecessary parens on exception. skip.
|
|
156
|
+
"ambiguous-unicode-character-string", # ambiguous characters. skip
|
|
157
|
+
"collection-literal-concatenation", # prefer star to concatenation. skip
|
|
158
|
+
"explicit-f-string-type-conversion", # use explicit conversion flag. skip
|
|
159
|
+
"mutable-class-default", # type with class var. should add
|
|
160
|
+
"unnecessary-iterable-allocation-for-first-element", # prefer next for single element. skip
|
|
161
|
+
"unused-noqa", # unused noqa. should add
|
|
162
162
|
"S", # should split up
|
|
163
|
-
"
|
|
164
|
-
"
|
|
165
|
-
"
|
|
166
|
-
"
|
|
167
|
-
"
|
|
168
|
-
"
|
|
169
|
-
"
|
|
170
|
-
"
|
|
171
|
-
"
|
|
172
|
-
"
|
|
173
|
-
"
|
|
174
|
-
"
|
|
175
|
-
"
|
|
176
|
-
"
|
|
177
|
-
"
|
|
178
|
-
"
|
|
163
|
+
"assert", # allow asserts. skip
|
|
164
|
+
"collapsible-if", # use single if instead of nested. skip
|
|
165
|
+
"suppressible-exception", # use exception supress. skip
|
|
166
|
+
"if-else-block-instead-of-if-exp", # use ternary. skip
|
|
167
|
+
"reimplemented-builtin", # use any/all. should add
|
|
168
|
+
"uncapitalized-environment-variables", # case of env variable. skip
|
|
169
|
+
"if-with-same-arms", # combine if branches. skip
|
|
170
|
+
"open-file-with-context-handler", # use context handler for files. should add
|
|
171
|
+
"multiple-with-statements", # use single with. should add
|
|
172
|
+
"private-member-access", # private member access. should add
|
|
173
|
+
"no-slots-in-str-subclass", # subclass of string should define slot. should add
|
|
174
|
+
"print", # print. skip
|
|
175
|
+
"p-print", # pprint. skip
|
|
176
|
+
"typing-only-first-party-import", # move application import into type checking. skip
|
|
177
|
+
"typing-only-third-party-import", # move third party import into type checking. consider
|
|
178
|
+
"typing-only-standard-library-import", # move library into type checking lbock. consider
|
|
179
179
|
"TD", # todo comments. skip
|
|
180
|
-
"
|
|
181
|
-
"
|
|
182
|
-
"
|
|
183
|
-
"
|
|
184
|
-
"
|
|
185
|
-
"
|
|
186
|
-
"
|
|
187
|
-
"
|
|
188
|
-
"
|
|
189
|
-
"
|
|
190
|
-
"
|
|
191
|
-
"
|
|
192
|
-
"
|
|
193
|
-
"
|
|
194
|
-
"
|
|
195
|
-
"
|
|
180
|
+
"relative-imports", # eliminate relative imports from parents. skip
|
|
181
|
+
"raise-vanilla-class", # create your own exception. skip
|
|
182
|
+
"raise-vanilla-args", # avoid long messages. skip
|
|
183
|
+
"type-check-without-type-error", # prefer type error. should add
|
|
184
|
+
"verbose-raise", # raise without exception name. consider
|
|
185
|
+
"try-consider-else", # move statement to else block. consider
|
|
186
|
+
"raise-within-try", # move raise to inner function. skip
|
|
187
|
+
"non-pep604-annotation-union", # use union for type annotations. should add
|
|
188
|
+
"convert-typed-dict-functional-to-class", # eliminate typeddict. should add
|
|
189
|
+
"printf-string-formatting", # use format specifiers. should add
|
|
190
|
+
"zip-without-explicit-strict", # zip strict. we have a deprecated pattern here, consider
|
|
191
|
+
"outdated-version-block", # outdated version block, consider
|
|
192
|
+
"zip-instead-of-pairwise", # prefer itertools.pairwise over zip, consider
|
|
193
|
+
"unsorted-dunder-all", # __all__ is not sorted. skip due to isort complication
|
|
194
|
+
"datetime-timezone-utc", # use datetime.UTC, TODO add back in
|
|
195
|
+
"deprecated-import", # replacing List with list, TODO add back in
|
|
196
196
|
# ## FROM RUFF UPGRADE
|
|
197
|
-
"
|
|
198
|
-
"
|
|
199
|
-
"
|
|
200
|
-
"
|
|
201
|
-
"
|
|
197
|
+
"import-private-name", # private name imports. should add
|
|
198
|
+
"too-many-nested-blocks", # too many nested blocks -- add with config. skip
|
|
199
|
+
"unnecessary-dict-comprehension-for-iterable", # unnecessary dict comprehension. skip
|
|
200
|
+
"enumerate-for-loop", # index variable should use enumerate. should add.
|
|
201
|
+
"too-many-locals" # too many local variables. configure below. should add with config
|
|
202
202
|
]
|
|
203
203
|
line-length = 90
|
|
204
204
|
target-version = "py311"
|
|
@@ -207,7 +207,7 @@ exclude = [
|
|
|
207
207
|
'env'
|
|
208
208
|
]
|
|
209
209
|
[tool.ruff.lint.per-file-ignores]
|
|
210
|
-
"__init__.py" = ["
|
|
210
|
+
"__init__.py" = ["unused-import"]
|
|
211
211
|
|
|
212
212
|
[tool.ruff.lint.isort]
|
|
213
213
|
split-on-trailing-comma = true
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import datetime
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import random
|
|
6
|
+
import time
|
|
7
|
+
from decimal import Decimal
|
|
8
|
+
|
|
9
|
+
import requests
|
|
10
|
+
from uncountable.types import dataset_measurements_t, identifier_t
|
|
11
|
+
from uncountable.types.api.time_series import ingest_dataset_measurements as api
|
|
12
|
+
|
|
13
|
+
from pkgs.serialization_util import serialize_for_api
|
|
14
|
+
|
|
15
|
+
API_ID_ENV_VAR = "UNC_API_ID"
|
|
16
|
+
API_SECRET_KEY_ENV_VAR = "UNC_API_SECRET_KEY"
|
|
17
|
+
MEASUREMENTS_PER_SECOND = 500
|
|
18
|
+
ONE_SECOND = datetime.timedelta(seconds=1)
|
|
19
|
+
VALUE_QUANTUM = Decimal("0.0001")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _random_value(*, min_value: Decimal, max_value: Decimal) -> Decimal:
|
|
23
|
+
span = max_value - min_value
|
|
24
|
+
sampled = (min_value + span * Decimal(str(random.random()))).quantize(VALUE_QUANTUM)
|
|
25
|
+
return max(min_value, min(max_value, sampled))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _window_sizes(*, num_measurements: int) -> list[int]:
|
|
29
|
+
full_windows, remainder = divmod(num_measurements, MEASUREMENTS_PER_SECOND)
|
|
30
|
+
window_sizes = [MEASUREMENTS_PER_SECOND] * full_windows
|
|
31
|
+
if remainder:
|
|
32
|
+
window_sizes.append(remainder)
|
|
33
|
+
return window_sizes
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _build_measurements(
|
|
37
|
+
*,
|
|
38
|
+
anchor: datetime.datetime,
|
|
39
|
+
window_index: int,
|
|
40
|
+
measurement_count: int,
|
|
41
|
+
min_value: Decimal,
|
|
42
|
+
max_value: Decimal,
|
|
43
|
+
) -> list[dataset_measurements_t.Measurement]:
|
|
44
|
+
window_start = anchor + window_index * ONE_SECOND
|
|
45
|
+
step = ONE_SECOND / measurement_count
|
|
46
|
+
return [
|
|
47
|
+
dataset_measurements_t.Measurement(
|
|
48
|
+
observation_timestamp=window_start + index * step,
|
|
49
|
+
value=dataset_measurements_t.NumericMeasurementValue(
|
|
50
|
+
value=_random_value(min_value=min_value, max_value=max_value)
|
|
51
|
+
),
|
|
52
|
+
)
|
|
53
|
+
for index in range(measurement_count)
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _sleep_until(instant: datetime.datetime) -> None:
|
|
58
|
+
remaining_seconds = (instant - datetime.datetime.now(datetime.UTC)).total_seconds()
|
|
59
|
+
if remaining_seconds > 0:
|
|
60
|
+
time.sleep(remaining_seconds)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _post_measurements(
|
|
64
|
+
*,
|
|
65
|
+
session: requests.Session,
|
|
66
|
+
url: str,
|
|
67
|
+
dataset_id: int,
|
|
68
|
+
measurements: list[dataset_measurements_t.Measurement],
|
|
69
|
+
) -> None:
|
|
70
|
+
arguments = api.Arguments(
|
|
71
|
+
dataset_key=identifier_t.IdentifierKeyId(id=dataset_id),
|
|
72
|
+
measurements=measurements,
|
|
73
|
+
)
|
|
74
|
+
body = {"data": json.dumps(serialize_for_api(arguments))}
|
|
75
|
+
response = session.post(url, data=body)
|
|
76
|
+
response.raise_for_status()
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _stream(
|
|
80
|
+
*,
|
|
81
|
+
session: requests.Session,
|
|
82
|
+
url: str,
|
|
83
|
+
dataset_id: int,
|
|
84
|
+
num_measurements: int,
|
|
85
|
+
min_value: Decimal,
|
|
86
|
+
max_value: Decimal,
|
|
87
|
+
) -> None:
|
|
88
|
+
anchor = datetime.datetime.now(datetime.UTC)
|
|
89
|
+
window_sizes = _window_sizes(num_measurements=num_measurements)
|
|
90
|
+
print(
|
|
91
|
+
f"streaming {num_measurements} measurement(s) to dataset {dataset_id} "
|
|
92
|
+
f"at {MEASUREMENTS_PER_SECOND}/second across {len(window_sizes)} second(s)",
|
|
93
|
+
flush=True,
|
|
94
|
+
)
|
|
95
|
+
streamed = 0
|
|
96
|
+
for window_index, measurement_count in enumerate(window_sizes):
|
|
97
|
+
measurements = _build_measurements(
|
|
98
|
+
anchor=anchor,
|
|
99
|
+
window_index=window_index,
|
|
100
|
+
measurement_count=measurement_count,
|
|
101
|
+
min_value=min_value,
|
|
102
|
+
max_value=max_value,
|
|
103
|
+
)
|
|
104
|
+
_sleep_until(anchor + (window_index + 1) * ONE_SECOND)
|
|
105
|
+
_post_measurements(
|
|
106
|
+
session=session,
|
|
107
|
+
url=url,
|
|
108
|
+
dataset_id=dataset_id,
|
|
109
|
+
measurements=measurements,
|
|
110
|
+
)
|
|
111
|
+
streamed += measurement_count
|
|
112
|
+
percent_complete = 100 * streamed / num_measurements
|
|
113
|
+
print(
|
|
114
|
+
f"streamed {streamed}/{num_measurements} measurement(s) "
|
|
115
|
+
f"({percent_complete:.1f}%)",
|
|
116
|
+
flush=True,
|
|
117
|
+
)
|
|
118
|
+
print(f"done: streamed {streamed} measurement(s)", flush=True)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _parse_args() -> argparse.Namespace:
|
|
122
|
+
parser = argparse.ArgumentParser(
|
|
123
|
+
description=(
|
|
124
|
+
"Stream random measurements to a monitor (timeseries) dataset via the "
|
|
125
|
+
"dataset stream API."
|
|
126
|
+
),
|
|
127
|
+
allow_abbrev=False,
|
|
128
|
+
)
|
|
129
|
+
parser.add_argument(
|
|
130
|
+
"--base-url",
|
|
131
|
+
required=True,
|
|
132
|
+
help="Base URL of the Uncountable server, e.g. http://localhost:5000",
|
|
133
|
+
)
|
|
134
|
+
parser.add_argument(
|
|
135
|
+
"--dataset-id",
|
|
136
|
+
type=int,
|
|
137
|
+
required=True,
|
|
138
|
+
help="Object id of the monitor dataset to receive measurements",
|
|
139
|
+
)
|
|
140
|
+
parser.add_argument(
|
|
141
|
+
"--num-measurements",
|
|
142
|
+
type=int,
|
|
143
|
+
required=True,
|
|
144
|
+
help="Total number of measurements to stream",
|
|
145
|
+
)
|
|
146
|
+
parser.add_argument(
|
|
147
|
+
"--min-value",
|
|
148
|
+
type=Decimal,
|
|
149
|
+
required=True,
|
|
150
|
+
help="Minimum random measurement value",
|
|
151
|
+
)
|
|
152
|
+
parser.add_argument(
|
|
153
|
+
"--max-value",
|
|
154
|
+
type=Decimal,
|
|
155
|
+
required=True,
|
|
156
|
+
help="Maximum random measurement value",
|
|
157
|
+
)
|
|
158
|
+
args = parser.parse_args()
|
|
159
|
+
if args.num_measurements <= 0:
|
|
160
|
+
parser.error("--num-measurements must be positive")
|
|
161
|
+
if args.max_value < args.min_value:
|
|
162
|
+
parser.error("--max-value must be greater than or equal to --min-value")
|
|
163
|
+
return args
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def main() -> None:
|
|
167
|
+
args = _parse_args()
|
|
168
|
+
|
|
169
|
+
api_id = os.environ.get(API_ID_ENV_VAR)
|
|
170
|
+
api_secret_key = os.environ.get(API_SECRET_KEY_ENV_VAR)
|
|
171
|
+
if not api_id or not api_secret_key:
|
|
172
|
+
missing = [
|
|
173
|
+
name
|
|
174
|
+
for name, value in (
|
|
175
|
+
(API_ID_ENV_VAR, api_id),
|
|
176
|
+
(API_SECRET_KEY_ENV_VAR, api_secret_key),
|
|
177
|
+
)
|
|
178
|
+
if not value
|
|
179
|
+
]
|
|
180
|
+
raise SystemExit(
|
|
181
|
+
f"missing required environment variable(s): {', '.join(missing)}"
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
session = requests.Session()
|
|
185
|
+
session.auth = (api_id, api_secret_key)
|
|
186
|
+
_stream(
|
|
187
|
+
session=session,
|
|
188
|
+
url=f"{args.base_url.rstrip('/')}/{api.ENDPOINT_PATH}",
|
|
189
|
+
dataset_id=args.dataset_id,
|
|
190
|
+
num_measurements=args.num_measurements,
|
|
191
|
+
min_value=args.min_value,
|
|
192
|
+
max_value=args.max_value,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
main()
|
pkgs/argument_parser/__init__.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
__all__ = [
|
|
4
4
|
"CachedParser",
|
|
5
|
+
"InternalCachedParser",
|
|
5
6
|
"ParserBase",
|
|
6
7
|
"ParserEnumError",
|
|
7
8
|
"ParserError",
|
|
@@ -10,6 +11,7 @@ __all__ = [
|
|
|
10
11
|
"ParserOptions",
|
|
11
12
|
"ParserTypeError",
|
|
12
13
|
"SourceEncoding",
|
|
14
|
+
"TestCachedParser",
|
|
13
15
|
"build_parser",
|
|
14
16
|
"camel_to_snake_case",
|
|
15
17
|
"is_missing",
|
|
@@ -20,7 +22,11 @@ __all__ = [
|
|
|
20
22
|
"snake_to_camel_case",
|
|
21
23
|
]
|
|
22
24
|
|
|
23
|
-
from .cached_parser import
|
|
25
|
+
from .cached_parser import (
|
|
26
|
+
CachedParser as CachedParser,
|
|
27
|
+
InternalCachedParser as InternalCachedParser,
|
|
28
|
+
TestCachedParser as TestCachedParser,
|
|
29
|
+
)
|
|
24
30
|
from .case_convert import (
|
|
25
31
|
camel_to_snake_case as camel_to_snake_case,
|
|
26
32
|
kebab_to_pascal_case as kebab_to_pascal_case,
|