django-esi 8.0.0a4__py3-none-any.whl → 8.0.0b1__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.

esi/openapi_clients.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  import pathlib
3
3
  import warnings
4
- from datetime import datetime, date
4
+ import datetime as dt
5
5
  from hashlib import md5
6
6
  from typing import Any
7
7
 
@@ -23,12 +23,16 @@ from django.utils.text import slugify
23
23
 
24
24
  from esi import app_settings
25
25
  from esi.exceptions import HTTPClientError, HTTPServerError, HTTPNotModified
26
- from esi.aiopenapi3.plugins import Add304ContentType, DjangoESIInit, PatchCompatibilityDatePlugin, Trim204ContentType
26
+ from esi.aiopenapi3.plugins import (
27
+ Add304ContentType, DjangoESIInit, PatchCompatibilityDatePlugin,
28
+ Trim204ContentType, MinifySpec
29
+ )
27
30
  from esi.exceptions import ESIErrorLimitException
28
31
  from esi.models import Token
29
32
  from esi.stubs import ESIClientStub
30
33
 
31
34
  from . import __title__, __url__, __version__
35
+ from .helpers import pascal_case_string
32
36
 
33
37
  logger = logging.getLogger(__name__)
34
38
 
@@ -43,8 +47,10 @@ def _time_to_expiry(expires_header: str) -> int:
43
47
  int: The cache TTL in seconds
44
48
  """
45
49
  try:
46
- expires_dt = datetime.strptime(str(expires_header), '%a, %d %b %Y %H:%M:%S %Z')
47
- return max(int((expires_dt - datetime.utcnow()).total_seconds()), 0)
50
+ expires_dt = dt.datetime.strptime(str(expires_header), '%a, %d %b %Y %H:%M:%S %Z')
51
+ if expires_dt.tzinfo is None:
52
+ expires_dt = expires_dt.replace(tzinfo=dt.timezone.utc)
53
+ return max(int((expires_dt - dt.datetime.now(dt.timezone.utc)).total_seconds()), 0)
48
54
  except ValueError:
49
55
  return 0
50
56
 
@@ -85,13 +91,19 @@ async def http_retry_async() -> AsyncRetrying:
85
91
  )
86
92
 
87
93
 
88
- def _load_plugins(app_name):
94
+ def _load_plugins(app_name, tags: list[str]=[], operations: list[str]=[]):
89
95
  """Load the plugins to make ESI work with this lib.
90
96
 
91
97
  Args:
92
98
  app_name (str): app name to use for internal etags
93
99
  """
94
- return [PatchCompatibilityDatePlugin(), Trim204ContentType(), Add304ContentType(), DjangoESIInit(app_name)]
100
+ return [
101
+ PatchCompatibilityDatePlugin(),
102
+ Trim204ContentType(),
103
+ Add304ContentType(),
104
+ DjangoESIInit(app_name),
105
+ MinifySpec(tags, operations)
106
+ ]
95
107
 
96
108
 
97
109
  def _load_aiopenapi_client_sync(
@@ -100,7 +112,9 @@ def _load_aiopenapi_client_sync(
100
112
  app_name: str,
101
113
  user_agent: str,
102
114
  tenant: str,
103
- spec_file: str | None = None) -> OpenAPI:
115
+ spec_file: str | None = None,
116
+ tags: list[str] = [],
117
+ operations: list[str] = []) -> OpenAPI:
104
118
  """Create an OpenAPI3 Client from Spec
105
119
 
106
120
  Args:
@@ -140,14 +154,14 @@ def _load_aiopenapi_client_sync(
140
154
  session_factory=session_factory,
141
155
  loader=FileSystemLoader(pathlib.Path(spec_file)),
142
156
  use_operation_tags=True,
143
- plugins=_load_plugins(app_name)
157
+ plugins=_load_plugins(app_name, tags, operations)
144
158
  )
145
159
  else:
146
160
  return OpenAPI.load_sync(
147
161
  url=spec_url,
148
162
  session_factory=session_factory,
149
163
  use_operation_tags=True,
150
- plugins=_load_plugins(app_name)
164
+ plugins=_load_plugins(app_name, tags, operations)
151
165
  )
152
166
 
153
167
 
@@ -218,10 +232,15 @@ def _build_user_agent(ua_appname: str, ua_version: str, ua_url: str | None = Non
218
232
  Returns:
219
233
  str: User-Agent string
220
234
  """
235
+
236
+ # Enforce PascalCase for `ua_appname` and strip whitespace
237
+ sanitized_ua_appname = pascal_case_string(ua_appname)
238
+ sanitized_appname = pascal_case_string(__title__)
239
+
221
240
  return (
222
- f"{ua_appname}/{ua_version} "
241
+ f"{sanitized_ua_appname}/{ua_version} "
223
242
  f"({app_settings.ESI_USER_CONTACT_EMAIL}{f'; +{ua_url})' if ua_url else ')'} "
224
- f"{__title__}/{__version__} (+{__url__})"
243
+ f"{sanitized_appname}/{__version__} (+{__url__})"
225
244
  )
226
245
 
227
246
 
@@ -234,6 +253,7 @@ def esi_client_factory_sync(
234
253
  ua_appname: str, ua_version: str, ua_url: str | None = None,
235
254
  spec_file: str | None = None,
236
255
  tenant: str = "tranquility",
256
+ tags: list[str]=[], operations: list[str]=[],
237
257
  **kwargs) -> OpenAPI:
238
258
  """Generate a new OpenAPI ESI client.
239
259
  Args:
@@ -248,7 +268,16 @@ def esi_client_factory_sync(
248
268
  """
249
269
  user_agent = _build_user_agent(ua_appname, ua_version, ua_url)
250
270
  spec_url = _get_spec_url()
251
- return _load_aiopenapi_client_sync(spec_url, compatibility_date, ua_appname, user_agent, tenant, spec_file)
271
+ return _load_aiopenapi_client_sync(
272
+ spec_url,
273
+ compatibility_date,
274
+ ua_appname,
275
+ user_agent,
276
+ tenant,
277
+ spec_file,
278
+ tags,
279
+ operations
280
+ )
252
281
 
253
282
 
254
283
  async def esi_client_factory_async(
@@ -421,7 +450,7 @@ class BaseEsiOperation():
421
450
 
422
451
  # check if etag is same before building models from cache
423
452
  if etag:
424
- if cached_response.headers.get('Expires') == etag:
453
+ if cached_response.headers.get('ETag') == etag:
425
454
  # refresh/store the etag's TTL
426
455
  self._store_etag(cached_response.headers)
427
456
  raise HTTPNotModified(
@@ -607,6 +636,7 @@ class EsiOperation(BaseEsiOperation):
607
636
 
608
637
  # last step store cache we dont want to catch the 304 `None` resonses
609
638
  self._store_cache(cache_key, response)
639
+ self._store_etag(response.headers)
610
640
 
611
641
  return (data, response) if return_response else data
612
642
 
@@ -1024,15 +1054,17 @@ class ESIClientProvider:
1024
1054
 
1025
1055
  def __init__(
1026
1056
  self,
1027
- compatibility_date: str | date,
1057
+ compatibility_date: str | dt.date,
1028
1058
  ua_appname: str,
1029
1059
  ua_version: str,
1030
1060
  ua_url: str | None = None,
1031
1061
  spec_file: None | str = None,
1032
1062
  tenant: str = "tranquility",
1063
+ operations: list[str] = [],
1064
+ tags: list[str] = [],
1033
1065
  **kwargs
1034
1066
  ) -> None:
1035
- if type(compatibility_date) is date:
1067
+ if type(compatibility_date) is dt.date:
1036
1068
  self._compatibility_date = self._date_to_string(compatibility_date)
1037
1069
  else:
1038
1070
  self._compatibility_date = compatibility_date
@@ -1042,6 +1074,8 @@ class ESIClientProvider:
1042
1074
  self._spec_file = spec_file
1043
1075
  self._tenant = tenant
1044
1076
  self._kwargs = kwargs
1077
+ self._operations = operations
1078
+ self._tags = tags
1045
1079
 
1046
1080
  @property
1047
1081
  def client(self) -> ESIClient:
@@ -1053,6 +1087,8 @@ class ESIClientProvider:
1053
1087
  ua_url=self._ua_url,
1054
1088
  spec_file=self._spec_file,
1055
1089
  tenant=self._tenant,
1090
+ operations=self._operations,
1091
+ tags=self._tags,
1056
1092
  **self._kwargs)
1057
1093
  self._client = ESIClient(api)
1058
1094
  return self._client
@@ -1072,7 +1108,7 @@ class ESIClientProvider:
1072
1108
  return self._client_async
1073
1109
 
1074
1110
  @classmethod
1075
- def _date_to_string(cls, compatibility_date: date) -> str:
1111
+ def _date_to_string(cls, compatibility_date: dt.date) -> str:
1076
1112
  """Turns a date object in a compatibility_date string"""
1077
1113
  return f"{compatibility_date.year}-{compatibility_date.month:02}-{compatibility_date.day:02}"
1078
1114
 
esi/stubs.pyi CHANGED
@@ -2100,18 +2100,18 @@ class GetUniverseSchematicsSchematicIdOperation(EsiOperation):
2100
2100
  ...
2101
2101
 
2102
2102
 
2103
- class GetRouteOriginDestinationOperation(EsiOperation):
2103
+ class PostRouteOperation(EsiOperation):
2104
2104
  """EsiOperation, use result(), results() or results_localized()"""
2105
- def result(self, use_etag: bool = True, return_response: bool = False, force_refresh: bool = False, use_cache: bool = True, **extra) -> list[int]:
2106
- """Get the systems between origin and destination"""
2105
+ def result(self, use_etag: bool = True, return_response: bool = False, force_refresh: bool = False, use_cache: bool = True, **extra) -> Any:
2106
+ """Calculate the systems between the given origin and destination."""
2107
2107
  ...
2108
2108
 
2109
- def results(self, use_etag: bool = True, return_response: bool = False, force_refresh: bool = False, use_cache: bool = True, **extra) -> list[int]:
2110
- """Get the systems between origin and destination"""
2109
+ def results(self, use_etag: bool = True, return_response: bool = False, force_refresh: bool = False, use_cache: bool = True, **extra) -> list[Any]:
2110
+ """Calculate the systems between the given origin and destination."""
2111
2111
  ...
2112
2112
 
2113
- def results_localized(self, languages: list[str] | str | None = None, **extra) -> dict[str, list[int]]:
2114
- """Get the systems between origin and destination"""
2113
+ def results_localized(self, languages: list[str] | str | None = None, **extra) -> dict[str, list[Any]]:
2114
+ """Calculate the systems between the given origin and destination."""
2115
2115
  ...
2116
2116
 
2117
2117
 
@@ -3581,8 +3581,8 @@ class ESIClientStub:
3581
3581
  Planetary_Interaction: _Planetary_Interaction = _Planetary_Interaction()
3582
3582
 
3583
3583
  class _Routes:
3584
- def GetRouteOriginDestination(self, destination: int, origin: int, avoid: list[Any] | None = ..., connections: list[Any] | None = ..., flag: str | None = ..., Accept_Language: str | None = ..., If_None_Match: str | None = ..., X_Compatibility_Date: str | None = ..., X_Tenant: str | None = ..., **kwargs: Any) -> GetRouteOriginDestinationOperation:
3585
- """Get the systems between origin and destination"""
3584
+ def PostRoute(self, body: dict[str, Any], origin_system_id: int, destination_system_id: int, Accept_Language: str | None = ..., If_None_Match: str | None = ..., X_Compatibility_Date: str | None = ..., X_Tenant: str | None = ..., **kwargs: Any) -> PostRouteOperation:
3585
+ """Calculate the systems between the given origin and destination."""
3586
3586
  ...
3587
3587
 
3588
3588
 
esi/tests/__init__.py CHANGED
@@ -23,10 +23,10 @@ def _generate_token(
23
23
  expires_in: int = 1200,
24
24
  sso_version: int = 2
25
25
  ) -> dict:
26
- from datetime import datetime, timedelta
26
+ import datetime as dt
27
27
 
28
28
  if timestamp_dt is None:
29
- timestamp_dt = datetime.utcnow()
29
+ timestamp_dt = dt.datetime.now(dt.timezone.utc)
30
30
  if scopes is None:
31
31
  scopes = [
32
32
  'esi-mail.read_mail.v1',
@@ -40,7 +40,7 @@ def _generate_token(
40
40
  'timestamp': int(timestamp_dt.timestamp()),
41
41
  'character_id': character_id,
42
42
  'name': character_name,
43
- 'ExpiresOn': _dt_eveformat(timestamp_dt + timedelta(seconds=expires_in)),
43
+ 'ExpiresOn': _dt_eveformat(timestamp_dt + dt.timedelta(seconds=expires_in)),
44
44
  'scp': scopes,
45
45
  'token_type': 'character',
46
46
  'owner': character_owner_hash,
esi/tests/test_clients.py CHANGED
@@ -1,4 +1,4 @@
1
- from datetime import datetime, timedelta, timezone
1
+ import datetime
2
2
  import os
3
3
  from unittest.mock import patch, Mock
4
4
  import json
@@ -49,7 +49,7 @@ def _load_json_file(path):
49
49
 
50
50
  class MockResultFuture:
51
51
  def __init__(self):
52
- dt = datetime.utcnow().replace(tzinfo=timezone.utc) + timedelta(seconds=60)
52
+ dt = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(seconds=60)
53
53
  self.headers = {"Expires": dt.strftime("%a, %d %b %Y %H:%M:%S %Z")}
54
54
  self.status_code = 200
55
55
  self.text = "dummy"
@@ -57,7 +57,7 @@ class MockResultFuture:
57
57
 
58
58
  class MockResultPast:
59
59
  def __init__(self):
60
- dt = datetime.utcnow().replace(tzinfo=timezone.utc) - timedelta(seconds=60)
60
+ dt = datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(seconds=60)
61
61
  self.headers = {"Expires": dt.strftime("%a, %d %b %Y %H:%M:%S %Z")}
62
62
 
63
63
 
@@ -198,7 +198,7 @@ class TestTokenAuthenticator(NoSocketsTestCase):
198
198
  request.headers = dict()
199
199
  request.params = dict()
200
200
 
201
- self.token.created -= timedelta(121)
201
+ self.token.created -= datetime.timedelta(121)
202
202
 
203
203
  x = TokenAuthenticator(token=self.token)
204
204
  request2 = x.apply(request)
@@ -212,7 +212,7 @@ class TestTokenAuthenticator(NoSocketsTestCase):
212
212
  request.headers = dict()
213
213
  request.params = dict()
214
214
 
215
- self.token.created -= timedelta(121)
215
+ self.token.created -= datetime.timedelta(121)
216
216
  self.token.refresh_token = None
217
217
 
218
218
  x = TokenAuthenticator(token=self.token)
@@ -733,7 +733,10 @@ class TestClientResult2(NoSocketsTestCase):
733
733
  # then
734
734
  self.assertTrue(requests_mocker.called)
735
735
  request = requests_mocker.last_request
736
- self.assertEqual(request._request.headers["User-Agent"], "Django-ESI/1.0.0 (email@example.com; +https://gitlab.com/allianceauth/django-esi)")
736
+
737
+ expected_title = 'DjangoEsi'
738
+
739
+ self.assertEqual(request._request.headers["User-Agent"], f"{expected_title}/1.0.0 (email@example.com; +https://gitlab.com/allianceauth/django-esi)")
737
740
 
738
741
  def test_existing_headers(self, requests_mocker):
739
742
  # given
@@ -743,7 +746,10 @@ class TestClientResult2(NoSocketsTestCase):
743
746
  # then
744
747
  self.assertTrue(requests_mocker.called)
745
748
  request = requests_mocker.last_request
746
- self.assertEqual(request._request.headers["User-Agent"], "Django-ESI/1.0.0 (email@example.com; +https://gitlab.com/allianceauth/django-esi)")
749
+
750
+ expected_title = 'DjangoEsi'
751
+
752
+ self.assertEqual(request._request.headers["User-Agent"], f"{expected_title}/1.0.0 (email@example.com; +https://gitlab.com/allianceauth/django-esi)")
747
753
 
748
754
 
749
755
  class TestRequestsClientPlus(NoSocketsTestCase):
@@ -809,7 +815,9 @@ class TestEsiClientFactoryAppText(NoSocketsTestCase):
809
815
  # when
810
816
  operation = client.Status.get_status()
811
817
  # then
812
- self.assertEqual(operation.future.request.headers["User-Agent"], "Django-ESI/1.0.0 (None; +https://gitlab.com/allianceauth/django-esi)")
818
+ expected_app_name = "MyApp"
819
+ expected_title = 'DjangoEsi'
820
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"{expected_title}/1.0.0 (None; +https://gitlab.com/allianceauth/django-esi)")
813
821
 
814
822
  @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", "email@example.com")
815
823
  def test_defaults_email(self, requests_mocker) -> None:
@@ -821,7 +829,9 @@ class TestEsiClientFactoryAppText(NoSocketsTestCase):
821
829
  # when
822
830
  operation = client.Status.get_status()
823
831
  # then
824
- self.assertEqual(operation.future.request.headers["User-Agent"], "Django-ESI/1.0.0 (email@example.com; +https://gitlab.com/allianceauth/django-esi)")
832
+ expected_app_name = "MyApp"
833
+ expected_title = 'DjangoEsi'
834
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"{expected_title}/1.0.0 (email@example.com; +https://gitlab.com/allianceauth/django-esi)")
825
835
 
826
836
  @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", None)
827
837
  def test_app_text(self, requests_mocker) -> None:
@@ -835,7 +845,9 @@ class TestEsiClientFactoryAppText(NoSocketsTestCase):
835
845
  # when
836
846
  operation = client.Status.get_status()
837
847
  # then
838
- self.assertEqual(operation.future.request.headers["User-Agent"], "my-app v1.0.0 (None) Django-ESI/1.0.0 (+https://gitlab.com/allianceauth/django-esi)",)
848
+ expected_app_name = "MyApp"
849
+ expected_title = 'DjangoEsi'
850
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"my-app v1.0.0 (None) {expected_title}/1.0.0 (+https://gitlab.com/allianceauth/django-esi)",)
839
851
 
840
852
  @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", "email@example.com")
841
853
  def test_app_text_with_email(self, requests_mocker):
@@ -848,7 +860,9 @@ class TestEsiClientFactoryAppText(NoSocketsTestCase):
848
860
  # when
849
861
  operation = client.Status.get_status()
850
862
  # then
851
- self.assertEqual(operation.future.request.headers["User-Agent"], "my-app v1.0.0 (email@example.com) Django-ESI/1.0.0 (+https://gitlab.com/allianceauth/django-esi)",)
863
+ expected_app_name = "MyApp"
864
+ expected_title = 'DjangoEsi'
865
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"my-app v1.0.0 (email@example.com) {expected_title}/1.0.0 (+https://gitlab.com/allianceauth/django-esi)",)
852
866
 
853
867
  @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", "email@example.com")
854
868
  def test_ua_generator(self, requests_mocker):
@@ -859,7 +873,41 @@ class TestEsiClientFactoryAppText(NoSocketsTestCase):
859
873
  # when
860
874
  operation = client.Status.get_status()
861
875
  # then
862
- self.assertEqual(operation.future.request.headers["User-Agent"], "MyApp/1.0.0 (email@example.com) Django-ESI/1.0.0 (+https://gitlab.com/allianceauth/django-esi)")
876
+ expected_app_name = "MyApp"
877
+ expected_title = 'DjangoEsi'
878
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"{expected_app_name}/1.0.0 (email@example.com) {expected_title}/1.0.0 (+https://gitlab.com/allianceauth/django-esi)")
879
+
880
+ @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", "email@example.com")
881
+ def test_ua_generator_for_appname_with_spaces(self, requests_mocker):
882
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec)
883
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec)
884
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/v1/status/", json=self.status_response)
885
+ client = esi_client_factory(ua_appname="My App", ua_version="1.0.0")
886
+
887
+ # when
888
+ operation = client.Status.get_status()
889
+
890
+ # then
891
+ expected_app_name = "MyApp"
892
+ expected_title = 'DjangoEsi'
893
+
894
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"{expected_app_name}/1.0.0 (email@example.com) {expected_title}/1.0.0 (+https://gitlab.com/allianceauth/django-esi)")
895
+
896
+ @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", "email@example.com")
897
+ def test_ua_generator_for_appname_with_hyphens(self, requests_mocker):
898
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec)
899
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec)
900
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/v1/status/", json=self.status_response)
901
+ client = esi_client_factory(ua_appname="My-App", ua_version="1.0.0")
902
+
903
+ # when
904
+ operation = client.Status.get_status()
905
+
906
+ # then
907
+ expected_app_name = "MyApp"
908
+ expected_title = 'DjangoEsi'
909
+
910
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"{expected_app_name}/1.0.0 (email@example.com) {expected_title}/1.0.0 (+https://gitlab.com/allianceauth/django-esi)")
863
911
 
864
912
  @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", "email@example.com")
865
913
  def test_ua_generator_with_url(self, requests_mocker):
@@ -870,7 +918,9 @@ class TestEsiClientFactoryAppText(NoSocketsTestCase):
870
918
  # when
871
919
  operation = client.Status.get_status()
872
920
  # then
873
- self.assertEqual(operation.future.request.headers["User-Agent"], "MyApp/1.0.0 (email@example.com; +https://example.com) Django-ESI/1.0.0 (+https://gitlab.com/allianceauth/django-esi)")
921
+ expected_app_name = "MyApp"
922
+ expected_title = 'DjangoEsi'
923
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"{expected_app_name}/1.0.0 (email@example.com; +https://example.com) {expected_title}/1.0.0 (+https://gitlab.com/allianceauth/django-esi)")
874
924
 
875
925
  @patch(MODULE_PATH + ".__title__", "Django-ESI")
876
926
  @patch(MODULE_PATH + ".__version__", "1.0.0")
@@ -897,7 +947,8 @@ class TestEsiClientProviderAppText(NoSocketsTestCase):
897
947
  # when
898
948
  operation = client.Status.get_status()
899
949
  # then
900
- self.assertEqual(operation.future.request.headers["User-Agent"], "Django-ESI/1.0.0 (None; +https://gitlab.com/allianceauth/django-esi)")
950
+ expected_title = 'DjangoEsi'
951
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"{expected_title}/1.0.0 (None; +https://gitlab.com/allianceauth/django-esi)")
901
952
 
902
953
  @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", "email@example.com")
903
954
  def test_defaults_email(self, requests_mocker) -> None:
@@ -909,7 +960,8 @@ class TestEsiClientProviderAppText(NoSocketsTestCase):
909
960
  # when
910
961
  operation = client.Status.get_status()
911
962
  # then
912
- self.assertEqual(operation.future.request.headers["User-Agent"], "Django-ESI/1.0.0 (email@example.com; +https://gitlab.com/allianceauth/django-esi)")
963
+ expected_title = 'DjangoEsi'
964
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"{expected_title}/1.0.0 (email@example.com; +https://gitlab.com/allianceauth/django-esi)")
913
965
 
914
966
  @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", None)
915
967
  def test_app_text(self, requests_mocker) -> None:
@@ -923,7 +975,8 @@ class TestEsiClientProviderAppText(NoSocketsTestCase):
923
975
  # when
924
976
  operation = client.Status.get_status()
925
977
  # then
926
- self.assertEqual(operation.future.request.headers["User-Agent"], "my-app v1.0.0 (None) Django-ESI/1.0.0 (+https://gitlab.com/allianceauth/django-esi)",)
978
+ expected_title = 'DjangoEsi'
979
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"my-app v1.0.0 (None) {expected_title}/1.0.0 (+https://gitlab.com/allianceauth/django-esi)",)
927
980
 
928
981
  @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", "email@example.com")
929
982
  def test_app_text_with_email(self, requests_mocker):
@@ -936,7 +989,8 @@ class TestEsiClientProviderAppText(NoSocketsTestCase):
936
989
  # when
937
990
  operation = client.Status.get_status()
938
991
  # then
939
- self.assertEqual(operation.future.request.headers["User-Agent"], "my-app v1.0.0 (email@example.com) Django-ESI/1.0.0 (+https://gitlab.com/allianceauth/django-esi)",)
992
+ expected_title = 'DjangoEsi'
993
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"my-app v1.0.0 (email@example.com) {expected_title}/1.0.0 (+https://gitlab.com/allianceauth/django-esi)",)
940
994
 
941
995
  @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", "email@example.com")
942
996
  def test_ua_generator(self, requests_mocker):
@@ -947,7 +1001,9 @@ class TestEsiClientProviderAppText(NoSocketsTestCase):
947
1001
  # when
948
1002
  operation = client.Status.get_status()
949
1003
  # then
950
- self.assertEqual(operation.future.request.headers["User-Agent"], "MyApp/1.0.0 (email@example.com) Django-ESI/1.0.0 (+https://gitlab.com/allianceauth/django-esi)")
1004
+ expected_app_name = "MyApp"
1005
+ expected_title = 'DjangoEsi'
1006
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"{expected_app_name}/1.0.0 (email@example.com) {expected_title}/1.0.0 (+https://gitlab.com/allianceauth/django-esi)")
951
1007
 
952
1008
  @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", "email@example.com")
953
1009
  def test_ua_generator_with_url(self, requests_mocker):
@@ -958,4 +1014,6 @@ class TestEsiClientProviderAppText(NoSocketsTestCase):
958
1014
  # when
959
1015
  operation = client.Status.get_status()
960
1016
  # then
961
- self.assertEqual(operation.future.request.headers["User-Agent"], "MyApp/1.0.0 (email@example.com; +https://example.com) Django-ESI/1.0.0 (+https://gitlab.com/allianceauth/django-esi)")
1017
+ expected_app_name = "MyApp"
1018
+ expected_title = 'DjangoEsi'
1019
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"{expected_app_name}/1.0.0 (email@example.com; +https://example.com) {expected_title}/1.0.0 (+https://gitlab.com/allianceauth/django-esi)")