squidcloud-backend 1.0.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.
- squidcloud_backend-1.0.0/PKG-INFO +21 -0
- squidcloud_backend-1.0.0/README.md +138 -0
- squidcloud_backend-1.0.0/pyproject.toml +53 -0
- squidcloud_backend-1.0.0/setup.cfg +4 -0
- squidcloud_backend-1.0.0/squidcloud_backend/__init__.py +155 -0
- squidcloud_backend-1.0.0/squidcloud_backend/context.py +64 -0
- squidcloud_backend-1.0.0/squidcloud_backend/decorators.py +667 -0
- squidcloud_backend-1.0.0/squidcloud_backend/llm_service.py +41 -0
- squidcloud_backend-1.0.0/squidcloud_backend/metadata.py +473 -0
- squidcloud_backend-1.0.0/squidcloud_backend/project.py +70 -0
- squidcloud_backend-1.0.0/squidcloud_backend/service.py +294 -0
- squidcloud_backend-1.0.0/squidcloud_backend/types.py +490 -0
- squidcloud_backend-1.0.0/squidcloud_backend.egg-info/PKG-INFO +21 -0
- squidcloud_backend-1.0.0/squidcloud_backend.egg-info/SOURCES.txt +15 -0
- squidcloud_backend-1.0.0/squidcloud_backend.egg-info/dependency_links.txt +1 -0
- squidcloud_backend-1.0.0/squidcloud_backend.egg-info/requires.txt +6 -0
- squidcloud_backend-1.0.0/squidcloud_backend.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: squidcloud-backend
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Squid Cloud Python backend SDK — decorators, services, and project entry point
|
|
5
|
+
Author-email: Squid Cloud <support@squid.cloud>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://squid.cloud
|
|
8
|
+
Project-URL: Documentation, https://docs.squid.cloud
|
|
9
|
+
Project-URL: Repository, https://github.com/squid-cloud/squid-cloud
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Typing :: Typed
|
|
16
|
+
Requires-Python: >=3.11
|
|
17
|
+
Requires-Dist: squidcloud-client>=1.0.0
|
|
18
|
+
Provides-Extra: dev
|
|
19
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
20
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
|
|
21
|
+
Requires-Dist: ruff>=0.11.0; extra == "dev"
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Squid Cloud Python Backend SDK
|
|
2
|
+
|
|
3
|
+
Python equivalent of `@squidcloud/backend` (the TypeScript backend SDK).
|
|
4
|
+
Provides decorators, `SquidService`, `SquidProject`, and types for building
|
|
5
|
+
Squid backend services in Python.
|
|
6
|
+
|
|
7
|
+
## Package: `squidcloud-backend`
|
|
8
|
+
|
|
9
|
+
Published to PyPI. Install with:
|
|
10
|
+
```bash
|
|
11
|
+
pip install squidcloud-backend
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Depends on `squidcloud-client` (the Python client SDK) for `self.squid` access.
|
|
15
|
+
|
|
16
|
+
## File Structure
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
squidcloud_backend/
|
|
20
|
+
├── __init__.py # Public API exports
|
|
21
|
+
├── types.py # All TypedDict types, enums, type aliases
|
|
22
|
+
├── context.py # Request-scoped context (contextvars — Python's AsyncLocalStorage)
|
|
23
|
+
├── metadata.py # Meta singleton — collects decorator registrations
|
|
24
|
+
├── decorators.py # All 27 decorators (@executable, @trigger, etc.)
|
|
25
|
+
├── service.py # SquidService base class
|
|
26
|
+
├── project.py # SquidProject entry point
|
|
27
|
+
└── llm_service.py # SquidLlmService abstract base
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## How It Works
|
|
31
|
+
|
|
32
|
+
### Decorator Registration
|
|
33
|
+
|
|
34
|
+
Python decorators execute before the class body is complete, so we use a
|
|
35
|
+
deferred registration pattern:
|
|
36
|
+
|
|
37
|
+
1. Each decorator stores a `(name, register_fn)` tuple on the function via
|
|
38
|
+
the `__squid_decorators__` attribute
|
|
39
|
+
2. When the class is defined, `SquidService.__init_subclass__()` iterates all
|
|
40
|
+
methods and calls each `register_fn(cls, method_name)`
|
|
41
|
+
3. `register_fn` calls the corresponding method on the `Meta` singleton
|
|
42
|
+
4. Class-level decorators (`@llm_service`, `@mcp_server`) store options as
|
|
43
|
+
class attributes, processed in `__init_subclass__()`
|
|
44
|
+
|
|
45
|
+
### Request Context (contextvars)
|
|
46
|
+
|
|
47
|
+
The Python equivalent of Node.js `AsyncLocalStorage` is `contextvars.ContextVar`.
|
|
48
|
+
Per-request state (auth, RunContext) is stored in a context var and accessed
|
|
49
|
+
via `SquidService.context`, `SquidService.get_user_auth()`, etc.
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
# The worker sets the context before calling a service method:
|
|
53
|
+
with RequestScope(ServiceRequestConfig(auth=auth, context=run_context)):
|
|
54
|
+
result = service.my_method(*params)
|
|
55
|
+
|
|
56
|
+
# Inside the method, the service accesses it:
|
|
57
|
+
class MyService(SquidService):
|
|
58
|
+
@executable()
|
|
59
|
+
async def my_method(self) -> str:
|
|
60
|
+
user = self.get_user_auth() # reads from context var
|
|
61
|
+
return f"Hello, {user['userId']}!"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Environment Variables
|
|
65
|
+
|
|
66
|
+
The following environment variables are used:
|
|
67
|
+
|
|
68
|
+
| Variable | Description | Default |
|
|
69
|
+
|----------|-------------|---------|
|
|
70
|
+
| `SQUID_REGION` | Deployment region (e.g., `us-east-1.aws`) | `local` |
|
|
71
|
+
| `SQUID_APP_ID` | Application ID | — |
|
|
72
|
+
|
|
73
|
+
Secrets and API keys are NOT set via env vars — they are passed per-request
|
|
74
|
+
in the `ExecuteFunctionPayload` from the tenant/local-backend.
|
|
75
|
+
|
|
76
|
+
### Global State
|
|
77
|
+
|
|
78
|
+
The worker subprocess sets these class-level globals on `SquidService` before
|
|
79
|
+
each request:
|
|
80
|
+
|
|
81
|
+
- `_global_secrets` — Custom secrets from the Squid console
|
|
82
|
+
- `_global_api_keys` — API keys from the Squid console
|
|
83
|
+
- `_global_backend_api_key` — Internal backend API key
|
|
84
|
+
- `_global_app_id` — Application ID
|
|
85
|
+
- `_global_assets_directory` — Path to the `public/` assets directory
|
|
86
|
+
|
|
87
|
+
### self.squid — Accessing the Client SDK
|
|
88
|
+
|
|
89
|
+
`SquidService.squid` returns a `squidcloud.Squid` instance (from the
|
|
90
|
+
`squidcloud-client` package). It is initialized lazily using the backend API
|
|
91
|
+
key and region. Backend services can call any Squid API:
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
class MyService(SquidService):
|
|
95
|
+
@executable()
|
|
96
|
+
async def summarize(self, url: str) -> str:
|
|
97
|
+
content = await self.squid.web().get_url_content(url)
|
|
98
|
+
return await self.squid.ai().agent("summarizer").ask(content)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Types
|
|
102
|
+
|
|
103
|
+
All types use `TypedDict` for JSON compatibility and IDE autocompletion.
|
|
104
|
+
Key types:
|
|
105
|
+
|
|
106
|
+
- **Request/Response**: `WebhookRequest`, `WebhookResponse`, `TriggerRequest`,
|
|
107
|
+
`OpenApiResponse`, `SquidFile`
|
|
108
|
+
- **Auth**: `AuthWithBearer`, `AuthWithApiKey`, `RunContext`, `ServiceRequestConfig`
|
|
109
|
+
- **Decorator options**: `TriggerOptions`, `SchedulerOptions`, `AiFunctionParam`,
|
|
110
|
+
`LimiterConfig`, `McpServerOptions`, `LlmServiceOptions`
|
|
111
|
+
- **Enums**: `CronExpression` (50+ common cron schedules)
|
|
112
|
+
- **Action types**: `DatabaseActionType`, `StorageActionType`, `TopicActionType`,
|
|
113
|
+
`MetricActionType`, `MutationType`
|
|
114
|
+
|
|
115
|
+
## Metadata Output
|
|
116
|
+
|
|
117
|
+
`SquidProject.metadata()` returns a dict matching the `ApplicationBundleData`
|
|
118
|
+
JSON schema. This is consumed by the platform to discover and route:
|
|
119
|
+
executables, webhooks, triggers, schedulers, security rules, AI functions,
|
|
120
|
+
LLM services, MCP servers, and rate/quota limits.
|
|
121
|
+
|
|
122
|
+
## Compatibility with TypeScript SDK
|
|
123
|
+
|
|
124
|
+
This SDK mirrors the TypeScript `@squidcloud/backend` package:
|
|
125
|
+
|
|
126
|
+
| TypeScript | Python |
|
|
127
|
+
|------------|--------|
|
|
128
|
+
| `class MyService extends SquidService` | `class MyService(SquidService)` |
|
|
129
|
+
| `@executable()` | `@executable()` |
|
|
130
|
+
| `@trigger('id', 'collection')` | `@trigger('id', 'collection')` |
|
|
131
|
+
| `@scheduler('id', CronExpression.EVERY_HOUR)` | `@scheduler('id', CronExpression.EVERY_HOUR)` |
|
|
132
|
+
| `@webhook('id')` | `@webhook('id')` |
|
|
133
|
+
| `@aiFunction('desc', params)` | `@ai_function('desc', params)` |
|
|
134
|
+
| `this.squid` | `self.squid` |
|
|
135
|
+
| `this.context` | `self.context` |
|
|
136
|
+
| `this.secrets` | `self.secrets` |
|
|
137
|
+
| `this.createWebhookResponse(...)` | `self.create_webhook_response(...)` |
|
|
138
|
+
| `new SquidProject()` | `SquidProject()` |
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "squidcloud-backend"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Squid Cloud Python backend SDK — decorators, services, and project entry point"
|
|
9
|
+
requires-python = ">=3.11"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
authors = [{name = "Squid Cloud", email = "support@squid.cloud"}]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Programming Language :: Python :: 3",
|
|
14
|
+
"Programming Language :: Python :: 3.11",
|
|
15
|
+
"Programming Language :: Python :: 3.12",
|
|
16
|
+
"Programming Language :: Python :: 3.13",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
"Typing :: Typed",
|
|
19
|
+
]
|
|
20
|
+
dependencies = [
|
|
21
|
+
"squidcloud-client>=1.0.0",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[project.urls]
|
|
25
|
+
Homepage = "https://squid.cloud"
|
|
26
|
+
Documentation = "https://docs.squid.cloud"
|
|
27
|
+
Repository = "https://github.com/squid-cloud/squid-cloud"
|
|
28
|
+
|
|
29
|
+
[project.optional-dependencies]
|
|
30
|
+
dev = [
|
|
31
|
+
"pytest>=7.0",
|
|
32
|
+
"pytest-asyncio>=0.21",
|
|
33
|
+
"ruff>=0.11.0",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[tool.setuptools.packages.find]
|
|
37
|
+
include = ["squidcloud_backend*"]
|
|
38
|
+
|
|
39
|
+
[tool.ruff]
|
|
40
|
+
target-version = "py311"
|
|
41
|
+
line-length = 100
|
|
42
|
+
|
|
43
|
+
[tool.ruff.lint]
|
|
44
|
+
select = ["E", "W", "F", "I", "UP", "B", "SIM", "TCH", "RUF"]
|
|
45
|
+
ignore = ["E501", "UP007"]
|
|
46
|
+
|
|
47
|
+
[tool.ruff.lint.isort]
|
|
48
|
+
known-first-party = ["squidcloud_backend"]
|
|
49
|
+
|
|
50
|
+
[tool.ruff.format]
|
|
51
|
+
quote-style = "double"
|
|
52
|
+
indent-style = "space"
|
|
53
|
+
docstring-code-format = true
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""Squid Cloud Python backend SDK.
|
|
2
|
+
|
|
3
|
+
Provides decorators, base classes, and types for building Squid backend
|
|
4
|
+
services in Python.
|
|
5
|
+
|
|
6
|
+
Usage::
|
|
7
|
+
|
|
8
|
+
from squidcloud_backend import SquidService, SquidProject, executable, webhook
|
|
9
|
+
|
|
10
|
+
class MyService(SquidService):
|
|
11
|
+
@webhook("hello")
|
|
12
|
+
async def hello_webhook(self, request: WebhookRequest) -> WebhookResponse:
|
|
13
|
+
return self.create_webhook_response(body={"message": "Hello!"})
|
|
14
|
+
|
|
15
|
+
@executable()
|
|
16
|
+
async def greet(self, name: str) -> str:
|
|
17
|
+
return f"Hello, {name}!"
|
|
18
|
+
|
|
19
|
+
project = SquidProject()
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from squidcloud_backend.decorators import (
|
|
23
|
+
ai_function,
|
|
24
|
+
ai_functions_configurator,
|
|
25
|
+
client_connection_state_handler,
|
|
26
|
+
executable,
|
|
27
|
+
limits,
|
|
28
|
+
llm_ask,
|
|
29
|
+
llm_service,
|
|
30
|
+
mcp_authorizer,
|
|
31
|
+
mcp_server,
|
|
32
|
+
mcp_tool,
|
|
33
|
+
scheduler,
|
|
34
|
+
secure_ai_agent,
|
|
35
|
+
secure_ai_query,
|
|
36
|
+
secure_api,
|
|
37
|
+
secure_collection,
|
|
38
|
+
secure_database,
|
|
39
|
+
secure_distributed_lock,
|
|
40
|
+
secure_graphql,
|
|
41
|
+
secure_metric,
|
|
42
|
+
secure_native_query,
|
|
43
|
+
secure_storage,
|
|
44
|
+
secure_topic,
|
|
45
|
+
transform_collection,
|
|
46
|
+
transform_database,
|
|
47
|
+
trigger,
|
|
48
|
+
webhook,
|
|
49
|
+
)
|
|
50
|
+
from squidcloud_backend.llm_service import SquidLlmService
|
|
51
|
+
from squidcloud_backend.project import SquidProject
|
|
52
|
+
from squidcloud_backend.service import (
|
|
53
|
+
OpenApiResponseException,
|
|
54
|
+
SquidService,
|
|
55
|
+
WebhookResponseException,
|
|
56
|
+
)
|
|
57
|
+
from squidcloud_backend.types import (
|
|
58
|
+
AiFunctionAttributes,
|
|
59
|
+
AiFunctionMetadataOptions,
|
|
60
|
+
AiFunctionParam,
|
|
61
|
+
AiFunctionsConfiguratorMetadataOptions,
|
|
62
|
+
Auth,
|
|
63
|
+
AuthWithApiKey,
|
|
64
|
+
AuthWithBearer,
|
|
65
|
+
ClientConnectionState,
|
|
66
|
+
CronExpression,
|
|
67
|
+
LimiterConfig,
|
|
68
|
+
LlmServiceOptions,
|
|
69
|
+
McpAuthorizationRequest,
|
|
70
|
+
McpServerOptions,
|
|
71
|
+
McpToolMetadataOptions,
|
|
72
|
+
OnIntegrationLifecycleInput,
|
|
73
|
+
OpenApiResponse,
|
|
74
|
+
QuotaLimitOptions,
|
|
75
|
+
RateLimitOptions,
|
|
76
|
+
RunContext,
|
|
77
|
+
SchedulerOptions,
|
|
78
|
+
SecureMetricOptions,
|
|
79
|
+
ServiceRequestConfig,
|
|
80
|
+
SquidFile,
|
|
81
|
+
TriggerOptions,
|
|
82
|
+
TriggerRequest,
|
|
83
|
+
UserAiAskResponse,
|
|
84
|
+
UserAiChatOptions,
|
|
85
|
+
WebhookRequest,
|
|
86
|
+
WebhookResponse,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
__all__ = [
|
|
90
|
+
# Core classes
|
|
91
|
+
"SquidService",
|
|
92
|
+
"SquidProject",
|
|
93
|
+
"SquidLlmService",
|
|
94
|
+
# Exceptions
|
|
95
|
+
"WebhookResponseException",
|
|
96
|
+
"OpenApiResponseException",
|
|
97
|
+
# Decorators
|
|
98
|
+
"ai_function",
|
|
99
|
+
"ai_functions_configurator",
|
|
100
|
+
"client_connection_state_handler",
|
|
101
|
+
"executable",
|
|
102
|
+
"limits",
|
|
103
|
+
"llm_ask",
|
|
104
|
+
"llm_service",
|
|
105
|
+
"mcp_authorizer",
|
|
106
|
+
"mcp_server",
|
|
107
|
+
"mcp_tool",
|
|
108
|
+
"scheduler",
|
|
109
|
+
"secure_ai_agent",
|
|
110
|
+
"secure_ai_query",
|
|
111
|
+
"secure_api",
|
|
112
|
+
"secure_collection",
|
|
113
|
+
"secure_database",
|
|
114
|
+
"secure_distributed_lock",
|
|
115
|
+
"secure_graphql",
|
|
116
|
+
"secure_metric",
|
|
117
|
+
"secure_native_query",
|
|
118
|
+
"secure_storage",
|
|
119
|
+
"secure_topic",
|
|
120
|
+
"transform_collection",
|
|
121
|
+
"transform_database",
|
|
122
|
+
"trigger",
|
|
123
|
+
"webhook",
|
|
124
|
+
# Auth & Context
|
|
125
|
+
"Auth",
|
|
126
|
+
"AuthWithApiKey",
|
|
127
|
+
"AuthWithBearer",
|
|
128
|
+
"ClientConnectionState",
|
|
129
|
+
"RunContext",
|
|
130
|
+
"ServiceRequestConfig",
|
|
131
|
+
# Types
|
|
132
|
+
"AiFunctionAttributes",
|
|
133
|
+
"AiFunctionMetadataOptions",
|
|
134
|
+
"AiFunctionParam",
|
|
135
|
+
"AiFunctionsConfiguratorMetadataOptions",
|
|
136
|
+
"CronExpression",
|
|
137
|
+
"LimiterConfig",
|
|
138
|
+
"LlmServiceOptions",
|
|
139
|
+
"McpAuthorizationRequest",
|
|
140
|
+
"McpServerOptions",
|
|
141
|
+
"McpToolMetadataOptions",
|
|
142
|
+
"OnIntegrationLifecycleInput",
|
|
143
|
+
"OpenApiResponse",
|
|
144
|
+
"QuotaLimitOptions",
|
|
145
|
+
"RateLimitOptions",
|
|
146
|
+
"SchedulerOptions",
|
|
147
|
+
"SecureMetricOptions",
|
|
148
|
+
"SquidFile",
|
|
149
|
+
"TriggerOptions",
|
|
150
|
+
"TriggerRequest",
|
|
151
|
+
"UserAiAskResponse",
|
|
152
|
+
"UserAiChatOptions",
|
|
153
|
+
"WebhookRequest",
|
|
154
|
+
"WebhookResponse",
|
|
155
|
+
]
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""Request-scoped context management using Python contextvars.
|
|
2
|
+
|
|
3
|
+
Python equivalent of Node.js AsyncLocalStorage used in the TS SDK for
|
|
4
|
+
per-request state (auth, RunContext, etc.).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import contextvars
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from squidcloud_backend.types import ServiceRequestConfig
|
|
13
|
+
|
|
14
|
+
_current_request: contextvars.ContextVar[ServiceRequestConfig | None] = contextvars.ContextVar(
|
|
15
|
+
"_current_request", default=None
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_request_config() -> ServiceRequestConfig:
|
|
20
|
+
"""Get the current request's ServiceRequestConfig.
|
|
21
|
+
|
|
22
|
+
Raises:
|
|
23
|
+
RuntimeError: If called outside of a request scope.
|
|
24
|
+
"""
|
|
25
|
+
config = _current_request.get()
|
|
26
|
+
if config is None:
|
|
27
|
+
raise RuntimeError(
|
|
28
|
+
"Failed to access request data outside of the request's scope. "
|
|
29
|
+
"This method can only be called during request execution."
|
|
30
|
+
)
|
|
31
|
+
return config
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def set_request_config(config: ServiceRequestConfig) -> contextvars.Token:
|
|
35
|
+
"""Set the request config for the current context. Returns a token for reset."""
|
|
36
|
+
return _current_request.set(config)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def reset_request_config(token: contextvars.Token) -> None:
|
|
40
|
+
"""Reset the request config to its previous value."""
|
|
41
|
+
_current_request.reset(token)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class RequestScope:
|
|
45
|
+
"""Context manager for running code within a request scope.
|
|
46
|
+
|
|
47
|
+
Usage::
|
|
48
|
+
|
|
49
|
+
with RequestScope(config):
|
|
50
|
+
result = service.my_method(*args)
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
def __init__(self, config: ServiceRequestConfig) -> None:
|
|
54
|
+
self._config = config
|
|
55
|
+
self._token: contextvars.Token | None = None
|
|
56
|
+
|
|
57
|
+
def __enter__(self) -> ServiceRequestConfig:
|
|
58
|
+
self._token = set_request_config(self._config)
|
|
59
|
+
return self._config
|
|
60
|
+
|
|
61
|
+
def __exit__(self, *args: Any) -> None:
|
|
62
|
+
if self._token is not None:
|
|
63
|
+
reset_request_config(self._token)
|
|
64
|
+
self._token = None
|