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

docs/conf.py CHANGED
@@ -8,6 +8,11 @@
8
8
 
9
9
  import datetime
10
10
 
11
+ from docutils import nodes # type: ignore[import-untyped]
12
+ from sphinx.addnodes import pending_xref # type: ignore[import-not-found]
13
+ from sphinx.application import Sphinx # type: ignore[import-not-found]
14
+ from sphinx.environment import BuildEnvironment # type: ignore[import-not-found]
15
+
11
16
  project = "Uncountable SDK"
12
17
  copyright = f"{datetime.datetime.now(tz=datetime.UTC).date().year}, Uncountable Inc"
13
18
  author = "Uncountable Inc"
@@ -27,17 +32,18 @@ myst_enable_extensions = ["fieldlist", "deflist"]
27
32
  autoapi_dirs = ["../uncountable"]
28
33
  autoapi_options = [
29
34
  "members",
35
+ "inherited-members",
30
36
  "undoc-members",
31
- "show-inheritance",
32
- "show-module-summary",
33
- "imported-members",
34
37
  ]
38
+ autoapi_root = "api"
35
39
  autoapi_ignore = ["*integration*"]
36
40
  autodoc_typehints = "description"
41
+ autoapi_member_order = "groupwise"
42
+ autoapi_own_page_level = "class"
37
43
 
38
44
  exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
39
45
 
40
-
46
+ python_use_unqualified_type_names = True
41
47
  # -- Options for HTML output -------------------------------------------------
42
48
  # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
43
49
 
@@ -55,3 +61,25 @@ favicons = [
55
61
  "favicons/mstile-150x150.png",
56
62
  "favicons/safari-pinned-tab.svg",
57
63
  ]
64
+
65
+
66
+ def _hook_missing_reference(
67
+ _app: Sphinx, _env: BuildEnvironment, node: pending_xref, contnode: nodes.Text
68
+ ) -> nodes.reference | None:
69
+ """
70
+ Manually resolve reference when autoapi reference resolution fails.
71
+ This is necessary because autoapi does not fully support type aliases.
72
+ """
73
+ target = node.get("reftarget", "")
74
+ if not target.startswith("uncountable"):
75
+ return None
76
+ module, name = target.rsplit(".", 1)
77
+ return nodes.reference(
78
+ text=name if python_use_unqualified_type_names else target,
79
+ children=[contnode],
80
+ refuri=f"/{autoapi_root}/{module.replace('.', '/')}/#{target}",
81
+ )
82
+
83
+
84
+ def setup(app: Sphinx) -> None:
85
+ app.connect("missing-reference", _hook_missing_reference)
docs/index.md CHANGED
@@ -7,7 +7,10 @@
7
7
 
8
8
  ```{toctree}
9
9
  :maxdepth: 2
10
+ :hidden:
10
11
 
11
12
  quickstart
13
+ Available SDK Methods <api/uncountable/core/client/Client>
14
+ SDK Reference <api/uncountable/index>
12
15
  ```
13
16
 
docs/requirements.txt CHANGED
@@ -1,4 +1,4 @@
1
- furo==2024.8.6
1
+ furo==2025.7.19
2
2
  myst-parser==4.0.0
3
3
  sphinx-autoapi==3.6.0
4
4
  sphinx-copybutton==0.5.2
@@ -6,3 +6,4 @@ Sphinx==8.2.0
6
6
  sphinx_design==0.6.1
7
7
  sphinx-favicon==1.0.1
8
8
  astroid==3.3.8
9
+ docutils==0.21.2
@@ -4,6 +4,7 @@ from uncountable.integration.http_server import (
4
4
  GenericHttpRequest,
5
5
  GenericHttpResponse,
6
6
  )
7
+ from uncountable.integration.http_server.types import HttpException
7
8
  from uncountable.integration.job import CustomHttpJob, register_job
8
9
  from uncountable.types import job_definition_t
9
10
 
@@ -14,6 +15,9 @@ class ExampleWebhookPayload:
14
15
  message: str
15
16
 
16
17
 
18
+ _EXPECTED_USER_ID = 1
19
+
20
+
17
21
  @register_job
18
22
  class HttpExample(CustomHttpJob):
19
23
  @staticmethod
@@ -23,7 +27,15 @@ class HttpExample(CustomHttpJob):
23
27
  job_definition: job_definition_t.HttpJobDefinitionBase, # noqa: ARG004
24
28
  profile_meta: job_definition_t.ProfileMetadata, # noqa: ARG004
25
29
  ) -> None:
26
- return None
30
+ if (
31
+ CustomHttpJob.get_validated_oauth_request_user_id(
32
+ request=request, profile_metadata=profile_meta
33
+ )
34
+ != _EXPECTED_USER_ID
35
+ ):
36
+ raise HttpException(
37
+ message="unauthorized; invalid oauth token", error_code=401
38
+ )
27
39
 
28
40
  @staticmethod
29
41
  def handle_request(
@@ -12,6 +12,7 @@ from uncountable.core.async_batch import AsyncBatchProcessor
12
12
  from uncountable.core.client import Client
13
13
  from uncountable.core.environment import get_local_admin_server_port
14
14
  from uncountable.core.file_upload import FileUpload
15
+ from uncountable.core.types import AuthDetailsOAuth
15
16
  from uncountable.integration.http_server import (
16
17
  GenericHttpRequest,
17
18
  GenericHttpResponse,
@@ -93,6 +94,19 @@ class WebhookResponse:
93
94
  pass
94
95
 
95
96
 
97
+ class _RequestValidatorClient(Client):
98
+ def __init__(self, *, base_url: str, oauth_bearer_token: str):
99
+ super().__init__(
100
+ base_url=base_url,
101
+ auth_details=AuthDetailsOAuth(refresh_token=""),
102
+ config=None,
103
+ )
104
+ self._oauth_bearer_token = oauth_bearer_token
105
+
106
+ def _get_oauth_bearer_token(self, *, oauth_details: AuthDetailsOAuth) -> str:
107
+ return self._oauth_bearer_token
108
+
109
+
96
110
  class CustomHttpJob(Job[GenericHttpRequest]):
97
111
  @property
98
112
  def payload_type(self) -> type[GenericHttpRequest]:
@@ -112,6 +126,24 @@ class CustomHttpJob(Job[GenericHttpRequest]):
112
126
  """
113
127
  ...
114
128
 
129
+ @staticmethod
130
+ def get_validated_oauth_request_user_id(
131
+ *, profile_metadata: ProfileMetadata, request: GenericHttpRequest
132
+ ) -> base_t.ObjectId:
133
+ token = request.headers.get("Authorization", "").replace("Bearer ", "")
134
+ if token == "":
135
+ raise HttpException(
136
+ message="unauthorized; no bearer token in request", error_code=401
137
+ )
138
+ return (
139
+ _RequestValidatorClient(
140
+ base_url=profile_metadata.base_url,
141
+ oauth_bearer_token=token,
142
+ )
143
+ .get_current_user_info()
144
+ .user_id
145
+ )
146
+
115
147
  @staticmethod
116
148
  @abstractmethod
117
149
  def handle_request(
@@ -30,4 +30,5 @@ class ListingExportUserTimezone:
30
30
  class ExportType(StrEnum):
31
31
  EXCEL = "excel"
32
32
  PDF = "pdf"
33
+ JSON = "json"
33
34
  # DO NOT MODIFY -- This file is generated by type_spec
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: UncountablePythonSDK
3
- Version: 0.0.121
3
+ Version: 0.0.122
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
@@ -1,9 +1,9 @@
1
1
  docs/.gitignore,sha256=_ebkZUcwfvfnGEJ95rfj1lxoBNd6EE9ZvtOc7FsbfFE,7
2
- docs/conf.py,sha256=B3WBkqPxlf3xYHXCy91599SJ75G2eGrDs-K_RbsxT5k,1725
3
- docs/index.md,sha256=eEdirX_Ds6ICTRtIS5iT4irCquHcQyKN7E4M5QP9T8A,257
2
+ docs/conf.py,sha256=Qaw_Ys35RUUXKpFyGjiX120kABf6keZIq7iUdsUQxGY,2843
3
+ docs/index.md,sha256=HOQ3H-hErtHlVJMQ-gZjWF_xj1U68Au4aHa_Rc-K8uk,363
4
4
  docs/justfile,sha256=WymCEQ6W2A8Ak79iUPmecmuaUNN2htb7STUrz5K7ELE,273
5
5
  docs/quickstart.md,sha256=3GuJ0MB1O5kjlsrgAmdSkDq0rYqATrYy-tzEHDy8H-c,422
6
- docs/requirements.txt,sha256=IBoo8nKwyuZXoaSX7XOYRJvfT6VjwJPXz49eZvcZGuY,153
6
+ docs/requirements.txt,sha256=Q5qvOf7nQa19R4kCWb_1DBhwW-Vtm3SAtZTPDR_aF9c,171
7
7
  docs/static/logo_blue.png,sha256=SyYpMTVhhBbhF5Wl8lWaVwz-_p1MIR6dW6bVhufQRME,46708
8
8
  docs/static/favicons/android-chrome-192x192.png,sha256=XoF-AhD55JlSBDGsEPJKfT_VeXT-awhwKyZnxLhrwvk,1369
9
9
  docs/static/favicons/android-chrome-512x512.png,sha256=1S4xwY9YtJQ5ifFsZ-DOzssoyBYs0t9uwdOUmYx0Xso,3888
@@ -26,7 +26,7 @@ examples/upload_files.py,sha256=qMaSvMSdTMPOOP55y1AwEurc0SOdZAMvEydlqJPsGpg,432
26
26
  examples/integration-server/pyproject.toml,sha256=-ZZ1R3B-Pf-F6gQX0-Me6u3G9cVW2B2_eechemCe7_4,9149
27
27
  examples/integration-server/jobs/materials_auto/concurrent_cron.py,sha256=xsK3H9ZEaniedC2nJUB0rqOcFI8y-ojfl_nLSJb9AMM,312
28
28
  examples/integration-server/jobs/materials_auto/example_cron.py,sha256=spUMiiTEFaepbVXecjD_4aEEfqEtZGGZuWTKs9J6Xcw,736
29
- examples/integration-server/jobs/materials_auto/example_http.py,sha256=eVq-Fss_AhmztxOMqqO-GYGF3KvPt1O5HbNwwC2arh8,1037
29
+ examples/integration-server/jobs/materials_auto/example_http.py,sha256=eIL46ElWo8SKY7W5JWWkwZk6Qo7KRd9EJBxfy7YQ_sE,1429
30
30
  examples/integration-server/jobs/materials_auto/example_instrument.py,sha256=czJF3qBFay1S8fuESOvmkvBv1wCtZGAlHjwvCyYr-Mw,2336
31
31
  examples/integration-server/jobs/materials_auto/example_runsheet_wh.py,sha256=_wILTnbzzLf9zrcQb_KQKytxxcya1ej6MqQnoUSS4fA,1180
32
32
  examples/integration-server/jobs/materials_auto/example_wh.py,sha256=PN-skP27yJwDZboWk5g5EZEc3AKfVayQLfnopjsDKJc,659
@@ -105,7 +105,7 @@ uncountable/integration/cli.py,sha256=eshJ0lv4u00UOFrlkCwamE8NaxX1qN2q79wCJcsFrJ
105
105
  uncountable/integration/construct_client.py,sha256=I53mGcdS88hba3HFwgXmWQaTd1d5u0jWNSwyc_vlVsQ,1937
106
106
  uncountable/integration/cron.py,sha256=6eH-kIs3sdYPCyb62_L2M7U_uQTdMTdwY5hreEJb0hw,887
107
107
  uncountable/integration/entrypoint.py,sha256=BHOYPQgKvZE6HG8Rv15MkdYl8lRkvfDgv1OdLo0oQ9Q,433
108
- uncountable/integration/job.py,sha256=X8mNoy01Q6h26eNuPi50XwV6YLgaqYCGWt2PFDEddZU,7111
108
+ uncountable/integration/job.py,sha256=HFYA3YxqwyCvQLqXpMnKxp2IJUjFgjMsWVz_DTb_5eo,8229
109
109
  uncountable/integration/scan_profiles.py,sha256=RHBmPc5E10YZzf4cmglwrn2yAy0jHBhQ-P_GlAk2TeU,2919
110
110
  uncountable/integration/scheduler.py,sha256=KK-1XCr8Rxi8puaynb3H0BySvsDBJJaPcGumy49ZMB8,4864
111
111
  uncountable/integration/server.py,sha256=lL9zmzqkQRf7V1fBT20SvIy-7ryz5hFf7DF4QX4pj1E,4699
@@ -167,7 +167,7 @@ uncountable/types/entity_t.py,sha256=cULJs6qZAWnN4U8pZadcsf9A5KmlLTkIlwW_sQf627I
167
167
  uncountable/types/experiment_groups.py,sha256=qUpFOx1AKgzaT_4khCOv5Xs6jwiQGbvHH-GUh3v1nv4,288
168
168
  uncountable/types/experiment_groups_t.py,sha256=29Ct-WPejpYMuGfnFfOoosU9iSfjzxpabpBX6oTPFUA,761
169
169
  uncountable/types/exports.py,sha256=VMmxUO2PpV1Y63hZ2AnVor4H-B6aswJ7YpSru_u89lU,334
170
- uncountable/types/exports_t.py,sha256=der2gk1YL5XjWTrqsLD2KNynXA_z7IzmvphOfvGT19M,894
170
+ uncountable/types/exports_t.py,sha256=p_ub9Ltk6bGE4CCe07Mfz7y4-uDMCIo5_jZr1l55zsE,912
171
171
  uncountable/types/field_values.py,sha256=iG4TvITLnlz023GuhFrlDwXB7oov5DPpAs_FBaMaJR8,1713
172
172
  uncountable/types/field_values_t.py,sha256=Br2D2dibU9avbomfkaXHXw1ineUcIkATBbEm0eZm1SE,10076
173
173
  uncountable/types/fields.py,sha256=M0_ZZr0QdNLXkdHAGo5mfU90kEtHedCSKrcod-FG30Y,245
@@ -326,7 +326,7 @@ uncountable/types/api/uploader/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr
326
326
  uncountable/types/api/uploader/invoke_uploader.py,sha256=Bj7Dq4A90k00suacwk3bLA_dCb2aovS1kAbVam2AQnM,1395
327
327
  uncountable/types/api/user/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
328
328
  uncountable/types/api/user/get_current_user_info.py,sha256=Avqi_RXtRgbefrT_dwJ9MrO6eDNSSa_Nu650FSuESlg,1109
329
- uncountablepythonsdk-0.0.121.dist-info/METADATA,sha256=t53LhUUiQvTlHYZC-eX4VQU2KiyBCglI5Ywlmsh_qAk,2174
330
- uncountablepythonsdk-0.0.121.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
331
- uncountablepythonsdk-0.0.121.dist-info/top_level.txt,sha256=1UVGjAU-6hJY9qw2iJ7nCBeEwZ793AEN5ZfKX9A1uj4,31
332
- uncountablepythonsdk-0.0.121.dist-info/RECORD,,
329
+ uncountablepythonsdk-0.0.122.dist-info/METADATA,sha256=KCzmpzYEmy6LpOZxLn9tvAVP2Q7H3UE5KeRynwvn9rM,2174
330
+ uncountablepythonsdk-0.0.122.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
331
+ uncountablepythonsdk-0.0.122.dist-info/top_level.txt,sha256=1UVGjAU-6hJY9qw2iJ7nCBeEwZ793AEN5ZfKX9A1uj4,31
332
+ uncountablepythonsdk-0.0.122.dist-info/RECORD,,