a3api 0.1.0__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.
a3api-0.1.0/.gitignore ADDED
@@ -0,0 +1,57 @@
1
+ # Dependencies
2
+ node_modules/
3
+
4
+ # Build output
5
+ dist/
6
+
7
+ # Serverless
8
+ .serverless/
9
+
10
+ # IDE
11
+ .idea/
12
+ .vscode/
13
+
14
+ # Claude local settings (may contain credentials)
15
+ .claude/settings.local.json
16
+ *.swp
17
+ *.swo
18
+
19
+ # OS files
20
+ .DS_Store
21
+ Thumbs.db
22
+
23
+ # Environment
24
+ .env
25
+ .env.*
26
+ !.env.example
27
+
28
+ # TypeScript incremental
29
+ *.tsbuildinfo
30
+
31
+ # Python
32
+ __pycache__/
33
+ *.pyc
34
+ *.egg-info/
35
+
36
+ # Next.js
37
+ .next/
38
+ out/
39
+
40
+ # AWS Amplify
41
+ amplify-builds/
42
+
43
+ # Benchmark generated datasets
44
+ **/benchmarks/benchmark_dataset_*.json
45
+ **/benchmarks/benchmark_results_*.json
46
+
47
+ # Lambda packaging artifacts
48
+ **/benchmarks/package/
49
+ function.zip
50
+
51
+ # Terraform
52
+ **/.terraform/
53
+ *.tfstate
54
+ *.tfstate.backup
55
+ *.tfplan
56
+ **/placeholder.zip
57
+ secrets.auto.tfvars
a3api-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 A3 API Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
a3api-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,136 @@
1
+ Metadata-Version: 2.4
2
+ Name: a3api
3
+ Version: 0.1.0
4
+ Summary: Official Python client for the A3 Age Assurance API
5
+ Project-URL: Homepage, https://www.a3api.io
6
+ Project-URL: Documentation, https://www.a3api.io/docs
7
+ Project-URL: Repository, https://github.com/a3api/a3api-python
8
+ Author: A3 API Team
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: a3,ab-1043,age-assurance,age-verification,coppa
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.9
23
+ Requires-Dist: httpx<1,>=0.24
24
+ Requires-Dist: pydantic<3,>=2
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
27
+ Requires-Dist: pytest-httpx>=0.30; extra == 'dev'
28
+ Requires-Dist: pytest>=7; extra == 'dev'
29
+ Description-Content-Type: text/markdown
30
+
31
+ # a3api
32
+
33
+ Official Python client for the [A3 Age Assurance API](https://www.a3api.io).
34
+
35
+ Typed, async-ready, with built-in retries — supports Python 3.9+.
36
+
37
+ ## Installation
38
+
39
+ ```bash
40
+ pip install a3api
41
+ ```
42
+
43
+ ## Quick Start
44
+
45
+ ```python
46
+ from a3api import A3Client, AssessAgeRequest, OsSignal
47
+
48
+ client = A3Client(api_key="your-api-key")
49
+
50
+ response = client.assess_age(AssessAgeRequest(
51
+ os_signal=OsSignal.AGE_18_PLUS,
52
+ user_country_code="US",
53
+ ))
54
+
55
+ print(response.verdict) # CONSISTENT
56
+ print(response.confidence_score) # 0.95
57
+ print(response.verification_token)
58
+ ```
59
+
60
+ ### Async
61
+
62
+ ```python
63
+ from a3api import AsyncA3Client, AssessAgeRequest, OsSignal
64
+
65
+ async with AsyncA3Client(api_key="your-api-key") as client:
66
+ response = await client.assess_age(AssessAgeRequest(
67
+ os_signal=OsSignal.AGE_18_PLUS,
68
+ user_country_code="US",
69
+ ))
70
+ ```
71
+
72
+ ### With Behavioral Signals
73
+
74
+ ```python
75
+ from a3api import (
76
+ A3Client, AssessAgeRequest, OsSignal,
77
+ BehavioralMetrics, DeviceContext,
78
+ )
79
+
80
+ client = A3Client(api_key="your-api-key")
81
+
82
+ response = client.assess_age(AssessAgeRequest(
83
+ os_signal=OsSignal.AGE_13_15,
84
+ user_country_code="US",
85
+ behavioral_metrics=BehavioralMetrics(
86
+ avg_touch_precision=0.82,
87
+ scroll_velocity=340.0,
88
+ form_completion_time_ms=12000.0,
89
+ ),
90
+ device_context=DeviceContext(
91
+ os_version="iOS 17.2",
92
+ device_model="iPhone 15",
93
+ is_high_contrast_enabled=False,
94
+ screen_scale_factor=3.0,
95
+ ),
96
+ ))
97
+ ```
98
+
99
+ ## Error Handling
100
+
101
+ ```python
102
+ from a3api import (
103
+ A3Client, A3AuthenticationError,
104
+ A3RateLimitError, A3ValidationError, A3ConnectionError,
105
+ )
106
+
107
+ try:
108
+ response = client.assess_age(request)
109
+ except A3AuthenticationError:
110
+ # Invalid or missing API key (401)
111
+ pass
112
+ except A3RateLimitError as e:
113
+ # Too many requests (429) — e.retry_after has the wait time
114
+ pass
115
+ except A3ValidationError as e:
116
+ # Bad request (400) — e.validation_errors has details
117
+ pass
118
+ except A3ConnectionError:
119
+ # Network or timeout error
120
+ pass
121
+ ```
122
+
123
+ ## Configuration
124
+
125
+ ```python
126
+ client = A3Client(
127
+ api_key="your-api-key",
128
+ base_url="https://api.a3api.io", # default
129
+ timeout=30.0, # seconds, default
130
+ max_retries=2, # default
131
+ )
132
+ ```
133
+
134
+ ## License
135
+
136
+ MIT
a3api-0.1.0/README.md ADDED
@@ -0,0 +1,106 @@
1
+ # a3api
2
+
3
+ Official Python client for the [A3 Age Assurance API](https://www.a3api.io).
4
+
5
+ Typed, async-ready, with built-in retries — supports Python 3.9+.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install a3api
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```python
16
+ from a3api import A3Client, AssessAgeRequest, OsSignal
17
+
18
+ client = A3Client(api_key="your-api-key")
19
+
20
+ response = client.assess_age(AssessAgeRequest(
21
+ os_signal=OsSignal.AGE_18_PLUS,
22
+ user_country_code="US",
23
+ ))
24
+
25
+ print(response.verdict) # CONSISTENT
26
+ print(response.confidence_score) # 0.95
27
+ print(response.verification_token)
28
+ ```
29
+
30
+ ### Async
31
+
32
+ ```python
33
+ from a3api import AsyncA3Client, AssessAgeRequest, OsSignal
34
+
35
+ async with AsyncA3Client(api_key="your-api-key") as client:
36
+ response = await client.assess_age(AssessAgeRequest(
37
+ os_signal=OsSignal.AGE_18_PLUS,
38
+ user_country_code="US",
39
+ ))
40
+ ```
41
+
42
+ ### With Behavioral Signals
43
+
44
+ ```python
45
+ from a3api import (
46
+ A3Client, AssessAgeRequest, OsSignal,
47
+ BehavioralMetrics, DeviceContext,
48
+ )
49
+
50
+ client = A3Client(api_key="your-api-key")
51
+
52
+ response = client.assess_age(AssessAgeRequest(
53
+ os_signal=OsSignal.AGE_13_15,
54
+ user_country_code="US",
55
+ behavioral_metrics=BehavioralMetrics(
56
+ avg_touch_precision=0.82,
57
+ scroll_velocity=340.0,
58
+ form_completion_time_ms=12000.0,
59
+ ),
60
+ device_context=DeviceContext(
61
+ os_version="iOS 17.2",
62
+ device_model="iPhone 15",
63
+ is_high_contrast_enabled=False,
64
+ screen_scale_factor=3.0,
65
+ ),
66
+ ))
67
+ ```
68
+
69
+ ## Error Handling
70
+
71
+ ```python
72
+ from a3api import (
73
+ A3Client, A3AuthenticationError,
74
+ A3RateLimitError, A3ValidationError, A3ConnectionError,
75
+ )
76
+
77
+ try:
78
+ response = client.assess_age(request)
79
+ except A3AuthenticationError:
80
+ # Invalid or missing API key (401)
81
+ pass
82
+ except A3RateLimitError as e:
83
+ # Too many requests (429) — e.retry_after has the wait time
84
+ pass
85
+ except A3ValidationError as e:
86
+ # Bad request (400) — e.validation_errors has details
87
+ pass
88
+ except A3ConnectionError:
89
+ # Network or timeout error
90
+ pass
91
+ ```
92
+
93
+ ## Configuration
94
+
95
+ ```python
96
+ client = A3Client(
97
+ api_key="your-api-key",
98
+ base_url="https://api.a3api.io", # default
99
+ timeout=30.0, # seconds, default
100
+ max_retries=2, # default
101
+ )
102
+ ```
103
+
104
+ ## License
105
+
106
+ MIT
@@ -0,0 +1,49 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "a3api"
7
+ version = "0.1.0"
8
+ description = "Official Python client for the A3 Age Assurance API"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "A3 API Team" }]
14
+ keywords = ["a3", "age-assurance", "age-verification", "ab-1043", "coppa"]
15
+ classifiers = [
16
+ "Development Status :: 4 - Beta",
17
+ "Intended Audience :: Developers",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.9",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
25
+ "Typing :: Typed",
26
+ ]
27
+ dependencies = [
28
+ "httpx>=0.24,<1",
29
+ "pydantic>=2,<3",
30
+ ]
31
+
32
+ [project.urls]
33
+ Homepage = "https://www.a3api.io"
34
+ Documentation = "https://www.a3api.io/docs"
35
+ Repository = "https://github.com/a3api/a3api-python"
36
+
37
+ [project.optional-dependencies]
38
+ dev = [
39
+ "pytest>=7",
40
+ "pytest-asyncio>=0.21",
41
+ "pytest-httpx>=0.30",
42
+ ]
43
+
44
+ [tool.hatch.build.targets.wheel]
45
+ packages = ["src/a3api"]
46
+
47
+ [tool.pytest.ini_options]
48
+ testpaths = ["tests"]
49
+ asyncio_mode = "auto"
@@ -0,0 +1,61 @@
1
+ """A3 Age Assurance API — official Python client."""
2
+
3
+ from ._client import A3Client, AsyncA3Client
4
+ from ._errors import (
5
+ A3ApiError,
6
+ A3AuthenticationError,
7
+ A3ConnectionError,
8
+ A3RateLimitError,
9
+ A3ValidationError,
10
+ )
11
+ from ._types import (
12
+ AccountLongevity,
13
+ AgeBracket,
14
+ AssessAgeRequest,
15
+ AssessAgeResponse,
16
+ BehavioralMetrics,
17
+ ConsentSource,
18
+ ContextualSignals,
19
+ DeviceContext,
20
+ FaceEstimationProvider,
21
+ FaceEstimationResult,
22
+ InputComplexity,
23
+ IpType,
24
+ OsSignal,
25
+ ParentalConsentStatus,
26
+ ReferrerCategory,
27
+ Verdict,
28
+ )
29
+ from ._version import __version__
30
+
31
+ __all__ = [
32
+ # Clients
33
+ "A3Client",
34
+ "AsyncA3Client",
35
+ # Errors
36
+ "A3ApiError",
37
+ "A3AuthenticationError",
38
+ "A3ConnectionError",
39
+ "A3RateLimitError",
40
+ "A3ValidationError",
41
+ # Request types
42
+ "AssessAgeRequest",
43
+ "OsSignal",
44
+ "ParentalConsentStatus",
45
+ "ConsentSource",
46
+ "FaceEstimationProvider",
47
+ "IpType",
48
+ "ReferrerCategory",
49
+ "BehavioralMetrics",
50
+ "DeviceContext",
51
+ "ContextualSignals",
52
+ "AccountLongevity",
53
+ "InputComplexity",
54
+ "FaceEstimationResult",
55
+ # Response types
56
+ "AssessAgeResponse",
57
+ "Verdict",
58
+ "AgeBracket",
59
+ # Version
60
+ "__version__",
61
+ ]
@@ -0,0 +1,192 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ import httpx
6
+
7
+ from ._errors import (
8
+ A3ApiError,
9
+ A3AuthenticationError,
10
+ A3ConnectionError,
11
+ A3RateLimitError,
12
+ A3ValidationError,
13
+ )
14
+ from ._retry import (
15
+ RetryConfig,
16
+ is_retryable_status,
17
+ parse_retry_after,
18
+ with_retry_async,
19
+ with_retry_sync,
20
+ )
21
+ from ._types import AssessAgeRequest, AssessAgeResponse
22
+ from ._version import __version__
23
+
24
+ DEFAULT_BASE_URL = "https://api.a3api.io"
25
+ DEFAULT_TIMEOUT = 30.0
26
+ DEFAULT_MAX_RETRIES = 2
27
+
28
+
29
+ def _build_headers(api_key: str) -> dict[str, str]:
30
+ return {
31
+ "Content-Type": "application/json",
32
+ "x-api-key": api_key,
33
+ "User-Agent": f"a3api-python/{__version__}",
34
+ }
35
+
36
+
37
+ def _handle_error(response: httpx.Response) -> None:
38
+ body: dict[str, Any] | None = None
39
+ try:
40
+ body = response.json()
41
+ except Exception:
42
+ pass
43
+
44
+ status = response.status_code
45
+ if status == 400:
46
+ raise A3ValidationError(body)
47
+ if status == 401:
48
+ raise A3AuthenticationError(body)
49
+ if status == 429:
50
+ retry_after = parse_retry_after(response.headers.get("retry-after"))
51
+ raise A3RateLimitError(retry_after, body)
52
+ raise A3ApiError(
53
+ body.get("error", f"HTTP {status}") if body else f"HTTP {status}",
54
+ status,
55
+ body,
56
+ )
57
+
58
+
59
+ def _should_retry(exc: Exception) -> tuple[bool, float | None]:
60
+ if isinstance(exc, A3RateLimitError):
61
+ return True, exc.retry_after
62
+ if isinstance(exc, A3ApiError) and is_retryable_status(exc.status_code):
63
+ return True, None
64
+ if isinstance(exc, A3ConnectionError):
65
+ return True, None
66
+ return False, None
67
+
68
+
69
+ class A3Client:
70
+ """Synchronous A3 API client using httpx."""
71
+
72
+ def __init__(
73
+ self,
74
+ api_key: str,
75
+ *,
76
+ base_url: str = DEFAULT_BASE_URL,
77
+ timeout: float = DEFAULT_TIMEOUT,
78
+ max_retries: int = DEFAULT_MAX_RETRIES,
79
+ ) -> None:
80
+ if not api_key:
81
+ raise ValueError("api_key is required")
82
+ self._api_key = api_key
83
+ self._base_url = base_url.rstrip("/")
84
+ self._retry_config = RetryConfig(max_retries=max_retries)
85
+ self._client = httpx.Client(
86
+ base_url=self._base_url,
87
+ headers=_build_headers(api_key),
88
+ timeout=timeout,
89
+ )
90
+
91
+ def __enter__(self) -> A3Client:
92
+ return self
93
+
94
+ def __exit__(self, *args: object) -> None:
95
+ self.close()
96
+
97
+ def close(self) -> None:
98
+ self._client.close()
99
+
100
+ def assess_age(self, request: AssessAgeRequest) -> AssessAgeResponse:
101
+ """Assess age and return a parsed response model."""
102
+ raw = self.assess_age_raw(request)
103
+ return AssessAgeResponse.model_validate(raw)
104
+
105
+ def assess_age_raw(self, request: AssessAgeRequest) -> dict[str, Any]:
106
+ """Assess age and return the raw JSON dict."""
107
+ return with_retry_sync(
108
+ lambda: self._do_assess_age(request),
109
+ self._retry_config,
110
+ _should_retry,
111
+ )
112
+
113
+ def _do_assess_age(self, request: AssessAgeRequest) -> dict[str, Any]:
114
+ try:
115
+ response = self._client.post(
116
+ "/v1/assurance/assess-age",
117
+ json=request.model_dump(exclude_none=True),
118
+ )
119
+ except httpx.TimeoutException as exc:
120
+ raise A3ConnectionError(f"Request timed out: {exc}", exc) from exc
121
+ except httpx.NetworkError as exc:
122
+ raise A3ConnectionError(f"Network error: {exc}", exc) from exc
123
+ except httpx.ProtocolError as exc:
124
+ raise A3ConnectionError(f"Protocol error: {exc}", exc) from exc
125
+
126
+ if response.is_success:
127
+ return response.json() # type: ignore[no-any-return]
128
+ _handle_error(response)
129
+ raise AssertionError("unreachable") # pragma: no cover
130
+
131
+
132
+ class AsyncA3Client:
133
+ """Asynchronous A3 API client using httpx."""
134
+
135
+ def __init__(
136
+ self,
137
+ api_key: str,
138
+ *,
139
+ base_url: str = DEFAULT_BASE_URL,
140
+ timeout: float = DEFAULT_TIMEOUT,
141
+ max_retries: int = DEFAULT_MAX_RETRIES,
142
+ ) -> None:
143
+ if not api_key:
144
+ raise ValueError("api_key is required")
145
+ self._api_key = api_key
146
+ self._base_url = base_url.rstrip("/")
147
+ self._retry_config = RetryConfig(max_retries=max_retries)
148
+ self._client = httpx.AsyncClient(
149
+ base_url=self._base_url,
150
+ headers=_build_headers(api_key),
151
+ timeout=timeout,
152
+ )
153
+
154
+ async def __aenter__(self) -> AsyncA3Client:
155
+ return self
156
+
157
+ async def __aexit__(self, *args: object) -> None:
158
+ await self.close()
159
+
160
+ async def close(self) -> None:
161
+ await self._client.aclose()
162
+
163
+ async def assess_age(self, request: AssessAgeRequest) -> AssessAgeResponse:
164
+ """Assess age and return a parsed response model."""
165
+ raw = await self.assess_age_raw(request)
166
+ return AssessAgeResponse.model_validate(raw)
167
+
168
+ async def assess_age_raw(self, request: AssessAgeRequest) -> dict[str, Any]:
169
+ """Assess age and return the raw JSON dict."""
170
+ return await with_retry_async(
171
+ lambda: self._do_assess_age(request),
172
+ self._retry_config,
173
+ _should_retry,
174
+ )
175
+
176
+ async def _do_assess_age(self, request: AssessAgeRequest) -> dict[str, Any]:
177
+ try:
178
+ response = await self._client.post(
179
+ "/v1/assurance/assess-age",
180
+ json=request.model_dump(exclude_none=True),
181
+ )
182
+ except httpx.TimeoutException as exc:
183
+ raise A3ConnectionError(f"Request timed out: {exc}", exc) from exc
184
+ except httpx.NetworkError as exc:
185
+ raise A3ConnectionError(f"Network error: {exc}", exc) from exc
186
+ except httpx.ProtocolError as exc:
187
+ raise A3ConnectionError(f"Protocol error: {exc}", exc) from exc
188
+
189
+ if response.is_success:
190
+ return response.json() # type: ignore[no-any-return]
191
+ _handle_error(response)
192
+ raise AssertionError("unreachable") # pragma: no cover
@@ -0,0 +1,62 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Optional, Union
4
+
5
+
6
+ class A3ApiError(Exception):
7
+ """Base error for all A3 API errors with an HTTP status code."""
8
+
9
+ def __init__(
10
+ self,
11
+ message: str,
12
+ status_code: int,
13
+ body: Optional[dict[str, Any]] = None,
14
+ ) -> None:
15
+ super().__init__(message)
16
+ self.status_code = status_code
17
+ self.body = body
18
+
19
+
20
+ class A3AuthenticationError(A3ApiError):
21
+ """Raised on 401 Unauthorized responses."""
22
+
23
+ def __init__(self, body: Optional[dict[str, Any]] = None) -> None:
24
+ raw = body.get("message", "Unauthorized") if body else "Unauthorized"
25
+ msg = ", ".join(raw) if isinstance(raw, list) else str(raw)
26
+ super().__init__(msg, 401, body)
27
+
28
+
29
+ class A3RateLimitError(A3ApiError):
30
+ """Raised on 429 Too Many Requests responses."""
31
+
32
+ def __init__(
33
+ self,
34
+ retry_after: Optional[float] = None,
35
+ body: Optional[dict[str, Any]] = None,
36
+ ) -> None:
37
+ super().__init__("Rate limit exceeded", 429, body)
38
+ self.retry_after = retry_after
39
+
40
+
41
+ class A3ValidationError(A3ApiError):
42
+ """Raised on 400 Bad Request responses with validation details."""
43
+
44
+ def __init__(self, body: Optional[dict[str, Any]] = None) -> None:
45
+ raw: Union[str, list[str]] = (body or {}).get("message", [])
46
+ self.validation_errors: list[str] = (
47
+ raw if isinstance(raw, list) else [raw] if raw else []
48
+ )
49
+ msg = (
50
+ f"Validation failed: {', '.join(self.validation_errors)}"
51
+ if self.validation_errors
52
+ else "Validation failed"
53
+ )
54
+ super().__init__(msg, 400, body)
55
+
56
+
57
+ class A3ConnectionError(Exception):
58
+ """Raised on network or timeout errors (no HTTP status code)."""
59
+
60
+ def __init__(self, message: str, cause: Optional[BaseException] = None) -> None:
61
+ super().__init__(message)
62
+ self.__cause__ = cause