looker-sdk 24.2.0__py3-none-any.whl → 24.4.0__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.
- looker_sdk/error.py +106 -11
- looker_sdk/rtl/api_methods.py +9 -1
- looker_sdk/sdk/api40/models.py +69 -57
- looker_sdk/sdk/constants.py +1 -1
- looker_sdk/version.py +1 -1
- {looker_sdk-24.2.0.dist-info → looker_sdk-24.4.0.dist-info}/METADATA +1 -1
- {looker_sdk-24.2.0.dist-info → looker_sdk-24.4.0.dist-info}/RECORD +10 -10
- {looker_sdk-24.2.0.dist-info → looker_sdk-24.4.0.dist-info}/WHEEL +1 -1
- {looker_sdk-24.2.0.dist-info → looker_sdk-24.4.0.dist-info}/LICENSE.txt +0 -0
- {looker_sdk-24.2.0.dist-info → looker_sdk-24.4.0.dist-info}/top_level.txt +0 -0
looker_sdk/error.py
CHANGED
|
@@ -21,33 +21,128 @@
|
|
|
21
21
|
# THE SOFTWARE.
|
|
22
22
|
|
|
23
23
|
import attr
|
|
24
|
-
from typing
|
|
24
|
+
from typing import cast, Dict, Optional, Sequence, Tuple
|
|
25
|
+
import requests
|
|
26
|
+
import json
|
|
27
|
+
import re
|
|
25
28
|
|
|
26
29
|
"""API error class
|
|
27
30
|
"""
|
|
28
31
|
|
|
32
|
+
|
|
29
33
|
@attr.s(auto_attribs=True, kw_only=True)
|
|
30
|
-
class ErrorDetail
|
|
34
|
+
class ErrorDetail:
|
|
31
35
|
"""Error detail:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
documentation_url: documentation link
|
|
37
|
+
field: field with error
|
|
38
|
+
code: error code
|
|
39
|
+
message: error info message
|
|
40
|
+
error_doc_url: URL that may point to additional useful information
|
|
41
|
+
error_doc: Markdown doc that may contain additional useful information
|
|
36
42
|
"""
|
|
43
|
+
|
|
37
44
|
documentation_url: str
|
|
38
45
|
field: Optional[str] = ""
|
|
39
46
|
code: Optional[str] = ""
|
|
40
47
|
message: Optional[str] = ""
|
|
48
|
+
error_doc_url: str = ""
|
|
49
|
+
error_doc: str = ""
|
|
50
|
+
|
|
51
|
+
def __str__(self):
|
|
52
|
+
return f"""
|
|
53
|
+
*****
|
|
54
|
+
documentation_url: {self.documentation_url}
|
|
55
|
+
field: {self.field}
|
|
56
|
+
code: {self.code}
|
|
57
|
+
message: {self.message}
|
|
58
|
+
error_doc_url: {self.error_doc_url}
|
|
59
|
+
"""
|
|
41
60
|
|
|
42
61
|
|
|
43
62
|
@attr.s(auto_attribs=True)
|
|
44
63
|
class SDKError(Exception):
|
|
45
64
|
"""API error class:
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
65
|
+
message: main error info message
|
|
66
|
+
errors: array of error details
|
|
67
|
+
documentation_url: documentation link
|
|
68
|
+
error_doc_url: URL that may point to additional useful information
|
|
69
|
+
error_doc: Markdown doc that may contain additional useful information
|
|
49
70
|
"""
|
|
50
71
|
|
|
51
72
|
message: str
|
|
52
|
-
errors:
|
|
53
|
-
documentation_url:
|
|
73
|
+
errors: Sequence[ErrorDetail] = attr.ib(default=[], kw_only=True)
|
|
74
|
+
documentation_url: str = attr.ib(default="", kw_only=True)
|
|
75
|
+
error_doc_url: str = ""
|
|
76
|
+
error_doc: str = ""
|
|
77
|
+
|
|
78
|
+
def __str__(self):
|
|
79
|
+
sep = "****\n"
|
|
80
|
+
return f"""
|
|
81
|
+
message: {self.message}
|
|
82
|
+
documentation_url: {self.documentation_url}
|
|
83
|
+
error_doc_url: {self.error_doc_url}
|
|
84
|
+
error details:
|
|
85
|
+
{sep.join(self.errors)}
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
"""Error Doc Helper class
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@attr.s(auto_attribs=True, kw_only=True)
|
|
94
|
+
class ErrorDocHelper:
|
|
95
|
+
"""Error Doc Helper:
|
|
96
|
+
error_doc_url: link
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
ERROR_CODES_URL: str = "https://static-a.cdn.looker.app/errorcodes/"
|
|
100
|
+
lookup_dict: Dict[str, Dict[str, str]] = {}
|
|
101
|
+
RE_PATTERN: str = (
|
|
102
|
+
"""(https://docs\.looker\.com/r/err/|https://cloud\.google\.com/looker/docs/r/err/)(.*)/(\d{3})(.*)"""
|
|
103
|
+
)
|
|
104
|
+
pattern = re.compile(RE_PATTERN, flags=re.IGNORECASE)
|
|
105
|
+
|
|
106
|
+
def get_index(self, url: str = ERROR_CODES_URL) -> None:
|
|
107
|
+
r = requests.get(f"{url}index.json")
|
|
108
|
+
self.lookup_dict = json.loads(r.text)
|
|
109
|
+
|
|
110
|
+
def lookup(
|
|
111
|
+
self, url: str = ERROR_CODES_URL, code: str = "", path: str = ""
|
|
112
|
+
) -> Tuple[str, str]:
|
|
113
|
+
if len(self.lookup_dict) == 0:
|
|
114
|
+
self.get_index(url=url)
|
|
115
|
+
|
|
116
|
+
error_doc_url: str = ""
|
|
117
|
+
error_doc: str = ""
|
|
118
|
+
if path:
|
|
119
|
+
try:
|
|
120
|
+
error_doc_url = self.lookup_dict[f"{code}{path}"]["url"]
|
|
121
|
+
except KeyError:
|
|
122
|
+
error_doc = f"### No documentation found for {code}{path}"
|
|
123
|
+
if not error_doc_url:
|
|
124
|
+
try:
|
|
125
|
+
error_doc_url = self.lookup_dict[code]["url"]
|
|
126
|
+
except KeyError:
|
|
127
|
+
if not error_doc:
|
|
128
|
+
error_doc = f"### No documentation found for {code}"
|
|
129
|
+
|
|
130
|
+
if error_doc_url:
|
|
131
|
+
r = requests.get(f"{self.ERROR_CODES_URL}{error_doc_url}")
|
|
132
|
+
error_doc = r.text
|
|
133
|
+
|
|
134
|
+
return (f"{self.ERROR_CODES_URL}{error_doc_url}", error_doc)
|
|
135
|
+
|
|
136
|
+
def parse_and_lookup(
|
|
137
|
+
self, error_url: str, url: str = ERROR_CODES_URL
|
|
138
|
+
) -> Tuple[str, str]:
|
|
139
|
+
m = re.search(self.RE_PATTERN, error_url)
|
|
140
|
+
if not m:
|
|
141
|
+
return ("", "")
|
|
142
|
+
|
|
143
|
+
code: str = cast(Tuple[str, str, str, str], m.groups())[2]
|
|
144
|
+
path: str = cast(Tuple[str, str, str, str], m.groups())[3]
|
|
145
|
+
try:
|
|
146
|
+
return self.lookup(url=url, code=code, path=path)
|
|
147
|
+
except requests.exceptions.RequestException:
|
|
148
|
+
return ("", "")
|
looker_sdk/rtl/api_methods.py
CHANGED
|
@@ -87,7 +87,15 @@ class APIMethods:
|
|
|
87
87
|
value = response.value.decode(encoding=encoding)
|
|
88
88
|
sdk_error: error.SDKError
|
|
89
89
|
try:
|
|
90
|
-
sdk_error = self.deserialize(data=value, structure=error.SDKError)
|
|
90
|
+
sdk_error = self.deserialize(data=value, structure=error.SDKError) # type: ignore
|
|
91
|
+
helper = error.ErrorDocHelper()
|
|
92
|
+
(sdk_error.error_doc_url, sdk_error.error_doc) = (
|
|
93
|
+
helper.parse_and_lookup(sdk_error.documentation_url)
|
|
94
|
+
)
|
|
95
|
+
for e in sdk_error.errors:
|
|
96
|
+
(e.error_doc_url, e.error_doc) = helper.parse_and_lookup(
|
|
97
|
+
e.documentation_url
|
|
98
|
+
)
|
|
91
99
|
except serialize.DeserializeError:
|
|
92
100
|
raise error.SDKError(value)
|
|
93
101
|
raise sdk_error
|
looker_sdk/sdk/api40/models.py
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
# SOFTWARE.
|
|
22
22
|
#
|
|
23
23
|
|
|
24
|
-
#
|
|
24
|
+
# 340 API models: 257 Spec, 0 Request, 61 Write, 22 Enum
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
# NOTE: Do not edit this file generated by Looker SDK Codegen for API 4.0
|
|
@@ -5778,65 +5778,17 @@ InvestigativeContentType.__new__ = model.safe_enum__new__ # type: ignore
|
|
|
5778
5778
|
class JsonBi(model.Model):
|
|
5779
5779
|
"""
|
|
5780
5780
|
Attributes:
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
pivots: Pivots
|
|
5784
|
-
has_subtotals: If the query has subtotals
|
|
5785
|
-
has_totals: If the query has totals
|
|
5786
|
-
columns_truncated: If the query results hit the maximum column limit and additional columns were truncated
|
|
5787
|
-
filter_expression: Filter expression applied to the query results
|
|
5788
|
-
filters: Filters applied to the query results
|
|
5789
|
-
sql: Raw sql query. Null if user does not have permission to view sql
|
|
5790
|
-
data: Json query results
|
|
5781
|
+
metadata:
|
|
5782
|
+
rows: Json query results
|
|
5791
5783
|
"""
|
|
5792
5784
|
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
has_subtotals: bool
|
|
5797
|
-
has_totals: bool
|
|
5798
|
-
columns_truncated: str
|
|
5799
|
-
filter_expression: str
|
|
5800
|
-
filters: MutableMapping[str, Any]
|
|
5801
|
-
sql: str
|
|
5802
|
-
data: Sequence[str]
|
|
5803
|
-
__annotations__ = {
|
|
5804
|
-
"big_query_metadata": ForwardRef("JsonBiBigQueryMetadata"),
|
|
5805
|
-
"fields": ForwardRef("JsonBiFields"),
|
|
5806
|
-
"pivots": Sequence["JsonBiPivots"],
|
|
5807
|
-
"has_subtotals": bool,
|
|
5808
|
-
"has_totals": bool,
|
|
5809
|
-
"columns_truncated": str,
|
|
5810
|
-
"filter_expression": str,
|
|
5811
|
-
"filters": MutableMapping[str, Any],
|
|
5812
|
-
"sql": str,
|
|
5813
|
-
"data": Sequence[str],
|
|
5814
|
-
}
|
|
5785
|
+
metadata: "JsonBiMetadata"
|
|
5786
|
+
rows: Sequence[str]
|
|
5787
|
+
__annotations__ = {"metadata": ForwardRef("JsonBiMetadata"), "rows": Sequence[str]}
|
|
5815
5788
|
|
|
5816
|
-
def __init__(
|
|
5817
|
-
self
|
|
5818
|
-
|
|
5819
|
-
big_query_metadata: "JsonBiBigQueryMetadata",
|
|
5820
|
-
fields: "JsonBiFields",
|
|
5821
|
-
pivots: Sequence["JsonBiPivots"],
|
|
5822
|
-
has_subtotals: bool,
|
|
5823
|
-
has_totals: bool,
|
|
5824
|
-
columns_truncated: str,
|
|
5825
|
-
filter_expression: str,
|
|
5826
|
-
filters: MutableMapping[str, Any],
|
|
5827
|
-
sql: str,
|
|
5828
|
-
data: Sequence[str]
|
|
5829
|
-
):
|
|
5830
|
-
self.big_query_metadata = big_query_metadata
|
|
5831
|
-
self.fields = fields
|
|
5832
|
-
self.pivots = pivots
|
|
5833
|
-
self.has_subtotals = has_subtotals
|
|
5834
|
-
self.has_totals = has_totals
|
|
5835
|
-
self.columns_truncated = columns_truncated
|
|
5836
|
-
self.filter_expression = filter_expression
|
|
5837
|
-
self.filters = filters
|
|
5838
|
-
self.sql = sql
|
|
5839
|
-
self.data = data
|
|
5789
|
+
def __init__(self, *, metadata: "JsonBiMetadata", rows: Sequence[str]):
|
|
5790
|
+
self.metadata = metadata
|
|
5791
|
+
self.rows = rows
|
|
5840
5792
|
|
|
5841
5793
|
|
|
5842
5794
|
@attr.s(auto_attribs=True, init=False)
|
|
@@ -5941,6 +5893,66 @@ class JsonBiFields(model.Model):
|
|
|
5941
5893
|
self.pivots = pivots
|
|
5942
5894
|
|
|
5943
5895
|
|
|
5896
|
+
@attr.s(auto_attribs=True, init=False)
|
|
5897
|
+
class JsonBiMetadata(model.Model):
|
|
5898
|
+
"""
|
|
5899
|
+
Attributes:
|
|
5900
|
+
big_query_metadata:
|
|
5901
|
+
fields:
|
|
5902
|
+
pivots: Pivots
|
|
5903
|
+
has_subtotals: If the query has subtotals
|
|
5904
|
+
has_totals: If the query has totals
|
|
5905
|
+
columns_truncated: If the query results hit the maximum column limit and additional columns were truncated
|
|
5906
|
+
filter_expression: Filter expression applied to the query results
|
|
5907
|
+
filters: Filters applied to the query results
|
|
5908
|
+
sql: Raw sql query. Null if user does not have permission to view sql
|
|
5909
|
+
"""
|
|
5910
|
+
|
|
5911
|
+
big_query_metadata: "JsonBiBigQueryMetadata"
|
|
5912
|
+
fields: "JsonBiFields"
|
|
5913
|
+
pivots: Sequence["JsonBiPivots"]
|
|
5914
|
+
has_subtotals: bool
|
|
5915
|
+
has_totals: bool
|
|
5916
|
+
columns_truncated: str
|
|
5917
|
+
filter_expression: str
|
|
5918
|
+
filters: MutableMapping[str, Any]
|
|
5919
|
+
sql: str
|
|
5920
|
+
__annotations__ = {
|
|
5921
|
+
"big_query_metadata": ForwardRef("JsonBiBigQueryMetadata"),
|
|
5922
|
+
"fields": ForwardRef("JsonBiFields"),
|
|
5923
|
+
"pivots": Sequence["JsonBiPivots"],
|
|
5924
|
+
"has_subtotals": bool,
|
|
5925
|
+
"has_totals": bool,
|
|
5926
|
+
"columns_truncated": str,
|
|
5927
|
+
"filter_expression": str,
|
|
5928
|
+
"filters": MutableMapping[str, Any],
|
|
5929
|
+
"sql": str,
|
|
5930
|
+
}
|
|
5931
|
+
|
|
5932
|
+
def __init__(
|
|
5933
|
+
self,
|
|
5934
|
+
*,
|
|
5935
|
+
big_query_metadata: "JsonBiBigQueryMetadata",
|
|
5936
|
+
fields: "JsonBiFields",
|
|
5937
|
+
pivots: Sequence["JsonBiPivots"],
|
|
5938
|
+
has_subtotals: bool,
|
|
5939
|
+
has_totals: bool,
|
|
5940
|
+
columns_truncated: str,
|
|
5941
|
+
filter_expression: str,
|
|
5942
|
+
filters: MutableMapping[str, Any],
|
|
5943
|
+
sql: str
|
|
5944
|
+
):
|
|
5945
|
+
self.big_query_metadata = big_query_metadata
|
|
5946
|
+
self.fields = fields
|
|
5947
|
+
self.pivots = pivots
|
|
5948
|
+
self.has_subtotals = has_subtotals
|
|
5949
|
+
self.has_totals = has_totals
|
|
5950
|
+
self.columns_truncated = columns_truncated
|
|
5951
|
+
self.filter_expression = filter_expression
|
|
5952
|
+
self.filters = filters
|
|
5953
|
+
self.sql = sql
|
|
5954
|
+
|
|
5955
|
+
|
|
5944
5956
|
@attr.s(auto_attribs=True, init=False)
|
|
5945
5957
|
class JsonBiPivots(model.Model):
|
|
5946
5958
|
"""
|
looker_sdk/sdk/constants.py
CHANGED
looker_sdk/version.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
looker_sdk/__init__.py,sha256=0UOw2v-BP1bNoBIIm-BnyKUpGQB3Zx-JZRmpYyLiIuY,2589
|
|
2
|
-
looker_sdk/error.py,sha256=
|
|
2
|
+
looker_sdk/error.py,sha256=4HKjj1f9pZ73USBSMoV5SOFbl8p4VyBBywKUWQGmdiw,4920
|
|
3
3
|
looker_sdk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
looker_sdk/version.py,sha256=
|
|
4
|
+
looker_sdk/version.py,sha256=VK50Bg5ftY_S2Mph7SAlt0BZn44HzNunxRW3dOGJ9lo,1155
|
|
5
5
|
looker_sdk/rtl/__init__.py,sha256=hgj6CO_Du2XcJ4bRYbhaVS3dvLxjCqPQDR8KwD9IPTQ,1132
|
|
6
|
-
looker_sdk/rtl/api_methods.py,sha256=
|
|
6
|
+
looker_sdk/rtl/api_methods.py,sha256=J-dm7UMyJajsJDCB0JMpGUmp80I8oPMs7cggdIaCWng,8862
|
|
7
7
|
looker_sdk/rtl/api_settings.py,sha256=0QbmNhfgjBJNnr1CNEMxCHoiu908jT8amAtSAha1xS8,6953
|
|
8
8
|
looker_sdk/rtl/auth_session.py,sha256=lLhj7dZfBOtzqUYeAds8x-7DOkp1q-hEWKzw9heqetA,13064
|
|
9
9
|
looker_sdk/rtl/auth_token.py,sha256=dRHNmwZPczYZ1KhRQbfye60rpGhHQN8TSofprMOjG3A,3635
|
|
@@ -14,10 +14,10 @@ looker_sdk/rtl/requests_transport.py,sha256=2lckuJyjeySAuAn7v-RA_xTjjWe53uCCLSWg
|
|
|
14
14
|
looker_sdk/rtl/serialize.py,sha256=Arm26aGLOhW-uUW4qgV1tTna83A3gNMYcF9YwRvf0gQ,4418
|
|
15
15
|
looker_sdk/rtl/transport.py,sha256=zNCaGmmJBtF87iLS6xtSTwiyEXP0BDdMJafPn0_tIrk,3911
|
|
16
16
|
looker_sdk/sdk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
-
looker_sdk/sdk/constants.py,sha256=
|
|
17
|
+
looker_sdk/sdk/constants.py,sha256=wjstQ4zDIQ4E_HAeleue9bmO0BuL0gYML-jRw2BSxdc,1186
|
|
18
18
|
looker_sdk/sdk/api40/__init__.py,sha256=Dvx1t9vDBvgEl-p1eeP7ebEC6Q6wb6rASPi7nx3z7dg,18
|
|
19
19
|
looker_sdk/sdk/api40/methods.py,sha256=sS2M9ASLWTTT_538NT9vATS9WQdkmUoH0Q6JsxuSWS8,511713
|
|
20
|
-
looker_sdk/sdk/api40/models.py,sha256=
|
|
20
|
+
looker_sdk/sdk/api40/models.py,sha256=RpgOyk0KTOwZPiYNxsSMa2TikwTrsN3ikx-kN5iYAGg,622211
|
|
21
21
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
22
|
tests/conftest.py,sha256=ZLymw2rfMVus_CRBbbcxpK3_rEpMJRMQX9A5m2aQgQs,3895
|
|
23
23
|
tests/integration/__init__.py,sha256=K4tvUu8CgFRwtDhDNixHKDDb8uubXgevQBq8JmZvf8Y,63
|
|
@@ -31,8 +31,8 @@ tests/rtl/test_auth_token.py,sha256=Ep4u0ushHqKiIkGgw-XVn1lSzPeH6pVmDB2bw-MXNAo,
|
|
|
31
31
|
tests/rtl/test_requests_transport.py,sha256=mSsxudpAkKe-uSVOIzDrV0XCFlj_ACt6T1yzbUbuwG0,5442
|
|
32
32
|
tests/rtl/test_serialize.py,sha256=1SC8jigZFFL3mrU2oSTnc2nbDxXve224_r3GaxEeU90,25917
|
|
33
33
|
tests/rtl/test_transport.py,sha256=tI83LYOeuWEmkngXyRqMjW-pv-ipLPLj4t0hGD8zqL8,1555
|
|
34
|
-
looker_sdk-24.
|
|
35
|
-
looker_sdk-24.
|
|
36
|
-
looker_sdk-24.
|
|
37
|
-
looker_sdk-24.
|
|
38
|
-
looker_sdk-24.
|
|
34
|
+
looker_sdk-24.4.0.dist-info/LICENSE.txt,sha256=N4Rmmbuo5EryYSCXcvjuXL1ZXwyXanRzuGP-dJzwsoE,1094
|
|
35
|
+
looker_sdk-24.4.0.dist-info/METADATA,sha256=1y4XLvsFSmaZupccJqvMRiTs25mTkJ5BW2lD-43WQgQ,7027
|
|
36
|
+
looker_sdk-24.4.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
37
|
+
looker_sdk-24.4.0.dist-info/top_level.txt,sha256=tDPNJRQM_A_Oncxlgxwvnzq7hZDWZaadt_nR8DmORTI,17
|
|
38
|
+
looker_sdk-24.4.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|