rucio-clients 32.8.6__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 rucio-clients might be problematic. Click here for more details.

Files changed (88) hide show
  1. rucio/__init__.py +18 -0
  2. rucio/alembicrevision.py +16 -0
  3. rucio/client/__init__.py +16 -0
  4. rucio/client/accountclient.py +413 -0
  5. rucio/client/accountlimitclient.py +155 -0
  6. rucio/client/baseclient.py +929 -0
  7. rucio/client/client.py +77 -0
  8. rucio/client/configclient.py +113 -0
  9. rucio/client/credentialclient.py +54 -0
  10. rucio/client/didclient.py +691 -0
  11. rucio/client/diracclient.py +48 -0
  12. rucio/client/downloadclient.py +1674 -0
  13. rucio/client/exportclient.py +44 -0
  14. rucio/client/fileclient.py +51 -0
  15. rucio/client/importclient.py +42 -0
  16. rucio/client/lifetimeclient.py +74 -0
  17. rucio/client/lockclient.py +99 -0
  18. rucio/client/metaclient.py +137 -0
  19. rucio/client/pingclient.py +45 -0
  20. rucio/client/replicaclient.py +444 -0
  21. rucio/client/requestclient.py +109 -0
  22. rucio/client/rseclient.py +664 -0
  23. rucio/client/ruleclient.py +287 -0
  24. rucio/client/scopeclient.py +88 -0
  25. rucio/client/subscriptionclient.py +161 -0
  26. rucio/client/touchclient.py +78 -0
  27. rucio/client/uploadclient.py +871 -0
  28. rucio/common/__init__.py +14 -0
  29. rucio/common/cache.py +74 -0
  30. rucio/common/config.py +796 -0
  31. rucio/common/constants.py +92 -0
  32. rucio/common/constraints.py +18 -0
  33. rucio/common/didtype.py +187 -0
  34. rucio/common/exception.py +1092 -0
  35. rucio/common/extra.py +37 -0
  36. rucio/common/logging.py +404 -0
  37. rucio/common/pcache.py +1387 -0
  38. rucio/common/policy.py +84 -0
  39. rucio/common/schema/__init__.py +143 -0
  40. rucio/common/schema/atlas.py +411 -0
  41. rucio/common/schema/belleii.py +406 -0
  42. rucio/common/schema/cms.py +478 -0
  43. rucio/common/schema/domatpc.py +399 -0
  44. rucio/common/schema/escape.py +424 -0
  45. rucio/common/schema/generic.py +431 -0
  46. rucio/common/schema/generic_multi_vo.py +410 -0
  47. rucio/common/schema/icecube.py +404 -0
  48. rucio/common/schema/lsst.py +423 -0
  49. rucio/common/stomp_utils.py +160 -0
  50. rucio/common/stopwatch.py +56 -0
  51. rucio/common/test_rucio_server.py +148 -0
  52. rucio/common/types.py +158 -0
  53. rucio/common/utils.py +1946 -0
  54. rucio/rse/__init__.py +97 -0
  55. rucio/rse/protocols/__init__.py +14 -0
  56. rucio/rse/protocols/cache.py +123 -0
  57. rucio/rse/protocols/dummy.py +112 -0
  58. rucio/rse/protocols/gfal.py +701 -0
  59. rucio/rse/protocols/globus.py +243 -0
  60. rucio/rse/protocols/gsiftp.py +93 -0
  61. rucio/rse/protocols/http_cache.py +83 -0
  62. rucio/rse/protocols/mock.py +124 -0
  63. rucio/rse/protocols/ngarc.py +210 -0
  64. rucio/rse/protocols/posix.py +251 -0
  65. rucio/rse/protocols/protocol.py +530 -0
  66. rucio/rse/protocols/rclone.py +365 -0
  67. rucio/rse/protocols/rfio.py +137 -0
  68. rucio/rse/protocols/srm.py +339 -0
  69. rucio/rse/protocols/ssh.py +414 -0
  70. rucio/rse/protocols/storm.py +207 -0
  71. rucio/rse/protocols/webdav.py +547 -0
  72. rucio/rse/protocols/xrootd.py +295 -0
  73. rucio/rse/rsemanager.py +752 -0
  74. rucio/vcsversion.py +11 -0
  75. rucio/version.py +46 -0
  76. rucio_clients-32.8.6.data/data/etc/rse-accounts.cfg.template +25 -0
  77. rucio_clients-32.8.6.data/data/etc/rucio.cfg.atlas.client.template +42 -0
  78. rucio_clients-32.8.6.data/data/etc/rucio.cfg.template +257 -0
  79. rucio_clients-32.8.6.data/data/requirements.txt +55 -0
  80. rucio_clients-32.8.6.data/data/rucio_client/merge_rucio_configs.py +147 -0
  81. rucio_clients-32.8.6.data/scripts/rucio +2540 -0
  82. rucio_clients-32.8.6.data/scripts/rucio-admin +2434 -0
  83. rucio_clients-32.8.6.dist-info/METADATA +50 -0
  84. rucio_clients-32.8.6.dist-info/RECORD +88 -0
  85. rucio_clients-32.8.6.dist-info/WHEEL +5 -0
  86. rucio_clients-32.8.6.dist-info/licenses/AUTHORS.rst +94 -0
  87. rucio_clients-32.8.6.dist-info/licenses/LICENSE +201 -0
  88. rucio_clients-32.8.6.dist-info/top_level.txt +1 -0
@@ -0,0 +1,44 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright European Organization for Nuclear Research (CERN) since 2012
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from requests.status_codes import codes
17
+
18
+ from rucio.client.baseclient import BaseClient
19
+ from rucio.client.baseclient import choice
20
+ from rucio.common.utils import build_url, parse_response
21
+
22
+
23
+ class ExportClient(BaseClient):
24
+ """RSE client class for exporting data from Rucio"""
25
+
26
+ EXPORT_BASEURL = 'export'
27
+
28
+ def export_data(self, distance=True):
29
+ """
30
+ Export RSE data (RSE, settings, attributes and distance).
31
+ :param distance: To include the distance.
32
+
33
+ :returns: A dict containing data
34
+ """
35
+ payload = {'distance': distance}
36
+ path = '/'.join([self.EXPORT_BASEURL])
37
+ url = build_url(choice(self.list_hosts), path=path, params=payload)
38
+
39
+ r = self._send_request(url, type_='GET')
40
+ if r.status_code == codes.ok:
41
+ return parse_response(r.text)
42
+ else:
43
+ exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
44
+ raise exc_cls(exc_msg)
@@ -0,0 +1,51 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright European Organization for Nuclear Research (CERN) since 2012
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from json import loads
17
+ from urllib.parse import quote_plus
18
+
19
+ from requests.status_codes import codes
20
+
21
+ from rucio.client.baseclient import BaseClient
22
+ from rucio.client.baseclient import choice
23
+ from rucio.common.utils import build_url
24
+
25
+
26
+ class FileClient(BaseClient):
27
+ """Dataset client class for working with dataset"""
28
+
29
+ BASEURL = 'files'
30
+
31
+ def list_file_replicas(self, scope, lfn):
32
+ """
33
+ List file replicas.
34
+
35
+ :param scope: the scope.
36
+ :param lfn: the lfn.
37
+
38
+ :return: List of replicas.
39
+ """
40
+ path = '/'.join([self.BASEURL, quote_plus(scope), quote_plus(lfn), 'rses'])
41
+ url = build_url(choice(self.list_hosts), path=path)
42
+
43
+ r = self._send_request(url, type_='GET')
44
+
45
+ if r.status_code == codes.ok:
46
+ rses = loads(r.text)
47
+ return rses
48
+ else:
49
+ print(r.status_code)
50
+ exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
51
+ raise exc_cls(exc_msg)
@@ -0,0 +1,42 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright European Organization for Nuclear Research (CERN) since 2012
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from requests.status_codes import codes
17
+
18
+ from rucio.client.baseclient import BaseClient
19
+ from rucio.client.baseclient import choice
20
+ from rucio.common.utils import build_url, render_json
21
+
22
+
23
+ class ImportClient(BaseClient):
24
+ """RSE client class for importing data into Rucio"""
25
+
26
+ IMPORT_BASEURL = 'import'
27
+
28
+ def import_data(self, data):
29
+ """
30
+ Imports data into Rucio.
31
+
32
+ :param data: a dict containing data to be imported into Rucio.
33
+ """
34
+ path = '/'.join([self.IMPORT_BASEURL])
35
+ url = build_url(choice(self.list_hosts), path=path)
36
+
37
+ r = self._send_request(url, type_='POST', data=render_json(**data))
38
+ if r.status_code == codes.created:
39
+ return r.text
40
+ else:
41
+ exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
42
+ raise exc_cls(exc_msg)
@@ -0,0 +1,74 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright European Organization for Nuclear Research (CERN) since 2012
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from json import loads
17
+
18
+ from requests.status_codes import codes
19
+
20
+ from rucio.client.baseclient import BaseClient
21
+ from rucio.client.baseclient import choice
22
+ from rucio.common.utils import build_url, render_json
23
+
24
+
25
+ class LifetimeClient(BaseClient):
26
+
27
+ """Lifetime client class for working with Lifetime Model exceptions"""
28
+
29
+ LIFETIME_BASEURL = 'lifetime_exceptions'
30
+
31
+ def list_exceptions(self, exception_id=None, states=None):
32
+ """
33
+ List exceptions to Lifetime Model.
34
+
35
+ :param id: The id of the exception
36
+ :param states: The states to filter
37
+ """
38
+
39
+ path = self.LIFETIME_BASEURL + '/'
40
+ params = {}
41
+ if exception_id:
42
+ params['exception_id'] = exception_id
43
+ if states:
44
+ params['states'] = exception_id
45
+ url = build_url(choice(self.list_hosts), path=path, params=params)
46
+
47
+ result = self._send_request(url)
48
+ if result.status_code == codes.ok:
49
+ lifetime_exceptions = self._load_json_data(result)
50
+ return lifetime_exceptions
51
+ else:
52
+ exc_cls, exc_msg = self._get_exception(headers=result.headers, status_code=result.status_code)
53
+ raise exc_cls(exc_msg)
54
+
55
+ def add_exception(self, dids, account, pattern, comments, expires_at):
56
+ """
57
+ Add exceptions to Lifetime Model.
58
+
59
+ :param dids: The list of dids
60
+ :param account: The account of the requester.
61
+ :param pattern: The account.
62
+ :param comments: The comments associated to the exception.
63
+ :param expires_at: The expiration date of the exception.
64
+
65
+ returns: The id of the exception.
66
+ """
67
+ path = self.LIFETIME_BASEURL + '/'
68
+ url = build_url(choice(self.list_hosts), path=path)
69
+ data = {'dids': dids, 'account': account, 'pattern': pattern, 'comments': comments, 'expires_at': expires_at}
70
+ result = self._send_request(url, type_='POST', data=render_json(**data))
71
+ if result.status_code == codes.created:
72
+ return loads(result.text)
73
+ exc_cls, exc_msg = self._get_exception(headers=result.headers, status_code=result.status_code, data=result.content)
74
+ raise exc_cls(exc_msg)
@@ -0,0 +1,99 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright European Organization for Nuclear Research (CERN) since 2012
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from urllib.parse import quote_plus
17
+
18
+ from requests.status_codes import codes
19
+
20
+ from rucio.client.baseclient import BaseClient
21
+ from rucio.client.baseclient import choice
22
+ from rucio.common.utils import build_url, render_json
23
+
24
+
25
+ class LockClient(BaseClient):
26
+
27
+ """Lock client class for working with rucio locks"""
28
+
29
+ LOCKS_BASEURL = 'locks'
30
+
31
+ def get_dataset_locks(self, scope, name):
32
+ """
33
+ Get a dataset locks of the specified dataset.
34
+
35
+ :param scope: the scope of the did of the locks to list.
36
+ :param name: the name of the did of the locks to list.
37
+ """
38
+
39
+ path = '/'.join([self.LOCKS_BASEURL, quote_plus(scope), quote_plus(name)])
40
+ url = build_url(choice(self.list_hosts), path=path, params={'did_type': 'dataset'})
41
+
42
+ result = self._send_request(url)
43
+ if result.status_code == codes.ok: # pylint: disable-msg=E1101
44
+ locks = self._load_json_data(result)
45
+ return locks
46
+ else:
47
+ exc_cls, exc_msg = self._get_exception(headers=result.headers,
48
+ status_code=result.status_code)
49
+ raise exc_cls(exc_msg)
50
+
51
+ def get_locks_for_dids(self, dids, **filter_args):
52
+ """
53
+ Get list of locks for for all the files found, recursively, in the listed datasets or containers.
54
+
55
+ :param dids: list of dictionaries {"scope":..., "name":..., "type":...}
56
+ type can be either "dataset" or "container"
57
+ type is optional, but if specified, improves the query performance
58
+ :returns: list of dictionaries with lock info
59
+ """
60
+
61
+ # convert did list to list of dictionaries
62
+
63
+ assert all(did.get("type", "dataset") in ("dataset", "container") for did in dids), "did type can be either 'container' or 'dataset'"
64
+
65
+ path = '/'.join([self.LOCKS_BASEURL, "bulk_locks_for_dids"])
66
+ url = build_url(choice(self.list_hosts), path=path)
67
+
68
+ result = self._send_request(url, type_='POST', data=render_json(dids=dids))
69
+ if result.status_code == codes.ok: # pylint: disable-msg=E1101
70
+ out = []
71
+ for lock in self._load_json_data(result):
72
+ filter_ok = (not filter_args) or all(lock.get(name) == value for name, value in filter_args.items())
73
+ if filter_ok:
74
+ out.append(lock)
75
+ return out
76
+ else:
77
+ exc_cls, exc_msg = self._get_exception(headers=result.headers,
78
+ status_code=result.status_code)
79
+ raise exc_cls(exc_msg)
80
+
81
+ def get_dataset_locks_by_rse(self, rse):
82
+ """
83
+ Get all dataset locks of the specified rse.
84
+
85
+ :param rse: the rse of the locks to list.
86
+ """
87
+
88
+ path = '/'.join([self.LOCKS_BASEURL, rse])
89
+ url = build_url(choice(self.list_hosts), path=path, params={'did_type': 'dataset'})
90
+
91
+ result = self._send_request(url)
92
+ if result.status_code == codes.ok: # pylint: disable-msg=E1101
93
+ locks = self._load_json_data(result)
94
+ return locks
95
+ else:
96
+ exc_cls, exc_msg = self._get_exception(headers=result.headers,
97
+ status_code=result.status_code)
98
+
99
+ raise exc_cls(exc_msg)
@@ -0,0 +1,137 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright European Organization for Nuclear Research (CERN) since 2012
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from json import dumps, loads
17
+ from urllib.parse import quote_plus
18
+
19
+ from requests.status_codes import codes
20
+
21
+ from rucio.client.baseclient import BaseClient
22
+ from rucio.client.baseclient import choice
23
+ from rucio.common.utils import build_url
24
+
25
+
26
+ class MetaClient(BaseClient):
27
+
28
+ """Meta client class for working with data identifier attributes"""
29
+
30
+ META_BASEURL = 'meta'
31
+
32
+ def add_key(self, key, key_type, value_type=None, value_regexp=None):
33
+ """
34
+ Sends the request to add a new key.
35
+
36
+ :param key: the name for the new key.
37
+ :param key_type: the type of the key: all(container, dataset, file), collection(dataset or container), file, derived(compute from file for collection).
38
+ :param value_type: the type of the value, if defined.
39
+ :param value_regexp: the regular expression that values should match, if defined.
40
+
41
+ :return: True if key was created successfully.
42
+ :raises Duplicate: if key already exists.
43
+ """
44
+
45
+ path = '/'.join([self.META_BASEURL, quote_plus(key)])
46
+ url = build_url(choice(self.list_hosts), path=path)
47
+ data = dumps({'value_type': value_type and str(value_type),
48
+ 'value_regexp': value_regexp,
49
+ 'key_type': key_type})
50
+
51
+ r = self._send_request(url, type_='POST', data=data)
52
+
53
+ if r.status_code == codes.created:
54
+ return True
55
+ else:
56
+ exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
57
+ raise exc_cls(exc_msg)
58
+
59
+ def list_keys(self):
60
+ """
61
+ Sends the request to list all keys.
62
+
63
+ :return: a list containing the names of all keys.
64
+ """
65
+ path = self.META_BASEURL + '/'
66
+ url = build_url(choice(self.list_hosts), path=path)
67
+ r = self._send_request(url)
68
+ if r.status_code == codes.ok:
69
+ keys = loads(r.text)
70
+ return keys
71
+ else:
72
+ exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
73
+ raise exc_cls(exc_msg)
74
+
75
+ def list_values(self, key):
76
+ """
77
+ Sends the request to list all values for a key.
78
+
79
+ :return: a list containing the names of all values for a key.
80
+ """
81
+ path = '/'.join([self.META_BASEURL, quote_plus(key)]) + '/'
82
+ url = build_url(choice(self.list_hosts), path=path)
83
+ r = self._send_request(url)
84
+ if r.status_code == codes.ok:
85
+ values = loads(r.text)
86
+ return values
87
+ else:
88
+ exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
89
+ raise exc_cls(exc_msg)
90
+
91
+ def add_value(self, key, value):
92
+ """
93
+ Sends the request to add a value to a key.
94
+
95
+ :param key: the name for key.
96
+ :param value: the value.
97
+
98
+ :return: True if value was created successfully.
99
+ :raises Duplicate: if valid already exists.
100
+ """
101
+
102
+ path = '/'.join([self.META_BASEURL, quote_plus(key)]) + '/'
103
+ data = dumps({'value': value})
104
+ url = build_url(choice(self.list_hosts), path=path)
105
+ r = self._send_request(url, type_='POST', data=data)
106
+ if r.status_code == codes.created:
107
+ return True
108
+ else:
109
+ exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
110
+ raise exc_cls(exc_msg)
111
+
112
+ def del_value(self, key, value):
113
+ """
114
+ Delete a value for a key.
115
+
116
+ :param key: the name for key.
117
+ :param value: the value.
118
+ """
119
+ pass
120
+
121
+ def del_key(self, key):
122
+ """
123
+ Delete an allowed key.
124
+
125
+ :param key: the name for key.
126
+ """
127
+ pass
128
+
129
+ def update_key(self, key, type_=None, regexp=None):
130
+ """
131
+ Update a key.
132
+
133
+ :param key: the name for key.
134
+ :param type_: the type of the value, if defined.
135
+ :param regexp: the regular expression that values should match, if defined.
136
+ """
137
+ pass
@@ -0,0 +1,45 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright European Organization for Nuclear Research (CERN) since 2012
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from json import loads
17
+
18
+ from requests.status_codes import codes
19
+
20
+ from rucio.client.baseclient import BaseClient
21
+ from rucio.common.utils import build_url
22
+
23
+
24
+ class PingClient(BaseClient):
25
+
26
+ """Ping client class"""
27
+
28
+ def ping(self):
29
+ """
30
+ Sends a ping request to the rucio server.
31
+
32
+ :return: Dictonnary with server information
33
+ """
34
+
35
+ headers = None
36
+ path = 'ping'
37
+ url = build_url(self.host, path=path)
38
+ r = self._send_request(url, headers=headers, type_='GET')
39
+
40
+ if r.status_code == codes.ok:
41
+ server_info = loads(r.text)
42
+ return server_info
43
+
44
+ exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
45
+ raise exc_cls(exc_msg)