FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
python-amazon-mws/mws/utils/params.py at develop · python-amazon-mws/python-amazon-mws · GitHub
Uh oh!
There was an error while loading.
Please reload this page
.
This repository was archived by the owner on Jan 4, 2025. It is now read-only.
python-amazon-mws
/
python-amazon-mws
Public archive
Notifications
You must be signed in to change notification settings
Fork
204
Star
380
Code
Issues
2
Pull requests
1
Discussions
Actions
Projects
Security and quality
0
Insights
Additional navigation options
Code
Issues
Pull requests
Discussions
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
python-amazon-mws
/
mws
/
utils
/
params.py
Copy path
More file actions
More file actions
Latest commit
History
History
History
277 lines (224 loc) · 9.36 KB
Breadcrumbs
python-amazon-mws
/
mws
/
utils
/
params.py
Copy path
File metadata and controls
277 lines (224 loc) · 9.36 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
"""Parameter manipulation utilities."""
import
datetime
import
json
from
collections
.
abc
import
Iterable
,
Mapping
from
enum
import
Enum
from
typing
import
Any
,
List
,
Union
from
urllib
.
parse
import
quote
def
enumerate_param
(
param
:
str
,
values
:
Union
[
list
,
set
,
tuple
])
->
dict
:
"""Builds a dictionary of an enumerated parameter, using the param string and some values.
If values is not a list, tuple, or set, it will be coerced to a list
with a single item.
Example:
enumerate_param('MarketplaceIdList.Id', (123, 345, 4343))
Returns:
{
MarketplaceIdList.Id.1: 123,
MarketplaceIdList.Id.2: 345,
MarketplaceIdList.Id.3: 4343
}
"""
if
not
isinstance
(
values
, (
list
,
set
,
tuple
)):
# Coerces a single value to a list before continuing.
values
=
[
values
]
if
not
any
(
values
):
# if not values -> returns ValueError
return
{}
param
=
dot_appended_param
(
param
)
# Return final output: dict comprehension of the enumerated param and values.
return
{
f"
{
param
}
{
idx
}
"
:
val
for
idx
,
val
in
enumerate
(
values
,
start
=
1
)}
def
enumerate_params
(
params
:
Mapping
=
None
)
->
dict
:
"""For each param and values, runs enumerate_param,
returning a flat dict of all results
"""
if
not
params
or
not
isinstance
(
params
,
Mapping
):
return
{}
params_output
=
{}
for
param
,
values
in
params
.
items
():
params_output
.
update
(
enumerate_param
(
param
,
values
))
return
params_output
def
enumerate_keyed_param
(
param
:
str
,
values
:
List
[
Mapping
])
->
dict
:
"""Given a param string and a list of values dicts, returns a flat dict of keyed, enumerated params.
Each dict in the values list must pertain to a single item and its data points.
Example:
param = "InboundShipmentPlanRequestItems.member"
values = [
{'SellerSKU': 'Football2415',
'Quantity': 3},
{'SellerSKU': 'TeeballBall3251',
'Quantity': 5},
...
]
Returns:
{
'InboundShipmentPlanRequestItems.member.1.SellerSKU': 'Football2415',
'InboundShipmentPlanRequestItems.member.1.Quantity': 3,
'InboundShipmentPlanRequestItems.member.2.SellerSKU': 'TeeballBall3251',
'InboundShipmentPlanRequestItems.member.2.Quantity': 5,
...
}
"""
if
not
isinstance
(
values
, (
list
,
set
,
tuple
)):
# If it's a single value, convert it to a list first
values
=
[
values
]
if
not
any
(
values
):
# Shortcut for empty values
return
{}
param
=
dot_appended_param
(
param
)
for
val
in
values
:
# Every value in the list must be a dict.
if
not
isinstance
(
val
,
dict
):
# Value is not a dict: can't work on it here.
raise
ValueError
(
(
"Non-dict value detected. "
"`values` must be a list, tuple, or set; containing only dicts."
)
)
params
=
{}
for
idx
,
val_dict
in
enumerate
(
values
,
start
=
1
):
# Build the final output.
params
.
update
({
f"
{
param
}
{
idx
}
.
{
k
}
"
:
v
for
k
,
v
in
val_dict
.
items
()})
return
params
def
dict_keyed_param
(
param
:
str
,
dict_from
:
Mapping
)
->
dict
:
"""Given a param string and a dict, returns a flat dict of keyed params without enumerate.
Example:
param = "ShipmentRequestDetails.PackageDimensions"
dict_from = {'Length': 5, 'Width': 5, 'Height': 5, 'Unit': 'inches'}
Returns:
{
'ShipmentRequestDetails.PackageDimensions.Length': 5,
'ShipmentRequestDetails.PackageDimensions.Width': 5,
'ShipmentRequestDetails.PackageDimensions.Height': 5,
'ShipmentRequestDetails.PackageDimensions.Unit': 'inches',
...
}
"""
params
=
{}
param
=
dot_appended_param
(
param
)
for
k
,
v
in
dict_from
.
items
():
params
.
update
({
f"
{
param
}
{
k
}
"
:
v
})
return
params
def
flat_param_dict
(
value
:
Union
[
str
,
Mapping
,
List
],
prefix
:
str
=
""
)
->
dict
:
"""Returns a flattened params dictionary by collapsing nested dicts and
non-string iterables.
Any arbitrarily-nested dict or iterable will be expanded and flattened.
- Each key in a child dict will be concatenated to its parent key.
- Elements of a non-string iterable will be enumerated using a 1-based index,
with the index number concatenated to the parent key.
- In both cases, keys and sub-keys are joined by ``.``.
If ``prefix`` is set, all keys in the resulting output will begin with
``prefix + '.'``.
"""
prefix
=
""
if
not
prefix
else
str
(
prefix
)
# Prefix is now either an empty string or a valid prefix string ending in '.'
# NOTE should ensure that a `None` value is changed to empty string, as well.
if
isinstance
(
value
,
str
)
or
not
isinstance
(
value
, (
Mapping
,
Iterable
)):
# Value is not one of the types we want to expand.
if
prefix
:
# Can return a single dict of the prefix and value as a base case
prefix
=
dot_appended_param
(
prefix
,
reverse
=
True
)
return
{
prefix
:
value
}
raise
ValueError
(
(
"Non-dict, non-iterable value requires a prefix "
"(would return a mapping of `prefix: value`)"
)
)
# Past here, the value is something that must be expanded.
# We'll build that output with recursive calls to `flat_param_dict`.
if
prefix
:
prefix
=
dot_appended_param
(
prefix
)
output
=
{}
if
isinstance
(
value
,
Mapping
):
for
key
,
val
in
value
.
items
():
new_key
=
f"
{
prefix
}
{
key
}
"
output
.
update
(
flat_param_dict
(
val
,
prefix
=
new_key
))
else
:
# value must be an Iterable
for
idx
,
val
in
enumerate
(
value
,
start
=
1
):
new_key
=
f"
{
prefix
}
{
idx
}
"
output
.
update
(
flat_param_dict
(
val
,
prefix
=
new_key
))
return
output
def
dot_appended_param
(
param_key
:
str
,
reverse
:
bool
=
False
):
"""Returns ``param_key`` string, ensuring that it ends with ``'.'``.
Set ``reverse`` to ``True`` (default ``False``) to reverse this behavior,
ensuring that ``param_key`` *does not* end with ``'.'``.
"""
if
not
param_key
.
endswith
(
"."
):
# Ensure this enumerated param ends in '.'
param_key
+=
"."
if
reverse
:
# Since param_key is guaranteed to end with '.' by this point,
# if `reverse` flag was set, now we just get rid of it.
param_key
=
param_key
[:
-
1
]
return
param_key
BOOL_FALSE_STRINGS
=
(
"no"
,
"n"
,
"none"
,
"off"
,
"false"
,
"0"
)
def
coerce_to_bool
(
val
:
Any
)
->
bool
:
"""Coerces ``val`` to a boolean for use in MWS requests.
If ``val`` is a string, converts certain (case-insensitive) string values
to "False", such as:
- "no"
- "n"
- "none"
- "off"
- "false"
- "0"
Otherwise, ``val`` is simply cast using built-in ``bool()`` function.
"""
if
isinstance
(
val
,
str
)
and
val
.
lower
()
in
BOOL_FALSE_STRINGS
:
return
False
return
bool
(
val
)
def
remove_empty_param_keys
(
params
:
Mapping
)
->
dict
:
"""Returns a copy of ``params`` dict where any key with a value of ``None``
or ``""`` (empty string) are removed.
"""
return
{
k
:
v
for
k
,
v
in
params
.
items
()
if
v
is
not
None
and
v
!=
""
}
def
clean_params_dict
(
params
:
Mapping
,
urlencode
=
False
)
->
dict
:
"""Clean multiple param values in a dict, returning a new dict
containing the original keys and cleaned values.
"""
cleaned_params
=
dict
()
for
key
,
val
in
params
.
items
():
newval
=
clean_value
(
val
)
if
urlencode
:
newval
=
quote
(
val
,
safe
=
"-_.~"
)
cleaned_params
[
key
]
=
newval
return
cleaned_params
def
clean_value
(
val
:
Any
)
->
str
:
"""Attempts to clean a value so that it can be sent in a request."""
if
isinstance
(
val
, (
Mapping
,
list
,
set
,
tuple
)):
raise
ValueError
(
"Cannot clean parameter value of type %s"
%
str
(
type
(
val
)))
if
isinstance
(
val
, (
datetime
.
datetime
,
datetime
.
date
)):
return
clean_date
(
val
)
if
isinstance
(
val
,
bool
):
return
clean_bool
(
val
)
if
isinstance
(
val
,
Enum
):
return
clean_enum
(
val
)
# For all else, simply convert to a string value.
return
str
(
val
)
def
clean_bool
(
val
:
bool
)
->
str
:
"""Converts a boolean value to its JSON string equivalent."""
if
val
is
not
True
and
val
is
not
False
:
raise
ValueError
(
"Expected a boolean, got %s"
%
val
)
return
json
.
dumps
(
val
)
def
clean_date
(
val
:
Union
[
datetime
.
datetime
,
datetime
.
date
])
->
str
:
"""Converts a datetime.datetime or datetime.date to ISO 8601 string.
Further passes that string through `urllib.parse.quote`.
"""
return
val
.
isoformat
()
def
clean_enum
(
val
:
Union
[
Enum
,
str
])
->
str
:
"""Simply put, converts an Enum to its ``.value`` attribute.
All known MWS Enum classes *should* return a proper value in this case.
"""
return
val
.
value
def
iterable_param
(
val
)
->
Iterable
:
"""Wraps single values (that are *not* non-string iterables) as a list.
Used for methods that require some iterable value that should be enumerated
(without exploding string values into enumerated lists of their characters).
"""
# Special case: strings are iterables, too, but shouldn't be treated the same.
# TODO make the type check at the end more generic?
if
isinstance
(
val
,
str
)
or
not
isinstance
(
val
,
Iterable
):
return
[
val
]
return
val
Back
|
FazBrowse Home
|
New Git URL