edgegrid-python 2.0.6__py3-none-any.whl → 2.0.8__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.
@@ -36,6 +36,6 @@ from .edgerc import EdgeRc
36
36
  __all__ = ['EdgeGridAuth', 'EdgeRc']
37
37
 
38
38
  __title__ = 'edgegrid-python'
39
- __version__ = '2.0.6'
39
+ __version__ = '2.0.8'
40
40
  __license__ = 'Apache 2.0'
41
41
  __copyright__ = 'Copyright 2026 Akamai Technologies'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: edgegrid-python
3
- Version: 2.0.6
3
+ Version: 2.0.8
4
4
  Summary: {OPEN} client authentication protocol for python-requests
5
5
  Home-page: https://github.com/akamai/AkamaiOPEN-edgegrid-python
6
6
  License: Apache 2.0
@@ -0,0 +1,22 @@
1
+ akamai/edgegrid/__init__.py,sha256=CjMtu4_OcSZFNYcw5QhtX6mrrraJzLQ67-RQ24adlk8,1217
2
+ akamai/edgegrid/edgegrid.py,sha256=pzJQ7qjC5KZIIM_yrhdVHUuJe6CMFzt-z1ucQeN2-vk,12002
3
+ akamai/edgegrid/edgerc.py,sha256=T9RoKyWnVIIOwAVaJZ3QV5xBAJ9vz7XiyUZ8tMET8dI,1170
4
+ akamai/edgegrid/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ akamai/edgegrid/test/conftest.py,sha256=ewP2gqZI0POKP0d3QQuD0yiPYkPM9sRqLBekk00GnFQ,908
6
+ akamai/edgegrid/test/edgerc_that_doesnt_parse,sha256=j1uEFSxZo_o9pYuj6QdxWIOSmRTLLlLPLWQ8sziHm1A,138
7
+ akamai/edgegrid/test/sample_edgerc,sha256=0DsP3KEoLXjd7fhkKcVoCT5cM1S69iNZmO8VvdwKWLA,1084
8
+ akamai/edgegrid/test/sample_file.txt,sha256=EBMsdifxSkOKTPB-eqA7be67wJ5YWG_G8NjoNdtZqBM,22
9
+ akamai/edgegrid/test/test_edgegrid.py,sha256=GhX1CjO3CS_cVV6hFOyOKL8ovxvEZpHbqrFBGmTKkw8,13506
10
+ akamai/edgegrid/test/testcases.json,sha256=81LV7AgNTmHSX4X56dZszrVk-Zk1Jw5vkvI6DFJazSE,15040
11
+ akamai/edgegrid/test/testdata.json,sha256=kJ0DYk94SJeatnvdqYTCw-itxMUdbIhzVta3rIYAVT0,1149
12
+ ci/check_namespace_pkg.py,sha256=mUy-bcH8KV2ujgkgFFJ_yJ2XzVn1_YdQhXDQeCENNnc,1594
13
+ ci/coverage_report.py,sha256=jykNDfg5MTHCCwEg6_GtgyUQO4B2Tt3Ws8SrKPtXmYI,2273
14
+ edgegrid_python-2.0.8.dist-info/licenses/LICENSE,sha256=aai-NM26EYkRybAI1eWSlozmBr8-EQ1GWLJe_9qc8M4,10294
15
+ examples/create-credentials.py,sha256=z-9ItuXNI3lFhMv3A5-dZC0QfSgTGvNJciQOPNWBurQ,1191
16
+ examples/delete-credentials.py,sha256=HM6a8fy-44beXKLhs_JVk8ChdOJlvF1s4XwWn9VATqE,1422
17
+ examples/get-credentials.py,sha256=duI0pRRwX9--Eibnp4EsIRQebwnsygzmCEScemKD27w,1198
18
+ examples/update-credentials.py,sha256=BEahXLHjIXuBW77wuQK98fbKSxlibugG1nQD1nvVcN0,1783
19
+ edgegrid_python-2.0.8.dist-info/METADATA,sha256=VjV-rZDHDL7v2jqxysL9f_6VxBQkQXJlvcE_NvLcnV0,9208
20
+ edgegrid_python-2.0.8.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
21
+ edgegrid_python-2.0.8.dist-info/top_level.txt,sha256=DuVRQFKn3UwJ6bDLD_ZYN02ri7mCMhx9mCXfeSmiqK4,19
22
+ edgegrid_python-2.0.8.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (82.0.1)
2
+ Generator: setuptools (84.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,41 +0,0 @@
1
- """
2
- akamai.edgegrid
3
- ~~~~~~~~~~~~~~~
4
-
5
- This library provides an authentication handler for Requests that implements the
6
- Akamai {OPEN} EdgeGrid client authentication protocol as
7
- specified by https://developer.akamai.com/introduction/Client_Auth.html.
8
- For more information visit https://developer.akamai.com.
9
-
10
- usage:
11
-
12
- >>> import requests
13
- >>> from akamai.edgegrid import EdgeGridAuth
14
- >>> from urlparse import urljoin
15
-
16
- >>> baseurl = 'https://akaa-WWWWWWWWWWWW.luna.akamaiapis.net/'
17
- >>> s = requests.Session()
18
- >>> s.auth = EdgeGridAuth(
19
- client_token='akab-XXXXXXXXXXXXXXXXXXXXXXX',
20
- client_secret='YYYYYYYYYYYYYYYYYYYYYYYYYY',
21
- access_token='akab-ZZZZZZZZZZZZZZZZZZZZZZZZZZZ'
22
- )
23
-
24
- ... now you have a requests session object that can be used to make {OPEN} requests
25
-
26
- >>> result = s.get(urljoin(baseurl, '/diagnostic-tools/v1/locations'))
27
- >>> result.status_code
28
- 200
29
- >>> result.json()['locations'][0]
30
- Hongkong, Hong Kong
31
- """
32
-
33
- from .edgegrid import EdgeGridAuth
34
- from .edgerc import EdgeRc
35
-
36
- __all__ = ['EdgeGridAuth', 'EdgeRc']
37
-
38
- __title__ = 'edgegrid-python'
39
- __version__ = '2.0.6'
40
- __license__ = 'Apache 2.0'
41
- __copyright__ = 'Copyright 2026 Akamai Technologies'
@@ -1,323 +0,0 @@
1
- # pylint: disable=too-many-arguments,missing-function-docstring
2
- """EdgeGrid requests Auth handler"""
3
-
4
- import logging
5
- import uuid
6
- import hashlib
7
- import hmac
8
- import base64
9
- import re
10
- import os
11
- from time import gmtime, strftime
12
- from urllib.parse import urlparse
13
-
14
- from requests.auth import AuthBase
15
-
16
- from .edgerc import EdgeRc
17
-
18
- logger = logging.getLogger(__name__)
19
-
20
- __all__ = ['EdgeGridAuth']
21
-
22
-
23
- def eg_timestamp():
24
- """Generates EdgeGrid compatible timestamp"""
25
- return strftime('%Y%m%dT%H:%M:%S+0000', gmtime())
26
-
27
-
28
- def new_nonce():
29
- return uuid.uuid4()
30
-
31
-
32
- def base64_hmac_sha256(data, key):
33
- return base64.b64encode(
34
- hmac.new(
35
- key.encode('utf8'),
36
- data.encode('utf8'),
37
- hashlib.sha256).digest()
38
- ).decode('utf8')
39
-
40
-
41
- def base64_sha256(data):
42
- digest = hashlib.sha256(data).digest()
43
- return base64.b64encode(digest).decode('utf8')
44
-
45
-
46
- def read_stream_and_rewind(f, max_read):
47
- """Reads up to read_max bytes from a python file object (like _io.BufferedReader)
48
- or a MultipartEncoder object, then rewinds the stream.
49
-
50
- The read() method of these objects is decorated by httpie with a side-effect code which
51
- prints the body content to stdout when the 'B' option is specified for --print. However,
52
- it does not trigger in the pre-request phase when this plugin is executed. Still, after reading
53
- we must set the stream position to the beginning to not impact subsequent reads outside
54
- the plugin. (We don't assume we can be passed a partially read stream to the plugin.)
55
-
56
- Raises TypeError if read() or seek() is not supported by f or f._buffer. May potentially raise
57
- OSError for any failed I/O operation, in particular io.UnsupportedOperation if the stream is
58
- not seekable (e.g. is a pipe which we don't expect here as httpie reads pipe contents and
59
- sets body as bytes).
60
- """
61
- try:
62
- res = f.read(max_read)
63
- except AttributeError as exc:
64
- raise TypeError(f'akamai.edgegrid: unexpected body type: {type(f).__name__}') from exc
65
-
66
- try:
67
- f.seek(0)
68
- except AttributeError:
69
- # a MultipartEncoder
70
- try:
71
- # During read(), MultipartEncoder lazily loads its upload parts into self._buffer
72
- # depending on the requested number of bytes. Then a regular read() on self._buffer
73
- # is performed. Therefore, rewinding self._buffer effectively rewinds the whole
74
- # MultipartEncoder content.
75
- # pylint: disable=protected-access
76
- f._buffer.seek(0)
77
- except AttributeError as exc:
78
- raise TypeError(f'akamai.edgegrid: unexpected body type: {type(f).__name__}') from exc
79
- return res
80
-
81
-
82
- def read_body_content(body, max_body):
83
- """The body argument may be one of the following:
84
- 1. bytes object
85
- 2. str object
86
- 3. _io.BufferedReader object for body input from file
87
- 4. requests_toolbelt.MultipartEncoder object for multipart form requests
88
- 5. httpie.uploads.ChunkedUploadStream object for chunked transfer encoding
89
- (when --chunked, currently not supported)
90
- May raise TypeError for unexpected input type or OSError for I/O operations.
91
- """
92
- if isinstance(body, bytes):
93
- return body[:max_body]
94
- if isinstance(body, str):
95
- return body.encode('utf8')[:max_body]
96
- return read_stream_and_rewind(body, max_body)
97
-
98
-
99
- def determine_body_len(body):
100
- """May raise exception if body appears to be a file (is not a str, bytes or MultipartEncoder)
101
- but either:
102
- - has no fileno method (TypeError)
103
- - raises OSError while trying to calculate the length using the file descriptor"""
104
- if isinstance(body, bytes):
105
- return len(body)
106
- if isinstance(body, str):
107
- return len(body.encode('utf8'))
108
-
109
- try:
110
- # a MultipartEncoder?
111
- return body.len
112
- except AttributeError:
113
- # a file object?
114
- try:
115
- return os.stat(body.fileno()).st_size
116
- except AttributeError as exc:
117
- raise TypeError(
118
- f'akamai.edgegrid: unexpected body type: {type(body).__name__}') from exc
119
-
120
-
121
- class EdgeGridAuth(AuthBase):
122
- """A Requests authentication handler that provides Akamai {OPEN} EdgeGrid support.
123
-
124
- Basic Usage::
125
- >>> import requests
126
- >>> from akamai.edgegrid import EdgeGridAuth
127
- >>> s = requests.Session()
128
- >>> s.auth = EdgeGridAuth(
129
- client_token='cccccccccccccccccc',
130
- client_secret='sssssssssssssssss',
131
- access_token='aaaaaaaaaaaaaaaaa'
132
- )
133
-
134
- """
135
-
136
- def __init__(self, client_token, client_secret, access_token,
137
- *, headers_to_sign=(), max_body=131072):
138
- """Initialize authentication using the given parameters from the Akamai OPEN APIs
139
- Interface:
140
-
141
- :param client_token: Client token provided by "Credentials" ui
142
- :param client_secret: Client secret provided by "Credentials" ui
143
- :param access_token: Access token provided by "Authorizations" ui
144
- :param headers_to_sign: An ordered list header names that will be included in
145
- the signature. This will be provided by specific APIs. (default [])
146
- :param max_body: Maximum content body size for POST requests. This will be provided by
147
- specific APIs. (default 131072)
148
-
149
- """
150
- # pylint: disable=invalid-name
151
- self.ah = EdgeGridAuthHeaders(
152
- client_token,
153
- client_secret,
154
- access_token,
155
- headers_to_sign=headers_to_sign,
156
- max_body=max_body
157
- )
158
-
159
- @staticmethod
160
- def from_edgerc(rcinput, section='default'):
161
- """
162
- Returns an EdgeGridAuth object from the configuration from the given section
163
- of the given edgerc file.
164
-
165
- :param rcinput: EdgeRc instance or path to the edgerc file
166
- :param section: the section to use (this is the [bracketed] part of the edgerc,
167
- default is 'default')
168
-
169
- """
170
- if isinstance(rcinput, EdgeRc):
171
- edgerc = rcinput
172
- else:
173
- edgerc = EdgeRc(rcinput)
174
-
175
- return EdgeGridAuth(
176
- client_token=edgerc.get(section, 'client_token'),
177
- client_secret=edgerc.get(section, 'client_secret'),
178
- access_token=edgerc.get(section, 'access_token'),
179
- headers_to_sign=edgerc.getlist(section, 'headers_to_sign'),
180
- max_body=edgerc.getint(section, 'max_body')
181
- )
182
-
183
- def handle_redirect(self, res, **_):
184
- if res.is_redirect:
185
- redirect_location = res.headers['location']
186
-
187
- logger.debug("signing the redirected url: %s", redirect_location)
188
- request_to_sign = res.request.copy()
189
- request_to_sign.url = redirect_location
190
-
191
- res.request.headers['Authorization'] = self.ah.make_auth_header(
192
- request_to_sign, eg_timestamp(), new_nonce())
193
-
194
- def __call__(self, r):
195
- timestamp = eg_timestamp()
196
- nonce = new_nonce()
197
-
198
- r.headers['Authorization'] = self.ah.make_auth_header(r, timestamp, nonce)
199
- r.register_hook('response', self.handle_redirect)
200
- return r
201
-
202
-
203
- class EdgeGridAuthHeaders:
204
- """
205
- A class for preparing requests authentication headers needed for
206
- Akamai {OPEN} EdgeGrid support.
207
- """
208
- def __init__(self, client_token, client_secret, access_token,
209
- *, headers_to_sign=(), max_body=131072):
210
- self.client_token = client_token
211
- self.client_secret = client_secret
212
- self.access_token = access_token
213
- self.headers_to_sign = [h.lower() for h in headers_to_sign]
214
- self.max_body = max_body
215
-
216
- def make_signing_key(self, timestamp):
217
- signing_key = base64_hmac_sha256(timestamp, self.client_secret)
218
- logger.debug('signing key: %s', signing_key)
219
- return signing_key
220
-
221
- def canonicalize_headers(self, headers):
222
- spaces_re = re.compile('\\s+')
223
-
224
- # note: r.headers is a case-insensitive dict and self.headers_to_sign
225
- # should already be in lowercase at this point
226
- # pylint: disable=consider-using-f-string
227
- return '\t'.join([
228
- "%s:%s" % (h, spaces_re.sub(' ', headers[h].strip()))
229
- for h in self.headers_to_sign if h in headers
230
- ])
231
-
232
- def make_content_hash(self, body, method):
233
- logger.debug("body is '%s'", body)
234
- content_hash = ""
235
- if method == 'POST':
236
- buf = read_body_content(body, self.max_body)
237
- if buf:
238
- logger.debug("signing content: %s", buf)
239
- content_hash = base64_sha256(buf)
240
- try:
241
- body_len = determine_body_len(body)
242
- if body_len > self.max_body:
243
- logger.debug(
244
- "data length %d is larger than maximum %d "
245
- "and will be truncated for computing the hash",
246
- body_len, self.max_body)
247
- except (TypeError, OSError) as e:
248
- # body length is needed only for debugging: just log a possible exception
249
- logger.warning("cannot determine length of request body=%s: %s", body, e)
250
- logger.debug("content hash is '%s'", content_hash)
251
- return content_hash
252
-
253
- @staticmethod
254
- def get_header_versions(header=None):
255
- if header is None:
256
- header = {}
257
-
258
- version_header = ''
259
- akamai_cli = os.getenv('AKAMAI_CLI')
260
- akamai_cli_version = os.getenv('AKAMAI_CLI_VERSION')
261
- if akamai_cli and akamai_cli_version:
262
- version_header += " AkamaiCLI/" + akamai_cli_version
263
-
264
- akamai_cli_command = os.getenv('AKAMAI_CLI_COMMAND')
265
- akamai_cli_command_version = os.getenv('AKAMAI_CLI_COMMAND_VERSION')
266
- if akamai_cli_command and akamai_cli_command_version:
267
- version_header += " AkamaiCLI-" + akamai_cli_command + \
268
- "/" + akamai_cli_command_version
269
-
270
- if version_header != '':
271
- if 'User-Agent' not in header:
272
- header['User-Agent'] = version_header.strip()
273
- else:
274
- header['User-Agent'] += version_header
275
-
276
- return header
277
-
278
- def make_data_to_sign(self, request, auth_header):
279
- parsed_url = urlparse(request.url)
280
-
281
- if request.headers.get('Host', False):
282
- netloc = request.headers['Host']
283
- else:
284
- netloc = parsed_url.netloc
285
-
286
- self.get_header_versions(request.headers)
287
-
288
- data_to_sign = '\t'.join([
289
- request.method,
290
- parsed_url.scheme,
291
- netloc,
292
- # Note: relative URL constraints are handled by requests when it sets up 'r'
293
- parsed_url.path + (';' + parsed_url.params if parsed_url.params else "") +
294
- ('?' + parsed_url.query if parsed_url.query else ""),
295
- self.canonicalize_headers(request.headers),
296
- self.make_content_hash(request.body or '', request.method),
297
- auth_header
298
- ])
299
- logger.debug('data to sign: %s', '\\t'.join(data_to_sign.split('\t')))
300
- return data_to_sign
301
-
302
- def sign_request(self, request, timestamp, auth_header):
303
- return base64_hmac_sha256(
304
- self.make_data_to_sign(request, auth_header),
305
- self.make_signing_key(timestamp)
306
- )
307
-
308
- def make_auth_header(self, request, timestamp, nonce):
309
- kvps = [
310
- ('client_token', self.client_token),
311
- ('access_token', self.access_token),
312
- ('timestamp', timestamp),
313
- ('nonce', nonce),
314
- ]
315
- auth_header = "EG1-HMAC-SHA256 " + \
316
- ';'.join([f"{k}={v}" for k, v in kvps]) + ';'
317
- logger.debug('unsigned authorization header: %s', auth_header)
318
-
319
- signed_auth_header = auth_header + \
320
- 'signature=' + self.sign_request(request, timestamp, auth_header)
321
-
322
- logger.debug('signed authorization header: %s', signed_auth_header)
323
- return signed_auth_header
@@ -1,37 +0,0 @@
1
- """Support for .edgerc file format"""
2
-
3
- import logging
4
- from configparser import ConfigParser
5
- from os.path import expanduser
6
-
7
- logger = logging.getLogger(__name__)
8
-
9
-
10
- class EdgeRc(ConfigParser):
11
- """Class for managing .edgerc files"""
12
- def __init__(self, filename):
13
- ConfigParser.__init__(self,
14
- {'client_token': '',
15
- 'client_secret': '',
16
- 'host': '',
17
- 'access_token': '',
18
- 'max_body': '131072',
19
- 'headers_to_sign': 'None'})
20
- logger.debug("loading edgerc from %s", filename)
21
-
22
- self.read(expanduser(filename))
23
-
24
- logger.debug("successfully loaded edgerc")
25
-
26
- def optionxform(self, optionstr):
27
- """support both max_body and max-body style keys"""
28
- return optionstr.replace('-', '_')
29
-
30
- def getlist(self, section, option):
31
- """
32
- returns the named option as a list, splitting the original value by ','
33
- """
34
- value = self.get(section, option)
35
- if value:
36
- return value.split(',')
37
- return None
File without changes
@@ -1,44 +0,0 @@
1
- # pylint: disable=missing-function-docstring
2
- """Unit tests helpers"""
3
-
4
- import json
5
- import os
6
- import pytest
7
-
8
- test_dir = os.path.abspath(os.path.dirname(__file__))
9
-
10
-
11
- def cases():
12
- with open(f'{test_dir}/testcases.json', encoding="utf-8") as data:
13
- data = json.load(data)
14
- return data
15
-
16
-
17
- @pytest.fixture(scope="package")
18
- def testdata():
19
- with open(f'{test_dir}/testdata.json', encoding="utf-8") as data:
20
- data = json.load(data)
21
- return data
22
-
23
-
24
- def names(tests):
25
- result = []
26
- for test in tests:
27
- result.append(test["testName"])
28
- return result
29
-
30
-
31
- @pytest.fixture
32
- def multipart_fields():
33
- with open(f'{test_dir}/sample_file.txt', "rb") as f:
34
- result = {
35
- "foo": "bar",
36
- "baz": ("sample_file.txt", f),
37
- }
38
- yield result
39
-
40
-
41
- @pytest.fixture
42
- def sample_file():
43
- with open(f'{test_dir}/sample_file.txt', "rb") as f:
44
- yield f
@@ -1,390 +0,0 @@
1
- # pylint: disable=missing-function-docstring
2
- """unit tests for edgegrid. It runs tests from testcases.json"""
3
-
4
- import io
5
- import logging
6
- import os
7
- import re
8
- import unittest.mock
9
- from urllib.parse import urljoin
10
-
11
- import requests
12
- import requests_toolbelt
13
- import pytest
14
-
15
- import akamai.edgegrid.edgegrid as eg
16
- from akamai.edgegrid import EdgeGridAuth, EdgeRc
17
- from akamai.edgegrid.test.conftest import cases, names, test_dir
18
-
19
- logger = logging.getLogger(__name__)
20
-
21
- EXPECTED_CLIENT_SECRET = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx='
22
-
23
-
24
- def test_edge_grid_auth_headers(testdata):
25
- auth_headers = eg.EdgeGridAuthHeaders(
26
- client_token=testdata['client_token'],
27
- client_secret=testdata['client_secret'],
28
- access_token=testdata['access_token'],
29
- headers_to_sign=testdata['headers_to_sign'],
30
- max_body=testdata['max_body']
31
- )
32
-
33
- sign_key = auth_headers.make_signing_key(testdata['timestamp'])
34
- assert sign_key == testdata["sign_key_test"]
35
-
36
- content_hash = auth_headers.make_content_hash(
37
- body="test_body",
38
- method="POST"
39
- )
40
- assert content_hash == testdata["content_hash_test"]
41
-
42
- header = auth_headers.get_header_versions()
43
- assert header == {}
44
-
45
-
46
- def test_make_content_hash_logs_warning_for_unknown_body_len(testdata, caplog):
47
- auth_headers = eg.EdgeGridAuthHeaders(
48
- client_token=testdata['client_token'],
49
- client_secret=testdata['client_secret'],
50
- access_token=testdata['access_token'],
51
- headers_to_sign=testdata['headers_to_sign'],
52
- max_body=testdata['max_body']
53
- )
54
-
55
- def throwing_determine_body_len(_):
56
- raise OSError('boom')
57
-
58
- with unittest.mock.patch('akamai.edgegrid.edgegrid.determine_body_len',
59
- throwing_determine_body_len):
60
- content_hash = auth_headers.make_content_hash(body="test_body", method="POST")
61
- assert content_hash == testdata["content_hash_test"]
62
- assert re.match(r'WARNING.+cannot determine length of request body=.+:\s+boom',
63
- caplog.text)
64
-
65
-
66
- @pytest.mark.parametrize("testcase", cases(), ids=names(cases()))
67
- def test_edge_grid(testdata, testcase):
68
- auth = EdgeGridAuth(
69
- client_token=testdata['client_token'],
70
- client_secret=testdata['client_secret'],
71
- access_token=testdata['access_token'],
72
- headers_to_sign=testdata['headers_to_sign'],
73
- max_body=testdata['max_body']
74
- )
75
-
76
- headers = {}
77
- if 'headers' in testcase['request']:
78
- for request_headers in testcase['request']['headers']:
79
- for key, val in request_headers.items():
80
- headers[key] = val
81
-
82
- req = requests.Request(
83
- method=testcase['request']['method'],
84
- url=urljoin(
85
- testdata['base_url'],
86
- testcase['request']['path']),
87
- headers=headers,
88
- data=testcase['request'].get('data')
89
- )
90
-
91
- # The auth plugin is called on a PreparedRequest object, not a Request (see
92
- # PreparedRequest.prepare()). That's why we want req to be a PreparedRequest
93
- # in order to test make_auth_header with proper data.
94
- if testcase.get('failsWithMessage') is None:
95
- req = req.prepare()
96
- data_to_sign = auth.ah.make_data_to_sign(req, "")
97
- auth_header = auth.ah.make_auth_header(req, testdata['timestamp'], testdata['nonce'])
98
- assert auth_header == testcase['expectedAuthorization']
99
- assert data_to_sign == testcase['expectedDataToSign']
100
- else:
101
- with pytest.raises(Exception) as exc_info:
102
- req.prepare()
103
- assert str(exc_info.value) == testcase['failsWithMessage']
104
-
105
-
106
- def test_nonce():
107
- count = 100
108
- nonces = set()
109
- while count > 0:
110
- nonce = eg.new_nonce()
111
- assert nonce not in nonces
112
- count -= 1
113
-
114
-
115
- def test_timestamp():
116
- valid_timestamp = re.compile(r"""
117
- ^
118
- \d{4} # year
119
- [0-1][0-9] # month
120
- [0-3][0-9] # day
121
- T
122
- [0-2][0-9] # hour
123
- :
124
- [0-5][0-9] # minute
125
- :
126
- [0-5][0-9] # second
127
- \+0000 # timezone
128
- $
129
- """, re.VERBOSE)
130
- assert re.match(valid_timestamp, eg.eg_timestamp())
131
-
132
-
133
- def test_defaults():
134
- auth = EdgeGridAuth(
135
- client_token='xxx', client_secret='xxx', access_token='xxx'
136
- )
137
- assert auth.ah.max_body == 131072
138
- assert auth.ah.headers_to_sign == []
139
-
140
-
141
- def test_edgerc_default():
142
- auth = EdgeGridAuth.from_edgerc(os.path.join(test_dir, 'sample_edgerc'))
143
- assert auth.ah.client_token == 'xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx'
144
- assert auth.ah.client_secret == EXPECTED_CLIENT_SECRET
145
- assert auth.ah.access_token == 'xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx'
146
- assert auth.ah.max_body == 131072
147
- assert auth.ah.headers_to_sign == ['none']
148
-
149
-
150
- def test_edgerc_broken():
151
- auth = EdgeGridAuth.from_edgerc(
152
- os.path.join(test_dir, 'sample_edgerc'), 'broken')
153
- assert auth.ah.client_secret == EXPECTED_CLIENT_SECRET
154
- assert auth.ah.access_token == 'xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx'
155
- assert auth.ah.max_body == 128 * 1024
156
- assert auth.ah.headers_to_sign == ['none']
157
-
158
-
159
- def test_edgerc_unparseable():
160
- with pytest.raises(BaseException):
161
- EdgeGridAuth.from_edgerc(
162
- os.path.join(test_dir, 'edgerc_that_doesnt_parse'))
163
-
164
-
165
- def test_edgerc_headers():
166
- auth = EdgeGridAuth.from_edgerc(
167
- os.path.join(test_dir, 'sample_edgerc'), 'headers')
168
- assert auth.ah.headers_to_sign == ['x-mything1', 'x-mything2']
169
-
170
-
171
- def test_get_header_versions():
172
- auth = EdgeGridAuth.from_edgerc(
173
- os.path.join(test_dir, 'sample_edgerc'), 'headers')
174
- header = auth.ah.get_header_versions()
175
- assert 'user-agent' not in header
176
-
177
- header = auth.ah.get_header_versions({'User-Agent': 'testvalue'})
178
- assert 'User-Agent' in header
179
-
180
- # setting environment variables with hardcoded `1.0.0` value, just for this test.
181
- # These variables are cleared at the end of this test.
182
- os.environ["AKAMAI_CLI"] = '1.0.0'
183
- os.environ["AKAMAI_CLI_VERSION"] = '1.0.0'
184
-
185
- header = auth.ah.get_header_versions()
186
- assert 'User-Agent' in header
187
- assert header['User-Agent'] == 'AkamaiCLI/1.0.0'
188
-
189
- header = auth.ah.get_header_versions({'User-Agent': 'test-agent'})
190
- assert 'User-Agent' in header
191
- assert header['User-Agent'] == 'test-agent AkamaiCLI/1.0.0'
192
-
193
- os.environ["AKAMAI_CLI_COMMAND"] = '1.0.0'
194
- os.environ["AKAMAI_CLI_COMMAND_VERSION"] = '1.0.0'
195
-
196
- header = auth.ah.get_header_versions()
197
- assert 'User-Agent' in header
198
- assert header['User-Agent'] == 'AkamaiCLI/1.0.0 AkamaiCLI-1.0.0/1.0.0'
199
-
200
- header = auth.ah.get_header_versions({'User-Agent': 'testvalue'})
201
- assert 'User-Agent' in header
202
- assert header['User-Agent'] == 'testvalue AkamaiCLI/1.0.0 AkamaiCLI-1.0.0/1.0.0'
203
-
204
- del os.environ['AKAMAI_CLI']
205
- del os.environ['AKAMAI_CLI_VERSION']
206
- del os.environ['AKAMAI_CLI_COMMAND']
207
- del os.environ['AKAMAI_CLI_COMMAND_VERSION']
208
-
209
- assert 'AKAMAI_CLI' not in os.environ
210
- assert 'AKAMAI_CLI_VERSION' not in os.environ
211
- assert 'AKAMAI_CLI_COMMAND' not in os.environ
212
- assert 'AKAMAI_CLI_COMMAND_VERSION' not in os.environ
213
-
214
-
215
- def test_edgerc_from_object():
216
- auth = EdgeGridAuth.from_edgerc(
217
- EdgeRc(os.path.join(test_dir, 'sample_edgerc')))
218
- assert auth.ah.client_token == 'xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx'
219
- assert auth.ah.client_secret == EXPECTED_CLIENT_SECRET
220
- assert auth.ah.access_token == 'xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx'
221
- assert auth.ah.max_body == 131072
222
- assert auth.ah.headers_to_sign == ['none']
223
-
224
-
225
- def test_edgerc_dashes():
226
- auth = EdgeGridAuth.from_edgerc(
227
- os.path.join(test_dir, 'sample_edgerc'), 'dashes')
228
- assert auth.ah.max_body == 128 * 1024
229
-
230
-
231
- class TestReadBodyContent:
232
- """Test read_body_content"""
233
- def test_reading_from_str(self):
234
- assert eg.read_body_content('foobar', 10) == b'foobar'
235
-
236
- def test_reading_from_str_truncated(self):
237
- assert eg.read_body_content('foobar', 3) == b'foo'
238
-
239
- def test_reading_from_bytes(self):
240
- assert eg.read_body_content(b'foobar', 10) == b'foobar'
241
-
242
- def test_reading_from_bytes_truncated(self):
243
- assert eg.read_body_content(b'foobar', 3) == b'foo'
244
-
245
- def test_basic_reading_from_file_object(self, sample_file):
246
- assert eg.read_body_content(sample_file, 32) == b'this is a sample file.'
247
-
248
- def test_basic_reading_from_multipart_encoder(self):
249
- def encoder():
250
- return requests_toolbelt.MultipartEncoder({'foo': 'bar'}, boundary='baz')
251
-
252
- assert eg.read_body_content(encoder(), 1024) == encoder().to_string()
253
-
254
-
255
- class TestReadStreamAndRewind:
256
- """Test read_stream_and_rewind"""
257
- def test_with_file_object(self, sample_file):
258
- assert eg.read_stream_and_rewind(sample_file, 32) == b'this is a sample file.'
259
- assert sample_file.read() == b'this is a sample file.'
260
-
261
- def test_with_file_object_truncated(self, sample_file):
262
- assert eg.read_stream_and_rewind(sample_file, 4) == b'this'
263
- assert sample_file.read() == b'this is a sample file.'
264
-
265
- def test_with_multipart_encoder(self, multipart_fields):
266
- encoder = requests_toolbelt.MultipartEncoder(multipart_fields, "multipart_boundary")
267
-
268
- buf = eg.read_stream_and_rewind(encoder, 1024)
269
- assert buf == encoder.to_string()
270
- assert buf.startswith(b'--multipart_boundary')
271
- assert len(buf) == encoder.len
272
-
273
- def test_with_multipart_encoder_truncated(self, multipart_fields):
274
- encoder = requests_toolbelt.MultipartEncoder(multipart_fields, "multipart_boundary")
275
-
276
- assert eg.read_stream_and_rewind(encoder, 20) == b'--multipart_boundary'
277
- buf = eg.read_stream_and_rewind(encoder, 1024)
278
- assert buf == encoder.to_string()
279
- assert buf.startswith(b'--multipart_boundary')
280
- assert len(buf) == encoder.len
281
-
282
- def test_raises_when_input_has_no_read_method(self):
283
- with pytest.raises(TypeError) as excinfo:
284
- eg.read_stream_and_rewind('foo', 10)
285
- assert excinfo.match('akamai.edgegrid: unexpected body type: str')
286
- assert str(excinfo.value.__cause__) == "'str' object has no attribute 'read'"
287
-
288
- def test_raises_when_input_has_no_seek_method(self):
289
- # pylint: disable=missing-class-docstring,too-few-public-methods
290
- class DummyReader:
291
- def read(self, _):
292
- return b'Hello'
293
-
294
- with pytest.raises(TypeError) as excinfo:
295
- eg.read_stream_and_rewind(DummyReader(), 10)
296
- assert excinfo.match('akamai.edgegrid: unexpected body type: DummyReader')
297
- assert str(excinfo.value.__cause__) == "'DummyReader' object has no attribute '_buffer'"
298
-
299
- def test_raises_when_stream_not_seekable(self):
300
- r, w = os.pipe()
301
- os.write(w, b'Hello, pipe!')
302
- os.close(w)
303
- with pytest.raises(io.UnsupportedOperation) as excinfo:
304
- with open(r, 'rb') as pipe:
305
- eg.read_stream_and_rewind(pipe, 10)
306
- assert excinfo.match('not seekable')
307
-
308
-
309
- class TestDetermineBodyLen:
310
- """Test determine_body_len"""
311
- def test_with_str(self):
312
- assert eg.determine_body_len('foobarbaz') == 9
313
-
314
- def test_with_bytes(self):
315
- assert eg.determine_body_len(b'foobarbaz') == 9
316
-
317
- def test_with_file(self, sample_file):
318
- assert eg.determine_body_len(sample_file) == len('this is a sample file.')
319
-
320
- def test_with_multipart_encoder(self, multipart_fields):
321
- encoder = requests_toolbelt.MultipartEncoder(multipart_fields, "boundary")
322
- assert eg.determine_body_len(encoder) == encoder.len
323
-
324
- def test_raises_on_unknown_body_type(self):
325
- with pytest.raises(TypeError) as excinfo:
326
- eg.determine_body_len({'foo': 'bar'})
327
- assert excinfo.match('akamai.edgegrid: unexpected body type: dict')
328
- assert str(excinfo.value.__cause__) == "'dict' object has no attribute 'fileno'"
329
-
330
- def test_raises_when_filelike_body_does_not_support_file_descriptors(self):
331
- with pytest.raises(io.UnsupportedOperation) as excinfo:
332
- eg.determine_body_len(io.StringIO("Hello, string"))
333
- assert excinfo.match('fileno')
334
-
335
-
336
- def test_json(testdata):
337
- auth = EdgeGridAuth(
338
- client_token=testdata['client_token'],
339
- client_secret=testdata['client_secret'],
340
- access_token=testdata['access_token'],
341
- )
342
-
343
- params = {
344
- 'extended': 'true',
345
- }
346
-
347
- data = {
348
- 'key': 'value',
349
- }
350
-
351
- request = requests.Request(
352
- method='POST',
353
- url=urljoin(testdata['base_url'], '/testapi/v1/t3'),
354
- params=params,
355
- json=data,
356
- )
357
-
358
- req = request.prepare()
359
- auth_header = auth.ah.make_auth_header(req, testdata['timestamp'], testdata['nonce'])
360
-
361
- assert auth_header == testdata['jsontest_hash']
362
-
363
-
364
- def test_multipart_encoder(testdata, multipart_fields):
365
- auth = EdgeGridAuth(
366
- client_token=testdata["client_token"],
367
- client_secret=testdata["client_secret"],
368
- access_token=testdata["access_token"],
369
- )
370
-
371
- params = {
372
- "extended": "true",
373
- }
374
-
375
- data = requests_toolbelt.MultipartEncoder(
376
- fields=multipart_fields,
377
- boundary="multipart_boundary",
378
- )
379
-
380
- request = requests.Request(
381
- method="POST",
382
- url=urljoin(testdata["base_url"], "/testapi/v1/t3"),
383
- params=params,
384
- data=data,
385
- )
386
-
387
- req = request.prepare()
388
- auth_header = auth.ah.make_auth_header(req, testdata["timestamp"], testdata["nonce"])
389
-
390
- assert auth_header == testdata["multipart_hash_test"]
@@ -1,33 +0,0 @@
1
- """
2
- Namespace package import test — run by ci/test_namespace_pkg.sh after both
3
- edgegrid-python and the temporary akamai-dummy fragment are installed.
4
- Requires REPO_DIR env var pointing to the edgegrid-python repo root.
5
- """
6
- import akamai
7
- import akamai.dummy
8
- import akamai.edgegrid
9
- import os
10
-
11
- from akamai.dummy import SENTINEL
12
- from akamai.edgegrid import EdgeGridAuth, EdgeRc
13
-
14
- assert SENTINEL == "akamai.dummy is here", f"Unexpected value: {SENTINEL!r}"
15
-
16
- # Exercise real EdgeRc code — parse the sample_edgerc shipped with the package.
17
- sample_edgerc = os.path.join(os.environ["REPO_DIR"], "akamai", "edgegrid", "test", "sample_edgerc")
18
- rc = EdgeRc(sample_edgerc)
19
- assert rc.get("default", "host") == "xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/", "EdgeRc.get failed"
20
-
21
- # Both fragments must live under the *same* namespace package object.
22
- # Each entry in akamai.__path__ is the `akamai/` dir from one fragment.
23
- # Derive expected dirs by going up one level from each sub-package's __file__.
24
- real_paths = [os.path.realpath(p) for p in akamai.__path__ if os.path.isdir(p)]
25
-
26
- edgegrid_frag = os.path.realpath(os.path.join(os.path.dirname(akamai.edgegrid.__file__), ".."))
27
- dummy_frag = os.path.realpath(os.path.join(os.path.dirname(akamai.dummy.__file__), ".."))
28
-
29
- assert edgegrid_frag in real_paths, f"edgegrid fragment {edgegrid_frag!r} not in {real_paths}"
30
- assert dummy_frag in real_paths, f"dummy fragment {dummy_frag!r} not in {real_paths}"
31
-
32
- print(f"OK — akamai.edgegrid is reachable from {edgegrid_frag}")
33
- print(f"OK — akamai.dummy is reachable from {dummy_frag}")
@@ -1,71 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Generate a coverage summary markdown table from Cobertura XML files.
3
-
4
- Usage:
5
- python ci/coverage_report.py <version>:<path/to/cobertura.xml> ...
6
-
7
- Each positional argument is a colon-separated pair of a label (e.g. the
8
- Python version) and the path to a Cobertura-format XML coverage report.
9
- The script reads the top-level ``line-rate`` attribute from each file,
10
- formats it as a percentage, and prints a markdown table to stdout.
11
- """
12
-
13
- import argparse
14
- import sys
15
- import xml.etree.ElementTree as ET
16
-
17
-
18
- def parse_line_coverage(xml_path: str) -> float:
19
- """Return the top-level line coverage rate (0–1) from a Cobertura XML file."""
20
- try:
21
- tree = ET.parse(xml_path) # noqa: S314 — file is a trusted CI artifact
22
- except ET.ParseError as exc:
23
- raise SystemExit(f"Failed to parse {xml_path!r}: {exc}") from exc
24
- root = tree.getroot()
25
- try:
26
- return float(root.attrib["line-rate"])
27
- except (KeyError, ValueError) as exc:
28
- raise SystemExit(f"Missing or invalid 'line-rate' in {xml_path!r}: {exc}") from exc
29
-
30
-
31
- def build_table(rows: list[tuple[str, float]]) -> str:
32
- lines = [
33
- "## Coverage Report",
34
- "",
35
- "| Python Version | Line Coverage |",
36
- "| :---: | :---: |",
37
- ]
38
- for version, rate in sorted(rows):
39
- pct = rate * 100
40
- badge = "✅" if pct >= 80 else "❌"
41
- lines.append(f"| {version} | {badge} {pct:.1f}% |")
42
- return "\n".join(lines) + "\n"
43
-
44
-
45
- def main() -> None:
46
- parser = argparse.ArgumentParser(
47
- description="Summarise Cobertura coverage reports into a GitHub step summary."
48
- )
49
- parser.add_argument(
50
- "entries",
51
- nargs="+",
52
- metavar="VERSION:XML_PATH",
53
- help="Colon-separated pair of a label and the path to a Cobertura XML file.",
54
- )
55
- args = parser.parse_args()
56
-
57
- rows: list[tuple[str, float]] = []
58
- for entry in args.entries:
59
- if ":" not in entry:
60
- print(f"Error: expected VERSION:PATH, got {entry!r}", file=sys.stderr)
61
- sys.exit(1)
62
- version, xml_path = entry.split(":", 1)
63
- rate = parse_line_coverage(xml_path)
64
- rows.append((version, rate))
65
-
66
- table = build_table(rows)
67
- print(table)
68
-
69
-
70
- if __name__ == "__main__":
71
- main()
@@ -1,34 +0,0 @@
1
- # This example creates your new API client credentials.
2
- #
3
- # To run this example:
4
- #
5
- # 1. Specify the location of your .edgerc file and the section header of the set of credentials to use.
6
- #
7
- ## The defaults here expect the .edgerc at your home directory and use the credentials under the heading of default.
8
- #
9
- # 2. Open a Terminal or shell instance and run "python examples/create-credentials.py".
10
- #
11
- # A successful call returns a new API client with its credentialId. Use this ID in both the update and delete examples.
12
- #
13
- # For more information on the call used in this example, see https://techdocs.akamai.com/iam-api/reference/post-self-credentials.
14
-
15
- import requests
16
- import json
17
- from akamai.edgegrid import EdgeGridAuth, EdgeRc
18
- from urllib.parse import urljoin
19
-
20
- edgerc = EdgeRc('~/.edgerc')
21
- section = 'default'
22
- baseurl = 'https://%s' % edgerc.get(section, 'host')
23
-
24
- session = requests.Session()
25
- session.auth = EdgeGridAuth.from_edgerc(edgerc, section)
26
-
27
- path = '/identity-management/v3/api-clients/self/credentials'
28
- headers = {
29
- "Accept": "application/json"
30
- }
31
-
32
- result = session.post(urljoin(baseurl, path), headers=headers)
33
- print(result.status_code)
34
- print(json.dumps(result.json(), indent=2))
@@ -1,35 +0,0 @@
1
- # This example deletes your API client credentials.
2
- #
3
- # To run this example:
4
- #
5
- # 1. Specify the location of your .edgerc file and the section header of the set of credentials to use.
6
- #
7
- # The defaults here expect the .edgerc at your home directory and use the credentials under the heading of default.
8
- #
9
- # 2. Add the credentialId from the update example to the path. You can only delete inactive credentials. Sending the request on an active set will return a 400. Use the update credentials example for deactivation.
10
- #
11
- # **Important:** Don't use the credentials you're actively using when deleting a set of credentials. Otherwise, you'll block your access to the Akamai APIs.
12
- #
13
- # 3. Open a Terminal or shell instance and run "python examples/delete-credentials.py".
14
- #
15
- # A successful call returns "" null.
16
- #
17
- # For more information on the call used in this example, see https://techdocs.akamai.com/iam-api/reference/delete-self-credential.
18
-
19
- import requests
20
- import json
21
- from akamai.edgegrid import EdgeGridAuth, EdgeRc
22
- from urllib.parse import urljoin
23
-
24
- edgerc = EdgeRc('~/.edgerc')
25
- section = 'default'
26
- baseurl = 'https://%s' % edgerc.get(section, 'host')
27
-
28
- session = requests.Session()
29
- session.auth = EdgeGridAuth.from_edgerc(edgerc, section)
30
- credentialId = 123456
31
-
32
- path = '/identity-management/v3/api-clients/self/credentials/{}'.format(credentialId)
33
-
34
- result = session.delete(urljoin(baseurl, path))
35
- print(result.status_code)
@@ -1,37 +0,0 @@
1
- # This example returns a list of your API client credentials.
2
- #
3
- # To run this example:
4
- #
5
- # 1. Specify the location of your .edgerc file and the section header of the set of credentials to use.
6
- #
7
- # The defaults here expect the .edgerc at your home directory and use the credentials under the heading of default.
8
- #
9
- # 2. Open a Terminal or shell instance and run "python examples/get-credentials.py".
10
- #
11
- # A successful call returns your credentials grouped by credentialId.
12
- #
13
- # For more information on the call used in this example, see https://techdocs.akamai.com/iam-api/reference/get-self-credentials.
14
-
15
- import requests
16
- import json
17
- from akamai.edgegrid import EdgeGridAuth, EdgeRc
18
- from urllib.parse import urljoin
19
-
20
- edgerc = EdgeRc('~/.edgerc')
21
- section = 'default'
22
- baseurl = 'https://%s' % edgerc.get(section, 'host')
23
-
24
- session = requests.Session()
25
- session.auth = EdgeGridAuth.from_edgerc(edgerc, section)
26
-
27
- path = '/identity-management/v3/api-clients/self/credentials'
28
- headers = {
29
- "Accept": "application/json"}
30
- querystring = {
31
- "actions": True
32
- }
33
-
34
- result = session.get(urljoin(baseurl, path), headers=headers, params=querystring)
35
- print(result.status_code)
36
- print(json.dumps(result.json(), indent=2))
37
-
@@ -1,47 +0,0 @@
1
- # This example updates the credentials from the create credentials example.
2
- #
3
- # To run this example:
4
- #
5
- # 1. Specify the location of your .edgerc file and the section header of the set of credentials to use.
6
- #
7
- # The defaults here expect the .edgerc at your home directory and use the credentials under the heading of default.
8
- #
9
- # 2. Add the credentialId for the set of credentials created using the create example as a path parameter.
10
- #
11
- # 3. Edit the expiresOn date to today's date. Optionally, you can change the description value.
12
- #
13
- # **Important:** Don't use the credentials you're actively using when inactivating a set of credentials. Otherwise, you'll block your access to the Akamai APIs.
14
- #
15
- # 4. Open a Terminal or shell instance and run "python examples/update-credentials.py".
16
- #
17
- # A successful call returns.
18
- #
19
- # For more information on the call used in this example, see https://techdocs.akamai.com/iam-api/reference/put-self-credential.
20
-
21
- import requests
22
- import json
23
- from akamai.edgegrid import EdgeGridAuth, EdgeRc
24
- from urllib.parse import urljoin
25
-
26
- edgerc = EdgeRc('~/.edgerc')
27
- section = 'default'
28
- baseurl = 'https://%s' % edgerc.get(section, 'host')
29
-
30
- session = requests.Session()
31
- session.auth = EdgeGridAuth.from_edgerc(edgerc, section)
32
- credentialId = 123456
33
-
34
- path = '/identity-management/v3/api-clients/self/credentials/{}'.format(credentialId)
35
- headers = {
36
- "Content-Type": "application/json",
37
- "Accept": "application/json"}
38
- payload = {
39
- "status": "INACTIVE",
40
- "expiresOn": "2024-12-30T22:09:24.000Z", # The date cannot be more than two years out or it will return a 400
41
- "description": "Update this credential"
42
- }
43
-
44
- result = session.put(urljoin(baseurl, path), headers=headers, json=payload)
45
- print(result.status_code)
46
- print(json.dumps(result.json(), indent=2))
47
-
@@ -1,34 +0,0 @@
1
- akamai/edgegrid/__init__.py,sha256=fzAqUKSNm_UqybPY6sXyTsNJYbuSBebdBqPJd43FKjg,1217
2
- akamai/edgegrid/edgegrid.py,sha256=pzJQ7qjC5KZIIM_yrhdVHUuJe6CMFzt-z1ucQeN2-vk,12002
3
- akamai/edgegrid/edgerc.py,sha256=T9RoKyWnVIIOwAVaJZ3QV5xBAJ9vz7XiyUZ8tMET8dI,1170
4
- akamai/edgegrid/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- akamai/edgegrid/test/conftest.py,sha256=ewP2gqZI0POKP0d3QQuD0yiPYkPM9sRqLBekk00GnFQ,908
6
- akamai/edgegrid/test/edgerc_that_doesnt_parse,sha256=j1uEFSxZo_o9pYuj6QdxWIOSmRTLLlLPLWQ8sziHm1A,138
7
- akamai/edgegrid/test/sample_edgerc,sha256=0DsP3KEoLXjd7fhkKcVoCT5cM1S69iNZmO8VvdwKWLA,1084
8
- akamai/edgegrid/test/sample_file.txt,sha256=EBMsdifxSkOKTPB-eqA7be67wJ5YWG_G8NjoNdtZqBM,22
9
- akamai/edgegrid/test/test_edgegrid.py,sha256=GhX1CjO3CS_cVV6hFOyOKL8ovxvEZpHbqrFBGmTKkw8,13506
10
- akamai/edgegrid/test/testcases.json,sha256=81LV7AgNTmHSX4X56dZszrVk-Zk1Jw5vkvI6DFJazSE,15040
11
- akamai/edgegrid/test/testdata.json,sha256=kJ0DYk94SJeatnvdqYTCw-itxMUdbIhzVta3rIYAVT0,1149
12
- build/lib/akamai/edgegrid/__init__.py,sha256=fzAqUKSNm_UqybPY6sXyTsNJYbuSBebdBqPJd43FKjg,1217
13
- build/lib/akamai/edgegrid/edgegrid.py,sha256=pzJQ7qjC5KZIIM_yrhdVHUuJe6CMFzt-z1ucQeN2-vk,12002
14
- build/lib/akamai/edgegrid/edgerc.py,sha256=T9RoKyWnVIIOwAVaJZ3QV5xBAJ9vz7XiyUZ8tMET8dI,1170
15
- build/lib/akamai/edgegrid/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- build/lib/akamai/edgegrid/test/conftest.py,sha256=ewP2gqZI0POKP0d3QQuD0yiPYkPM9sRqLBekk00GnFQ,908
17
- build/lib/akamai/edgegrid/test/test_edgegrid.py,sha256=GhX1CjO3CS_cVV6hFOyOKL8ovxvEZpHbqrFBGmTKkw8,13506
18
- build/lib/ci/check_namespace_pkg.py,sha256=mUy-bcH8KV2ujgkgFFJ_yJ2XzVn1_YdQhXDQeCENNnc,1594
19
- build/lib/ci/coverage_report.py,sha256=jykNDfg5MTHCCwEg6_GtgyUQO4B2Tt3Ws8SrKPtXmYI,2273
20
- build/lib/examples/create-credentials.py,sha256=z-9ItuXNI3lFhMv3A5-dZC0QfSgTGvNJciQOPNWBurQ,1191
21
- build/lib/examples/delete-credentials.py,sha256=HM6a8fy-44beXKLhs_JVk8ChdOJlvF1s4XwWn9VATqE,1422
22
- build/lib/examples/get-credentials.py,sha256=duI0pRRwX9--Eibnp4EsIRQebwnsygzmCEScemKD27w,1198
23
- build/lib/examples/update-credentials.py,sha256=BEahXLHjIXuBW77wuQK98fbKSxlibugG1nQD1nvVcN0,1783
24
- ci/check_namespace_pkg.py,sha256=mUy-bcH8KV2ujgkgFFJ_yJ2XzVn1_YdQhXDQeCENNnc,1594
25
- ci/coverage_report.py,sha256=jykNDfg5MTHCCwEg6_GtgyUQO4B2Tt3Ws8SrKPtXmYI,2273
26
- edgegrid_python-2.0.6.dist-info/licenses/LICENSE,sha256=aai-NM26EYkRybAI1eWSlozmBr8-EQ1GWLJe_9qc8M4,10294
27
- examples/create-credentials.py,sha256=z-9ItuXNI3lFhMv3A5-dZC0QfSgTGvNJciQOPNWBurQ,1191
28
- examples/delete-credentials.py,sha256=HM6a8fy-44beXKLhs_JVk8ChdOJlvF1s4XwWn9VATqE,1422
29
- examples/get-credentials.py,sha256=duI0pRRwX9--Eibnp4EsIRQebwnsygzmCEScemKD27w,1198
30
- examples/update-credentials.py,sha256=BEahXLHjIXuBW77wuQK98fbKSxlibugG1nQD1nvVcN0,1783
31
- edgegrid_python-2.0.6.dist-info/METADATA,sha256=D27jiABY-ZRgoTXiqtRN1w6SVmfKe-JC34itGjUuBZY,9208
32
- edgegrid_python-2.0.6.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
33
- edgegrid_python-2.0.6.dist-info/top_level.txt,sha256=ttvQo9dlYgqcI6oEw8zYerOg7riO5DwNVGFS_I_o8E8,25
34
- edgegrid_python-2.0.6.dist-info/RECORD,,