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.
Files changed (144) hide show
  1. britecore_sdk/__init__.py +169 -0
  2. britecore_sdk/api/__init__.py +14 -0
  3. britecore_sdk/api/api_calls/__init__.py +369 -0
  4. britecore_sdk/api/api_calls/v1/__init__.py +23 -0
  5. britecore_sdk/api/api_calls/v1/contacts.py +241 -0
  6. britecore_sdk/api/api_calls/v1/custom_ui.py +90 -0
  7. britecore_sdk/api/api_calls/v1/deliverables.py +66 -0
  8. britecore_sdk/api/api_calls/v1/notes.py +38 -0
  9. britecore_sdk/api/api_calls/v1/payments.py +64 -0
  10. britecore_sdk/api/api_calls/v1/policies.py +122 -0
  11. britecore_sdk/api/api_calls/v1/printing.py +122 -0
  12. britecore_sdk/api/api_calls/v1/reports.py +38 -0
  13. britecore_sdk/api/api_calls/v2/__init__.py +375 -0
  14. britecore_sdk/api/api_calls/v2/_common.py +35 -0
  15. britecore_sdk/api/api_calls/v2/accounting.py +210 -0
  16. britecore_sdk/api/api_calls/v2/agentcy.py +53 -0
  17. britecore_sdk/api/api_calls/v2/async_contacts.py +215 -0
  18. britecore_sdk/api/api_calls/v2/async_lines.py +179 -0
  19. britecore_sdk/api/api_calls/v2/async_policies.py +695 -0
  20. britecore_sdk/api/api_calls/v2/async_quotes.py +91 -0
  21. britecore_sdk/api/api_calls/v2/attachments.py +323 -0
  22. britecore_sdk/api/api_calls/v2/auth.py +35 -0
  23. britecore_sdk/api/api_calls/v2/authority_limits.py +125 -0
  24. britecore_sdk/api/api_calls/v2/background_jobs.py +35 -0
  25. britecore_sdk/api/api_calls/v2/billing.py +111 -0
  26. britecore_sdk/api/api_calls/v2/claim_adjuster_assignment_configs.py +74 -0
  27. britecore_sdk/api/api_calls/v2/claim_catastrophes.py +126 -0
  28. britecore_sdk/api/api_calls/v2/claim_changes.py +35 -0
  29. britecore_sdk/api/api_calls/v2/claim_contacts.py +89 -0
  30. britecore_sdk/api/api_calls/v2/claim_dates.py +89 -0
  31. britecore_sdk/api/api_calls/v2/claim_estimations.py +107 -0
  32. britecore_sdk/api/api_calls/v2/claim_exposures.py +365 -0
  33. britecore_sdk/api/api_calls/v2/claim_injuries.py +107 -0
  34. britecore_sdk/api/api_calls/v2/claim_properties.py +107 -0
  35. britecore_sdk/api/api_calls/v2/claim_vehicles.py +125 -0
  36. britecore_sdk/api/api_calls/v2/claims.py +591 -0
  37. britecore_sdk/api/api_calls/v2/commissions.py +401 -0
  38. britecore_sdk/api/api_calls/v2/configurations.py +89 -0
  39. britecore_sdk/api/api_calls/v2/contacts.py +1493 -0
  40. britecore_sdk/api/api_calls/v2/coverages.py +215 -0
  41. britecore_sdk/api/api_calls/v2/custom_data.py +125 -0
  42. britecore_sdk/api/api_calls/v2/dashboards.py +193 -0
  43. britecore_sdk/api/api_calls/v2/data.py +163 -0
  44. britecore_sdk/api/api_calls/v2/deliverables.py +649 -0
  45. britecore_sdk/api/api_calls/v2/disputes.py +89 -0
  46. britecore_sdk/api/api_calls/v2/drivers.py +143 -0
  47. britecore_sdk/api/api_calls/v2/errors.py +33 -0
  48. britecore_sdk/api/api_calls/v2/files.py +69 -0
  49. britecore_sdk/api/api_calls/v2/geometries.py +107 -0
  50. britecore_sdk/api/api_calls/v2/geometry.py +35 -0
  51. britecore_sdk/api/api_calls/v2/imports.py +60 -0
  52. britecore_sdk/api/api_calls/v2/ingestion_job.py +107 -0
  53. britecore_sdk/api/api_calls/v2/inspections.py +126 -0
  54. britecore_sdk/api/api_calls/v2/insured.py +323 -0
  55. britecore_sdk/api/api_calls/v2/intacct.py +122 -0
  56. britecore_sdk/api/api_calls/v2/integrations.py +280 -0
  57. britecore_sdk/api/api_calls/v2/jobrunner.py +44 -0
  58. britecore_sdk/api/api_calls/v2/lines.py +893 -0
  59. britecore_sdk/api/api_calls/v2/named_insureds.py +161 -0
  60. britecore_sdk/api/api_calls/v2/nightly_jobs.py +125 -0
  61. britecore_sdk/api/api_calls/v2/notes.py +98 -0
  62. britecore_sdk/api/api_calls/v2/notifications.py +66 -0
  63. britecore_sdk/api/api_calls/v2/payments.py +900 -0
  64. britecore_sdk/api/api_calls/v2/permissions.py +35 -0
  65. britecore_sdk/api/api_calls/v2/policies.py +2884 -0
  66. britecore_sdk/api/api_calls/v2/policy_types.py +179 -0
  67. britecore_sdk/api/api_calls/v2/premium_finance_companies.py +107 -0
  68. britecore_sdk/api/api_calls/v2/prior_policies.py +53 -0
  69. britecore_sdk/api/api_calls/v2/quick_code_values.py +53 -0
  70. britecore_sdk/api/api_calls/v2/quick_codes.py +53 -0
  71. britecore_sdk/api/api_calls/v2/quick_quote_templates.py +188 -0
  72. britecore_sdk/api/api_calls/v2/quote.py +413 -0
  73. britecore_sdk/api/api_calls/v2/quotes.py +569 -0
  74. britecore_sdk/api/api_calls/v2/related_policies.py +53 -0
  75. britecore_sdk/api/api_calls/v2/reports.py +352 -0
  76. britecore_sdk/api/api_calls/v2/return_premium.py +112 -0
  77. britecore_sdk/api/api_calls/v2/rules.py +90 -0
  78. britecore_sdk/api/api_calls/v2/search.py +55 -0
  79. britecore_sdk/api/api_calls/v2/settings.py +539 -0
  80. britecore_sdk/api/api_calls/v2/signatures.py +189 -0
  81. britecore_sdk/api/api_calls/v2/statement_of_value.py +221 -0
  82. britecore_sdk/api/api_calls/v2/subjectivities.py +198 -0
  83. britecore_sdk/api/api_calls/v2/suspensions.py +144 -0
  84. britecore_sdk/api/api_calls/v2/tasks.py +179 -0
  85. britecore_sdk/api/api_calls/v2/term_credit_scores.py +53 -0
  86. britecore_sdk/api/api_calls/v2/uploads.py +89 -0
  87. britecore_sdk/api/api_calls/v2/user_groups.py +107 -0
  88. britecore_sdk/api/api_calls/v2/utils.py +630 -0
  89. britecore_sdk/api/api_calls/v2/vehicles.py +253 -0
  90. britecore_sdk/api/api_calls/v2/vendors.py +448 -0
  91. britecore_sdk/api/api_calls/v2/violations.py +179 -0
  92. britecore_sdk/api/api_calls/v2/watercrafts.py +125 -0
  93. britecore_sdk/api/britecore_api_client.py +1232 -0
  94. britecore_sdk/api/britecore_async_api_client.py +488 -0
  95. britecore_sdk/api/britecore_oauth_token_manager.py +116 -0
  96. britecore_sdk/api/rate_limiter.py +249 -0
  97. britecore_sdk/api/request_cache.py +150 -0
  98. britecore_sdk/api/types.py +156 -0
  99. britecore_sdk/api/workflows/__init__.py +96 -0
  100. britecore_sdk/api/workflows/async_batch_contacts.py +128 -0
  101. britecore_sdk/api/workflows/async_batch_policies.py +236 -0
  102. britecore_sdk/api/workflows/async_batch_quotes.py +119 -0
  103. britecore_sdk/api/workflows/async_staged_creation.py +362 -0
  104. britecore_sdk/api/workflows/batch_contacts.py +123 -0
  105. britecore_sdk/api/workflows/batch_policies.py +224 -0
  106. britecore_sdk/api/workflows/batch_quotes.py +115 -0
  107. britecore_sdk/api/workflows/staged_creation.py +433 -0
  108. britecore_sdk/base_logger.py +68 -0
  109. britecore_sdk/classes/__init__.py +6 -0
  110. britecore_sdk/constants.py +9 -0
  111. britecore_sdk/exceptions.py +249 -0
  112. britecore_sdk/maps/__init__.py +145 -0
  113. britecore_sdk/models/__init__.py +7 -0
  114. britecore_sdk/models/contact.py +102 -0
  115. britecore_sdk/models/policy.py +38 -0
  116. britecore_sdk/models/quote.py +53 -0
  117. britecore_sdk/py.typed +0 -0
  118. britecore_sdk/resources/__init__.py +0 -0
  119. britecore_sdk/resources/zip_codes.csv +41484 -0
  120. britecore_sdk/settings/__init__.py +13 -0
  121. britecore_sdk/settings/config.py +211 -0
  122. britecore_sdk/settings/defaults.py +67 -0
  123. britecore_sdk/utils/__init__.py +0 -0
  124. britecore_sdk/utils/_config_common.py +236 -0
  125. britecore_sdk/utils/check_api_spec_sync.py +118 -0
  126. britecore_sdk/utils/check_site_configs.py +166 -0
  127. britecore_sdk/utils/check_test_data.py +41 -0
  128. britecore_sdk/utils/config_manager.py +735 -0
  129. britecore_sdk/utils/generate_spec_wrappers.py +533 -0
  130. britecore_sdk/utils/healthcheck.py +152 -0
  131. britecore_sdk/utils/interactive_menu.py +269 -0
  132. britecore_sdk/utils/policy_helpers.py +40 -0
  133. britecore_sdk/utils/run_all_checks.py +35 -0
  134. britecore_sdk/utils/zip_code_lookup.py +89 -0
  135. britecore_sdk/validators/__init__.py +21 -0
  136. britecore_sdk/validators/address_validator.py +687 -0
  137. britecore_sdk/validators/email_validator.py +147 -0
  138. britecore_sdk/validators/name_validator.py +92 -0
  139. britecore_sdk/validators/phone_validator.py +167 -0
  140. britecore_sdk-1.5.2.dist-info/METADATA +557 -0
  141. britecore_sdk-1.5.2.dist-info/RECORD +144 -0
  142. britecore_sdk-1.5.2.dist-info/WHEEL +5 -0
  143. britecore_sdk-1.5.2.dist-info/licenses/LICENSE +165 -0
  144. 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
+ ]