unique-search-proxy-core 2026.32.0.dev0__tar.gz → 2026.32.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_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/PKG-INFO +2 -2
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/pyproject.toml +2 -2
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/schema.py +8 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/url_safety/service.py +31 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/README.md +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/__init__.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/agent_engines/__init__.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/agent_engines/base.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/agent_engines/bing/__init__.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/agent_engines/bing/schema.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/agent_engines/config_types.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/agent_engines/output_schema.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/agent_engines/resolve.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/agent_engines/response_parsing.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/agent_engines/vertexai/__init__.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/agent_engines/vertexai/schema.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/context.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/crawlers/__init__.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/crawlers/base.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/crawlers/basic/__init__.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/crawlers/basic/content_types.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/crawlers/basic/processing/policy.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/crawlers/basic/schema.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/crawlers/config_types.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/crawlers/firecrawl/schema.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/crawlers/jina/schema.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/crawlers/tavily/schema.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/errors.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/logging.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/param_policy/__init__.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/param_policy/annotations.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/param_policy/derive.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/param_policy/exposable_param.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/param_policy/exposed_params.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/param_policy/request_base.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/providers/schema.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/search_engines/__init__.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/search_engines/base.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/search_engines/brave/__init__.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/search_engines/brave/schema.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/search_engines/config_types.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/search_engines/google/__init__.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/search_engines/google/schema.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/search_engines/perplexity/__init__.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/search_engines/perplexity/schema.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/url_safety/__init__.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/url_safety/dns.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/url_safety/egress.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/url_safety/models.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/url_safety/netloc.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/url_safety/policy.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/url_safety/redirect.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/url_safety/resolver.py +0 -0
- {unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/unique_search_proxy_core/url_safety/settings.py +0 -0
{unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: unique-search-proxy-core
|
|
3
|
-
Version: 2026.32.0.
|
|
3
|
+
Version: 2026.32.0.dev2
|
|
4
4
|
Summary: Shared Pydantic types for the Unique Search Proxy API
|
|
5
5
|
Author: ThePhilAz
|
|
6
6
|
Author-email: ThePhilAz <rami.azouz@philico.com>
|
|
@@ -8,7 +8,7 @@ Requires-Dist: httpx>=0.28.0,<0.29
|
|
|
8
8
|
Requires-Dist: pydantic>=2.12.5,<3.0.0
|
|
9
9
|
Requires-Dist: pydantic-settings>=2.10.1,<3
|
|
10
10
|
Requires-Dist: pyhumps>=3.8.0,<4
|
|
11
|
-
Requires-Dist: unique-toolkit[monitoring]>=2026.32.0.
|
|
11
|
+
Requires-Dist: unique-toolkit[monitoring]>=2026.32.0.dev3,<2026.32.0rc0
|
|
12
12
|
Requires-Python: >=3.12
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
|
{unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/pyproject.toml
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "unique-search-proxy-core"
|
|
3
|
-
version = "2026.32.0.
|
|
3
|
+
version = "2026.32.0.dev2"
|
|
4
4
|
description = "Shared Pydantic types for the Unique Search Proxy API"
|
|
5
5
|
authors = [{ name = "ThePhilAz", email = "rami.azouz@philico.com" }]
|
|
6
6
|
readme = "README.md"
|
|
@@ -10,7 +10,7 @@ dependencies = [
|
|
|
10
10
|
"pydantic>=2.12.5,<3.0.0",
|
|
11
11
|
"pydantic-settings>=2.10.1,<3",
|
|
12
12
|
"pyhumps>=3.8.0,<4",
|
|
13
|
-
"unique-toolkit[monitoring]>=2026.32.0.
|
|
13
|
+
"unique-toolkit[monitoring]>=2026.32.0.dev3,<2026.32.0rc0",
|
|
14
14
|
|
|
15
15
|
]
|
|
16
16
|
|
|
@@ -142,6 +142,14 @@ class PerUrlError(BaseModel):
|
|
|
142
142
|
|
|
143
143
|
code: str
|
|
144
144
|
message: str
|
|
145
|
+
status_code: int | None = Field(
|
|
146
|
+
default=None,
|
|
147
|
+
description=(
|
|
148
|
+
"Upstream HTTP status code for this URL when the failure was an HTTP "
|
|
149
|
+
"error (e.g. 403, 404, 500 from the Basic crawler); null when no HTTP "
|
|
150
|
+
"response was received (timeouts, transport, processing, blocked targets)"
|
|
151
|
+
),
|
|
152
|
+
)
|
|
145
153
|
|
|
146
154
|
|
|
147
155
|
class CrawlUrlResult(BaseModel):
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import logging
|
|
3
4
|
from ipaddress import ip_address
|
|
4
5
|
from urllib.parse import urlsplit
|
|
5
6
|
|
|
6
7
|
from unique_search_proxy_core.url_safety import dns, redirect, resolver
|
|
7
8
|
from unique_search_proxy_core.url_safety.models import (
|
|
9
|
+
BlockedCrawlTarget,
|
|
8
10
|
CrawlTargetValidationError,
|
|
9
11
|
ResolvedCrawlTarget,
|
|
10
12
|
UrlSafetyOutcome,
|
|
@@ -13,6 +15,21 @@ from unique_search_proxy_core.url_safety.models import (
|
|
|
13
15
|
from unique_search_proxy_core.url_safety.policy import validate_target_cheap
|
|
14
16
|
from unique_search_proxy_core.url_safety.settings import url_safety_settings
|
|
15
17
|
|
|
18
|
+
_LOGGER = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _safe_hostname(url: str) -> str | None:
|
|
22
|
+
"""Extract the hostname from a URL without ever raising.
|
|
23
|
+
|
|
24
|
+
``urlsplit(...).hostname`` raises ``ValueError`` for malformed IPv6 hosts
|
|
25
|
+
(e.g. ``http://[::1``). This must never happen on the fail-closed path,
|
|
26
|
+
where a single bad URL would otherwise abort the whole batch.
|
|
27
|
+
"""
|
|
28
|
+
try:
|
|
29
|
+
return urlsplit(url).hostname
|
|
30
|
+
except ValueError:
|
|
31
|
+
return None
|
|
32
|
+
|
|
16
33
|
|
|
17
34
|
class UrlSafetyService:
|
|
18
35
|
@staticmethod
|
|
@@ -37,6 +54,20 @@ class UrlSafetyService:
|
|
|
37
54
|
except CrawlTargetValidationError as exc:
|
|
38
55
|
blocked = exc.blocked_targets[0]
|
|
39
56
|
outcomes.append(UrlSafetyOutcome(url=url, blocked=blocked))
|
|
57
|
+
except Exception:
|
|
58
|
+
# Fail closed: an unexpected error while validating a single URL
|
|
59
|
+
# must block only that URL, never fail the whole batch.
|
|
60
|
+
_LOGGER.exception("URL safety validation failed unexpectedly")
|
|
61
|
+
outcomes.append(
|
|
62
|
+
UrlSafetyOutcome(
|
|
63
|
+
url=url,
|
|
64
|
+
blocked=BlockedCrawlTarget(
|
|
65
|
+
hostname=_safe_hostname(working_url),
|
|
66
|
+
category="validation_error",
|
|
67
|
+
reason="URL safety validation failed unexpectedly",
|
|
68
|
+
),
|
|
69
|
+
)
|
|
70
|
+
)
|
|
40
71
|
return outcomes
|
|
41
72
|
|
|
42
73
|
@staticmethod
|
{unique_search_proxy_core-2026.32.0.dev0 → unique_search_proxy_core-2026.32.0.dev2}/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|