britecore-sdk 1.5.2__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.
- britecore_sdk/__init__.py +169 -0
- britecore_sdk/api/__init__.py +14 -0
- britecore_sdk/api/api_calls/__init__.py +369 -0
- britecore_sdk/api/api_calls/v1/__init__.py +23 -0
- britecore_sdk/api/api_calls/v1/contacts.py +241 -0
- britecore_sdk/api/api_calls/v1/custom_ui.py +90 -0
- britecore_sdk/api/api_calls/v1/deliverables.py +66 -0
- britecore_sdk/api/api_calls/v1/notes.py +38 -0
- britecore_sdk/api/api_calls/v1/payments.py +64 -0
- britecore_sdk/api/api_calls/v1/policies.py +122 -0
- britecore_sdk/api/api_calls/v1/printing.py +122 -0
- britecore_sdk/api/api_calls/v1/reports.py +38 -0
- britecore_sdk/api/api_calls/v2/__init__.py +375 -0
- britecore_sdk/api/api_calls/v2/_common.py +35 -0
- britecore_sdk/api/api_calls/v2/accounting.py +210 -0
- britecore_sdk/api/api_calls/v2/agentcy.py +53 -0
- britecore_sdk/api/api_calls/v2/async_contacts.py +215 -0
- britecore_sdk/api/api_calls/v2/async_lines.py +179 -0
- britecore_sdk/api/api_calls/v2/async_policies.py +695 -0
- britecore_sdk/api/api_calls/v2/async_quotes.py +91 -0
- britecore_sdk/api/api_calls/v2/attachments.py +323 -0
- britecore_sdk/api/api_calls/v2/auth.py +35 -0
- britecore_sdk/api/api_calls/v2/authority_limits.py +125 -0
- britecore_sdk/api/api_calls/v2/background_jobs.py +35 -0
- britecore_sdk/api/api_calls/v2/billing.py +111 -0
- britecore_sdk/api/api_calls/v2/claim_adjuster_assignment_configs.py +74 -0
- britecore_sdk/api/api_calls/v2/claim_catastrophes.py +126 -0
- britecore_sdk/api/api_calls/v2/claim_changes.py +35 -0
- britecore_sdk/api/api_calls/v2/claim_contacts.py +89 -0
- britecore_sdk/api/api_calls/v2/claim_dates.py +89 -0
- britecore_sdk/api/api_calls/v2/claim_estimations.py +107 -0
- britecore_sdk/api/api_calls/v2/claim_exposures.py +365 -0
- britecore_sdk/api/api_calls/v2/claim_injuries.py +107 -0
- britecore_sdk/api/api_calls/v2/claim_properties.py +107 -0
- britecore_sdk/api/api_calls/v2/claim_vehicles.py +125 -0
- britecore_sdk/api/api_calls/v2/claims.py +591 -0
- britecore_sdk/api/api_calls/v2/commissions.py +401 -0
- britecore_sdk/api/api_calls/v2/configurations.py +89 -0
- britecore_sdk/api/api_calls/v2/contacts.py +1493 -0
- britecore_sdk/api/api_calls/v2/coverages.py +215 -0
- britecore_sdk/api/api_calls/v2/custom_data.py +125 -0
- britecore_sdk/api/api_calls/v2/dashboards.py +193 -0
- britecore_sdk/api/api_calls/v2/data.py +163 -0
- britecore_sdk/api/api_calls/v2/deliverables.py +649 -0
- britecore_sdk/api/api_calls/v2/disputes.py +89 -0
- britecore_sdk/api/api_calls/v2/drivers.py +143 -0
- britecore_sdk/api/api_calls/v2/errors.py +33 -0
- britecore_sdk/api/api_calls/v2/files.py +69 -0
- britecore_sdk/api/api_calls/v2/geometries.py +107 -0
- britecore_sdk/api/api_calls/v2/geometry.py +35 -0
- britecore_sdk/api/api_calls/v2/imports.py +60 -0
- britecore_sdk/api/api_calls/v2/ingestion_job.py +107 -0
- britecore_sdk/api/api_calls/v2/inspections.py +126 -0
- britecore_sdk/api/api_calls/v2/insured.py +323 -0
- britecore_sdk/api/api_calls/v2/intacct.py +122 -0
- britecore_sdk/api/api_calls/v2/integrations.py +280 -0
- britecore_sdk/api/api_calls/v2/jobrunner.py +44 -0
- britecore_sdk/api/api_calls/v2/lines.py +893 -0
- britecore_sdk/api/api_calls/v2/named_insureds.py +161 -0
- britecore_sdk/api/api_calls/v2/nightly_jobs.py +125 -0
- britecore_sdk/api/api_calls/v2/notes.py +98 -0
- britecore_sdk/api/api_calls/v2/notifications.py +66 -0
- britecore_sdk/api/api_calls/v2/payments.py +900 -0
- britecore_sdk/api/api_calls/v2/permissions.py +35 -0
- britecore_sdk/api/api_calls/v2/policies.py +2884 -0
- britecore_sdk/api/api_calls/v2/policy_types.py +179 -0
- britecore_sdk/api/api_calls/v2/premium_finance_companies.py +107 -0
- britecore_sdk/api/api_calls/v2/prior_policies.py +53 -0
- britecore_sdk/api/api_calls/v2/quick_code_values.py +53 -0
- britecore_sdk/api/api_calls/v2/quick_codes.py +53 -0
- britecore_sdk/api/api_calls/v2/quick_quote_templates.py +188 -0
- britecore_sdk/api/api_calls/v2/quote.py +413 -0
- britecore_sdk/api/api_calls/v2/quotes.py +569 -0
- britecore_sdk/api/api_calls/v2/related_policies.py +53 -0
- britecore_sdk/api/api_calls/v2/reports.py +352 -0
- britecore_sdk/api/api_calls/v2/return_premium.py +112 -0
- britecore_sdk/api/api_calls/v2/rules.py +90 -0
- britecore_sdk/api/api_calls/v2/search.py +55 -0
- britecore_sdk/api/api_calls/v2/settings.py +539 -0
- britecore_sdk/api/api_calls/v2/signatures.py +189 -0
- britecore_sdk/api/api_calls/v2/statement_of_value.py +221 -0
- britecore_sdk/api/api_calls/v2/subjectivities.py +198 -0
- britecore_sdk/api/api_calls/v2/suspensions.py +144 -0
- britecore_sdk/api/api_calls/v2/tasks.py +179 -0
- britecore_sdk/api/api_calls/v2/term_credit_scores.py +53 -0
- britecore_sdk/api/api_calls/v2/uploads.py +89 -0
- britecore_sdk/api/api_calls/v2/user_groups.py +107 -0
- britecore_sdk/api/api_calls/v2/utils.py +630 -0
- britecore_sdk/api/api_calls/v2/vehicles.py +253 -0
- britecore_sdk/api/api_calls/v2/vendors.py +448 -0
- britecore_sdk/api/api_calls/v2/violations.py +179 -0
- britecore_sdk/api/api_calls/v2/watercrafts.py +125 -0
- britecore_sdk/api/britecore_api_client.py +1232 -0
- britecore_sdk/api/britecore_async_api_client.py +488 -0
- britecore_sdk/api/britecore_oauth_token_manager.py +116 -0
- britecore_sdk/api/rate_limiter.py +249 -0
- britecore_sdk/api/request_cache.py +150 -0
- britecore_sdk/api/types.py +156 -0
- britecore_sdk/api/workflows/__init__.py +96 -0
- britecore_sdk/api/workflows/async_batch_contacts.py +128 -0
- britecore_sdk/api/workflows/async_batch_policies.py +236 -0
- britecore_sdk/api/workflows/async_batch_quotes.py +119 -0
- britecore_sdk/api/workflows/async_staged_creation.py +362 -0
- britecore_sdk/api/workflows/batch_contacts.py +123 -0
- britecore_sdk/api/workflows/batch_policies.py +224 -0
- britecore_sdk/api/workflows/batch_quotes.py +115 -0
- britecore_sdk/api/workflows/staged_creation.py +433 -0
- britecore_sdk/base_logger.py +68 -0
- britecore_sdk/classes/__init__.py +6 -0
- britecore_sdk/constants.py +9 -0
- britecore_sdk/exceptions.py +249 -0
- britecore_sdk/maps/__init__.py +145 -0
- britecore_sdk/models/__init__.py +7 -0
- britecore_sdk/models/contact.py +102 -0
- britecore_sdk/models/policy.py +38 -0
- britecore_sdk/models/quote.py +53 -0
- britecore_sdk/py.typed +0 -0
- britecore_sdk/resources/__init__.py +0 -0
- britecore_sdk/resources/zip_codes.csv +41484 -0
- britecore_sdk/settings/__init__.py +13 -0
- britecore_sdk/settings/config.py +211 -0
- britecore_sdk/settings/defaults.py +67 -0
- britecore_sdk/utils/__init__.py +0 -0
- britecore_sdk/utils/_config_common.py +236 -0
- britecore_sdk/utils/check_api_spec_sync.py +118 -0
- britecore_sdk/utils/check_site_configs.py +166 -0
- britecore_sdk/utils/check_test_data.py +41 -0
- britecore_sdk/utils/config_manager.py +735 -0
- britecore_sdk/utils/generate_spec_wrappers.py +533 -0
- britecore_sdk/utils/healthcheck.py +152 -0
- britecore_sdk/utils/interactive_menu.py +269 -0
- britecore_sdk/utils/policy_helpers.py +40 -0
- britecore_sdk/utils/run_all_checks.py +35 -0
- britecore_sdk/utils/zip_code_lookup.py +89 -0
- britecore_sdk/validators/__init__.py +21 -0
- britecore_sdk/validators/address_validator.py +687 -0
- britecore_sdk/validators/email_validator.py +147 -0
- britecore_sdk/validators/name_validator.py +92 -0
- britecore_sdk/validators/phone_validator.py +167 -0
- britecore_sdk-1.5.2.dist-info/METADATA +557 -0
- britecore_sdk-1.5.2.dist-info/RECORD +144 -0
- britecore_sdk-1.5.2.dist-info/WHEEL +5 -0
- britecore_sdk-1.5.2.dist-info/licenses/LICENSE +165 -0
- britecore_sdk-1.5.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"""
|
|
2
|
+
BriteCore Libraries - Core utilities for BriteCore API integration.
|
|
3
|
+
|
|
4
|
+
This package provides:
|
|
5
|
+
- Domain models for contacts and policies
|
|
6
|
+
- Validators for data normalization
|
|
7
|
+
- API clients and authentication
|
|
8
|
+
- Custom exceptions
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
from importlib import import_module
|
|
13
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import TYPE_CHECKING, Any
|
|
16
|
+
|
|
17
|
+
from britecore_sdk.base_logger import configure_logging, get_logger
|
|
18
|
+
|
|
19
|
+
logger = get_logger(__package__)
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
__version__ = version("britecore_sdk")
|
|
23
|
+
except PackageNotFoundError: # pragma: no cover
|
|
24
|
+
__version__ = "0.0.0"
|
|
25
|
+
|
|
26
|
+
if TYPE_CHECKING:
|
|
27
|
+
from britecore_sdk.api.api_calls import (
|
|
28
|
+
get_api_client,
|
|
29
|
+
get_async_api_client,
|
|
30
|
+
use_api_client,
|
|
31
|
+
)
|
|
32
|
+
from britecore_sdk.constants import (
|
|
33
|
+
COMMON_CITY_REPLACEMENT,
|
|
34
|
+
DEFAULT_ADDRESS_TYPE,
|
|
35
|
+
DEFAULT_EMAIL_TYPE,
|
|
36
|
+
DEFAULT_PHONE_TYPE,
|
|
37
|
+
)
|
|
38
|
+
from britecore_sdk.exceptions import (
|
|
39
|
+
AuthenticationError,
|
|
40
|
+
BritecoreError,
|
|
41
|
+
ConfigurationError,
|
|
42
|
+
NotFoundError,
|
|
43
|
+
RateLimitError,
|
|
44
|
+
RequestTimeoutError,
|
|
45
|
+
ServerError,
|
|
46
|
+
ValidationError,
|
|
47
|
+
)
|
|
48
|
+
from britecore_sdk.maps import get_common_regexes, load_regexes
|
|
49
|
+
from britecore_sdk.models import BritecoreContact, BritecorePolicy
|
|
50
|
+
from britecore_sdk.validators import (
|
|
51
|
+
AddressValidator,
|
|
52
|
+
EmailValidator,
|
|
53
|
+
NameValidator,
|
|
54
|
+
PhoneValidator,
|
|
55
|
+
fix_apostrophe_capitalization,
|
|
56
|
+
fix_suffix_capitalization,
|
|
57
|
+
normalize_business_name,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
_EXPORT_MAP: dict[str, tuple[str, str]] = {
|
|
62
|
+
"get_api_client": ("britecore_sdk.api.api_calls", "get_api_client"),
|
|
63
|
+
"get_async_api_client": (
|
|
64
|
+
"britecore_sdk.api.api_calls",
|
|
65
|
+
"get_async_api_client",
|
|
66
|
+
),
|
|
67
|
+
"use_api_client": ("britecore_sdk.api.api_calls", "use_api_client"),
|
|
68
|
+
"COMMON_CITY_REPLACEMENT": (
|
|
69
|
+
"britecore_sdk.constants",
|
|
70
|
+
"COMMON_CITY_REPLACEMENT",
|
|
71
|
+
),
|
|
72
|
+
"DEFAULT_ADDRESS_TYPE": ("britecore_sdk.constants", "DEFAULT_ADDRESS_TYPE"),
|
|
73
|
+
"DEFAULT_EMAIL_TYPE": ("britecore_sdk.constants", "DEFAULT_EMAIL_TYPE"),
|
|
74
|
+
"DEFAULT_PHONE_TYPE": ("britecore_sdk.constants", "DEFAULT_PHONE_TYPE"),
|
|
75
|
+
"BritecoreError": ("britecore_sdk.exceptions", "BritecoreError"),
|
|
76
|
+
# Flat exception aliases
|
|
77
|
+
"AuthenticationError": ("britecore_sdk.exceptions", "AuthenticationError"),
|
|
78
|
+
"ConfigurationError": ("britecore_sdk.exceptions", "ConfigurationError"),
|
|
79
|
+
"NotFoundError": ("britecore_sdk.exceptions", "NotFoundError"),
|
|
80
|
+
"RateLimitError": ("britecore_sdk.exceptions", "RateLimitError"),
|
|
81
|
+
"RequestTimeoutError": ("britecore_sdk.exceptions", "RequestTimeoutError"),
|
|
82
|
+
"ServerError": ("britecore_sdk.exceptions", "ServerError"),
|
|
83
|
+
"ValidationError": ("britecore_sdk.exceptions", "ValidationError"),
|
|
84
|
+
"load_regexes": ("britecore_sdk.maps", "load_regexes"),
|
|
85
|
+
"get_common_regexes": ("britecore_sdk.maps", "get_common_regexes"),
|
|
86
|
+
"BritecoreContact": ("britecore_sdk.models", "BritecoreContact"),
|
|
87
|
+
"BritecorePolicy": ("britecore_sdk.models", "BritecorePolicy"),
|
|
88
|
+
"AddressValidator": ("britecore_sdk.validators", "AddressValidator"),
|
|
89
|
+
"EmailValidator": ("britecore_sdk.validators", "EmailValidator"),
|
|
90
|
+
"NameValidator": ("britecore_sdk.validators", "NameValidator"),
|
|
91
|
+
"PhoneValidator": ("britecore_sdk.validators", "PhoneValidator"),
|
|
92
|
+
"fix_suffix_capitalization": (
|
|
93
|
+
"britecore_sdk.validators",
|
|
94
|
+
"fix_suffix_capitalization",
|
|
95
|
+
),
|
|
96
|
+
"fix_apostrophe_capitalization": (
|
|
97
|
+
"britecore_sdk.validators",
|
|
98
|
+
"fix_apostrophe_capitalization",
|
|
99
|
+
),
|
|
100
|
+
"normalize_business_name": (
|
|
101
|
+
"britecore_sdk.validators",
|
|
102
|
+
"normalize_business_name",
|
|
103
|
+
),
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def __getattr__(name: str) -> Any:
|
|
108
|
+
"""Lazily resolve convenience exports from their authored modules."""
|
|
109
|
+
try:
|
|
110
|
+
module_name, attribute_name = _EXPORT_MAP[name]
|
|
111
|
+
except KeyError as exc:
|
|
112
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}") from exc
|
|
113
|
+
|
|
114
|
+
value = getattr(import_module(module_name), attribute_name)
|
|
115
|
+
globals()[name] = value
|
|
116
|
+
return value
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def __dir__() -> list[str]:
|
|
120
|
+
"""Return package attributes including lazily exported convenience names."""
|
|
121
|
+
return sorted(set(globals()) | set(__all__))
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
if os.environ.get("BRITECORE_ENV") == "development":
|
|
125
|
+
try:
|
|
126
|
+
from britecore_sdk.utils import check_site_configs
|
|
127
|
+
|
|
128
|
+
settings_path = Path(__file__).resolve().parent / "settings" / "settings.toml"
|
|
129
|
+
check_site_configs.warn_if_secrets_in_settings(str(settings_path))
|
|
130
|
+
except Exception:
|
|
131
|
+
pass # Do not block startup
|
|
132
|
+
|
|
133
|
+
__all__ = [
|
|
134
|
+
# Models
|
|
135
|
+
"BritecoreContact",
|
|
136
|
+
"BritecorePolicy",
|
|
137
|
+
# Validators
|
|
138
|
+
"AddressValidator",
|
|
139
|
+
"EmailValidator",
|
|
140
|
+
"NameValidator",
|
|
141
|
+
"PhoneValidator",
|
|
142
|
+
"fix_suffix_capitalization",
|
|
143
|
+
"fix_apostrophe_capitalization",
|
|
144
|
+
"normalize_business_name",
|
|
145
|
+
# Exceptions
|
|
146
|
+
"BritecoreError",
|
|
147
|
+
"AuthenticationError",
|
|
148
|
+
"ConfigurationError",
|
|
149
|
+
"NotFoundError",
|
|
150
|
+
"RateLimitError",
|
|
151
|
+
"RequestTimeoutError",
|
|
152
|
+
"ServerError",
|
|
153
|
+
"ValidationError",
|
|
154
|
+
# Constants
|
|
155
|
+
"DEFAULT_ADDRESS_TYPE",
|
|
156
|
+
"DEFAULT_EMAIL_TYPE",
|
|
157
|
+
"DEFAULT_PHONE_TYPE",
|
|
158
|
+
"COMMON_CITY_REPLACEMENT",
|
|
159
|
+
"load_regexes",
|
|
160
|
+
"get_common_regexes",
|
|
161
|
+
# API client helpers
|
|
162
|
+
"get_api_client",
|
|
163
|
+
"get_async_api_client",
|
|
164
|
+
"use_api_client",
|
|
165
|
+
# Version
|
|
166
|
+
"__version__",
|
|
167
|
+
"logger",
|
|
168
|
+
"configure_logging",
|
|
169
|
+
]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""BriteCore API client and authentication."""
|
|
2
|
+
|
|
3
|
+
from britecore_sdk.api.britecore_api_client import BritecoreAPIClient
|
|
4
|
+
from britecore_sdk.api.britecore_async_api_client import AsyncBritecoreAPIClient
|
|
5
|
+
from britecore_sdk.api.britecore_oauth_token_manager import OAuthToken
|
|
6
|
+
from britecore_sdk.api.request_cache import RequestCache, build_cache_key
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"OAuthToken",
|
|
10
|
+
"BritecoreAPIClient",
|
|
11
|
+
"AsyncBritecoreAPIClient",
|
|
12
|
+
"RequestCache",
|
|
13
|
+
"build_cache_key",
|
|
14
|
+
]
|
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
from contextlib import contextmanager
|
|
2
|
+
from contextvars import ContextVar
|
|
3
|
+
from typing import cast
|
|
4
|
+
|
|
5
|
+
from britecore_sdk.api.britecore_api_client import (
|
|
6
|
+
BritecoreAPIClient,
|
|
7
|
+
RequestParameters,
|
|
8
|
+
)
|
|
9
|
+
from britecore_sdk.api.britecore_async_api_client import AsyncBritecoreAPIClient
|
|
10
|
+
from britecore_sdk.exceptions import BritecoreError
|
|
11
|
+
from britecore_sdk.settings import get_target_site
|
|
12
|
+
|
|
13
|
+
_TARGET_SITE_UNSET = object()
|
|
14
|
+
_context_api_client: ContextVar[BritecoreAPIClient | None] = ContextVar(
|
|
15
|
+
"_context_api_client", default=None
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _set_module_client_state(name: str, client: object) -> None:
|
|
20
|
+
"""Set module-level client state without using global statements."""
|
|
21
|
+
globals()[name] = client
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def init_api_client(
|
|
25
|
+
target_site: str | None | object = _TARGET_SITE_UNSET,
|
|
26
|
+
*,
|
|
27
|
+
client_dry_run: bool = False,
|
|
28
|
+
base_url: str | None = None,
|
|
29
|
+
api_key: str | None = None,
|
|
30
|
+
client_id: str | None = None,
|
|
31
|
+
client_secret: str | None = None,
|
|
32
|
+
enable_rate_limiter: bool | None = None,
|
|
33
|
+
rate_limiter_requests_per_second: float | None = None,
|
|
34
|
+
rate_limiter_burst_size: int | None = None,
|
|
35
|
+
rate_limiter_adaptive_backoff: bool | None = None,
|
|
36
|
+
rate_limiter_backoff_timeout_seconds: float | None = None,
|
|
37
|
+
) -> BritecoreAPIClient:
|
|
38
|
+
"""
|
|
39
|
+
Initializes and returns a configured Britecore API client instance.
|
|
40
|
+
|
|
41
|
+
This function creates a new BritecoreAPIClient object using the specified target site
|
|
42
|
+
and initializes the client connection.
|
|
43
|
+
|
|
44
|
+
Calling this function also sets the module-level ``_api_client`` so that the
|
|
45
|
+
lazy proxy (``api_client``) used by endpoint wrappers resolves to this instance
|
|
46
|
+
rather than re-initialising without a site on first use.
|
|
47
|
+
|
|
48
|
+
Credentials can be supplied in two ways:
|
|
49
|
+
|
|
50
|
+
**File-based (default):** omit all credential kwargs. The client reads credentials
|
|
51
|
+
from the layered config file search hierarchy (SDK defaults →
|
|
52
|
+
``~/.britecore/`` → CWD → ``BRITECORE_SDK_SETTINGS_FILE``).
|
|
53
|
+
|
|
54
|
+
**Explicit (inline):** pass ``base_url`` (required) plus any combination of
|
|
55
|
+
``api_key``, ``client_id``, and ``client_secret``. When ``base_url`` is given,
|
|
56
|
+
no config files are read and ``target_site`` becomes optional (defaults to
|
|
57
|
+
``"explicit"`` when omitted).
|
|
58
|
+
|
|
59
|
+
**Rate Limiting (optional):** pass ``enable_rate_limiter=True`` to enable
|
|
60
|
+
client-side rate limiting. Configuration can be provided explicitly via
|
|
61
|
+
``rate_limiter_*`` parameters, or read from settings.toml if omitted.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
target_site: The target site URL or identifier for the Britecore API.
|
|
65
|
+
If omitted, this is resolved from settings via
|
|
66
|
+
``get_target_site()``. Passing ``None`` or an empty value
|
|
67
|
+
explicitly is treated as invalid input **unless** ``base_url``
|
|
68
|
+
is also provided, in which case ``"explicit"`` is used as the
|
|
69
|
+
site label.
|
|
70
|
+
client_dry_run: When ``True``, requests made through this client inherit
|
|
71
|
+
dry-run behavior unless explicitly overridden per call.
|
|
72
|
+
base_url: Override the site base URL directly. When provided, file-based
|
|
73
|
+
credential lookup is bypassed and ``target_site`` becomes optional.
|
|
74
|
+
api_key: Explicit API key (used only when ``base_url`` is also given).
|
|
75
|
+
client_id: Explicit OAuth client ID (used only when ``base_url`` is given).
|
|
76
|
+
client_secret: Explicit OAuth client secret (used only when ``base_url`` is given).
|
|
77
|
+
enable_rate_limiter: Enable client-side rate limiting. When ``None`` (default),
|
|
78
|
+
reads from settings ``rate_limiter_enabled``. When ``True`` or ``False``,
|
|
79
|
+
overrides the setting.
|
|
80
|
+
rate_limiter_requests_per_second: Target request rate for rate limiter
|
|
81
|
+
(default: 10.0 req/s from settings). Only used if rate limiter is enabled.
|
|
82
|
+
rate_limiter_burst_size: Maximum burst capacity for rate limiter
|
|
83
|
+
(default: 20 requests from settings). Only used if rate limiter is enabled.
|
|
84
|
+
rate_limiter_adaptive_backoff: Enable automatic backoff on 429 responses
|
|
85
|
+
(default: True from settings). Only used if rate limiter is enabled.
|
|
86
|
+
rate_limiter_backoff_timeout_seconds: Duration to back off after 429
|
|
87
|
+
(default: 60.0 seconds from settings). Only used if rate limiter is enabled.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
BritecoreAPIClient: A configured and initialized Britecore API client instance.
|
|
91
|
+
|
|
92
|
+
"""
|
|
93
|
+
if base_url is not None:
|
|
94
|
+
# Explicit-credential mode: target_site is optional
|
|
95
|
+
if (
|
|
96
|
+
target_site is _TARGET_SITE_UNSET
|
|
97
|
+
or not isinstance(target_site, str)
|
|
98
|
+
or not target_site
|
|
99
|
+
):
|
|
100
|
+
resolved: str = "explicit"
|
|
101
|
+
else:
|
|
102
|
+
resolved = target_site
|
|
103
|
+
else:
|
|
104
|
+
resolved = cast(
|
|
105
|
+
str,
|
|
106
|
+
get_target_site() if target_site is _TARGET_SITE_UNSET else target_site,
|
|
107
|
+
)
|
|
108
|
+
if not isinstance(resolved, str) or not resolved:
|
|
109
|
+
raise BritecoreError.ConfigurationError(
|
|
110
|
+
"target_site must be specified: pass a non-empty value, or omit the argument "
|
|
111
|
+
"to use configured fallback resolution."
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
client: BritecoreAPIClient = BritecoreAPIClient(resolved)
|
|
115
|
+
kwargs: dict[str, object] = {"client_dry_run": client_dry_run}
|
|
116
|
+
if base_url is not None:
|
|
117
|
+
# Explicit-credential mode: always pass all credential kwargs explicitly
|
|
118
|
+
kwargs["base_url"] = base_url
|
|
119
|
+
kwargs["api_key"] = api_key
|
|
120
|
+
kwargs["client_id"] = client_id
|
|
121
|
+
kwargs["client_secret"] = client_secret
|
|
122
|
+
else:
|
|
123
|
+
# File-based mode: only pass credentials if they're provided
|
|
124
|
+
if api_key is not None:
|
|
125
|
+
kwargs["api_key"] = api_key
|
|
126
|
+
if client_id is not None:
|
|
127
|
+
kwargs["client_id"] = client_id
|
|
128
|
+
if client_secret is not None:
|
|
129
|
+
kwargs["client_secret"] = client_secret
|
|
130
|
+
# Rate limiter options — always forwarded (None means "use settings default")
|
|
131
|
+
kwargs["enable_rate_limiter"] = enable_rate_limiter
|
|
132
|
+
if rate_limiter_requests_per_second is not None:
|
|
133
|
+
kwargs["rate_limiter_requests_per_second"] = rate_limiter_requests_per_second
|
|
134
|
+
if rate_limiter_burst_size is not None:
|
|
135
|
+
kwargs["rate_limiter_burst_size"] = rate_limiter_burst_size
|
|
136
|
+
if rate_limiter_adaptive_backoff is not None:
|
|
137
|
+
kwargs["rate_limiter_adaptive_backoff"] = rate_limiter_adaptive_backoff
|
|
138
|
+
if rate_limiter_backoff_timeout_seconds is not None:
|
|
139
|
+
kwargs["rate_limiter_backoff_timeout_seconds"] = (
|
|
140
|
+
rate_limiter_backoff_timeout_seconds
|
|
141
|
+
)
|
|
142
|
+
client.init_client(**kwargs) # type: ignore[arg-type]
|
|
143
|
+
_set_module_client_state("_api_client", client)
|
|
144
|
+
return client
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def init_async_api_client(
|
|
148
|
+
target_site: str | None | object = _TARGET_SITE_UNSET,
|
|
149
|
+
*,
|
|
150
|
+
client_dry_run: bool = False,
|
|
151
|
+
base_url: str | None = None,
|
|
152
|
+
api_key: str | None = None,
|
|
153
|
+
client_id: str | None = None,
|
|
154
|
+
client_secret: str | None = None,
|
|
155
|
+
) -> AsyncBritecoreAPIClient:
|
|
156
|
+
"""Initialize and return a lazy async API client wrapper.
|
|
157
|
+
|
|
158
|
+
The target site may be provided explicitly. If omitted, it is resolved
|
|
159
|
+
from settings via ``get_target_site()``.
|
|
160
|
+
|
|
161
|
+
Also sets the module-level ``_async_api_client`` so the lazy proxy resolves
|
|
162
|
+
to this instance rather than re-initialising without a site on first use.
|
|
163
|
+
|
|
164
|
+
Credentials can be supplied in two ways:
|
|
165
|
+
|
|
166
|
+
**File-based (default):** omit all credential kwargs. The client reads credentials
|
|
167
|
+
from the layered config file search hierarchy.
|
|
168
|
+
|
|
169
|
+
**Explicit (inline):** pass ``base_url`` plus optional ``api_key``,
|
|
170
|
+
``client_id``, and ``client_secret``. File-based lookup is bypassed, and
|
|
171
|
+
``target_site`` defaults to ``"explicit"`` when omitted.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
target_site: Explicit target site name. If omitted, resolve from settings.
|
|
175
|
+
client_dry_run: When ``True``, async requests inherit dry-run behavior
|
|
176
|
+
unless explicitly overridden per call.
|
|
177
|
+
base_url: Override the site base URL directly.
|
|
178
|
+
api_key: Explicit API key (used only when ``base_url`` is also given).
|
|
179
|
+
client_id: Explicit OAuth client ID (used only when ``base_url`` is given).
|
|
180
|
+
client_secret: Explicit OAuth client secret (used only when ``base_url`` is given).
|
|
181
|
+
"""
|
|
182
|
+
if base_url is not None:
|
|
183
|
+
if (
|
|
184
|
+
target_site is _TARGET_SITE_UNSET
|
|
185
|
+
or not isinstance(target_site, str)
|
|
186
|
+
or not target_site
|
|
187
|
+
):
|
|
188
|
+
resolved = "explicit"
|
|
189
|
+
else:
|
|
190
|
+
resolved = target_site
|
|
191
|
+
else:
|
|
192
|
+
resolved = cast(
|
|
193
|
+
str,
|
|
194
|
+
get_target_site() if target_site is _TARGET_SITE_UNSET else target_site,
|
|
195
|
+
)
|
|
196
|
+
if not isinstance(resolved, str) or not resolved:
|
|
197
|
+
raise BritecoreError.ConfigurationError(
|
|
198
|
+
"target_site must be specified: pass a non-empty value, or omit the argument "
|
|
199
|
+
"to use configured fallback resolution."
|
|
200
|
+
)
|
|
201
|
+
async_kwargs: dict[str, object] = {
|
|
202
|
+
"client_dry_run": client_dry_run,
|
|
203
|
+
}
|
|
204
|
+
if base_url is not None:
|
|
205
|
+
async_kwargs["base_url"] = base_url
|
|
206
|
+
if api_key is not None:
|
|
207
|
+
async_kwargs["api_key"] = api_key
|
|
208
|
+
if client_id is not None:
|
|
209
|
+
async_kwargs["client_id"] = client_id
|
|
210
|
+
if client_secret is not None:
|
|
211
|
+
async_kwargs["client_secret"] = client_secret
|
|
212
|
+
client = AsyncBritecoreAPIClient(resolved, **async_kwargs) # type: ignore[arg-type]
|
|
213
|
+
_set_module_client_state("_async_api_client", client)
|
|
214
|
+
return client
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def reset_api_client() -> None:
|
|
218
|
+
"""Reset the module-level API client to ``None``.
|
|
219
|
+
|
|
220
|
+
Useful for test isolation and multi-site workflows where a fresh client
|
|
221
|
+
should be initialized for a different target site. After calling this,
|
|
222
|
+
the next call to :func:`get_api_client` (or any endpoint wrapper) will
|
|
223
|
+
raise :class:`~britecore_sdk.exceptions.BritecoreError.ConfigurationError`
|
|
224
|
+
until :func:`init_api_client` is called again.
|
|
225
|
+
|
|
226
|
+
Example::
|
|
227
|
+
|
|
228
|
+
from britecore_sdk.api.api_calls import init_api_client, reset_api_client
|
|
229
|
+
|
|
230
|
+
client_a = init_api_client("site_a")
|
|
231
|
+
reset_api_client()
|
|
232
|
+
client_b = init_api_client("site_b")
|
|
233
|
+
"""
|
|
234
|
+
_set_module_client_state("_api_client", None)
|
|
235
|
+
_set_module_client_state("_async_api_client", None)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
@contextmanager
|
|
239
|
+
def use_api_client(client: BritecoreAPIClient):
|
|
240
|
+
"""Temporarily bind a specific sync client for endpoint wrapper calls.
|
|
241
|
+
|
|
242
|
+
Within this context, wrappers that access ``api_client``/``API_CLIENT``
|
|
243
|
+
resolve to ``client`` instead of the module-level global ``_api_client``.
|
|
244
|
+
This enables safe multi-site workflows without resetting global state.
|
|
245
|
+
"""
|
|
246
|
+
token = _context_api_client.set(client)
|
|
247
|
+
try:
|
|
248
|
+
yield client
|
|
249
|
+
finally:
|
|
250
|
+
_context_api_client.reset(token)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
# Lazy initialization: _api_client is only created on first access to avoid
|
|
254
|
+
# import-time failures in contexts without config/env setup.
|
|
255
|
+
_api_client: BritecoreAPIClient | None = None
|
|
256
|
+
_async_api_client: AsyncBritecoreAPIClient | None = None
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def get_api_client() -> BritecoreAPIClient:
|
|
260
|
+
"""
|
|
261
|
+
Get or lazily initialize the global API client instance.
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
BritecoreAPIClient: A configured and initialized Britecore API client instance.
|
|
265
|
+
|
|
266
|
+
Raises:
|
|
267
|
+
BritecoreError.Base: If lazy initialization fails.
|
|
268
|
+
Any exceptions from BritecoreAPIClient.init_client() if initialization fails.
|
|
269
|
+
"""
|
|
270
|
+
context_client = _context_api_client.get()
|
|
271
|
+
if context_client is not None:
|
|
272
|
+
return context_client
|
|
273
|
+
|
|
274
|
+
if _api_client is None:
|
|
275
|
+
raise BritecoreError.ConfigurationError(
|
|
276
|
+
"API client has not been initialized. Call init_api_client(target_site=...) first.\n"
|
|
277
|
+
"Tip: To check your site configuration, run: python -m britecore_sdk.utils.check_site_configs"
|
|
278
|
+
)
|
|
279
|
+
return _api_client
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def get_async_api_client() -> AsyncBritecoreAPIClient:
|
|
283
|
+
"""
|
|
284
|
+
Get or lazily initialize the global async API client instance.
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
AsyncBritecoreAPIClient: A configured async API client instance.
|
|
288
|
+
|
|
289
|
+
Raises:
|
|
290
|
+
BritecoreError.Base: If lazy initialization fails.
|
|
291
|
+
"""
|
|
292
|
+
if _async_api_client is None:
|
|
293
|
+
raise BritecoreError.ConfigurationError(
|
|
294
|
+
"Async API client has not been initialized. Call init_async_api_client(target_site=...) first."
|
|
295
|
+
)
|
|
296
|
+
return _async_api_client
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
# Module-level api_client proxy that triggers lazy init
|
|
300
|
+
class _LazyAPIClient:
|
|
301
|
+
"""Lazy-loading proxy for the global API client.
|
|
302
|
+
|
|
303
|
+
``__func__ = None`` prevents Python 3.14's ``unittest.mock._is_async_obj``
|
|
304
|
+
from triggering lazy initialisation via ``hasattr(proxy, '__func__')``.
|
|
305
|
+
"""
|
|
306
|
+
|
|
307
|
+
__func__ = None # sentinel: stops mock.__enter__ from probing __getattr__
|
|
308
|
+
|
|
309
|
+
def __getattr__(self, name: str):
|
|
310
|
+
return getattr(get_api_client(), name)
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
api_client: BritecoreAPIClient = cast(
|
|
314
|
+
BritecoreAPIClient, cast(object, _LazyAPIClient())
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
class _LazyAsyncAPIClient:
|
|
319
|
+
"""Lazy-loading proxy for the global async API client.
|
|
320
|
+
|
|
321
|
+
``__func__ = None`` prevents Python 3.14's ``unittest.mock._is_async_obj``
|
|
322
|
+
from triggering lazy initialisation via ``hasattr(proxy, '__func__')``.
|
|
323
|
+
"""
|
|
324
|
+
|
|
325
|
+
__func__ = None # sentinel: stops mock.__enter__ from probing __getattr__
|
|
326
|
+
|
|
327
|
+
def __getattr__(self, name: str):
|
|
328
|
+
return getattr(get_async_api_client(), name)
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
async_api_client: AsyncBritecoreAPIClient = cast(
|
|
332
|
+
AsyncBritecoreAPIClient, cast(object, _LazyAsyncAPIClient())
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
# Default timeout values used by modules that import these names at
|
|
337
|
+
# import-time. They intentionally do not force client initialization.
|
|
338
|
+
# Once a client is initialized, request methods still use the client's own
|
|
339
|
+
# configured timeout values unless a wrapper explicitly passes these values.
|
|
340
|
+
web_timeout_long: int = 50
|
|
341
|
+
web_timeout: int = 5
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
__all__ = [
|
|
345
|
+
"RequestParameters",
|
|
346
|
+
"api_client",
|
|
347
|
+
"async_api_client",
|
|
348
|
+
"get_api_client",
|
|
349
|
+
"get_async_api_client",
|
|
350
|
+
"init_api_client",
|
|
351
|
+
"init_async_api_client",
|
|
352
|
+
"reset_api_client",
|
|
353
|
+
"use_api_client",
|
|
354
|
+
"BritecoreAPIClient",
|
|
355
|
+
"AsyncBritecoreAPIClient",
|
|
356
|
+
"web_timeout_long",
|
|
357
|
+
"web_timeout",
|
|
358
|
+
]
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def __getattr__(name: str):
|
|
362
|
+
"""
|
|
363
|
+
Lazily expose module attributes via PEP 562.
|
|
364
|
+
|
|
365
|
+
Timeout values are read from the initialized API client instance so that
|
|
366
|
+
multiple clients with different configurations do not share one global
|
|
367
|
+
timeout state.
|
|
368
|
+
"""
|
|
369
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Version 1 API wrapper modules."""
|
|
2
|
+
|
|
3
|
+
from britecore_sdk.api.api_calls.v1 import (
|
|
4
|
+
contacts,
|
|
5
|
+
custom_ui,
|
|
6
|
+
deliverables,
|
|
7
|
+
notes,
|
|
8
|
+
payments,
|
|
9
|
+
policies,
|
|
10
|
+
printing,
|
|
11
|
+
reports,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"contacts",
|
|
16
|
+
"custom_ui",
|
|
17
|
+
"deliverables",
|
|
18
|
+
"notes",
|
|
19
|
+
"payments",
|
|
20
|
+
"policies",
|
|
21
|
+
"printing",
|
|
22
|
+
"reports",
|
|
23
|
+
]
|