pyixapi 0.2.2__tar.gz → 0.2.4__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.
- {pyixapi-0.2.2 → pyixapi-0.2.4}/PKG-INFO +8 -6
- {pyixapi-0.2.2 → pyixapi-0.2.4}/pyixapi/core/api.py +38 -37
- {pyixapi-0.2.2 → pyixapi-0.2.4}/pyixapi/core/endpoint.py +15 -12
- {pyixapi-0.2.2 → pyixapi-0.2.4}/pyixapi/core/query.py +34 -38
- {pyixapi-0.2.2 → pyixapi-0.2.4}/pyixapi/core/response.py +14 -18
- {pyixapi-0.2.2 → pyixapi-0.2.4}/pyixapi/core/util.py +4 -1
- {pyixapi-0.2.2 → pyixapi-0.2.4}/pyproject.toml +15 -31
- pyixapi-0.2.2/pyixapi/__main__.py +0 -69
- {pyixapi-0.2.2 → pyixapi-0.2.4}/LICENSE +0 -0
- {pyixapi-0.2.2 → pyixapi-0.2.4}/README.md +0 -0
- {pyixapi-0.2.2 → pyixapi-0.2.4}/pyixapi/__init__.py +0 -0
- {pyixapi-0.2.2 → pyixapi-0.2.4}/pyixapi/core/__init__.py +0 -0
- {pyixapi-0.2.2 → pyixapi-0.2.4}/pyixapi/core/token.py +0 -0
- {pyixapi-0.2.2 → pyixapi-0.2.4}/pyixapi/models.py +0 -0
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: pyixapi
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
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
|
+
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
|
-
|
|
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
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Any
|
|
2
|
-
|
|
3
1
|
import requests
|
|
4
2
|
|
|
5
3
|
from pyixapi.core.endpoint import Endpoint
|
|
@@ -31,7 +29,7 @@ from pyixapi.models import (
|
|
|
31
29
|
RoleAssignment,
|
|
32
30
|
)
|
|
33
31
|
|
|
34
|
-
__version__ = "0.2.
|
|
32
|
+
__version__ = "0.2.4"
|
|
35
33
|
|
|
36
34
|
|
|
37
35
|
class API(object):
|
|
@@ -44,13 +42,14 @@ class API(object):
|
|
|
44
42
|
|
|
45
43
|
def __init__(
|
|
46
44
|
self,
|
|
47
|
-
url
|
|
48
|
-
key
|
|
49
|
-
secret
|
|
50
|
-
access_token
|
|
51
|
-
refresh_token
|
|
52
|
-
user_agent
|
|
53
|
-
|
|
45
|
+
url,
|
|
46
|
+
key,
|
|
47
|
+
secret,
|
|
48
|
+
access_token="",
|
|
49
|
+
refresh_token="",
|
|
50
|
+
user_agent=f"pyixapi/{__version__}",
|
|
51
|
+
proxies=None,
|
|
52
|
+
):
|
|
54
53
|
self.url = url.rstrip("/")
|
|
55
54
|
self.key = key
|
|
56
55
|
self.secret = secret
|
|
@@ -58,6 +57,7 @@ class API(object):
|
|
|
58
57
|
self.refresh_token = Token.from_jwt(refresh_token) if refresh_token else None
|
|
59
58
|
self.http_session = requests.Session()
|
|
60
59
|
self.user_agent = user_agent
|
|
60
|
+
self.proxies = proxies
|
|
61
61
|
|
|
62
62
|
self.auth = Endpoint(self, "auth")
|
|
63
63
|
self.connections = Endpoint(self, "connections", model=Connection)
|
|
@@ -67,54 +67,46 @@ class API(object):
|
|
|
67
67
|
self.facilities = Endpoint(self, "facilities", model=Facility)
|
|
68
68
|
self.ips = Endpoint(self, "ips", model=IP)
|
|
69
69
|
self.macs = Endpoint(self, "macs", model=MAC)
|
|
70
|
-
self.network_feature_configs = Endpoint(
|
|
71
|
-
self, "network-feature-configs", model=NetworkFeatureConfig
|
|
72
|
-
)
|
|
70
|
+
self.network_feature_configs = Endpoint(self, "network-feature-configs", model=NetworkFeatureConfig)
|
|
73
71
|
self.network_features = Endpoint(self, "network-features", model=NetworkFeature)
|
|
74
|
-
self.network_service_configs = Endpoint(
|
|
75
|
-
self, "network-service-configs", model=NetworkServiceConfig
|
|
76
|
-
)
|
|
72
|
+
self.network_service_configs = Endpoint(self, "network-service-configs", model=NetworkServiceConfig)
|
|
77
73
|
self.network_services = Endpoint(self, "network-services", model=NetworkService)
|
|
78
74
|
self.pops = Endpoint(self, "pops", model=PoP)
|
|
79
75
|
# Version 2+
|
|
80
|
-
self.member_joining_rules = Endpoint(
|
|
81
|
-
self, "member-joining-rules", model=MemberJoiningRule
|
|
82
|
-
)
|
|
76
|
+
self.member_joining_rules = Endpoint(self, "member-joining-rules", model=MemberJoiningRule)
|
|
83
77
|
self.metro_areas = Endpoint(self, "metro-areas", model=MetroArea)
|
|
84
|
-
self.metro_area_networks = Endpoint(
|
|
85
|
-
self, "metro-area-networks", model=MetroAreaNetwork
|
|
86
|
-
)
|
|
78
|
+
self.metro_area_networks = Endpoint(self, "metro-area-networks", model=MetroAreaNetwork)
|
|
87
79
|
self.ports = Endpoint(self, "ports", model=Port)
|
|
88
|
-
self.port_reservations = Endpoint(
|
|
89
|
-
self, "port-reservations", model=PortReservation
|
|
90
|
-
)
|
|
80
|
+
self.port_reservations = Endpoint(self, "port-reservations", model=PortReservation)
|
|
91
81
|
self.roles = Endpoint(self, "roles", model=Role)
|
|
92
82
|
self.role_assignments = Endpoint(self, "role-assignments", model=RoleAssignment)
|
|
93
83
|
|
|
94
84
|
@property
|
|
95
|
-
def version(self)
|
|
85
|
+
def version(self):
|
|
96
86
|
"""
|
|
97
87
|
Get the API version of IX-API.
|
|
98
88
|
"""
|
|
99
89
|
return Request(
|
|
100
|
-
base=self.url,
|
|
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,
|
|
101
95
|
).get_version()
|
|
102
96
|
|
|
103
97
|
@property
|
|
104
|
-
def accounts(self)
|
|
105
|
-
return Endpoint(
|
|
106
|
-
self, "customers" if self.version == 1 else "accounts", model=Account
|
|
107
|
-
)
|
|
98
|
+
def accounts(self):
|
|
99
|
+
return Endpoint(self, "customers" if self.version == 1 else "accounts", model=Account)
|
|
108
100
|
|
|
109
101
|
@property
|
|
110
|
-
def product_offerings(self)
|
|
102
|
+
def product_offerings(self):
|
|
111
103
|
return Endpoint(
|
|
112
104
|
self,
|
|
113
105
|
"products" if self.version == 1 else "product-offerings",
|
|
114
106
|
model=ProductOffering,
|
|
115
107
|
)
|
|
116
108
|
|
|
117
|
-
def authenticate(self)
|
|
109
|
+
def authenticate(self):
|
|
118
110
|
"""
|
|
119
111
|
Authenticate and generate a pair of tokens.
|
|
120
112
|
|
|
@@ -133,7 +125,10 @@ class API(object):
|
|
|
133
125
|
return self.refresh_authentication()
|
|
134
126
|
|
|
135
127
|
r = Request(
|
|
136
|
-
cat(self.url, "auth", "token"),
|
|
128
|
+
cat(self.url, "auth", "token"),
|
|
129
|
+
http_session=self.http_session,
|
|
130
|
+
user_agent=self.user_agent,
|
|
131
|
+
proxies=self.proxies,
|
|
137
132
|
).post(data={"api_key": self.key, "api_secret": self.secret})
|
|
138
133
|
|
|
139
134
|
self.access_token = Token.from_jwt(r["access_token"])
|
|
@@ -141,7 +136,7 @@ class API(object):
|
|
|
141
136
|
|
|
142
137
|
return Record(r, self, self.auth)
|
|
143
138
|
|
|
144
|
-
def refresh_authentication(self)
|
|
139
|
+
def refresh_authentication(self):
|
|
145
140
|
"""
|
|
146
141
|
Prolong authentication by refreshing the tokens pair.
|
|
147
142
|
"""
|
|
@@ -149,6 +144,8 @@ class API(object):
|
|
|
149
144
|
cat(self.url, "auth", "refresh"),
|
|
150
145
|
token=self.refresh_token.encoded,
|
|
151
146
|
http_session=self.http_session,
|
|
147
|
+
user_agent=self.user_agent,
|
|
148
|
+
proxies=self.proxies,
|
|
152
149
|
).post(data={"refresh_token": self.refresh_token.encoded})
|
|
153
150
|
|
|
154
151
|
self.access_token = Token.from_jwt(r["access_token"])
|
|
@@ -156,7 +153,7 @@ class API(object):
|
|
|
156
153
|
|
|
157
154
|
return Record(r, self, self.auth)
|
|
158
155
|
|
|
159
|
-
def health(self)
|
|
156
|
+
def health(self):
|
|
160
157
|
"""
|
|
161
158
|
Get the health information from IX-API.
|
|
162
159
|
|
|
@@ -166,5 +163,9 @@ class API(object):
|
|
|
166
163
|
return {}
|
|
167
164
|
|
|
168
165
|
return Request(
|
|
169
|
-
base=self.url,
|
|
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,
|
|
170
171
|
).get_health()
|
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
from typing import TYPE_CHECKING, Optional
|
|
2
|
-
|
|
3
1
|
from pyixapi.core.query import Request, RequestError
|
|
4
2
|
from pyixapi.core.response import Record, RecordSet
|
|
5
3
|
from pyixapi.core.util import cat
|
|
6
4
|
|
|
7
|
-
if TYPE_CHECKING:
|
|
8
|
-
from .api import API
|
|
9
|
-
|
|
10
5
|
|
|
11
|
-
class Endpoint:
|
|
6
|
+
class Endpoint(object):
|
|
12
7
|
"""
|
|
13
8
|
Represent actions available on endpoints in the IX-API.
|
|
14
9
|
|
|
@@ -16,16 +11,16 @@ class Endpoint:
|
|
|
16
11
|
object.
|
|
17
12
|
"""
|
|
18
13
|
|
|
19
|
-
def __init__(self, api
|
|
14
|
+
def __init__(self, api, name, model=None):
|
|
20
15
|
self.return_obj = model if model else Record
|
|
21
16
|
self.api = api
|
|
22
17
|
self.url = cat(api.url, name)
|
|
23
18
|
self.name = name
|
|
24
19
|
|
|
25
|
-
def __str__(self)
|
|
20
|
+
def __str__(self):
|
|
26
21
|
return self.url
|
|
27
22
|
|
|
28
|
-
def all(self)
|
|
23
|
+
def all(self):
|
|
29
24
|
"""
|
|
30
25
|
Return all objects from an endpoint.
|
|
31
26
|
"""
|
|
@@ -33,10 +28,12 @@ class Endpoint:
|
|
|
33
28
|
base=self.url,
|
|
34
29
|
token=self.api.access_token,
|
|
35
30
|
http_session=self.api.http_session,
|
|
31
|
+
user_agent=self.user_agent,
|
|
32
|
+
proxies=self.api.proxies,
|
|
36
33
|
)
|
|
37
34
|
return RecordSet(self, r)
|
|
38
35
|
|
|
39
|
-
def filter(self, *args, **kwargs)
|
|
36
|
+
def filter(self, *args, **kwargs):
|
|
40
37
|
"""
|
|
41
38
|
Query the list of a given endpoint. Also take named arguments that match the
|
|
42
39
|
usable filters on a given endpoint.
|
|
@@ -46,10 +43,12 @@ class Endpoint:
|
|
|
46
43
|
base=self.url,
|
|
47
44
|
token=self.api.access_token,
|
|
48
45
|
http_session=self.api.http_session,
|
|
46
|
+
user_agent=self.user_agent,
|
|
47
|
+
proxies=self.api.proxies,
|
|
49
48
|
)
|
|
50
49
|
return RecordSet(self, r)
|
|
51
50
|
|
|
52
|
-
def get(self, *args, **kwargs)
|
|
51
|
+
def get(self, *args, **kwargs):
|
|
53
52
|
"""
|
|
54
53
|
Return a single object from an endpoint.
|
|
55
54
|
"""
|
|
@@ -79,6 +78,8 @@ class Endpoint:
|
|
|
79
78
|
base=self.url,
|
|
80
79
|
token=self.api.access_token,
|
|
81
80
|
http_session=self.api.http_session,
|
|
81
|
+
user_agent=self.user_agent,
|
|
82
|
+
proxies=self.api.proxies,
|
|
82
83
|
)
|
|
83
84
|
try:
|
|
84
85
|
return next(RecordSet(self, r), None)
|
|
@@ -88,7 +89,7 @@ class Endpoint:
|
|
|
88
89
|
else:
|
|
89
90
|
raise e
|
|
90
91
|
|
|
91
|
-
def create(self, *args, **kwargs)
|
|
92
|
+
def create(self, *args, **kwargs):
|
|
92
93
|
"""
|
|
93
94
|
Creates an object on an endpoint.
|
|
94
95
|
|
|
@@ -99,6 +100,8 @@ class Endpoint:
|
|
|
99
100
|
base=self.url,
|
|
100
101
|
token=self.api.access_token,
|
|
101
102
|
http_session=self.api.http_session,
|
|
103
|
+
user_agent=self.user_agent,
|
|
104
|
+
proxies=self.api.proxies,
|
|
102
105
|
).post(args[0] if args else kwargs)
|
|
103
106
|
|
|
104
107
|
return self.return_obj(req, self.api, self)
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import json
|
|
2
|
-
from typing import Any, Optional
|
|
3
2
|
|
|
4
3
|
from pyixapi.core.util import cat
|
|
5
4
|
|
|
@@ -15,26 +14,20 @@ class RequestError(Exception):
|
|
|
15
14
|
if r.status_code == 404:
|
|
16
15
|
self.message = f"The requested url: {r.url} could not be found."
|
|
17
16
|
elif r.status_code == 401:
|
|
18
|
-
self.message =
|
|
19
|
-
"Authentication credentials are invalid, tokens renewal required."
|
|
20
|
-
)
|
|
17
|
+
self.message = "Authentication credentials are invalid, tokens renewal required."
|
|
21
18
|
else:
|
|
22
19
|
try:
|
|
23
|
-
self.message = (
|
|
24
|
-
f"The request failed with code {r.status_code} "
|
|
25
|
-
f"{r.reason}: {r.json()}"
|
|
26
|
-
)
|
|
20
|
+
self.message = f"The request failed with code {r.status_code} {r.reason}: {r.json()}"
|
|
27
21
|
except ValueError:
|
|
28
22
|
self.message = (
|
|
29
|
-
f"The request failed with code {r.status_code} "
|
|
30
|
-
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."
|
|
31
24
|
)
|
|
32
25
|
|
|
33
26
|
super(RequestError, self).__init__(r)
|
|
34
27
|
self.req = r
|
|
35
28
|
self.error = r.text
|
|
36
29
|
|
|
37
|
-
def __str__(self)
|
|
30
|
+
def __str__(self):
|
|
38
31
|
return self.message
|
|
39
32
|
|
|
40
33
|
|
|
@@ -45,19 +38,17 @@ class ContentError(Exception):
|
|
|
45
38
|
those cases.
|
|
46
39
|
"""
|
|
47
40
|
|
|
48
|
-
def __init__(self, req)
|
|
41
|
+
def __init__(self, req):
|
|
49
42
|
super(ContentError, self).__init__(req)
|
|
50
43
|
|
|
51
44
|
self.req = req
|
|
52
|
-
self.error = (
|
|
53
|
-
"The server returned invalid (non-JSON) data. Maybe not an IX-API server?"
|
|
54
|
-
)
|
|
45
|
+
self.error = "The server returned invalid (non-JSON) data. Maybe not an IX-API server?"
|
|
55
46
|
|
|
56
|
-
def __str__(self)
|
|
47
|
+
def __str__(self):
|
|
57
48
|
return self.error
|
|
58
49
|
|
|
59
50
|
|
|
60
|
-
class Request:
|
|
51
|
+
class Request(object):
|
|
61
52
|
"""
|
|
62
53
|
Create requests to the IX-API.
|
|
63
54
|
|
|
@@ -71,7 +62,14 @@ class Request:
|
|
|
71
62
|
"""
|
|
72
63
|
|
|
73
64
|
def __init__(
|
|
74
|
-
self,
|
|
65
|
+
self,
|
|
66
|
+
base,
|
|
67
|
+
http_session,
|
|
68
|
+
filters=None,
|
|
69
|
+
key=None,
|
|
70
|
+
token=None,
|
|
71
|
+
user_agent=None,
|
|
72
|
+
proxies=None,
|
|
75
73
|
):
|
|
76
74
|
self.base = base
|
|
77
75
|
self.filters = filters or None
|
|
@@ -80,21 +78,20 @@ class Request:
|
|
|
80
78
|
self.http_session = http_session
|
|
81
79
|
self.url = self.base if not key else cat(self.base, key)
|
|
82
80
|
self.user_agent = user_agent
|
|
81
|
+
self.proxies = proxies
|
|
83
82
|
|
|
84
|
-
def get_openapi(self)
|
|
83
|
+
def get_openapi(self):
|
|
85
84
|
"""
|
|
86
85
|
Get the OpenAPI Spec.
|
|
87
86
|
"""
|
|
88
87
|
headers = {"Content-Type": "application/json;"}
|
|
89
|
-
req = self.http_session.get(
|
|
90
|
-
cat(self.base, "docs/?format=openapi"), headers=headers
|
|
91
|
-
)
|
|
88
|
+
req = self.http_session.get(cat(self.base, "docs/?format=openapi"), headers=headers)
|
|
92
89
|
if req.ok:
|
|
93
90
|
return req.json()
|
|
94
91
|
else:
|
|
95
92
|
raise RequestError(req)
|
|
96
93
|
|
|
97
|
-
def get_version(self)
|
|
94
|
+
def get_version(self):
|
|
98
95
|
"""
|
|
99
96
|
Get the API version of IX-API.
|
|
100
97
|
|
|
@@ -108,7 +105,7 @@ class Request:
|
|
|
108
105
|
except RequestError:
|
|
109
106
|
return 1
|
|
110
107
|
|
|
111
|
-
def get_health(self)
|
|
108
|
+
def get_health(self):
|
|
112
109
|
"""
|
|
113
110
|
Get the health from /api/health endpoint in IX-API.
|
|
114
111
|
"""
|
|
@@ -121,13 +118,7 @@ class Request:
|
|
|
121
118
|
else:
|
|
122
119
|
raise RequestError(r)
|
|
123
120
|
|
|
124
|
-
def _make_call(
|
|
125
|
-
self,
|
|
126
|
-
verb: str = "get",
|
|
127
|
-
url_override: Optional[str] = None,
|
|
128
|
-
add_params: Optional[dict[str, Any]] = None,
|
|
129
|
-
data: Optional[Any] = None,
|
|
130
|
-
) -> Any:
|
|
121
|
+
def _make_call(self, verb="get", url_override=None, add_params=None, data=None):
|
|
131
122
|
if verb in ("post", "put") or verb == "delete" and data:
|
|
132
123
|
headers = {"Content-Type": "application/json;"}
|
|
133
124
|
else:
|
|
@@ -144,7 +135,12 @@ class Request:
|
|
|
144
135
|
params.update(add_params)
|
|
145
136
|
|
|
146
137
|
r = getattr(self.http_session, verb)(
|
|
147
|
-
url_override or self.url,
|
|
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,
|
|
148
144
|
)
|
|
149
145
|
|
|
150
146
|
if verb == "delete":
|
|
@@ -160,7 +156,7 @@ class Request:
|
|
|
160
156
|
else:
|
|
161
157
|
raise RequestError(r)
|
|
162
158
|
|
|
163
|
-
def get(self, add_params
|
|
159
|
+
def get(self, add_params=None):
|
|
164
160
|
"""
|
|
165
161
|
Make a GET request to IX-API.
|
|
166
162
|
|
|
@@ -179,7 +175,7 @@ class Request:
|
|
|
179
175
|
self.count = len(req)
|
|
180
176
|
yield req
|
|
181
177
|
|
|
182
|
-
def put(self, data
|
|
178
|
+
def put(self, data):
|
|
183
179
|
"""
|
|
184
180
|
Make a PUT request to IX-API.
|
|
185
181
|
|
|
@@ -191,7 +187,7 @@ class Request:
|
|
|
191
187
|
"""
|
|
192
188
|
return self._make_call(verb="put", data=data)
|
|
193
189
|
|
|
194
|
-
def post(self, data
|
|
190
|
+
def post(self, data):
|
|
195
191
|
"""
|
|
196
192
|
Make a POST request to IX-API.
|
|
197
193
|
|
|
@@ -203,7 +199,7 @@ class Request:
|
|
|
203
199
|
"""
|
|
204
200
|
return self._make_call(verb="post", data=data)
|
|
205
201
|
|
|
206
|
-
def delete(self, data
|
|
202
|
+
def delete(self, data=None):
|
|
207
203
|
"""
|
|
208
204
|
Make a DELETE request to IX-API.
|
|
209
205
|
|
|
@@ -217,7 +213,7 @@ class Request:
|
|
|
217
213
|
"""
|
|
218
214
|
return self._make_call(verb="delete", data=data)
|
|
219
215
|
|
|
220
|
-
def patch(self, data
|
|
216
|
+
def patch(self, data):
|
|
221
217
|
"""
|
|
222
218
|
Make a PATCH request to IX-API.
|
|
223
219
|
|
|
@@ -229,7 +225,7 @@ class Request:
|
|
|
229
225
|
"""
|
|
230
226
|
return self._make_call(verb="patch", data=data)
|
|
231
227
|
|
|
232
|
-
def options(self)
|
|
228
|
+
def options(self):
|
|
233
229
|
"""
|
|
234
230
|
Make an OPTIONS request to IX-API.
|
|
235
231
|
|
|
@@ -2,7 +2,7 @@ from pyixapi.core.query import Request
|
|
|
2
2
|
from pyixapi.core.util import Hashabledict
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
def get_return(lookup)
|
|
5
|
+
def get_return(lookup):
|
|
6
6
|
"""
|
|
7
7
|
Return simple representations for items passed to lookup.
|
|
8
8
|
|
|
@@ -15,7 +15,7 @@ def get_return(lookup) -> int:
|
|
|
15
15
|
return lookup
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
class RecordSet:
|
|
18
|
+
class RecordSet(object):
|
|
19
19
|
"""
|
|
20
20
|
Iterator containing :py:class:`.Record` objects.
|
|
21
21
|
|
|
@@ -52,23 +52,19 @@ class RecordSet:
|
|
|
52
52
|
>>>
|
|
53
53
|
"""
|
|
54
54
|
|
|
55
|
-
def __init__(self, endpoint, request, **kwargs)
|
|
55
|
+
def __init__(self, endpoint, request, **kwargs):
|
|
56
56
|
self.endpoint = endpoint
|
|
57
57
|
self.request = request
|
|
58
58
|
self.response = self.request.get()
|
|
59
59
|
self._response_cache = []
|
|
60
60
|
|
|
61
|
-
def __iter__(self)
|
|
61
|
+
def __iter__(self):
|
|
62
62
|
return self
|
|
63
63
|
|
|
64
64
|
def __next__(self):
|
|
65
65
|
if self._response_cache:
|
|
66
|
-
return self.endpoint.return_obj(
|
|
67
|
-
|
|
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:
|
|
@@ -81,7 +77,7 @@ class RecordSet:
|
|
|
81
77
|
return self.request.count
|
|
82
78
|
|
|
83
79
|
|
|
84
|
-
class Record:
|
|
80
|
+
class Record(object):
|
|
85
81
|
"""
|
|
86
82
|
Create Python objects from IX-API responses.
|
|
87
83
|
|
|
@@ -144,7 +140,7 @@ class Record:
|
|
|
144
140
|
|
|
145
141
|
url = None
|
|
146
142
|
|
|
147
|
-
def __init__(self, values, api, endpoint)
|
|
143
|
+
def __init__(self, values, api, endpoint):
|
|
148
144
|
self._full_cache = []
|
|
149
145
|
self._init_cache = []
|
|
150
146
|
self.api = api
|
|
@@ -250,9 +246,7 @@ class Record:
|
|
|
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:
|
|
|
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:
|
|
|
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:
|
|
|
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: str = "/", trailing: str = "") -> str:
|
|
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
|
-
[
|
|
1
|
+
[project]
|
|
2
2
|
name = "pyixapi"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.4"
|
|
4
4
|
description = "Python API client library for IX-API"
|
|
5
|
-
authors = ["Guillaume Mazoyer
|
|
5
|
+
authors = [{ name = "Guillaume Mazoyer", email = "oss@mazoyer.eu" }]
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
license = "Apache-2.0"
|
|
8
|
-
|
|
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
|
-
[
|
|
19
|
-
|
|
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
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
[tool.poetry]
|
|
24
|
+
requires-poetry = ">=2.0"
|
|
25
|
+
packages = [{ include = "pyixapi" }]
|
|
26
26
|
|
|
27
27
|
[tool.ruff]
|
|
28
|
-
line-length =
|
|
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"
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
from pyixapi import api
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
def create_mac_address(ixapi, mac_address):
|
|
5
|
-
"""
|
|
6
|
-
Create a new MAC address in IX-API. If the MAC already exists, return it
|
|
7
|
-
without creation.
|
|
8
|
-
"""
|
|
9
|
-
# Make sure to have a consistent case
|
|
10
|
-
mac_address = str(mac_address).lower()
|
|
11
|
-
|
|
12
|
-
# Return existing object if MAC already exists
|
|
13
|
-
for mac in ixapi.macs.all():
|
|
14
|
-
if mac["address"] == mac_address:
|
|
15
|
-
return mac
|
|
16
|
-
|
|
17
|
-
return ixapi.macs.create(
|
|
18
|
-
address=mac_address, consuming_customer="2", managing_customer="2"
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
# ixapi = api(
|
|
23
|
-
# "https://api.de-cix.net/api/v1/",
|
|
24
|
-
# "-GnNlMD8hBuxSSUJmpbfUkss9dyOKfTV1SnZibNyyr4",
|
|
25
|
-
# "XKq8M6NVh5lCbPJ2Ml1h7V93QNIMsGVBfM6g2nRZF-E",
|
|
26
|
-
# )
|
|
27
|
-
|
|
28
|
-
ixapi = api(
|
|
29
|
-
"https://api.de-cix.net/api/v2/",
|
|
30
|
-
"lZJ_sV59gydj12RFATG4NaQFRI15iKRi9RC0oDqn2_A",
|
|
31
|
-
"Yt_RImR_ymuhx2r9YQXerh5q9EyE6TxaREjzmEQNr1o",
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
# ixapi = api(
|
|
35
|
-
# "http://localhost:8000/api/v1/",
|
|
36
|
-
# "c25f077c899694fc",
|
|
37
|
-
# "zZm-hzDIR5BZUhn5ULo4-_BQyx39ayRRn_0HFaSNDShqunrTiNY4a6n0Bnjqg62F-NsywRLvn3Dt3pRXWRgS1A",
|
|
38
|
-
# )
|
|
39
|
-
|
|
40
|
-
authentication = ixapi.authenticate()
|
|
41
|
-
print(authentication)
|
|
42
|
-
|
|
43
|
-
print(f"IX-API is at version {ixapi.version}")
|
|
44
|
-
|
|
45
|
-
authentication = ixapi.authenticate()
|
|
46
|
-
print(authentication)
|
|
47
|
-
|
|
48
|
-
print([i for i in ixapi.accounts.all()])
|
|
49
|
-
|
|
50
|
-
# for i in ixapi.ips.all():
|
|
51
|
-
# print(f"{i.ip} - {i.network}")
|
|
52
|
-
# print(ixapi.network_service_configs.get("DXDB:PAS:509177"))
|
|
53
|
-
|
|
54
|
-
# for i in ixapi.ports.all():
|
|
55
|
-
# print(i)
|
|
56
|
-
|
|
57
|
-
# print(len(ixapi.network_services.filter(consuming_customer="DXDB:CUST:1348")))
|
|
58
|
-
# print(len(ixapi.network_services.all()))
|
|
59
|
-
|
|
60
|
-
# mac = create_mac_address(ixapi, "e4:f7:ad:58:87:ff")
|
|
61
|
-
|
|
62
|
-
# for i in ixapi.macs.all():
|
|
63
|
-
# print(dict(i))
|
|
64
|
-
|
|
65
|
-
# for i in ixapi.network_service_configs.all():
|
|
66
|
-
# # i.macs = [mac]
|
|
67
|
-
# # print(i.save())
|
|
68
|
-
# i.update({"macs": [mac]})
|
|
69
|
-
# print(dict(i))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|