unique-search-proxy 2026.28.0.dev0__tar.gz → 2026.28.0.dev2__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.
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/PKG-INFO +4 -3
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/pyproject.toml +6 -3
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/app.py +1 -1
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/agent_engines/bing/client.py +1 -1
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/agent_engines/vertexai/client.py +12 -4
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/client/service.py +4 -2
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/crawlers/firecrawl/service.py +1 -1
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/crawlers/jina/service.py +1 -1
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/crawlers/tavily/service.py +1 -1
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/search_engines/brave/service.py +1 -1
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/search_engines/google/service.py +1 -1
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/search_engines/perplexity/service.py +1 -1
- unique_search_proxy-2026.28.0.dev2/unique_search_proxy_client/web/helm/__init__.py +1 -0
- unique_search_proxy-2026.28.0.dev2/unique_search_proxy_client/web/helm/generator/__init__.py +73 -0
- unique_search_proxy-2026.28.0.dev2/unique_search_proxy_client/web/helm/generator/introspect.py +324 -0
- unique_search_proxy-2026.28.0.dev2/unique_search_proxy_client/web/helm/generator/schema.py +139 -0
- unique_search_proxy-2026.28.0.dev2/unique_search_proxy_client/web/helm/generator/template.py +308 -0
- unique_search_proxy-2026.28.0.dev2/unique_search_proxy_client/web/helm/generator/templates/provider_values_yaml.j2 +40 -0
- unique_search_proxy-2026.28.0.dev2/unique_search_proxy_client/web/helm/generator/values_yaml.py +205 -0
- unique_search_proxy-2026.28.0.dev2/unique_search_proxy_client/web/helm/metadata.py +175 -0
- unique_search_proxy-2026.28.0.dev2/unique_search_proxy_client/web/helm/registry.py +117 -0
- unique_search_proxy-2026.28.0.dev2/unique_search_proxy_client/web/helm/url_safety_registration.py +84 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/settings/client.py +19 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/settings/monitoring.py +8 -0
- unique_search_proxy-2026.28.0.dev2/unique_search_proxy_client/web/settings/providers/__init__.py +37 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/settings/providers/base.py +13 -30
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/settings/providers/bing_agent.py +3 -1
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/settings/providers/brave.py +6 -2
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/settings/providers/firecrawl.py +6 -2
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/settings/providers/google.py +6 -2
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/settings/providers/jina.py +15 -2
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/settings/providers/perplexity.py +6 -2
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/settings/providers/tavily.py +6 -2
- unique_search_proxy-2026.28.0.dev2/unique_search_proxy_client/web/settings/providers/vertexai_agent.py +46 -0
- unique_search_proxy-2026.28.0.dev2/unique_search_proxy_client/web/settings/secret_str.py +96 -0
- {unique_search_proxy-2026.28.0.dev0/unique_search_proxy_client/web/settings → unique_search_proxy-2026.28.0.dev2/unique_search_proxy_client/web}/startup_report.py +7 -52
- unique_search_proxy-2026.28.0.dev0/unique_search_proxy_client/web/settings/providers/__init__.py +0 -17
- unique_search_proxy-2026.28.0.dev0/unique_search_proxy_client/web/settings/providers/vertexai_agent.py +0 -29
- unique_search_proxy-2026.28.0.dev0/unique_search_proxy_client/web/settings/secret_str.py +0 -41
- unique_search_proxy-2026.28.0.dev0/unique_search_proxy_client/web/settings/startup_log.py +0 -29
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/README.md +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/__init__.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/__init__.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/api/__init__.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/api/health.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/api/v1/__init__.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/api/v1/agent_search.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/api/v1/configuration.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/api/v1/crawl.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/api/v1/openapi_examples.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/api/v1/search.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/__init__.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/agent_engines/__init__.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/agent_engines/bing/runner.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/agent_engines/bing/service.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/agent_engines/factory.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/agent_engines/serialization.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/agent_engines/service_base.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/agent_engines/structured_output.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/agent_engines/vertexai/gemini.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/agent_engines/vertexai/service.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/client/__init__.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/crawlers/__init__.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/crawlers/basic/__init__.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/crawlers/basic/processing/__init__.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/crawlers/basic/processing/errors.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/crawlers/basic/processing/html_markdown.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/crawlers/basic/processing/processors/__init__.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/crawlers/basic/processing/processors/html.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/crawlers/basic/processing/processors/pdf.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/crawlers/basic/processing/processors/plain_text.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/crawlers/basic/processing/registry.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/crawlers/basic/service.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/crawlers/basic/settings.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/crawlers/basic/user_agent.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/crawlers/factory.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/crawlers/firecrawl/polling.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/crawlers/firecrawl/request_body.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/crawlers/jina/request_body.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/crawlers/pinned_egress.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/crawlers/tavily/request_body.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/provider_response.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/providers.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/registry.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/search_engines/__init__.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/search_engines/brave/__init__.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/search_engines/brave/pagination.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/search_engines/brave/query_params.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/search_engines/descriptor.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/search_engines/factory.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/search_engines/google/__init__.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/search_engines/google/pagination.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/search_engines/google/query_params.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/search_engines/pagination.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/search_engines/perplexity/__init__.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/search_engines/perplexity/request_body.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/search_engines/service_base.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/url_safety/__init__.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/core/url_safety/gate.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/error_handlers.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/logging_config.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/monitoring/__init__.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/monitoring/metrics.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/monitoring/setup.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/presets/__init__.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/presets/common.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/presets/crawl.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/presets/search.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/presets/types.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/settings/__init__.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/settings/base.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/utils/__init__.py +0 -0
- {unique_search_proxy-2026.28.0.dev0 → unique_search_proxy-2026.28.0.dev2}/unique_search_proxy_client/web/utils/url.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: unique-search-proxy
|
|
3
|
-
Version: 2026.28.0.
|
|
3
|
+
Version: 2026.28.0.dev2
|
|
4
4
|
Summary: Web Search Proxy implementation
|
|
5
5
|
Author: ThePhilAz
|
|
6
6
|
Author-email: ThePhilAz <rami.azouz@philico.com>
|
|
@@ -18,8 +18,9 @@ Requires-Dist: azure-core>=1.36.0,<2
|
|
|
18
18
|
Requires-Dist: certifi>=2025.11.12,<2027
|
|
19
19
|
Requires-Dist: google-genai>=1.73.0,<2
|
|
20
20
|
Requires-Dist: google-auth>=2.43.0,<3
|
|
21
|
-
Requires-Dist:
|
|
22
|
-
Requires-Dist: unique-
|
|
21
|
+
Requires-Dist: jinja2>=3.1.6,<4
|
|
22
|
+
Requires-Dist: unique-toolkit[monitoring]>=2026.28.0.dev3,<2026.28.0rc0
|
|
23
|
+
Requires-Dist: unique-search-proxy-core>=2026.28.0.dev1,<2026.28.0rc0
|
|
23
24
|
Requires-Python: >=3.12
|
|
24
25
|
Description-Content-Type: text/markdown
|
|
25
26
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "unique-search-proxy"
|
|
3
|
-
version = "2026.28.0.
|
|
3
|
+
version = "2026.28.0.dev2"
|
|
4
4
|
description = "Web Search Proxy implementation"
|
|
5
5
|
authors = [{ name = "ThePhilAz", email = "rami.azouz@philico.com" }]
|
|
6
6
|
readme = "README.md"
|
|
@@ -20,8 +20,9 @@ dependencies = [
|
|
|
20
20
|
"certifi>=2025.11.12,<2027",
|
|
21
21
|
"google-genai>=1.73.0,<2",
|
|
22
22
|
"google-auth>=2.43.0,<3",
|
|
23
|
-
"
|
|
24
|
-
"unique-
|
|
23
|
+
"jinja2>=3.1.6,<4",
|
|
24
|
+
"unique-toolkit[monitoring]>=2026.28.0.dev3,<2026.28.0rc0",
|
|
25
|
+
"unique-search-proxy-core>=2026.28.0.dev1,<2026.28.0rc0",
|
|
25
26
|
]
|
|
26
27
|
|
|
27
28
|
[dependency-groups]
|
|
@@ -77,6 +78,8 @@ DEP003 = ["unique_toolkit", "unique_search_proxy_core"]
|
|
|
77
78
|
|
|
78
79
|
[tool.poe.tasks]
|
|
79
80
|
generate-sdk = "python scripts/generate_sdk.py"
|
|
81
|
+
generate-helm-config = "python scripts/generate_helm_config.py"
|
|
82
|
+
render-helm-fixtures = "bash scripts/render_helm_fixtures.sh"
|
|
80
83
|
lint = "ruff check ."
|
|
81
84
|
lint-fix = "ruff check . --fix"
|
|
82
85
|
format = "ruff format ."
|
|
@@ -18,7 +18,7 @@ from unique_search_proxy_client.web.logging_config import (
|
|
|
18
18
|
configure_logging,
|
|
19
19
|
)
|
|
20
20
|
from unique_search_proxy_client.web.monitoring import setup_prometheus
|
|
21
|
-
from unique_search_proxy_client.web.
|
|
21
|
+
from unique_search_proxy_client.web.startup_report import (
|
|
22
22
|
log_startup_settings_report,
|
|
23
23
|
)
|
|
24
24
|
|
|
@@ -8,10 +8,10 @@ from azure.core.credentials_async import AsyncTokenCredential
|
|
|
8
8
|
from azure.core.pipeline.transport import AsyncioRequestsTransport
|
|
9
9
|
from azure.identity.aio import DefaultAzureCredential, WorkloadIdentityCredential
|
|
10
10
|
|
|
11
|
-
from unique_search_proxy_client.web.settings.providers.base import NOT_PROVIDED
|
|
12
11
|
from unique_search_proxy_client.web.settings.providers.bing_agent import (
|
|
13
12
|
bing_agent_credentials,
|
|
14
13
|
)
|
|
14
|
+
from unique_search_proxy_client.web.settings.secret_str import NOT_PROVIDED
|
|
15
15
|
|
|
16
16
|
_LOGGER = logging.getLogger(__name__)
|
|
17
17
|
|
|
@@ -8,16 +8,24 @@ from google.auth import load_credentials_from_dict
|
|
|
8
8
|
from google.genai._api_client import BaseApiClient
|
|
9
9
|
from google.genai.client import AsyncClient
|
|
10
10
|
|
|
11
|
-
from unique_search_proxy_client.web.settings.providers.base import read_secret
|
|
12
11
|
from unique_search_proxy_client.web.settings.providers.vertexai_agent import (
|
|
13
12
|
vertexai_agent_credentials,
|
|
14
13
|
)
|
|
14
|
+
from unique_search_proxy_client.web.settings.secret_str import (
|
|
15
|
+
is_secret_configured,
|
|
16
|
+
read_secret,
|
|
17
|
+
)
|
|
15
18
|
|
|
16
19
|
_LOGGER = logging.getLogger(__name__)
|
|
17
20
|
|
|
18
21
|
|
|
19
22
|
def _get_base_api_client_from_service_account() -> BaseApiClient:
|
|
20
|
-
|
|
23
|
+
if not is_secret_configured(vertexai_agent_credentials.service_account_credentials):
|
|
24
|
+
msg = (
|
|
25
|
+
"VERTEXAI_AGENT_CREDENTIAL_TYPE is 'service_account' but "
|
|
26
|
+
"VERTEXAI_AGENT_SERVICE_ACCOUNT_CREDENTIALS is not set."
|
|
27
|
+
)
|
|
28
|
+
raise ValueError(msg)
|
|
21
29
|
|
|
22
30
|
scopes = vertexai_agent_credentials.service_account_scopes or [
|
|
23
31
|
"https://www.googleapis.com/auth/cloud-platform",
|
|
@@ -43,11 +51,11 @@ def _get_base_api_client_from_adc() -> BaseApiClient:
|
|
|
43
51
|
|
|
44
52
|
|
|
45
53
|
def get_vertex_client() -> AsyncClient:
|
|
46
|
-
if vertexai_agent_credentials.
|
|
54
|
+
if vertexai_agent_credentials.credential_type == "service_account":
|
|
47
55
|
_LOGGER.info("Using explicit service account credentials for VertexAI agent")
|
|
48
56
|
base_api_client = _get_base_api_client_from_service_account()
|
|
49
57
|
else:
|
|
50
|
-
_LOGGER.info("Using ADC for VertexAI agent")
|
|
58
|
+
_LOGGER.info("Using workload identity (ADC) for VertexAI agent")
|
|
51
59
|
base_api_client = _get_base_api_client_from_adc()
|
|
52
60
|
return AsyncClient(api_client=base_api_client)
|
|
53
61
|
|
|
@@ -14,8 +14,10 @@ from unique_search_proxy_client.web.settings.client import (
|
|
|
14
14
|
ProxyConfig,
|
|
15
15
|
http_client_settings,
|
|
16
16
|
)
|
|
17
|
-
from unique_search_proxy_client.web.settings.
|
|
18
|
-
|
|
17
|
+
from unique_search_proxy_client.web.settings.secret_str import (
|
|
18
|
+
read_secret,
|
|
19
|
+
read_secret_headers,
|
|
20
|
+
)
|
|
19
21
|
|
|
20
22
|
if TYPE_CHECKING:
|
|
21
23
|
from fastapi import FastAPI
|
|
@@ -25,10 +25,10 @@ from unique_search_proxy_client.web.core.provider_response import (
|
|
|
25
25
|
upstream_error_message,
|
|
26
26
|
upstream_response_raw,
|
|
27
27
|
)
|
|
28
|
-
from unique_search_proxy_client.web.settings.providers.base import read_secret
|
|
29
28
|
from unique_search_proxy_client.web.settings.providers.firecrawl import (
|
|
30
29
|
firecrawl_crawl_credentials as credentials,
|
|
31
30
|
)
|
|
31
|
+
from unique_search_proxy_client.web.settings.secret_str import read_secret
|
|
32
32
|
from unique_search_proxy_client.web.utils.url import join_url_path
|
|
33
33
|
|
|
34
34
|
_LOGGER = logging.getLogger(__name__)
|
|
@@ -18,10 +18,10 @@ from unique_search_proxy_client.web.core.provider_response import (
|
|
|
18
18
|
transport_error_raw,
|
|
19
19
|
upstream_response_raw,
|
|
20
20
|
)
|
|
21
|
-
from unique_search_proxy_client.web.settings.providers.base import read_secret
|
|
22
21
|
from unique_search_proxy_client.web.settings.providers.jina import (
|
|
23
22
|
jina_crawl_credentials as credentials,
|
|
24
23
|
)
|
|
24
|
+
from unique_search_proxy_client.web.settings.secret_str import read_secret
|
|
25
25
|
|
|
26
26
|
_LOGGER = logging.getLogger(__name__)
|
|
27
27
|
|
|
@@ -19,10 +19,10 @@ from unique_search_proxy_client.web.core.provider_response import (
|
|
|
19
19
|
upstream_error_message,
|
|
20
20
|
upstream_response_raw,
|
|
21
21
|
)
|
|
22
|
-
from unique_search_proxy_client.web.settings.providers.base import read_secret
|
|
23
22
|
from unique_search_proxy_client.web.settings.providers.tavily import (
|
|
24
23
|
tavily_crawl_credentials as credentials,
|
|
25
24
|
)
|
|
25
|
+
from unique_search_proxy_client.web.settings.secret_str import read_secret
|
|
26
26
|
|
|
27
27
|
_LOGGER = logging.getLogger(__name__)
|
|
28
28
|
|
|
@@ -37,10 +37,10 @@ from unique_search_proxy_client.web.core.search_engines.pagination import PageRe
|
|
|
37
37
|
from unique_search_proxy_client.web.core.search_engines.service_base import (
|
|
38
38
|
SearchEngineService,
|
|
39
39
|
)
|
|
40
|
-
from unique_search_proxy_client.web.settings.providers.base import read_secret
|
|
41
40
|
from unique_search_proxy_client.web.settings.providers.brave import (
|
|
42
41
|
brave_search_credentials as credentials,
|
|
43
42
|
)
|
|
43
|
+
from unique_search_proxy_client.web.settings.secret_str import read_secret
|
|
44
44
|
|
|
45
45
|
_LOGGER = logging.getLogger(__name__)
|
|
46
46
|
_BRAVE_PROVIDER_LABEL = "Brave Web Search API"
|
|
@@ -37,10 +37,10 @@ from unique_search_proxy_client.web.core.search_engines.pagination import PageRe
|
|
|
37
37
|
from unique_search_proxy_client.web.core.search_engines.service_base import (
|
|
38
38
|
SearchEngineService,
|
|
39
39
|
)
|
|
40
|
-
from unique_search_proxy_client.web.settings.providers.base import read_secret
|
|
41
40
|
from unique_search_proxy_client.web.settings.providers.google import (
|
|
42
41
|
google_search_credentials as credentials,
|
|
43
42
|
)
|
|
43
|
+
from unique_search_proxy_client.web.settings.secret_str import read_secret
|
|
44
44
|
|
|
45
45
|
_GOOGLE_PROVIDER_LABEL = "Google Custom Search API"
|
|
46
46
|
|
|
@@ -36,7 +36,7 @@ from unique_search_proxy_client.web.core.search_engines.service_base import (
|
|
|
36
36
|
from unique_search_proxy_client.web.settings.providers import (
|
|
37
37
|
perplexity_search_credentials as credentials,
|
|
38
38
|
)
|
|
39
|
-
from unique_search_proxy_client.web.settings.
|
|
39
|
+
from unique_search_proxy_client.web.settings.secret_str import read_secret
|
|
40
40
|
|
|
41
41
|
_LOGGER = logging.getLogger(__name__)
|
|
42
42
|
_PERPLEXITY_PROVIDER_LABEL = "Perplexity Search API"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Helm chart metadata, registry, and artifact generation for the search proxy."""
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from unique_search_proxy_client.web.helm.generator.schema import (
|
|
6
|
+
render_additional_schema,
|
|
7
|
+
)
|
|
8
|
+
from unique_search_proxy_client.web.helm.generator.template import (
|
|
9
|
+
render_generated_template,
|
|
10
|
+
)
|
|
11
|
+
from unique_search_proxy_client.web.helm.generator.values_yaml import (
|
|
12
|
+
patch_values_yaml,
|
|
13
|
+
)
|
|
14
|
+
from unique_search_proxy_client.web.helm.registry import (
|
|
15
|
+
HelmSettingsGroup,
|
|
16
|
+
helm_generated_groups,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def chart_paths(chart_dir: Path) -> dict[str, Path]:
|
|
21
|
+
return {
|
|
22
|
+
"additional_schema": chart_dir / "values.additional.schema.json",
|
|
23
|
+
"generated_tpl": chart_dir / "templates" / "_generated.tpl",
|
|
24
|
+
"values_yaml": chart_dir / "values.yaml",
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def generated_groups_tuple() -> tuple[HelmSettingsGroup, ...]:
|
|
29
|
+
return tuple(helm_generated_groups())
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def generate_artifacts(chart_dir: Path) -> dict[str, str]:
|
|
33
|
+
groups = generated_groups_tuple()
|
|
34
|
+
paths = chart_paths(chart_dir)
|
|
35
|
+
values_text = paths["values_yaml"].read_text(encoding="utf-8")
|
|
36
|
+
|
|
37
|
+
outputs = {
|
|
38
|
+
str(paths["additional_schema"]): render_additional_schema(groups),
|
|
39
|
+
str(paths["generated_tpl"]): render_generated_template(groups),
|
|
40
|
+
str(paths["values_yaml"]): patch_values_yaml(values_text, groups),
|
|
41
|
+
}
|
|
42
|
+
return outputs
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def write_artifacts(chart_dir: Path) -> dict[str, Path]:
|
|
46
|
+
outputs = generate_artifacts(chart_dir)
|
|
47
|
+
written: dict[str, Path] = {}
|
|
48
|
+
for path_str, content in outputs.items():
|
|
49
|
+
path = Path(path_str)
|
|
50
|
+
path.write_text(content, encoding="utf-8")
|
|
51
|
+
written[path.name] = path
|
|
52
|
+
return written
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def check_artifacts(chart_dir: Path) -> list[str]:
|
|
56
|
+
drift: list[str] = []
|
|
57
|
+
outputs = generate_artifacts(chart_dir)
|
|
58
|
+
for path_str, expected in outputs.items():
|
|
59
|
+
path = Path(path_str)
|
|
60
|
+
if not path.exists():
|
|
61
|
+
drift.append(f"missing -> {path}")
|
|
62
|
+
continue
|
|
63
|
+
actual = path.read_text(encoding="utf-8")
|
|
64
|
+
if actual != expected:
|
|
65
|
+
drift.append(f"drift -> {path}")
|
|
66
|
+
# Files emitted by earlier generator versions; flag them so they are removed
|
|
67
|
+
# rather than silently shadowing the current output. (_google.tpl predates the
|
|
68
|
+
# consolidated template; _providers.tpl was renamed to _generated.tpl.)
|
|
69
|
+
for stale_name in ("_google.tpl", "_providers.tpl"):
|
|
70
|
+
stale = chart_dir / "templates" / stale_name
|
|
71
|
+
if stale.exists():
|
|
72
|
+
drift.append(f"stale file should be removed -> {stale}")
|
|
73
|
+
return drift
|
unique_search_proxy-2026.28.0.dev2/unique_search_proxy_client/web/helm/generator/introspect.py
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import inspect
|
|
4
|
+
import re
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from typing import Any, Literal, cast, get_args, get_origin
|
|
8
|
+
|
|
9
|
+
from pydantic import SecretStr
|
|
10
|
+
from pydantic.fields import FieldInfo
|
|
11
|
+
|
|
12
|
+
from unique_search_proxy_client.web.settings.secret_str import (
|
|
13
|
+
NOT_PROVIDED,
|
|
14
|
+
LogSecretStr,
|
|
15
|
+
field_has_not_provided_default,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
_URI_DEFAULT_RE = re.compile(r"^https?://", re.IGNORECASE)
|
|
19
|
+
|
|
20
|
+
DEFAULT_HELM_SECTION = "connection"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def snake_to_camel(name: str) -> str:
|
|
24
|
+
parts = name.split("_")
|
|
25
|
+
return parts[0] + "".join(part.capitalize() for part in parts[1:])
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def env_var_name(field_name: str, env_prefix: str) -> str:
|
|
29
|
+
return f"{env_prefix}{field_name.upper()}"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _helm_extra(field_info: FieldInfo) -> dict[str, Any]:
|
|
33
|
+
extra = field_info.json_schema_extra
|
|
34
|
+
if isinstance(extra, dict):
|
|
35
|
+
helm = extra.get("helm")
|
|
36
|
+
if isinstance(helm, dict):
|
|
37
|
+
return helm
|
|
38
|
+
return {}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _unwrap_annotation(annotation: Any) -> Any:
|
|
42
|
+
origin = get_origin(annotation)
|
|
43
|
+
if origin is None:
|
|
44
|
+
return annotation
|
|
45
|
+
args = get_args(annotation)
|
|
46
|
+
non_none = [arg for arg in args if arg is not type(None)]
|
|
47
|
+
if len(non_none) == 1:
|
|
48
|
+
return non_none[0]
|
|
49
|
+
return annotation
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _is_secret_type(annotation: Any) -> bool:
|
|
53
|
+
inner = _unwrap_annotation(annotation)
|
|
54
|
+
return inner in {SecretStr, LogSecretStr}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _is_scalar_type(annotation: Any) -> bool:
|
|
58
|
+
origin = get_origin(annotation)
|
|
59
|
+
if origin is Literal:
|
|
60
|
+
return True
|
|
61
|
+
inner = _unwrap_annotation(annotation)
|
|
62
|
+
if inner in {str, int, float, bool}:
|
|
63
|
+
return True
|
|
64
|
+
if isinstance(inner, type) and issubclass(inner, str):
|
|
65
|
+
return True
|
|
66
|
+
return False
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _is_list_str_type(annotation: Any) -> bool:
|
|
70
|
+
origin = get_origin(annotation)
|
|
71
|
+
if origin is not list:
|
|
72
|
+
return False
|
|
73
|
+
args = get_args(annotation)
|
|
74
|
+
if not args:
|
|
75
|
+
return False
|
|
76
|
+
inner = args[0]
|
|
77
|
+
return inner is str or (isinstance(inner, type) and issubclass(inner, str))
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _factory_takes_validated_data(factory: Callable[..., Any]) -> bool:
|
|
81
|
+
try:
|
|
82
|
+
params = inspect.signature(factory).parameters
|
|
83
|
+
except (TypeError, ValueError):
|
|
84
|
+
return False
|
|
85
|
+
return any(
|
|
86
|
+
p.kind
|
|
87
|
+
in (
|
|
88
|
+
inspect.Parameter.POSITIONAL_ONLY,
|
|
89
|
+
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
90
|
+
inspect.Parameter.VAR_POSITIONAL,
|
|
91
|
+
)
|
|
92
|
+
for p in params.values()
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _default_value(field_info: FieldInfo) -> Any:
|
|
97
|
+
factory = field_info.default_factory
|
|
98
|
+
if factory is not None:
|
|
99
|
+
factory = cast(Callable[..., Any], factory)
|
|
100
|
+
try:
|
|
101
|
+
if _factory_takes_validated_data(factory):
|
|
102
|
+
return factory({})
|
|
103
|
+
return factory()
|
|
104
|
+
except TypeError:
|
|
105
|
+
return None
|
|
106
|
+
return field_info.default
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _default_is_uri(default: Any) -> bool:
|
|
110
|
+
return isinstance(default, str) and bool(_URI_DEFAULT_RE.match(default))
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@dataclass(frozen=True)
|
|
114
|
+
class HelmFieldSpec:
|
|
115
|
+
"""One Helm-mapped field derived from a Pydantic model field."""
|
|
116
|
+
|
|
117
|
+
python_name: str
|
|
118
|
+
helm_name: str
|
|
119
|
+
env_var: str
|
|
120
|
+
sensitive: bool
|
|
121
|
+
required_when_enabled: bool
|
|
122
|
+
schema_ref: str | None
|
|
123
|
+
plain_type: str | None
|
|
124
|
+
format_uri: bool
|
|
125
|
+
default: Any
|
|
126
|
+
section: str
|
|
127
|
+
block_level: bool
|
|
128
|
+
container: bool
|
|
129
|
+
overridable: bool
|
|
130
|
+
emit_in_template: bool
|
|
131
|
+
emit_in_values: bool
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _schema_ref_for_field(
|
|
135
|
+
*,
|
|
136
|
+
field_info: FieldInfo,
|
|
137
|
+
sensitive: bool,
|
|
138
|
+
default: Any,
|
|
139
|
+
helm_extra: dict[str, Any],
|
|
140
|
+
) -> tuple[str | None, str | None]:
|
|
141
|
+
override = helm_extra.get("value_source")
|
|
142
|
+
if isinstance(override, str):
|
|
143
|
+
return f"#/$defs/valueSource{override}", None
|
|
144
|
+
|
|
145
|
+
if sensitive:
|
|
146
|
+
return "#/$defs/valueSourceSensitive", None
|
|
147
|
+
|
|
148
|
+
inner = _unwrap_annotation(field_info.annotation)
|
|
149
|
+
if inner is bool:
|
|
150
|
+
return "#/$defs/valueSourceBoolean", None
|
|
151
|
+
if inner is int:
|
|
152
|
+
return "#/$defs/valueSourceInteger", None
|
|
153
|
+
if inner is float:
|
|
154
|
+
return None, "number"
|
|
155
|
+
if _default_is_uri(default):
|
|
156
|
+
return None, "string"
|
|
157
|
+
if inner is str or (isinstance(inner, type) and issubclass(inner, str)):
|
|
158
|
+
return "#/$defs/valueSourceString", None
|
|
159
|
+
return "#/$defs/valueSourceString", None
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def iter_helm_fields(
|
|
163
|
+
model: type[Any],
|
|
164
|
+
*,
|
|
165
|
+
env_prefix: str,
|
|
166
|
+
) -> tuple[HelmFieldSpec, ...]:
|
|
167
|
+
specs: list[HelmFieldSpec] = []
|
|
168
|
+
for field_name, field_info in model.model_fields.items():
|
|
169
|
+
helm_extra = _helm_extra(field_info)
|
|
170
|
+
if helm_extra.get("skip"):
|
|
171
|
+
continue
|
|
172
|
+
|
|
173
|
+
annotation = field_info.annotation
|
|
174
|
+
origin = get_origin(annotation)
|
|
175
|
+
container = False
|
|
176
|
+
if origin is dict:
|
|
177
|
+
continue
|
|
178
|
+
if origin is list:
|
|
179
|
+
if not _is_list_str_type(annotation):
|
|
180
|
+
continue
|
|
181
|
+
container = True
|
|
182
|
+
elif not _is_scalar_type(annotation) and not _is_secret_type(annotation):
|
|
183
|
+
continue
|
|
184
|
+
|
|
185
|
+
default = _default_value(field_info)
|
|
186
|
+
sensitive = bool(helm_extra.get("sensitive")) or _is_secret_type(annotation)
|
|
187
|
+
required_when_enabled = bool(
|
|
188
|
+
helm_extra.get("required_when_enabled")
|
|
189
|
+
) or field_has_not_provided_default(field_info)
|
|
190
|
+
schema_ref, plain_type = _connection_property_types(
|
|
191
|
+
field_info=field_info,
|
|
192
|
+
sensitive=sensitive,
|
|
193
|
+
default=default,
|
|
194
|
+
helm_extra=helm_extra,
|
|
195
|
+
container=container,
|
|
196
|
+
)
|
|
197
|
+
helm_name = str(helm_extra.get("helm_name", snake_to_camel(field_name)))
|
|
198
|
+
section = str(helm_extra.get("section", DEFAULT_HELM_SECTION))
|
|
199
|
+
block_level = bool(helm_extra.get("block_level"))
|
|
200
|
+
overridable = bool(helm_extra.get("overridable"))
|
|
201
|
+
spec = HelmFieldSpec(
|
|
202
|
+
python_name=field_name,
|
|
203
|
+
helm_name=helm_name,
|
|
204
|
+
env_var=env_var_name(field_name, env_prefix),
|
|
205
|
+
sensitive=sensitive,
|
|
206
|
+
required_when_enabled=required_when_enabled,
|
|
207
|
+
schema_ref=schema_ref,
|
|
208
|
+
plain_type=plain_type,
|
|
209
|
+
format_uri=_default_is_uri(default),
|
|
210
|
+
default=default,
|
|
211
|
+
section=section,
|
|
212
|
+
block_level=block_level,
|
|
213
|
+
container=container,
|
|
214
|
+
overridable=overridable,
|
|
215
|
+
emit_in_template=False,
|
|
216
|
+
emit_in_values=True,
|
|
217
|
+
)
|
|
218
|
+
specs.append(
|
|
219
|
+
HelmFieldSpec(
|
|
220
|
+
python_name=spec.python_name,
|
|
221
|
+
helm_name=spec.helm_name,
|
|
222
|
+
env_var=spec.env_var,
|
|
223
|
+
sensitive=spec.sensitive,
|
|
224
|
+
required_when_enabled=spec.required_when_enabled,
|
|
225
|
+
schema_ref=spec.schema_ref,
|
|
226
|
+
plain_type=spec.plain_type,
|
|
227
|
+
format_uri=spec.format_uri,
|
|
228
|
+
default=spec.default,
|
|
229
|
+
section=spec.section,
|
|
230
|
+
block_level=spec.block_level,
|
|
231
|
+
container=spec.container,
|
|
232
|
+
overridable=spec.overridable,
|
|
233
|
+
emit_in_template=_should_emit_in_template(spec),
|
|
234
|
+
emit_in_values=spec.emit_in_values,
|
|
235
|
+
)
|
|
236
|
+
)
|
|
237
|
+
return tuple(specs)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def _connection_property_types(
|
|
241
|
+
*,
|
|
242
|
+
field_info: FieldInfo,
|
|
243
|
+
sensitive: bool,
|
|
244
|
+
default: Any,
|
|
245
|
+
helm_extra: dict[str, Any],
|
|
246
|
+
container: bool,
|
|
247
|
+
) -> tuple[str | None, str | None]:
|
|
248
|
+
if container:
|
|
249
|
+
return None, None
|
|
250
|
+
return _schema_ref_for_field(
|
|
251
|
+
field_info=field_info,
|
|
252
|
+
sensitive=sensitive,
|
|
253
|
+
default=default,
|
|
254
|
+
helm_extra=helm_extra,
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def _should_emit_in_template(field: HelmFieldSpec) -> bool:
|
|
259
|
+
if field.container:
|
|
260
|
+
# Lists are documentation-only unless explicitly marked overridable, in
|
|
261
|
+
# which case they are injected (JSON-encoded) so overlays can set them.
|
|
262
|
+
return field.overridable
|
|
263
|
+
if field.required_when_enabled or field.sensitive:
|
|
264
|
+
return True
|
|
265
|
+
# Optional fields default to ``None`` (no literal in values.yaml) but are
|
|
266
|
+
# still settable via overlays, so they must be emitted — guarded so the env
|
|
267
|
+
# var only renders when the overlay actually provides a value.
|
|
268
|
+
return field.default is not NOT_PROVIDED
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def literal_default_for_values(field: HelmFieldSpec) -> str | int | float | bool | None:
|
|
272
|
+
if field.container:
|
|
273
|
+
return None
|
|
274
|
+
if field.sensitive or field.required_when_enabled:
|
|
275
|
+
return None
|
|
276
|
+
default = field.default
|
|
277
|
+
if isinstance(default, SecretStr):
|
|
278
|
+
default = default.get_secret_value()
|
|
279
|
+
if default is NOT_PROVIDED:
|
|
280
|
+
return None
|
|
281
|
+
if default is None:
|
|
282
|
+
return None
|
|
283
|
+
if isinstance(default, (str, int, float, bool)):
|
|
284
|
+
return default
|
|
285
|
+
return str(default)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def container_default_items(field: HelmFieldSpec) -> tuple[str, ...] | None:
|
|
289
|
+
if not field.container:
|
|
290
|
+
return None
|
|
291
|
+
default = field.default
|
|
292
|
+
if not isinstance(default, list):
|
|
293
|
+
return None
|
|
294
|
+
return tuple(str(item) for item in default)
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def group_fields_by_section(
|
|
298
|
+
fields: tuple[HelmFieldSpec, ...],
|
|
299
|
+
) -> tuple[tuple[str, tuple[HelmFieldSpec, ...]], ...]:
|
|
300
|
+
"""Group fields by section; ``connection`` first, then declaration order."""
|
|
301
|
+
by_section: dict[str, list[HelmFieldSpec]] = {}
|
|
302
|
+
section_order: list[str] = []
|
|
303
|
+
for field in fields:
|
|
304
|
+
if field.block_level:
|
|
305
|
+
continue
|
|
306
|
+
if field.section not in by_section:
|
|
307
|
+
by_section[field.section] = []
|
|
308
|
+
section_order.append(field.section)
|
|
309
|
+
by_section[field.section].append(field)
|
|
310
|
+
|
|
311
|
+
ordered_names: list[str] = []
|
|
312
|
+
if DEFAULT_HELM_SECTION in by_section:
|
|
313
|
+
ordered_names.append(DEFAULT_HELM_SECTION)
|
|
314
|
+
for name in section_order:
|
|
315
|
+
if name != DEFAULT_HELM_SECTION:
|
|
316
|
+
ordered_names.append(name)
|
|
317
|
+
|
|
318
|
+
return tuple((name, tuple(by_section[name])) for name in ordered_names)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def block_level_fields(
|
|
322
|
+
fields: tuple[HelmFieldSpec, ...],
|
|
323
|
+
) -> tuple[HelmFieldSpec, ...]:
|
|
324
|
+
return tuple(field for field in fields if field.block_level)
|