pyixapi 0.2.3__tar.gz → 0.2.5__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.
@@ -1,21 +1,23 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: pyixapi
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: Python API client library for IX-API
5
5
  License: Apache-2.0
6
6
  Author: Guillaume Mazoyer
7
7
  Author-email: oss@mazoyer.eu
8
- Requires-Python: >=3.8,<4.0
8
+ Requires-Python: >=3.9
9
9
  Classifier: Intended Audience :: Developers
10
- Classifier: License :: OSI Approved :: Apache Software License
11
10
  Classifier: Programming Language :: Python :: 3
12
- Classifier: Programming Language :: Python :: 3.8
13
11
  Classifier: Programming Language :: Python :: 3.9
14
12
  Classifier: Programming Language :: Python :: 3.10
15
13
  Classifier: Programming Language :: Python :: 3.11
16
14
  Classifier: Programming Language :: Python :: 3.12
17
- Requires-Dist: PyJWT (>=2.4.0,<2.9)
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Provides-Extra: dev
17
+ Requires-Dist: PyJWT (>=2.4.0,<2.11)
18
+ Requires-Dist: pytest ; extra == "dev"
18
19
  Requires-Dist: requests (>=2.20.0,<3.0)
20
+ Requires-Dist: ruff (>=0.9,<0.10) ; extra == "dev"
19
21
  Description-Content-Type: text/markdown
20
22
 
21
23
  # pyixapi
@@ -29,7 +29,7 @@ from pyixapi.models import (
29
29
  RoleAssignment,
30
30
  )
31
31
 
32
- __version__ = "0.2.2"
32
+ __version__ = "0.2.5"
33
33
 
34
34
 
35
35
  class API(object):
@@ -48,6 +48,7 @@ class API(object):
48
48
  access_token="",
49
49
  refresh_token="",
50
50
  user_agent=f"pyixapi/{__version__}",
51
+ proxies=None,
51
52
  ):
52
53
  self.url = url.rstrip("/")
53
54
  self.key = key
@@ -56,6 +57,7 @@ class API(object):
56
57
  self.refresh_token = Token.from_jwt(refresh_token) if refresh_token else None
57
58
  self.http_session = requests.Session()
58
59
  self.user_agent = user_agent
60
+ self.proxies = proxies
59
61
 
60
62
  self.auth = Endpoint(self, "auth")
61
63
  self.connections = Endpoint(self, "connections", model=Connection)
@@ -65,27 +67,17 @@ class API(object):
65
67
  self.facilities = Endpoint(self, "facilities", model=Facility)
66
68
  self.ips = Endpoint(self, "ips", model=IP)
67
69
  self.macs = Endpoint(self, "macs", model=MAC)
68
- self.network_feature_configs = Endpoint(
69
- self, "network-feature-configs", model=NetworkFeatureConfig
70
- )
70
+ self.network_feature_configs = Endpoint(self, "network-feature-configs", model=NetworkFeatureConfig)
71
71
  self.network_features = Endpoint(self, "network-features", model=NetworkFeature)
72
- self.network_service_configs = Endpoint(
73
- self, "network-service-configs", model=NetworkServiceConfig
74
- )
72
+ self.network_service_configs = Endpoint(self, "network-service-configs", model=NetworkServiceConfig)
75
73
  self.network_services = Endpoint(self, "network-services", model=NetworkService)
76
74
  self.pops = Endpoint(self, "pops", model=PoP)
77
75
  # Version 2+
78
- self.member_joining_rules = Endpoint(
79
- self, "member-joining-rules", model=MemberJoiningRule
80
- )
76
+ self.member_joining_rules = Endpoint(self, "member-joining-rules", model=MemberJoiningRule)
81
77
  self.metro_areas = Endpoint(self, "metro-areas", model=MetroArea)
82
- self.metro_area_networks = Endpoint(
83
- self, "metro-area-networks", model=MetroAreaNetwork
84
- )
78
+ self.metro_area_networks = Endpoint(self, "metro-area-networks", model=MetroAreaNetwork)
85
79
  self.ports = Endpoint(self, "ports", model=Port)
86
- self.port_reservations = Endpoint(
87
- self, "port-reservations", model=PortReservation
88
- )
80
+ self.port_reservations = Endpoint(self, "port-reservations", model=PortReservation)
89
81
  self.roles = Endpoint(self, "roles", model=Role)
90
82
  self.role_assignments = Endpoint(self, "role-assignments", model=RoleAssignment)
91
83
 
@@ -95,14 +87,16 @@ class API(object):
95
87
  Get the API version of IX-API.
96
88
  """
97
89
  return Request(
98
- base=self.url, token=self.access_token, http_session=self.http_session
90
+ base=self.url,
91
+ token=self.access_token,
92
+ http_session=self.http_session,
93
+ user_agent=self.user_agent,
94
+ proxies=self.proxies,
99
95
  ).get_version()
100
96
 
101
97
  @property
102
98
  def accounts(self):
103
- return Endpoint(
104
- self, "customers" if self.version == 1 else "accounts", model=Account
105
- )
99
+ return Endpoint(self, "customers" if self.version == 1 else "accounts", model=Account)
106
100
 
107
101
  @property
108
102
  def product_offerings(self):
@@ -131,7 +125,10 @@ class API(object):
131
125
  return self.refresh_authentication()
132
126
 
133
127
  r = Request(
134
- cat(self.url, "auth", "token"), http_session=self.http_session
128
+ cat(self.url, "auth", "token"),
129
+ http_session=self.http_session,
130
+ user_agent=self.user_agent,
131
+ proxies=self.proxies,
135
132
  ).post(data={"api_key": self.key, "api_secret": self.secret})
136
133
 
137
134
  self.access_token = Token.from_jwt(r["access_token"])
@@ -147,6 +144,8 @@ class API(object):
147
144
  cat(self.url, "auth", "refresh"),
148
145
  token=self.refresh_token.encoded,
149
146
  http_session=self.http_session,
147
+ user_agent=self.user_agent,
148
+ proxies=self.proxies,
150
149
  ).post(data={"refresh_token": self.refresh_token.encoded})
151
150
 
152
151
  self.access_token = Token.from_jwt(r["access_token"])
@@ -164,5 +163,9 @@ class API(object):
164
163
  return {}
165
164
 
166
165
  return Request(
167
- base=self.url, token=self.access_token, http_session=self.http_session
166
+ base=self.url,
167
+ token=self.access_token,
168
+ http_session=self.http_session,
169
+ user_agent=self.user_agent,
170
+ proxies=self.proxies,
168
171
  ).get_health()
@@ -28,6 +28,8 @@ class Endpoint(object):
28
28
  base=self.url,
29
29
  token=self.api.access_token,
30
30
  http_session=self.api.http_session,
31
+ user_agent=self.api.user_agent,
32
+ proxies=self.api.proxies,
31
33
  )
32
34
  return RecordSet(self, r)
33
35
 
@@ -41,6 +43,8 @@ class Endpoint(object):
41
43
  base=self.url,
42
44
  token=self.api.access_token,
43
45
  http_session=self.api.http_session,
46
+ user_agent=self.api.user_agent,
47
+ proxies=self.api.proxies,
44
48
  )
45
49
  return RecordSet(self, r)
46
50
 
@@ -74,6 +78,8 @@ class Endpoint(object):
74
78
  base=self.url,
75
79
  token=self.api.access_token,
76
80
  http_session=self.api.http_session,
81
+ user_agent=self.api.user_agent,
82
+ proxies=self.api.proxies,
77
83
  )
78
84
  try:
79
85
  return next(RecordSet(self, r), None)
@@ -94,6 +100,8 @@ class Endpoint(object):
94
100
  base=self.url,
95
101
  token=self.api.access_token,
96
102
  http_session=self.api.http_session,
103
+ user_agent=self.api.user_agent,
104
+ proxies=self.api.proxies,
97
105
  ).post(args[0] if args else kwargs)
98
106
 
99
107
  return self.return_obj(req, self.api, self)
@@ -14,19 +14,13 @@ class RequestError(Exception):
14
14
  if r.status_code == 404:
15
15
  self.message = f"The requested url: {r.url} could not be found."
16
16
  elif r.status_code == 401:
17
- self.message = (
18
- "Authentication credentials are invalid, tokens renewal required."
19
- )
17
+ self.message = "Authentication credentials are invalid, tokens renewal required."
20
18
  else:
21
19
  try:
22
- self.message = (
23
- f"The request failed with code {r.status_code} "
24
- f"{r.reason}: {r.json()}"
25
- )
20
+ self.message = f"The request failed with code {r.status_code} {r.reason}: {r.json()}"
26
21
  except ValueError:
27
22
  self.message = (
28
- f"The request failed with code {r.status_code} "
29
- f"{r.reason} but details were not found as JSON."
23
+ f"The request failed with code {r.status_code} {r.reason} but details were not found as JSON."
30
24
  )
31
25
 
32
26
  super(RequestError, self).__init__(r)
@@ -48,9 +42,7 @@ class ContentError(Exception):
48
42
  super(ContentError, self).__init__(req)
49
43
 
50
44
  self.req = req
51
- self.error = (
52
- "The server returned invalid (non-JSON) data. Maybe not an IX-API server?"
53
- )
45
+ self.error = "The server returned invalid (non-JSON) data. Maybe not an IX-API server?"
54
46
 
55
47
  def __str__(self):
56
48
  return self.error
@@ -70,7 +62,14 @@ class Request(object):
70
62
  """
71
63
 
72
64
  def __init__(
73
- self, base, http_session, filters=None, key=None, token=None, user_agent=None
65
+ self,
66
+ base,
67
+ http_session,
68
+ filters=None,
69
+ key=None,
70
+ token=None,
71
+ user_agent=None,
72
+ proxies=None,
74
73
  ):
75
74
  self.base = base
76
75
  self.filters = filters or None
@@ -79,15 +78,14 @@ class Request(object):
79
78
  self.http_session = http_session
80
79
  self.url = self.base if not key else cat(self.base, key)
81
80
  self.user_agent = user_agent
81
+ self.proxies = proxies
82
82
 
83
83
  def get_openapi(self):
84
84
  """
85
85
  Get the OpenAPI Spec.
86
86
  """
87
87
  headers = {"Content-Type": "application/json;"}
88
- req = self.http_session.get(
89
- cat(self.base, "docs/?format=openapi"), headers=headers
90
- )
88
+ req = self.http_session.get(cat(self.base, "docs/?format=openapi"), headers=headers)
91
89
  if req.ok:
92
90
  return req.json()
93
91
  else:
@@ -137,7 +135,12 @@ class Request(object):
137
135
  params.update(add_params)
138
136
 
139
137
  r = getattr(self.http_session, verb)(
140
- url_override or self.url, headers=headers, params=params, json=data
138
+ url_override or self.url,
139
+ headers=headers,
140
+ params=params,
141
+ json=data,
142
+ user_agent=self.user_agent,
143
+ proxies=self.proxies,
141
144
  )
142
145
 
143
146
  if verb == "delete":
@@ -63,12 +63,8 @@ class RecordSet(object):
63
63
 
64
64
  def __next__(self):
65
65
  if self._response_cache:
66
- return self.endpoint.return_obj(
67
- self._response_cache.pop(), self.endpoint.api, self.endpoint
68
- )
69
- return self.endpoint.return_obj(
70
- next(self.response), self.endpoint.api, self.endpoint
71
- )
66
+ return self.endpoint.return_obj(self._response_cache.pop(), self.endpoint.api, self.endpoint)
67
+ return self.endpoint.return_obj(next(self.response), self.endpoint.api, self.endpoint)
72
68
 
73
69
  def __len__(self):
74
70
  try:
@@ -250,9 +246,7 @@ class Record(object):
250
246
  if isinstance(current_val, Record):
251
247
  current_val = getattr(current_val, "serialize")(nested=True)
252
248
  if isinstance(current_val, list):
253
- current_val = [
254
- v.id if isinstance(v, Record) else v for v in current_val
255
- ]
249
+ current_val = [v.id if isinstance(v, Record) else v for v in current_val]
256
250
  r[i] = current_val
257
251
  return r
258
252
 
@@ -265,9 +259,7 @@ class Record(object):
265
259
  return k, v
266
260
 
267
261
  current = Hashabledict({fmt_dict(k, v) for k, v in self.serialize().items()})
268
- init = Hashabledict(
269
- {fmt_dict(k, v) for k, v in self.serialize(init=True).items()}
270
- )
262
+ init = Hashabledict({fmt_dict(k, v) for k, v in self.serialize(init=True).items()})
271
263
  return set([i[0] for i in set(current.items()) ^ set(init.items())])
272
264
 
273
265
  def updates(self):
@@ -298,6 +290,8 @@ class Record(object):
298
290
  base=self.endpoint.url,
299
291
  token=self.api.access_token,
300
292
  http_session=self.api.http_session,
293
+ user_agent=self.user_agent,
294
+ proxies=self.api.proxies,
301
295
  )
302
296
  if r.patch(updates):
303
297
  return True
@@ -324,5 +318,7 @@ class Record(object):
324
318
  base=self.endpoint.url,
325
319
  token=self.api.access_token,
326
320
  http_session=self.api.http_session,
321
+ user_agent=self.user_agent,
322
+ proxies=self.api.proxies,
327
323
  )
328
324
  return True if r.delete() else False
@@ -1,9 +1,12 @@
1
+ from typing import Any
2
+
3
+
1
4
  class Hashabledict(dict):
2
5
  def __hash__(self):
3
6
  return hash(frozenset(self))
4
7
 
5
8
 
6
- def cat(*args, separator="/", trailing=""):
9
+ def cat(*args: Any, separator: str = "/", trailing: str = "") -> str:
7
10
  """
8
11
  Concatenate strings given a separator. All items will be parsed as string.
9
12
 
@@ -1,47 +1,34 @@
1
- [tool.poetry]
1
+ [project]
2
2
  name = "pyixapi"
3
- version = "0.2.3"
3
+ version = "0.2.5"
4
4
  description = "Python API client library for IX-API"
5
- authors = ["Guillaume Mazoyer <oss@mazoyer.eu>"]
5
+ authors = [{ name = "Guillaume Mazoyer", email = "oss@mazoyer.eu" }]
6
6
  readme = "README.md"
7
7
  license = "Apache-2.0"
8
- packages = [{ include = "pyixapi" }]
8
+ requires-python = ">=3.9"
9
9
  classifiers = [
10
10
  "Intended Audience :: Developers",
11
11
  "Programming Language :: Python :: 3",
12
- "Programming Language :: Python :: 3.8",
13
12
  "Programming Language :: Python :: 3.9",
14
13
  "Programming Language :: Python :: 3.10",
15
14
  "Programming Language :: Python :: 3.11",
15
+ "Programming Language :: Python :: 3.12",
16
+ "Programming Language :: Python :: 3.13",
16
17
  ]
18
+ dependencies = ["PyJWT>=2.4.0,<2.11", "requests>=2.20.0,<3.0"]
17
19
 
18
- [tool.poetry.dependencies]
19
- python = "^3.8"
20
- PyJWT = ">=2.4.0,<2.9"
21
- requests = ">=2.20.0,<3.0"
20
+ [project.optional-dependencies]
21
+ dev = ["pytest", "ruff>=0.9,<0.10"]
22
22
 
23
- [tool.poetry.group.dev.dependencies]
24
- pytest = "*"
25
- ruff = "~0.2"
23
+ [tool.poetry]
24
+ requires-poetry = ">=2.0"
25
+ packages = [{ include = "pyixapi" }]
26
26
 
27
27
  [tool.ruff]
28
- line-length = 88
29
-
30
- exclude = [
31
- ".git",
32
- ".tox",
33
- ".venv",
34
- "env",
35
- "_build",
36
- "build",
37
- "dist",
38
- "examples",
39
- "__main__.py",
40
- ]
28
+ line-length = 120
29
+ exclude = [".git", ".tox", ".venv", "env", "_build", "build", "dist", "examples", "__main__.py"]
41
30
 
42
31
  [tool.ruff.lint]
43
- preview = true
44
-
45
32
  select = [
46
33
  "C90", # mccabe complexity
47
34
  "E", # pycodestyle errors
@@ -67,12 +54,9 @@ line-ending = "auto"
67
54
  [tool.ruff.lint.isort]
68
55
  known-first-party = ["pyixapi"]
69
56
 
70
- [tool.ruff.lint.pycodestyle]
71
- max-line-length = 88
72
-
73
57
  [tool.ruff.lint.mccabe]
74
58
  max-complexity = 31
75
59
 
76
60
  [build-system]
77
- requires = ["poetry-core"]
61
+ requires = ["poetry-core>=2.0"]
78
62
  build-backend = "poetry.core.masonry.api"
File without changes
File without changes
File without changes
File without changes
File without changes