mostlyright-data 0.31.2__tar.gz → 0.31.3__tar.gz

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 (136) hide show
  1. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/PKG-INFO +1 -1
  2. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/transport.py +100 -1
  3. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/.gitignore +0 -0
  4. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/README.md +0 -0
  5. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/pyproject.toml +0 -0
  6. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/scripts/hatch_build.py +0 -0
  7. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/SKILL.md +0 -0
  8. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/agents/openai.yaml +0 -0
  9. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/1-open-the-page-and-the-link-to-it-in-the-first-message.md +0 -0
  10. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/2-brief-two-to-four-questions-each-with-a-recommended-answer.md +0 -0
  11. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/3-probe-read-a-source-before-committing-to-it.md +0 -0
  12. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/4-decide-say-what-you-chose-what-you-refused-and-ask-one-question.md +0 -0
  13. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/5-draft-one-recipe-document-one-call.md +0 -0
  14. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/6-build-one-run-sized-to-acquire-every-measured-source-whole.md +0 -0
  15. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/7-interrogate-ask-the-run-what-it-actually-delivered.md +0 -0
  16. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/8-fix-revise-the-document-and-register-it-again.md +0 -0
  17. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/9-present-only-what-survived-inspection-with-caveats.md +0 -0
  18. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/agent-protocol.md +0 -0
  19. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/autonomous-delivery.md +0 -0
  20. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/before-the-first-tool-call.md +0 -0
  21. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/boundaries.md +0 -0
  22. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/cloud-authentication-preflight.md +0 -0
  23. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/commands.md +0 -0
  24. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/cross-repository-protocol-reference.md +0 -0
  25. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/enriching-with-small-models.md +0 -0
  26. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/installation-parity.md +0 -0
  27. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/live-run.md +0 -0
  28. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/making-a-table-incremental.md +0 -0
  29. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/narrating-the-run.md +0 -0
  30. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/not-hosted-yet.md +0 -0
  31. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/one-install.md +0 -0
  32. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/patterns.md +0 -0
  33. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/prediction-labels.md +0 -0
  34. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/preparing-table-search.md +0 -0
  35. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/promote.md +0 -0
  36. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/readers.md +0 -0
  37. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/receipts.md +0 -0
  38. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/recipe-test.md +0 -0
  39. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/recording-a-stream-venue.md +0 -0
  40. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/recovering-an-import-failure.md +0 -0
  41. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/reference-pages.md +0 -0
  42. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/required-protocol.md +0 -0
  43. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/source-credentials.md +0 -0
  44. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/sources.md +0 -0
  45. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/the-one-thing-to-say-about-the-skill-itself.md +0 -0
  46. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/transforms.md +0 -0
  47. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/user-communication-contract.md +0 -0
  48. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/references/writing-a-decision-record.md +0 -0
  49. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/skills/mr-data-build/scripts/write_research_notebook.py +0 -0
  50. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/__init__.py +0 -0
  51. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/agent_protocol.py +0 -0
  52. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/canonical.py +0 -0
  53. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/formats.py +0 -0
  54. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/hosted_crawler_protocol.py +0 -0
  55. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/key_seam.py +0 -0
  56. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/page_coverage.py +0 -0
  57. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/part_check_evidence.py +0 -0
  58. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/session_probes.py +0 -0
  59. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/skill_assets.py +0 -0
  60. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/table_manifest.py +0 -0
  61. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/__init__.py +0 -0
  62. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/acquire.py +0 -0
  63. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/acquire_cancel.py +0 -0
  64. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/activity.py +0 -0
  65. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/approvals.py +0 -0
  66. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/backoff.py +0 -0
  67. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/categories.py +0 -0
  68. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/commands.py +0 -0
  69. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/dataset-categories-v1.json +0 -0
  70. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/download.py +0 -0
  71. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/enrichment.py +0 -0
  72. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/fast_features.py +0 -0
  73. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/matching_benchmark.py +0 -0
  74. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/narrative.py +0 -0
  75. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/parity.py +0 -0
  76. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/probe.py +0 -0
  77. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/progress_rate.py +0 -0
  78. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/progress_vocabulary.py +0 -0
  79. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/propose.py +0 -0
  80. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/recipe.py +0 -0
  81. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/recipe_brief.py +0 -0
  82. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/recipe_explain.py +0 -0
  83. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/recipe_forecast.py +0 -0
  84. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/recipe_lint.py +0 -0
  85. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/recipe_test.py +0 -0
  86. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/refresh_rehearsal.py +0 -0
  87. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/release_check.py +0 -0
  88. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/research.py +0 -0
  89. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/router.py +0 -0
  90. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/run_diagnose.py +0 -0
  91. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/run_prefix.py +0 -0
  92. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/runs.py +0 -0
  93. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/session.py +0 -0
  94. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/stream.py +0 -0
  95. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/stream_venue.py +0 -0
  96. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/studio_capabilities.py +0 -0
  97. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/support.py +0 -0
  98. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/table_search_contract.json +0 -0
  99. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/user_agent.py +0 -0
  100. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/v4.py +0 -0
  101. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/v4_artifacts.py +0 -0
  102. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/v4_catalog.py +0 -0
  103. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/v4_connected.py +0 -0
  104. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/v4_connections.py +0 -0
  105. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/v4_dataset_covers.py +0 -0
  106. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/v4_datasets.py +0 -0
  107. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/v4_handoff.py +0 -0
  108. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/v4_matching.py +0 -0
  109. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/v4_narrative.py +0 -0
  110. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/v4_public.py +0 -0
  111. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/v4_query.py +0 -0
  112. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/v4_reader.py +0 -0
  113. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/v4_runs.py +0 -0
  114. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/v4_search.py +0 -0
  115. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/v4_search_contract.py +0 -0
  116. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/v4_secrets.py +0 -0
  117. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/v4_stream.py +0 -0
  118. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/v4_tables.py +0 -0
  119. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/thin/vocabulary.py +0 -0
  120. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/ux/__init__.py +0 -0
  121. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/ux/attendance.py +0 -0
  122. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/ux/clarification.py +0 -0
  123. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/ux/cloud_auth.py +0 -0
  124. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/ux/commands/__init__.py +0 -0
  125. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/ux/commands/auth.py +0 -0
  126. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/ux/commands/clarify.py +0 -0
  127. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/ux/commands/login.py +0 -0
  128. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/ux/commands/whoami.py +0 -0
  129. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/ux/credential_native.py +0 -0
  130. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/ux/credential_store.py +0 -0
  131. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/ux/credentials.py +0 -0
  132. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/ux/login.py +0 -0
  133. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/ux/path_kind.py +0 -0
  134. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/ux/plain_file.py +0 -0
  135. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/ux/remediation.py +0 -0
  136. {mostlyright_data-0.31.2 → mostlyright_data-0.31.3}/src/mostlyright/data_harness/ux/render.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mostlyright-data
3
- Version: 0.31.2
3
+ Version: 0.31.3
4
4
  Summary: Mostly Right hosted CLI for reviewed datasets
5
5
  Project-URL: Homepage, https://mostlyright.md/
6
6
  Project-URL: Documentation, https://mostlyright.md/docs/guides/cli/
@@ -10,14 +10,20 @@ to relax any of it.
10
10
 
11
11
  from __future__ import annotations
12
12
 
13
+ import hashlib
13
14
  import http.client
14
15
  import ipaddress
15
16
  import math
17
+ import re
16
18
  import ssl
17
19
  import threading
18
20
  import time
19
21
  from collections.abc import Callable, Iterator, Mapping
20
22
  from contextlib import contextmanager
23
+ from email.message import Message
24
+ from email.utils import parsedate_to_datetime
25
+ from http.cookiejar import Cookie, CookieJar, DefaultCookiePolicy
26
+ from http.cookies import CookieError, SimpleCookie
21
27
  from typing import Any, Protocol
22
28
  from urllib.error import HTTPError
23
29
  from urllib.parse import urlsplit
@@ -176,6 +182,78 @@ class UrlLibTransport:
176
182
  response.close()
177
183
 
178
184
 
185
+ class _RoutingCookiePolicy(DefaultCookiePolicy):
186
+ """Only Cloud Run's observed host-only routing cookie is retained."""
187
+
188
+ def set_ok(self, cookie: Cookie, request: Request) -> bool:
189
+ if (
190
+ cookie.name != "GAESA"
191
+ or cookie.domain_specified
192
+ or not cookie.path_specified
193
+ or cookie.path != "/"
194
+ or len(cookie.value or "") > 4096
195
+ ):
196
+ return False
197
+ # Cloud Run emits this without Secure. The transport accepts only
198
+ # verified HTTPS, and the stored form must never permit an HTTP send.
199
+ cookie.secure = True
200
+ return super().set_ok(cookie, request)
201
+
202
+
203
+ class _RoutingCookieResponse:
204
+ def __init__(self, header: str) -> None:
205
+ self.headers = Message()
206
+ self.headers["Set-Cookie"] = header
207
+
208
+ def info(self) -> Message:
209
+ return self.headers
210
+
211
+
212
+ def _remember_routing_cookie(
213
+ jar: CookieJar, response: http.client.HTTPResponse, request: Request
214
+ ) -> None:
215
+ candidates = [
216
+ value
217
+ for key, value in response.getheaders()
218
+ if key.lower() == "set-cookie" and value.partition("=")[0].strip() == "GAESA"
219
+ ]
220
+ if len(candidates) != 1:
221
+ return
222
+ header = candidates[0]
223
+ if (
224
+ len(header) > 8192
225
+ or "\r" in header
226
+ or "\n" in header
227
+ or len(re.findall(r"(?:^|[;,])\s*GAESA\s*=", header)) != 1
228
+ ):
229
+ return
230
+ parsed = SimpleCookie()
231
+ try:
232
+ parsed.load(header)
233
+ if set(parsed) != {"GAESA"}:
234
+ return
235
+ routing = parsed["GAESA"]
236
+ if not re.fullmatch(r"[\x21\x23-\x2b\x2d-\x3a\x3c-\x5b\x5d-\x7e]*", routing.value):
237
+ return
238
+ if routing["max-age"]:
239
+ age = routing["max-age"]
240
+ if (
241
+ not re.fullmatch(r"-?\d+", age)
242
+ or len(age.lstrip("-")) > 10
243
+ or abs(int(age)) > 2_147_483_647
244
+ ):
245
+ return
246
+ if routing["expires"]:
247
+ parsedate_to_datetime(routing["expires"])
248
+ except (CookieError, ValueError, OverflowError):
249
+ return
250
+ try:
251
+ jar.extract_cookies(_RoutingCookieResponse(header), request)
252
+ except (ValueError, OverflowError):
253
+ # Optional routing metadata must never invalidate a complete answer.
254
+ return
255
+
256
+
179
257
  class ReusableHttpsTransport(UrlLibTransport):
180
258
  """One serialized, verified HTTPS connection for repeated query requests.
181
259
 
@@ -183,6 +261,8 @@ class ReusableHttpsTransport(UrlLibTransport):
183
261
  own connection instead, never a global credential-bearing pool. Changing
184
262
  origin closes the old socket. Responses are bounded and fully framed;
185
263
  any failure discards the socket and is raised without replaying a POST.
264
+ Only the host-only root GAESA routing cookie is retained in memory, bound
265
+ to this client's exact origin and authorization context, never login cookies.
186
266
  Streams retain the original urllib/proxy-free/redirect-free behavior.
187
267
  """
188
268
 
@@ -191,6 +271,8 @@ class ReusableHttpsTransport(UrlLibTransport):
191
271
  self._lock = threading.Lock()
192
272
  self._connection: http.client.HTTPSConnection | None = None
193
273
  self._connection_origin: tuple[str, str, int] | None = None
274
+ self._routing = CookieJar(policy=_RoutingCookiePolicy())
275
+ self._routing_context: tuple[tuple[str, str, int], bytes] | None = None
194
276
 
195
277
  def _discard(self) -> None:
196
278
  connection, self._connection = self._connection, None
@@ -201,6 +283,8 @@ class ReusableHttpsTransport(UrlLibTransport):
201
283
  def close(self) -> None:
202
284
  with self._lock:
203
285
  self._discard()
286
+ self._routing.clear()
287
+ self._routing_context = None
204
288
 
205
289
  def __enter__(self) -> ReusableHttpsTransport:
206
290
  return self
@@ -248,6 +332,19 @@ class ReusableHttpsTransport(UrlLibTransport):
248
332
  return value
249
333
 
250
334
  try:
335
+ context_headers = sorted(
336
+ (name.lower(), value)
337
+ for name, value in headers.items()
338
+ if name.lower() in {"authorization", "proxy-authorization", "cookie", "x-api-key"}
339
+ )
340
+ context = (origin, hashlib.sha256(repr(context_headers).encode()).digest())
341
+ if context != self._routing_context:
342
+ self._routing.clear()
343
+ self._routing_context = context
344
+ caller_cookie = any(name.lower() == "cookie" for name in headers)
345
+ cookie_request = Request(url, headers=dict(with_user_agent(headers)), method=method)
346
+ if not caller_cookie:
347
+ self._routing.add_cookie_header(cookie_request)
251
348
  if self._connection_origin != origin:
252
349
  self._discard()
253
350
  if self._connection is None:
@@ -262,7 +359,7 @@ class ReusableHttpsTransport(UrlLibTransport):
262
359
  path = parts.path or "/"
263
360
  if parts.query:
264
361
  path += "?" + parts.query
265
- connection.request(method, path, body=body, headers=dict(with_user_agent(headers)))
362
+ connection.request(method, path, body=body, headers=dict(cookie_request.header_items()))
266
363
  if connection.sock is not None:
267
364
  connection.sock.settimeout(remaining())
268
365
  response = connection.getresponse()
@@ -285,6 +382,8 @@ class ReusableHttpsTransport(UrlLibTransport):
285
382
  )
286
383
  if expected is not None and length != expected:
287
384
  raise http.client.IncompleteRead(raw, expected - length)
385
+ if not caller_cookie:
386
+ _remember_routing_cookie(self._routing, response, cookie_request)
288
387
  status = int(response.status)
289
388
  response_headers = {key.lower(): value for key, value in response.headers.items()}
290
389
  response.close()