rbx 3.21.1.dev179__tar.gz → 3.22.0.dev181__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/PKG-INFO +1 -1
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/pyproject.toml +2 -2
- rbx-3.22.0.dev181/rbx/__init__.py +1 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/clients/__init__.py +2 -13
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/clients/adsquare.py +1 -70
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/clients/place.py +0 -23
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx.egg-info/PKG-INFO +1 -1
- rbx-3.21.1.dev179/rbx/__init__.py +0 -1
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/LICENSE +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/README.md +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/auth/__init__.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/auth/decorators.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/auth/id_token.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/auth/keystore.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/auth/mock.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/aws/__init__.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/aws/s3.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/buildtools/__init__.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/buildtools/cli.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/buildtools/tasks/__init__.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/buildtools/tasks/ec2.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/buildtools/tasks/image.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/buildtools/tasks/misc.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/clients/broadsign.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/clients/oxr.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/clients/panels.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/clients/reporting.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/clients/retry.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/exceptions.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/gcp/__init__.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/gcp/cloud_tasks.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/gcp/pubsub.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/gcp/storage.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/logging.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/settings.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/utils/__init__.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/utils/mdm.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/utils/vast.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/web/__init__.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx/web/handlers.py +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx.egg-info/SOURCES.txt +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx.egg-info/dependency_links.txt +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx.egg-info/entry_points.txt +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx.egg-info/requires.txt +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/rbx.egg-info/top_level.txt +0 -0
- {rbx-3.21.1.dev179 → rbx-3.22.0.dev181}/setup.cfg +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "rbx"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.22.0.dev181"
|
|
8
8
|
description = "A collection of common tools for Scoota services."
|
|
9
9
|
authors = [
|
|
10
10
|
{ name = "The Scoota Engineering Team", email = "engineering@scoota.com" }
|
|
@@ -80,7 +80,7 @@ homepage = "https://github.com/rockabox/rbx"
|
|
|
80
80
|
repository = "https://github.com/rockabox/rbx.git"
|
|
81
81
|
|
|
82
82
|
[tool.bumpversion]
|
|
83
|
-
current_version = "3.
|
|
83
|
+
current_version = "3.22.0.dev181"
|
|
84
84
|
commit = true
|
|
85
85
|
parse = """
|
|
86
86
|
(?P<major>\\d+)\\.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "3.22.0.dev181"
|
|
@@ -124,7 +124,6 @@ class Client(metaclass=Singleton):
|
|
|
124
124
|
headers=None,
|
|
125
125
|
params=None,
|
|
126
126
|
timeout=None,
|
|
127
|
-
include_headers=False,
|
|
128
127
|
):
|
|
129
128
|
"""Wrap the method call in common error handling."""
|
|
130
129
|
endpoint = endpoint if endpoint is not None else self.ENDPOINT
|
|
@@ -218,15 +217,13 @@ class Client(metaclass=Singleton):
|
|
|
218
217
|
|
|
219
218
|
# 204 "No Content" responses return nothing
|
|
220
219
|
if response.status_code == 204:
|
|
221
|
-
if include_headers:
|
|
222
|
-
return {"content": None, "headers": dict(response.headers)}
|
|
223
220
|
return
|
|
224
221
|
|
|
225
222
|
if content_type == "text/plain":
|
|
226
|
-
|
|
223
|
+
return response.text
|
|
227
224
|
else:
|
|
228
225
|
try:
|
|
229
|
-
|
|
226
|
+
return self.get_response(response)
|
|
230
227
|
except ValueError:
|
|
231
228
|
extra = {
|
|
232
229
|
"request": payload,
|
|
@@ -236,12 +233,6 @@ class Client(metaclass=Singleton):
|
|
|
236
233
|
"Invalid JSON response", details=extra, status_code=500, url=url
|
|
237
234
|
)
|
|
238
235
|
|
|
239
|
-
# Return content with headers if requested, otherwise just content
|
|
240
|
-
if include_headers:
|
|
241
|
-
return {"content": content, "headers": dict(response.headers)}
|
|
242
|
-
else:
|
|
243
|
-
return content
|
|
244
|
-
|
|
245
236
|
def request(
|
|
246
237
|
self,
|
|
247
238
|
method,
|
|
@@ -252,7 +243,6 @@ class Client(metaclass=Singleton):
|
|
|
252
243
|
headers=None,
|
|
253
244
|
params=None,
|
|
254
245
|
timeout=None,
|
|
255
|
-
include_headers=False,
|
|
256
246
|
):
|
|
257
247
|
"""Attempt to re-authenticate when the token has expired.
|
|
258
248
|
|
|
@@ -271,7 +261,6 @@ class Client(metaclass=Singleton):
|
|
|
271
261
|
headers=headers,
|
|
272
262
|
params=params,
|
|
273
263
|
timeout=timeout,
|
|
274
|
-
include_headers=include_headers,
|
|
275
264
|
)
|
|
276
265
|
|
|
277
266
|
try:
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import csv
|
|
2
2
|
from io import StringIO
|
|
3
3
|
import logging
|
|
4
|
-
from os import path
|
|
5
|
-
import shelve
|
|
6
4
|
|
|
7
5
|
import arrow
|
|
8
6
|
|
|
@@ -25,11 +23,10 @@ class AdsquareClient(Client):
|
|
|
25
23
|
STANDARD_COMPANY_ID = "588b6428e4b0d7d5f6895bd1"
|
|
26
24
|
TIME_FORMAT = "YYYY-MM-DDTHH:mm:ss.SSS[Z]"
|
|
27
25
|
|
|
28
|
-
def __init__(self, company_id, dsp_id
|
|
26
|
+
def __init__(self, company_id, dsp_id):
|
|
29
27
|
super().__init__()
|
|
30
28
|
self.company_id = company_id
|
|
31
29
|
self.dsp_id = dsp_id
|
|
32
|
-
self.shelf = path.join(destination, "adsquare.segments")
|
|
33
30
|
|
|
34
31
|
@property
|
|
35
32
|
def auth(self):
|
|
@@ -83,62 +80,6 @@ class AdsquareClient(Client):
|
|
|
83
80
|
|
|
84
81
|
return pois
|
|
85
82
|
|
|
86
|
-
def get_segments(self, company_ids=None, country_code=None):
|
|
87
|
-
"""Get segments from local cache."""
|
|
88
|
-
with shelve.open(self.shelf) as shelf:
|
|
89
|
-
try:
|
|
90
|
-
segments = shelf["segments"]
|
|
91
|
-
except KeyError:
|
|
92
|
-
# The cache is empty
|
|
93
|
-
segments = []
|
|
94
|
-
|
|
95
|
-
# Always include Standard segments (i.e.: Company ID = adsquare).
|
|
96
|
-
company_ids = company_ids or []
|
|
97
|
-
company_ids.append(self.STANDARD_COMPANY_ID)
|
|
98
|
-
|
|
99
|
-
# Exclude company_ids that are either None or empty.
|
|
100
|
-
company_ids[:] = [cid for cid in company_ids if cid]
|
|
101
|
-
|
|
102
|
-
segment_list = []
|
|
103
|
-
for segment in segments:
|
|
104
|
-
if segment["company_id"] not in company_ids:
|
|
105
|
-
continue
|
|
106
|
-
if country_code and country_code not in [segment["country"], "ZZ"]:
|
|
107
|
-
continue
|
|
108
|
-
segment_list.append(segment)
|
|
109
|
-
|
|
110
|
-
return segment_list
|
|
111
|
-
|
|
112
|
-
@retry.Retry(deadline=300.0)
|
|
113
|
-
def list_segments(self):
|
|
114
|
-
"""List all segments available.
|
|
115
|
-
|
|
116
|
-
According to the documentation, there is no pagination on this endpoint, so we expect the
|
|
117
|
-
full list to be returned with a single call.
|
|
118
|
-
|
|
119
|
-
See: https://docs.adsquare.com/#!/enrichmentMetaApi/getEnrichmentAudiences_1
|
|
120
|
-
"""
|
|
121
|
-
path = f"enrichmentMeta/audiences/{self.dsp_id}"
|
|
122
|
-
response = self.request("get", path, data={"namev2": "true"})
|
|
123
|
-
|
|
124
|
-
return [
|
|
125
|
-
{
|
|
126
|
-
"company_id": audience["companyId"],
|
|
127
|
-
"country": audience["countryCode"],
|
|
128
|
-
"cpm": audience["cpm"],
|
|
129
|
-
"currency": audience["currency"],
|
|
130
|
-
"id": audience["audienceId"],
|
|
131
|
-
"name": audience["name"],
|
|
132
|
-
"owner": (
|
|
133
|
-
"Standard"
|
|
134
|
-
if audience["companyId"] == self.STANDARD_COMPANY_ID
|
|
135
|
-
else "Custom"
|
|
136
|
-
),
|
|
137
|
-
"type": audience["type"],
|
|
138
|
-
}
|
|
139
|
-
for audience in response["audiences"]
|
|
140
|
-
]
|
|
141
|
-
|
|
142
83
|
def pause_config(self, config_id):
|
|
143
84
|
"""Pause the given configuration."""
|
|
144
85
|
self.update_config(config_id=config_id, active=False)
|
|
@@ -168,16 +109,6 @@ class AdsquareClient(Client):
|
|
|
168
109
|
"""Resume the given configuration."""
|
|
169
110
|
self.update_config(config_id=config_id, active=True)
|
|
170
111
|
|
|
171
|
-
def store_segments(self):
|
|
172
|
-
"""Retrieve the list of segments, and then cache the results on a shelf.
|
|
173
|
-
|
|
174
|
-
As no caching mechanism exists on the API, we simply override the content of the cache
|
|
175
|
-
with the results from the list_segments() call.
|
|
176
|
-
"""
|
|
177
|
-
segments = self.list_segments()
|
|
178
|
-
with shelve.open(self.shelf) as shelf:
|
|
179
|
-
shelf["segments"] = segments
|
|
180
|
-
|
|
181
112
|
@retry.Retry(deadline=300.0)
|
|
182
113
|
def update_config(self, config_id, active=None, start_date=None, end_date=None):
|
|
183
114
|
"""Update the given configuration ID.
|
|
@@ -275,26 +275,3 @@ class PlaceExchangeClient(Client):
|
|
|
275
275
|
path=path,
|
|
276
276
|
params=params if params else None,
|
|
277
277
|
)
|
|
278
|
-
|
|
279
|
-
def get_screens(self, page=None):
|
|
280
|
-
"""Retrieve a page of screens from Place Exchange."""
|
|
281
|
-
path = f"v3/orgs/{self.org_id}/avails"
|
|
282
|
-
params = {"page_size": 1000}
|
|
283
|
-
|
|
284
|
-
if page:
|
|
285
|
-
params["page"] = page
|
|
286
|
-
|
|
287
|
-
response = self.request("get", path, params=params, include_headers=True)
|
|
288
|
-
|
|
289
|
-
# Extract the page for the next page from the Link header if it exists
|
|
290
|
-
next_page = None
|
|
291
|
-
if "Link" in response["headers"]:
|
|
292
|
-
links = response["headers"]["Link"].split(",")
|
|
293
|
-
for link in links:
|
|
294
|
-
if "rel='next'" in link:
|
|
295
|
-
# Extract the page parameter from the URL
|
|
296
|
-
url_part = link.split(";")[0].strip("<>")
|
|
297
|
-
if "page=" in url_part:
|
|
298
|
-
next_page = int(url_part.split("page=")[1].split("&")[0])
|
|
299
|
-
|
|
300
|
-
return response["content"], next_page
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "3.21.1.dev179"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|