django-esi 7.0.1__py3-none-any.whl → 8.0.0a2__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.
Potentially problematic release.
This version of django-esi might be problematic. Click here for more details.
- {django_esi-7.0.1.dist-info → django_esi-8.0.0a2.dist-info}/METADATA +6 -5
- {django_esi-7.0.1.dist-info → django_esi-8.0.0a2.dist-info}/RECORD +25 -16
- esi/__init__.py +2 -1
- esi/admin.py +4 -3
- esi/aiopenapi3/plugins.py +96 -0
- esi/app_settings.py +15 -2
- esi/checks.py +1 -1
- esi/clients.py +13 -14
- esi/decorators.py +35 -3
- esi/exceptions.py +18 -0
- esi/helpers.py +25 -0
- esi/management/commands/generate_esi_stubs.py +228 -0
- esi/managers.py +18 -17
- esi/managers.pyi +82 -0
- esi/models.py +9 -16
- esi/openapi_clients.py +903 -0
- esi/rate_limiting.py +78 -0
- esi/stubs.py +2 -0
- esi/stubs.pyi +3787 -0
- esi/tasks.py +1 -2
- esi/tests/jwt_factory.py +3 -4
- esi/urls.py +0 -1
- esi/views.py +4 -3
- {django_esi-7.0.1.dist-info → django_esi-8.0.0a2.dist-info}/WHEEL +0 -0
- {django_esi-7.0.1.dist-info → django_esi-8.0.0a2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import re
|
|
3
|
+
|
|
4
|
+
from aiopenapi3 import OpenAPI
|
|
5
|
+
from httpx import Client, Timeout
|
|
6
|
+
|
|
7
|
+
from django.core.management.base import BaseCommand
|
|
8
|
+
|
|
9
|
+
from esi import __title__, __url__, __version__, app_settings, stubs, __build_date__
|
|
10
|
+
from esi.aiopenapi3.plugins import PatchCompatibilityDatePlugin
|
|
11
|
+
|
|
12
|
+
# OpenAPI Types to Python
|
|
13
|
+
TYPE_MAP = {
|
|
14
|
+
"integer": "int",
|
|
15
|
+
"number": "float",
|
|
16
|
+
"string": "str",
|
|
17
|
+
"boolean": "bool",
|
|
18
|
+
"array": "list[Any]",
|
|
19
|
+
"object": "dict[str, Any]",
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def sanitize_class_name(name: str) -> str:
|
|
24
|
+
"""Convert a tag into a valid Python class name."""
|
|
25
|
+
sanitized = re.sub(r'[^0-9a-zA-Z_]', '_', name.strip())
|
|
26
|
+
if sanitized and not sanitized[0].isalpha():
|
|
27
|
+
sanitized = f"_{sanitized}"
|
|
28
|
+
return sanitized
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def sanitize_operation_class(name: str) -> str:
|
|
32
|
+
return re.sub(r'[^0-9a-zA-Z_]', '', name[0].upper() + name[1:] + "Operation")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def schema_to_type(schema) -> str:
|
|
36
|
+
"""Convert an OpenAPI schema to a Python type hint."""
|
|
37
|
+
if not schema:
|
|
38
|
+
return "Any"
|
|
39
|
+
schema_type = getattr(schema, "type", None)
|
|
40
|
+
if schema_type == "array":
|
|
41
|
+
items_schema = getattr(schema, "items", None)
|
|
42
|
+
inner = schema_to_type(items_schema)
|
|
43
|
+
return f"list[{inner}]"
|
|
44
|
+
if schema_type == "object":
|
|
45
|
+
return "dict[str, Any]"
|
|
46
|
+
return TYPE_MAP.get(schema_type, "Any")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class Command(BaseCommand):
|
|
50
|
+
help = "Generate ESI Stubs from the current ESI spec with correct type hints."
|
|
51
|
+
|
|
52
|
+
def add_arguments(self, parser):
|
|
53
|
+
parser.add_argument(
|
|
54
|
+
"--output",
|
|
55
|
+
default=None,
|
|
56
|
+
help="Custom output path for the generated ESI stub file (default: stubs.pyi next to openapi_clients.py).",
|
|
57
|
+
)
|
|
58
|
+
parser.add_argument(
|
|
59
|
+
"--compatibility_date",
|
|
60
|
+
default=__build_date__,
|
|
61
|
+
help="Compatibility Date to build ESI Stubs from.",
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
def handle(self, *args, **options):
|
|
65
|
+
self.stdout.write("Starting ESI stub generation...")
|
|
66
|
+
|
|
67
|
+
headers = {
|
|
68
|
+
"User-Agent": f"{__title__}/{__version__} (+{__url__})",
|
|
69
|
+
"X-Tenant": "tranquility",
|
|
70
|
+
"X-Compatibility-Date": options["compatibility_date"]
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
def session_factory(**kwargs) -> Client:
|
|
74
|
+
kwargs.pop("headers", None)
|
|
75
|
+
return Client(
|
|
76
|
+
headers=headers,
|
|
77
|
+
timeout=Timeout(
|
|
78
|
+
connect=app_settings.ESI_REQUESTS_CONNECT_TIMEOUT,
|
|
79
|
+
read=app_settings.ESI_REQUESTS_READ_TIMEOUT,
|
|
80
|
+
write=app_settings.ESI_REQUESTS_WRITE_TIMEOUT,
|
|
81
|
+
pool=app_settings.ESI_REQUESTS_POOL_TIMEOUT
|
|
82
|
+
),
|
|
83
|
+
**kwargs
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
spec_url = f"{app_settings.ESI_API_URL}meta/openapi.json"
|
|
87
|
+
stub_api = OpenAPI.load_sync(
|
|
88
|
+
url=spec_url,
|
|
89
|
+
session_factory=session_factory,
|
|
90
|
+
use_operation_tags=True,
|
|
91
|
+
plugins=[PatchCompatibilityDatePlugin()],
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
base_path = os.path.dirname(stubs.__file__)
|
|
95
|
+
output_path = options["output"] or os.path.join(base_path, "stubs.pyi")
|
|
96
|
+
|
|
97
|
+
self.stdout.write(f"Outputting to: {output_path}")
|
|
98
|
+
|
|
99
|
+
spec_root = stub_api._root
|
|
100
|
+
with open(output_path, "w", encoding="utf-8") as f:
|
|
101
|
+
# File headers
|
|
102
|
+
f.write("# flake8: noqa=E501\n")
|
|
103
|
+
f.write("# Auto Generated do not edit\n")
|
|
104
|
+
# Python Imports
|
|
105
|
+
f.write("from typing import Any\n\n")
|
|
106
|
+
f.write("from esi.openapi_clients import EsiOperation\n")
|
|
107
|
+
f.write("from esi.models import Token\n\n\n")
|
|
108
|
+
|
|
109
|
+
operation_classes = {}
|
|
110
|
+
|
|
111
|
+
for tag in sorted(stub_api._operationindex._tags.keys()):
|
|
112
|
+
# ESI Operation
|
|
113
|
+
# The various methods called on an ESI Operation
|
|
114
|
+
# result(), Results(), Results_Localized() etc. all live here
|
|
115
|
+
ops = stub_api._operationindex._tags[tag]
|
|
116
|
+
for nm, op in sorted(ops._operations.items()):
|
|
117
|
+
op_type = op[0]
|
|
118
|
+
op_obj = op[2]
|
|
119
|
+
docstring = (op_obj.description or op_obj.summary or "").replace("\n", " ").strip()
|
|
120
|
+
op_class_name = sanitize_operation_class(nm)
|
|
121
|
+
|
|
122
|
+
response_type = "Any"
|
|
123
|
+
try:
|
|
124
|
+
match op_type:
|
|
125
|
+
case "post":
|
|
126
|
+
resp_201 = op_obj.responses.get("201")
|
|
127
|
+
if resp_201 and "application/json" in resp_201.content:
|
|
128
|
+
response_type = schema_to_type(resp_201.content["application/json"].schema_)
|
|
129
|
+
case "put" | "delete":
|
|
130
|
+
response_type = "None"
|
|
131
|
+
case _:
|
|
132
|
+
resp_200 = op_obj.responses.get("200")
|
|
133
|
+
if resp_200 and "application/json" in resp_200.content:
|
|
134
|
+
response_type = schema_to_type(resp_200.content["application/json"].schema_)
|
|
135
|
+
|
|
136
|
+
except Exception:
|
|
137
|
+
response_type = "Any"
|
|
138
|
+
|
|
139
|
+
results_type = response_type if response_type.startswith("list[") else f"list[{response_type}]"
|
|
140
|
+
|
|
141
|
+
if op_class_name not in operation_classes:
|
|
142
|
+
f.write(f"class {op_class_name}(EsiOperation):\n")
|
|
143
|
+
if response_type != "None":
|
|
144
|
+
f.write(" \"\"\"EsiOperation, use result(), results() or results_localized()\"\"\"\n")
|
|
145
|
+
else:
|
|
146
|
+
f.write(" \"\"\"EsiOperation, use result()\"\"\"\n")
|
|
147
|
+
|
|
148
|
+
# result()
|
|
149
|
+
f.write(f" def result(self, etag: str | None = None, return_response: bool = False, use_cache: bool = True, **extra) -> {response_type}:\n") # noqa: E501
|
|
150
|
+
f.write(f" \"\"\"{docstring}\"\"\"\n") if docstring else None
|
|
151
|
+
f.write(" ...\n\n")
|
|
152
|
+
if response_type != "None":
|
|
153
|
+
# We only need the extra utility functions if its actually an endpoint that returns data
|
|
154
|
+
# results()
|
|
155
|
+
f.write(f" def results(self, etag: str | None = None, return_response: bool = False, use_cache: bool = True, **extra) -> {results_type}:\n") # noqa: E501
|
|
156
|
+
f.write(f" \"\"\"{docstring}\"\"\"\n") if docstring else None
|
|
157
|
+
f.write(" ...\n\n")
|
|
158
|
+
|
|
159
|
+
# results_localized()
|
|
160
|
+
f.write(f" def results_localized(self, languages: list[str] | str | None = None, **extra) -> dict[str, {results_type}]:\n")
|
|
161
|
+
f.write(f" \"\"\"{docstring}\"\"\"\n") if docstring else None
|
|
162
|
+
f.write(" ...\n\n\n")
|
|
163
|
+
|
|
164
|
+
operation_classes[op_class_name] = True
|
|
165
|
+
|
|
166
|
+
f.write("class ESIClientStub:\n")
|
|
167
|
+
for tag in sorted(stub_api._operationindex._tags.keys()):
|
|
168
|
+
# ESI ESIClientStub
|
|
169
|
+
# The various ESI Tags and Operations
|
|
170
|
+
ops = stub_api._operationindex._tags[tag]
|
|
171
|
+
class_name = f"_{sanitize_class_name(tag)}"
|
|
172
|
+
f.write(f" class {class_name}:\n")
|
|
173
|
+
for nm, op in sorted(ops._operations.items()):
|
|
174
|
+
op_obj = op[2]
|
|
175
|
+
effective_security = (
|
|
176
|
+
getattr(op_obj, "security", None) or getattr(spec_root, "security", None)
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
def _has_oauth2(sec) -> bool:
|
|
180
|
+
data = sec if isinstance(sec, dict) else getattr(sec, "root", None)
|
|
181
|
+
if not isinstance(data, dict):
|
|
182
|
+
return False
|
|
183
|
+
return any(k.lower() == "oauth2" for k in data)
|
|
184
|
+
|
|
185
|
+
needs_oauth = any(_has_oauth2(s) for s in (effective_security or []))
|
|
186
|
+
|
|
187
|
+
params = ["self"]
|
|
188
|
+
optional_params = []
|
|
189
|
+
if getattr(op_obj, "requestBody", None):
|
|
190
|
+
params.append(f"body: {schema_to_type(op_obj.requestBody.content['application/json'].schema_)}")
|
|
191
|
+
|
|
192
|
+
for p in getattr(op_obj, "parameters", []):
|
|
193
|
+
required = getattr(p, "required", False)
|
|
194
|
+
schema_type_value = getattr(getattr(p, "schema_", None), "type", None)
|
|
195
|
+
if isinstance(schema_type_value, str):
|
|
196
|
+
param_type = TYPE_MAP.get(schema_type_value, "Any")
|
|
197
|
+
else:
|
|
198
|
+
param_type = "Any"
|
|
199
|
+
default = ""
|
|
200
|
+
if not required:
|
|
201
|
+
param_type = f"{param_type} | None"
|
|
202
|
+
default = " = ..."
|
|
203
|
+
param_name = p.name.replace("-", "_")
|
|
204
|
+
if param_name == "authorization" and needs_oauth:
|
|
205
|
+
# Skip the Authorization Parameter, we inject this at HTTP Header Level
|
|
206
|
+
continue
|
|
207
|
+
if required:
|
|
208
|
+
params.append(f"{param_name}: {param_type}{default}")
|
|
209
|
+
else:
|
|
210
|
+
optional_params.append(f"{param_name}: {param_type}{default}")
|
|
211
|
+
if needs_oauth:
|
|
212
|
+
# Here, we add our own custom param instead of the earlier Authorization
|
|
213
|
+
# Our library will pick this up and use it later
|
|
214
|
+
params.append("token: Token")
|
|
215
|
+
optional_params.append("**kwargs: Any")
|
|
216
|
+
params_str = ", ".join(params + optional_params)
|
|
217
|
+
op_class_name = sanitize_operation_class(nm)
|
|
218
|
+
docstring = (op_obj.description or op_obj.summary or "").replace("\n", " ").strip()
|
|
219
|
+
|
|
220
|
+
if docstring:
|
|
221
|
+
f.write(f" def {nm}({params_str}) -> {op_class_name}:\n")
|
|
222
|
+
f.write(f" \"\"\"{docstring}\"\"\"\n")
|
|
223
|
+
f.write(" ...\n\n")
|
|
224
|
+
else:
|
|
225
|
+
f.write(f" def {nm}({params_str}) -> {op_class_name}: ...\n")
|
|
226
|
+
f.write(f"\n {sanitize_class_name(tag)}: {class_name} = {class_name}()\n\n")
|
|
227
|
+
|
|
228
|
+
self.stdout.write(self.style.SUCCESS(f"ESI stubs written to {output_path}"))
|
esi/managers.py
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from datetime import timedelta
|
|
3
|
-
from typing import Any
|
|
3
|
+
from typing import Any
|
|
4
4
|
|
|
5
5
|
import requests
|
|
6
|
-
from django.db import models
|
|
7
|
-
from django.utils import timezone
|
|
8
6
|
from jose import jwt
|
|
9
7
|
from jose.exceptions import ExpiredSignatureError, JWTError
|
|
10
8
|
from requests_oauthlib import OAuth2Session
|
|
11
9
|
|
|
10
|
+
from django.db import models
|
|
11
|
+
from django.utils import timezone
|
|
12
|
+
|
|
12
13
|
from . import app_settings
|
|
13
14
|
from .errors import IncompleteResponseError, TokenError
|
|
14
15
|
|
|
15
16
|
logger = logging.getLogger(__name__)
|
|
16
17
|
|
|
17
18
|
|
|
18
|
-
def _process_scopes(scopes):
|
|
19
|
+
def _process_scopes(scopes) -> set[str]:
|
|
19
20
|
if scopes is None:
|
|
20
21
|
# support filtering by no scopes with None passed
|
|
21
22
|
scopes = []
|
|
@@ -28,8 +29,8 @@ def _process_scopes(scopes):
|
|
|
28
29
|
return {str(s) for s in scopes}
|
|
29
30
|
|
|
30
31
|
|
|
31
|
-
class TokenQueryset(models.QuerySet):
|
|
32
|
-
def get_expired(self) ->
|
|
32
|
+
class TokenQueryset(models.QuerySet["Token"]):
|
|
33
|
+
def get_expired(self) -> "TokenQueryset":
|
|
33
34
|
"""Get all tokens which have expired.
|
|
34
35
|
|
|
35
36
|
Returns:
|
|
@@ -39,7 +40,7 @@ class TokenQueryset(models.QuerySet):
|
|
|
39
40
|
timezone.now() - timedelta(seconds=app_settings.ESI_TOKEN_VALID_DURATION)
|
|
40
41
|
return self.filter(created__lte=max_age)
|
|
41
42
|
|
|
42
|
-
def bulk_refresh(self) ->
|
|
43
|
+
def bulk_refresh(self) -> "TokenQueryset":
|
|
43
44
|
"""Refresh all refreshable tokens in the queryset and delete any expired token
|
|
44
45
|
that fails to refresh or can not be refreshed.
|
|
45
46
|
|
|
@@ -65,7 +66,7 @@ class TokenQueryset(models.QuerySet):
|
|
|
65
66
|
self.filter(refresh_token__isnull=True).get_expired().delete()
|
|
66
67
|
return self.exclude(pk__in=incomplete)
|
|
67
68
|
|
|
68
|
-
def require_valid(self) ->
|
|
69
|
+
def require_valid(self) -> "TokenQueryset":
|
|
69
70
|
"""Ensure all tokens are still valid and attempt to refresh any which are expired
|
|
70
71
|
|
|
71
72
|
Deletes those which fail to refresh or cannot be refreshed.
|
|
@@ -80,7 +81,7 @@ class TokenQueryset(models.QuerySet):
|
|
|
80
81
|
qs = self.filter(pk__in=fresh_pks | refreshed_pks)
|
|
81
82
|
return qs
|
|
82
83
|
|
|
83
|
-
def require_scopes(self, scope_string:
|
|
84
|
+
def require_scopes(self, scope_string: str | list) -> "TokenQueryset":
|
|
84
85
|
"""Filter tokens which have at least a subset of given scopes.
|
|
85
86
|
|
|
86
87
|
Args:
|
|
@@ -103,7 +104,7 @@ class TokenQueryset(models.QuerySet):
|
|
|
103
104
|
tokens = tokens.filter(scopes__pk=pk)
|
|
104
105
|
return tokens
|
|
105
106
|
|
|
106
|
-
def require_scopes_exact(self, scope_string:
|
|
107
|
+
def require_scopes_exact(self, scope_string: str | list) -> "TokenQueryset":
|
|
107
108
|
"""Filter tokens which exactly have the given scopes.
|
|
108
109
|
|
|
109
110
|
Args:
|
|
@@ -121,7 +122,7 @@ class TokenQueryset(models.QuerySet):
|
|
|
121
122
|
pks = [v['pk'] for v in scopes_qs]
|
|
122
123
|
return self.filter(pk__in=pks)
|
|
123
124
|
|
|
124
|
-
def equivalent_to(self, token) ->
|
|
125
|
+
def equivalent_to(self, token) -> "TokenQueryset":
|
|
125
126
|
"""Fetch all tokens which match the character and scopes of given reference token
|
|
126
127
|
|
|
127
128
|
Args:
|
|
@@ -134,8 +135,8 @@ class TokenQueryset(models.QuerySet):
|
|
|
134
135
|
.exclude(pk=token.pk)
|
|
135
136
|
|
|
136
137
|
|
|
137
|
-
class TokenManager(models.Manager):
|
|
138
|
-
def get_queryset(self):
|
|
138
|
+
class TokenManager(models.Manager["Token"]):
|
|
139
|
+
def get_queryset(self) -> TokenQueryset:
|
|
139
140
|
"""
|
|
140
141
|
Replace base queryset model with custom TokenQueryset
|
|
141
142
|
:rtype: :class:`esi.managers.TokenQueryset`
|
|
@@ -143,7 +144,7 @@ class TokenManager(models.Manager):
|
|
|
143
144
|
return TokenQueryset(self.model, using=self._db)
|
|
144
145
|
|
|
145
146
|
@staticmethod
|
|
146
|
-
def _decode_jwt(jwt_token:
|
|
147
|
+
def _decode_jwt(jwt_token: str, jwk_set: dict, issuer: Any) -> dict[str, Any]:
|
|
147
148
|
"""
|
|
148
149
|
Helper function to decide the JWT access token supplied by EVE SSO
|
|
149
150
|
"""
|
|
@@ -162,7 +163,7 @@ class TokenManager(models.Manager):
|
|
|
162
163
|
return token_data
|
|
163
164
|
|
|
164
165
|
@staticmethod
|
|
165
|
-
def validate_access_token(token: str):
|
|
166
|
+
def validate_access_token(token: str) -> dict[str, Any] | None:
|
|
166
167
|
"""
|
|
167
168
|
Validate a JWT token retrieved from the EVE SSO.
|
|
168
169
|
:param token: A JWT token originating from the EVE SSO v2
|
|
@@ -200,7 +201,7 @@ class TokenManager(models.Manager):
|
|
|
200
201
|
logger.warning("The JWT signature was invalid: %s", e)
|
|
201
202
|
return None
|
|
202
203
|
|
|
203
|
-
def create_from_code(self, code, user=None):
|
|
204
|
+
def create_from_code(self, code, user=None) -> "Token":
|
|
204
205
|
"""
|
|
205
206
|
Perform OAuth code exchange to retrieve a token.
|
|
206
207
|
:param code: OAuth grant code.
|
|
@@ -282,7 +283,7 @@ class TokenManager(models.Manager):
|
|
|
282
283
|
logger.debug("Successfully created %r for user %s", model, user)
|
|
283
284
|
return model
|
|
284
285
|
|
|
285
|
-
def create_from_request(self, request):
|
|
286
|
+
def create_from_request(self, request) -> "Token":
|
|
286
287
|
"""
|
|
287
288
|
Generate a token from the OAuth callback request. Must contain 'code' in GET.
|
|
288
289
|
:param request: OAuth callback request.
|
esi/managers.pyi
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from django.db.models import QuerySet, Manager
|
|
3
|
+
from .models import Token
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class TokenQueryset(QuerySet[Token]):
|
|
7
|
+
def get_expired(self) -> "TokenQueryset":
|
|
8
|
+
...
|
|
9
|
+
|
|
10
|
+
def bulk_refresh(self) -> "TokenQueryset":
|
|
11
|
+
...
|
|
12
|
+
|
|
13
|
+
def require_scopes(self, scope_string: str | list) -> "TokenQueryset":
|
|
14
|
+
...
|
|
15
|
+
|
|
16
|
+
def require_scopes_exact(self, scope_string: str | list) -> "TokenQueryset":
|
|
17
|
+
...
|
|
18
|
+
|
|
19
|
+
def require_valid(self) -> "TokenQueryset":
|
|
20
|
+
...
|
|
21
|
+
|
|
22
|
+
def equivalent_to(self, token: Token) -> "TokenQueryset":
|
|
23
|
+
...
|
|
24
|
+
|
|
25
|
+
def filter(self, *args: Any, **kwargs: Any) -> "TokenQueryset":
|
|
26
|
+
...
|
|
27
|
+
|
|
28
|
+
def exclude(self, *args: Any, **kwargs: Any) -> "TokenQueryset":
|
|
29
|
+
...
|
|
30
|
+
|
|
31
|
+
def order_by(self, *field_names: str) -> "TokenQueryset":
|
|
32
|
+
...
|
|
33
|
+
|
|
34
|
+
def annotate(self, *args: Any, **kwargs: Any) -> "TokenQueryset":
|
|
35
|
+
...
|
|
36
|
+
|
|
37
|
+
def select_related(self, *fields: str) -> "TokenQueryset":
|
|
38
|
+
...
|
|
39
|
+
|
|
40
|
+
def prefetch_related(self, *lookups: str) -> "TokenQueryset":
|
|
41
|
+
...
|
|
42
|
+
|
|
43
|
+
def distinct(self, *field_names: str) -> "TokenQueryset":
|
|
44
|
+
...
|
|
45
|
+
|
|
46
|
+
def none(self) -> "TokenQueryset":
|
|
47
|
+
...
|
|
48
|
+
|
|
49
|
+
def all(self) -> "TokenQueryset":
|
|
50
|
+
...
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class TokenManager(Manager[Token]):
|
|
54
|
+
def get_queryset(self) -> "TokenQueryset":
|
|
55
|
+
...
|
|
56
|
+
|
|
57
|
+
def filter(self, *args: Any, **kwargs: Any) -> "TokenQueryset":
|
|
58
|
+
...
|
|
59
|
+
|
|
60
|
+
def exclude(self, *args: Any, **kwargs: Any) -> "TokenQueryset":
|
|
61
|
+
...
|
|
62
|
+
|
|
63
|
+
def order_by(self, *field_names: str) -> "TokenQueryset":
|
|
64
|
+
...
|
|
65
|
+
|
|
66
|
+
def annotate(self, *args: Any, **kwargs: Any) -> "TokenQueryset":
|
|
67
|
+
...
|
|
68
|
+
|
|
69
|
+
def select_related(self, *fields: str) -> "TokenQueryset":
|
|
70
|
+
...
|
|
71
|
+
|
|
72
|
+
def prefetch_related(self, *lookups: str) -> "TokenQueryset":
|
|
73
|
+
...
|
|
74
|
+
|
|
75
|
+
def distinct(self, *field_names: str) -> "TokenQueryset":
|
|
76
|
+
...
|
|
77
|
+
|
|
78
|
+
def none(self) -> "TokenQueryset":
|
|
79
|
+
...
|
|
80
|
+
|
|
81
|
+
def all(self) -> "TokenQueryset":
|
|
82
|
+
...
|
esi/models.py
CHANGED
|
@@ -1,36 +1,29 @@
|
|
|
1
1
|
import datetime
|
|
2
|
-
import re
|
|
3
2
|
import logging
|
|
3
|
+
import re
|
|
4
4
|
from typing import ClassVar
|
|
5
5
|
|
|
6
6
|
from bravado.client import SwaggerClient
|
|
7
|
-
from requests.auth import HTTPBasicAuth
|
|
8
|
-
from requests_oauthlib import OAuth2Session
|
|
9
7
|
from oauthlib.oauth2.rfc6749.errors import (
|
|
10
|
-
InvalidClientError,
|
|
11
|
-
|
|
12
|
-
InvalidGrantError,
|
|
13
|
-
InvalidTokenError,
|
|
14
|
-
MissingTokenError,
|
|
8
|
+
InvalidClientError, InvalidClientIdError, InvalidGrantError,
|
|
9
|
+
InvalidTokenError, MissingTokenError,
|
|
15
10
|
)
|
|
11
|
+
from requests.auth import HTTPBasicAuth
|
|
12
|
+
from requests_oauthlib import OAuth2Session
|
|
16
13
|
|
|
17
|
-
from django.core.exceptions import ImproperlyConfigured
|
|
18
14
|
from django.conf import settings
|
|
15
|
+
from django.core.exceptions import ImproperlyConfigured
|
|
19
16
|
from django.db import models
|
|
20
17
|
from django.utils import timezone
|
|
21
18
|
from django.utils.translation import gettext_lazy as _
|
|
22
19
|
|
|
23
20
|
from . import app_settings
|
|
24
21
|
from .clients import esi_client_factory
|
|
25
|
-
from .managers import TokenManager
|
|
26
22
|
from .errors import (
|
|
27
|
-
IncompleteResponseError,
|
|
28
|
-
|
|
29
|
-
TokenExpiredError,
|
|
30
|
-
TokenInvalidError,
|
|
31
|
-
TokenError
|
|
23
|
+
IncompleteResponseError, NotRefreshableTokenError, TokenError,
|
|
24
|
+
TokenExpiredError, TokenInvalidError,
|
|
32
25
|
)
|
|
33
|
-
|
|
26
|
+
from .managers import TokenManager
|
|
34
27
|
|
|
35
28
|
logger = logging.getLogger(__name__)
|
|
36
29
|
|