UncountablePythonSDK 0.0.57__py3-none-any.whl → 0.0.58__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.

Potentially problematic release.


This version of UncountablePythonSDK might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: UncountablePythonSDK
3
- Version: 0.0.57
3
+ Version: 0.0.58
4
4
  Summary: Uncountable SDK
5
5
  Project-URL: Homepage, https://github.com/uncountableinc/uncountable-python-sdk
6
6
  Project-URL: Repository, https://github.com/uncountableinc/uncountable-python-sdk.git
@@ -81,10 +81,11 @@ uncountable/core/version.py,sha256=SqQIHLhiVZXQBeOwygS2FRZ4WEO27JmWhse0lKm7fgU,2
81
81
  uncountable/integration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
82
82
  uncountable/integration/construct_client.py,sha256=I2XTamht13vs-JYkV4PpNS_Pc4FJm-KVYqNNvxI4qNk,1916
83
83
  uncountable/integration/cron.py,sha256=e5456IYJF2ipiSsd1R2T334lfe7mtp-gwP7JpS645L0,1858
84
- uncountable/integration/entrypoint.py,sha256=9rk06gBTsCqytIs8Shsnlf6ir_4Uq5d5rfP1veiSLzc,1437
84
+ uncountable/integration/entrypoint.py,sha256=wgOXhTzErttRjOzV4rS4psZW5qUKIa5ez89QndQl61k,785
85
85
  uncountable/integration/job.py,sha256=UTzcMes2KrBBRLOM3u94imMKLLnv50glqOkNf8-JOZw,1022
86
+ uncountable/integration/scan_profiles.py,sha256=3o_h5Ta8ZQEX1epWyXhtyEof0M1b7MobVG7bRKcsFuM,1166
86
87
  uncountable/integration/server.py,sha256=bmX-ukLiNDq0ThVB2lUyXl-vtID5HI4gqJHxhsVNG3w,4440
87
- uncountable/integration/telemetry.py,sha256=LAXKVqq96h2pbEwUODIXKhfSt8GVqTDpDiGvAiBQhMk,5341
88
+ uncountable/integration/telemetry.py,sha256=wJMMlGWJTCXB1WxfpSI56x_qLmH9TgIAm9lx137gDH4,5966
88
89
  uncountable/integration/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
89
90
  uncountable/integration/db/connect.py,sha256=YtQHJ1DBGPhxKFRCfiXqohOYUceKSxMVOJ88aPI48Ug,181
90
91
  uncountable/integration/executors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -126,8 +127,8 @@ uncountable/types/input_attributes.py,sha256=IrIKQnHqHdS1Utdfzr9GnOe17a8riaqYcO1
126
127
  uncountable/types/input_attributes_t.py,sha256=wE1ekiQfb72Z9VpF5SHipKJkgaJFUHJrNkkJdmuhF9w,820
127
128
  uncountable/types/inputs.py,sha256=6RIEFfCxLqpeHEGOpu63O4i8zPogjGeB7wiV_rPBw_g,404
128
129
  uncountable/types/inputs_t.py,sha256=RW7gF9zTOwByu-nMTMVuBabLOuWKx4O1nvfgvx_R55o,1611
129
- uncountable/types/job_definition.py,sha256=Cgwop6iNcWEsEpfjMl1EtkRES_3-SVzpMe-w73V4G_U,1862
130
- uncountable/types/job_definition_t.py,sha256=pL-0YVyR0oz6-5wWXJsX1UyYo4R_FPwhOYFj9iMKgvo,7170
130
+ uncountable/types/job_definition.py,sha256=HXfaYl5Nafm9C0teQLBtqzroe1HlfKJtfGVm2-40hvg,1937
131
+ uncountable/types/job_definition_t.py,sha256=0BKIqg1fSJKXHxLAWm11bgz7OC4ye1k4EPaY439_Mns,7549
131
132
  uncountable/types/outputs.py,sha256=sUZx_X-TKCZtLm1YCEH8OISX9DdPlv9ZuUfM3-askCc,281
132
133
  uncountable/types/outputs_t.py,sha256=2aORUOr0ls1ZYo-ddkWax3D1ZndmQsWtHfJxpYozlhg,656
133
134
  uncountable/types/overrides.py,sha256=Mv-smwK1B3pvbt48fNOiqkeQn9wMgYlBFJKUBOJqceE,431
@@ -243,7 +244,7 @@ uncountable/types/api/triggers/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr
243
244
  uncountable/types/api/triggers/run_trigger.py,sha256=_Rpha9nxXI3Xr17CrGDtofg4HZ81x2lt0rMZ6As0qfE,893
244
245
  uncountable/types/api/uploader/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
245
246
  uncountable/types/api/uploader/invoke_uploader.py,sha256=Rc77y5q-3R9-SNQgm8P35zKaW2D1Hbtm7PDixnOn1G0,1025
246
- UncountablePythonSDK-0.0.57.dist-info/METADATA,sha256=Ay-ZqQ6b7KqlG96Kv9ZJjBheNvYMCQBgfhkbaRCQLas,1934
247
- UncountablePythonSDK-0.0.57.dist-info/WHEEL,sha256=uCRv0ZEik_232NlR4YDw4Pv3Ajt5bKvMH13NUU7hFuI,91
248
- UncountablePythonSDK-0.0.57.dist-info/top_level.txt,sha256=1UVGjAU-6hJY9qw2iJ7nCBeEwZ793AEN5ZfKX9A1uj4,31
249
- UncountablePythonSDK-0.0.57.dist-info/RECORD,,
247
+ UncountablePythonSDK-0.0.58.dist-info/METADATA,sha256=IPsP_FApLq2unwFPEHKdIBZ9yaQr8EGgdcr4YojkYAA,1934
248
+ UncountablePythonSDK-0.0.58.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
249
+ UncountablePythonSDK-0.0.58.dist-info/top_level.txt,sha256=1UVGjAU-6hJY9qw2iJ7nCBeEwZ793AEN5ZfKX9A1uj4,31
250
+ UncountablePythonSDK-0.0.58.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (74.1.1)
2
+ Generator: setuptools (74.1.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,38 +1,17 @@
1
- import os
2
- from importlib import resources
3
-
4
- from pkgs.argument_parser import CachedParser
5
1
  from uncountable.integration.db.connect import create_db_engine
2
+ from uncountable.integration.scan_profiles import load_profiles
6
3
  from uncountable.integration.server import IntegrationServer
7
- from uncountable.types.job_definition_t import ProfileDefinition
8
-
9
- profile_parser = CachedParser(ProfileDefinition)
10
4
 
11
5
 
12
6
  def main(blocking: bool) -> None:
13
- profiles_module = os.environ["UNC_PROFILES_MODULE"]
14
7
  with IntegrationServer(create_db_engine()) as server:
15
- profiles = [
16
- entry
17
- for entry in resources.files(profiles_module).iterdir()
18
- if entry.is_dir()
19
- ]
20
- for profile_file in profiles:
21
- profile_name = profile_file.name
22
- try:
23
- profile = profile_parser.parse_yaml_resource(
24
- package=".".join([profiles_module, profile_name]),
25
- resource="profile.yaml",
26
- )
27
- except FileNotFoundError as e:
28
- print(f"WARN: profile.yaml not found for {profile_name}", e)
29
- continue
8
+ for profile_details in load_profiles():
30
9
  server.register_profile(
31
- profile_name=profile_name,
32
- base_url=profile.base_url,
33
- auth_retrieval=profile.auth_retrieval,
34
- jobs=profile.jobs,
35
- client_options=profile.client_options,
10
+ profile_name=profile_details.name,
11
+ base_url=profile_details.definition.base_url,
12
+ auth_retrieval=profile_details.definition.auth_retrieval,
13
+ jobs=profile_details.definition.jobs,
14
+ client_options=profile_details.definition.client_options,
36
15
  )
37
16
 
38
17
  if blocking:
@@ -0,0 +1,36 @@
1
+ import os
2
+ from dataclasses import dataclass
3
+ from importlib import resources
4
+
5
+ from pkgs.argument_parser import CachedParser
6
+ from uncountable.types import job_definition_t
7
+
8
+ profile_parser = CachedParser(job_definition_t.ProfileDefinition)
9
+
10
+
11
+ @dataclass(kw_only=True)
12
+ class ProfileDetails:
13
+ name: str
14
+ definition: job_definition_t.ProfileDefinition
15
+
16
+
17
+ def load_profiles() -> list[ProfileDetails]:
18
+ profiles_module = os.environ["UNC_PROFILES_MODULE"]
19
+ profiles = [
20
+ entry for entry in resources.files(profiles_module).iterdir() if entry.is_dir()
21
+ ]
22
+ profile_details: list[ProfileDetails] = []
23
+ for profile_file in profiles:
24
+ profile_name = profile_file.name
25
+ try:
26
+ definition = profile_parser.parse_yaml_resource(
27
+ package=".".join([profiles_module, profile_name]),
28
+ resource="profile.yaml",
29
+ )
30
+ profile_details.append(
31
+ ProfileDetails(name=profile_name, definition=definition)
32
+ )
33
+ except FileNotFoundError as e:
34
+ print(f"WARN: profile.yaml not found for {profile_name}", e)
35
+ continue
36
+ return profile_details
@@ -1,14 +1,16 @@
1
1
  import functools
2
2
  import os
3
- import sys
4
3
  import time
5
4
  from contextlib import contextmanager
6
5
  from enum import StrEnum
7
- from typing import Generator, TextIO, assert_never, cast
6
+ from typing import Generator, assert_never, cast
8
7
 
9
- from opentelemetry import trace
8
+ from opentelemetry import _logs, trace
9
+ from opentelemetry.exporter.otlp.proto.http._log_exporter import OTLPLogExporter
10
10
  from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
11
- from opentelemetry.sdk._logs import LogRecord
11
+ from opentelemetry.sdk._logs import Logger as OTELLogger
12
+ from opentelemetry.sdk._logs import LoggerProvider, LogRecord
13
+ from opentelemetry.sdk._logs.export import BatchLogRecordProcessor, ConsoleLogExporter
12
14
  from opentelemetry.sdk.resources import Attributes, Resource
13
15
  from opentelemetry.sdk.trace import TracerProvider
14
16
  from opentelemetry.sdk.trace.export import (
@@ -25,7 +27,7 @@ def _cast_attributes(attributes: dict[str, base_t.JsonValue]) -> Attributes:
25
27
 
26
28
 
27
29
  @functools.cache
28
- def get_tracer() -> Tracer:
30
+ def get_otel_resource() -> Resource:
29
31
  attributes: dict[str, base_t.JsonValue] = {
30
32
  "service.name": "integration-server",
31
33
  "sdk.version": get_version(),
@@ -37,12 +39,26 @@ def get_tracer() -> Tracer:
37
39
  if unc_env is not None:
38
40
  attributes["deployment.environment"] = unc_env
39
41
  resource = Resource.create(attributes=_cast_attributes(attributes))
40
- provider = TracerProvider(resource=resource)
42
+ return resource
43
+
44
+
45
+ @functools.cache
46
+ def get_otel_tracer() -> Tracer:
47
+ provider = TracerProvider(resource=get_otel_resource())
41
48
  provider.add_span_processor(SimpleSpanProcessor(OTLPSpanExporter()))
42
49
  trace.set_tracer_provider(provider)
43
50
  return provider.get_tracer("integration.telemetry")
44
51
 
45
52
 
53
+ @functools.cache
54
+ def get_otel_logger() -> OTELLogger:
55
+ provider = LoggerProvider(resource=get_otel_resource())
56
+ provider.add_log_record_processor(BatchLogRecordProcessor(ConsoleLogExporter()))
57
+ provider.add_log_record_processor(BatchLogRecordProcessor(OTLPLogExporter()))
58
+ _logs.set_logger_provider(provider)
59
+ return provider.get_logger("integration.telemetry")
60
+
61
+
46
62
  class LogSeverity(StrEnum):
47
63
  INFO = "Info"
48
64
  WARN = "Warn"
@@ -59,6 +75,7 @@ class Logger:
59
75
  def _emit_log(
60
76
  self, message: str, *, severity: LogSeverity, attributes: Attributes | None
61
77
  ) -> None:
78
+ otel_logger = get_otel_logger()
62
79
  log_record = LogRecord(
63
80
  body=message,
64
81
  severity_text=severity,
@@ -67,9 +84,7 @@ class Logger:
67
84
  span_id=self.current_span_id,
68
85
  trace_id=self.current_trace_id,
69
86
  )
70
- log_file: TextIO = sys.stderr if severity == LogSeverity.ERROR else sys.stdout
71
- log_file.write(log_record.to_json())
72
- log_file.flush()
87
+ otel_logger.emit(log_record)
73
88
 
74
89
  def log_info(self, message: str, *, attributes: Attributes | None = None) -> None:
75
90
  self._emit_log(
@@ -135,7 +150,7 @@ class JobLogger(Logger):
135
150
  def push_scope(
136
151
  self, scope_name: str, *, attributes: Attributes | None = None
137
152
  ) -> Generator["JobLogger", None, None]:
138
- with get_tracer().start_as_current_span(
153
+ with get_otel_tracer().start_as_current_span(
139
154
  scope_name, attributes=self._patch_attributes(attributes)
140
155
  ) as span:
141
156
  self.current_span_id = span.get_span_context().span_id
@@ -19,6 +19,7 @@ from .job_definition_t import JobExecutorGenericUpload as JobExecutorGenericUplo
19
19
  from .job_definition_t import JobExecutor as JobExecutor
20
20
  from .job_definition_t import JobDefinitionBase as JobDefinitionBase
21
21
  from .job_definition_t import CronJobDefinition as CronJobDefinition
22
+ from .job_definition_t import WebhookJobDefinition as WebhookJobDefinition
22
23
  from .job_definition_t import JobDefinition as JobDefinition
23
24
  from .job_definition_t import AuthRetrievalBase as AuthRetrievalBase
24
25
  from .job_definition_t import AuthRetrievalOAuth as AuthRetrievalOAuth
@@ -39,12 +39,14 @@ __all__: list[str] = [
39
39
  "ProfileDefinition",
40
40
  "ProfileMetadata",
41
41
  "S3CloudProvider",
42
+ "WebhookJobDefinition",
42
43
  ]
43
44
 
44
45
 
45
46
  # DO NOT MODIFY -- This file is generated by type_spec
46
47
  class JobDefinitionType(StrEnum):
47
48
  CRON = "cron"
49
+ WEBHOOK = "webhook"
48
50
 
49
51
 
50
52
  # DO NOT MODIFY -- This file is generated by type_spec
@@ -177,6 +179,16 @@ class CronJobDefinition(JobDefinitionBase):
177
179
  cron_spec: str
178
180
 
179
181
 
182
+ # DO NOT MODIFY -- This file is generated by type_spec
183
+ @serial_class(
184
+ parse_require={"type"},
185
+ )
186
+ @dataclasses.dataclass(kw_only=True)
187
+ class WebhookJobDefinition(JobDefinitionBase):
188
+ type: typing.Literal[JobDefinitionType.WEBHOOK] = JobDefinitionType.WEBHOOK
189
+ signature_key_secret: secret_retrieval_t.SecretRetrieval
190
+
191
+
180
192
  # DO NOT MODIFY -- This file is generated by type_spec
181
193
  JobDefinition = typing.Annotated[
182
194
  typing.Union[CronJobDefinition],