Skip to content

Commit c545e12

Browse files
author
rllin
authored
[BACKEND-826] yapf enforcer + yapf entire repo (#33)
* Create python-package.yml * fix syntax errors * remove unused function * env key * test against prod * let tox manage pyenv for now * tox gh actions * install python * environ chooser * fix * move environ to conftest * environ * remove import * fix * fix * prod * fix * no comments * fix * fix * fix * fix * yapf in action * yapf * yapf
1 parent 6be1a12 commit c545e12

33 files changed

+353
-292
lines changed

.github/workflows/python-package.yml

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
2-
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
3-
4-
name: Python package
1+
name: Labelbox Python SDK
52

63
on:
74
push:
@@ -11,6 +8,8 @@ on:
118

129
jobs:
1310
build:
11+
if: github.event.pull_request.head.repo.full_name == github.repository
12+
1413
runs-on: ubuntu-latest
1514
strategy:
1615
max-parallel: 1
@@ -19,22 +18,33 @@ jobs:
1918

2019
steps:
2120
- uses: actions/checkout@v2
21+
with:
22+
token: ${{ secrets.ACTIONS_ACCESS_TOKEN }}
23+
ref: ${{ github.head_ref }}
2224

2325
- name: Set up Python ${{ matrix.python-version }}
2426
uses: actions/setup-python@v2
2527
with:
2628
python-version: ${{ matrix.python-version }}
27-
- name: Install dependencies
29+
30+
- name: yapf
31+
id: yapf
32+
uses: AlexanderMelde/yapf-action@master
33+
with:
34+
args: --verbose --recursive --parallel --style "google"
35+
36+
- name: install labelbox package
2837
run: |
29-
python -m pip install --upgrade pip
30-
pip install flake8 tox tox-gh-actions
3138
python setup.py install
32-
- name: Lint with flake8
39+
- name: mypy
3340
run: |
34-
# stop the build if there are Python syntax errors or undefined names
35-
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
36-
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
37-
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
41+
python -m pip install --upgrade pip
42+
pip install mypy==0.782
43+
mypy -p labelbox --pretty --show-error-codes
44+
- name: Install package and test dependencies
45+
run: |
46+
pip install tox==3.18.1 tox-gh-actions==1.3.0
47+
3848
- name: Test with tox
3949
env:
4050
# make sure to tell tox to use these environs in tox.ini
@@ -45,4 +55,4 @@ jobs:
4555
# the main branch which is develop right now
4656
LABELBOX_TEST_ENVIRON: "PROD"
4757
run: |
48-
tox -- -svv
58+
tox -- -svv

labelbox/client.py

Lines changed: 40 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,8 @@
1818
from labelbox.schema.organization import Organization
1919
from labelbox.schema.labeling_frontend import LabelingFrontend
2020

21-
2221
logger = logging.getLogger(__name__)
2322

24-
2523
_LABELBOX_API_KEY = "LABELBOX_API_KEY"
2624

2725

@@ -31,7 +29,8 @@ class Client:
3129
querying and creating top-level data objects (Projects, Datasets).
3230
"""
3331

34-
def __init__(self, api_key=None,
32+
def __init__(self,
33+
api_key=None,
3534
endpoint='https://api.labelbox.com/graphql'):
3635
""" Creates and initializes a Labelbox Client.
3736
@@ -54,9 +53,11 @@ def __init__(self, api_key=None,
5453
logger.info("Initializing Labelbox client at '%s'", endpoint)
5554

5655
self.endpoint = endpoint
57-
self.headers = {'Accept': 'application/json',
58-
'Content-Type': 'application/json',
59-
'Authorization': 'Bearer %s' % api_key}
56+
self.headers = {
57+
'Accept': 'application/json',
58+
'Content-Type': 'application/json',
59+
'Authorization': 'Bearer %s' % api_key
60+
}
6061

6162
def execute(self, query, params=None, timeout=10.0):
6263
""" Sends a request to the server for the execution of the
@@ -95,15 +96,17 @@ def convert_value(value):
9596
return value
9697

9798
if params is not None:
98-
params = {key: convert_value(value) for key, value in params.items()}
99+
params = {
100+
key: convert_value(value) for key, value in params.items()
101+
}
99102

100-
data = json.dumps(
101-
{'query': query, 'variables': params}).encode('utf-8')
103+
data = json.dumps({'query': query, 'variables': params}).encode('utf-8')
102104

103105
try:
104-
response = requests.post(self.endpoint, data=data,
105-
headers=self.headers,
106-
timeout=timeout)
106+
response = requests.post(self.endpoint,
107+
data=data,
108+
headers=self.headers,
109+
timeout=timeout)
107110
logger.debug("Response: %s", response.text)
108111
except requests.exceptions.Timeout as e:
109112
raise labelbox.exceptions.TimeoutError(str(e))
@@ -136,8 +139,8 @@ def check_errors(keywords, *path):
136139
return error
137140
return None
138141

139-
if check_errors(["AUTHENTICATION_ERROR"],
140-
"extensions", "exception", "code") is not None:
142+
if check_errors(["AUTHENTICATION_ERROR"], "extensions", "exception",
143+
"code") is not None:
141144
raise labelbox.exceptions.AuthenticationError("Invalid API key")
142145

143146
authorization_error = check_errors(["AUTHORIZATION_ERROR"],
@@ -155,7 +158,8 @@ def check_errors(keywords, *path):
155158
else:
156159
raise labelbox.exceptions.InvalidQueryError(message)
157160

158-
graphql_error = check_errors(["GRAPHQL_PARSE_FAILED"], "extensions", "code")
161+
graphql_error = check_errors(["GRAPHQL_PARSE_FAILED"], "extensions",
162+
"code")
159163
if graphql_error is not None:
160164
raise labelbox.exceptions.InvalidQueryError(
161165
graphql_error["message"])
@@ -167,8 +171,8 @@ def check_errors(keywords, *path):
167171

168172
if len(errors) > 0:
169173
logger.warning("Unparsed errors on query execution: %r", errors)
170-
raise labelbox.exceptions.LabelboxError(
171-
"Unknown error: %s" % str(errors))
174+
raise labelbox.exceptions.LabelboxError("Unknown error: %s" %
175+
str(errors))
172176

173177
return response["data"]
174178

@@ -201,24 +205,30 @@ def upload_data(self, data):
201205
labelbox.exceptions.LabelboxError: If upload failed.
202206
"""
203207
request_data = {
204-
"operations": json.dumps({
205-
"variables": {"file": None, "contentLength": len(data), "sign": False},
206-
"query": """mutation UploadFile($file: Upload!, $contentLength: Int!,
208+
"operations":
209+
json.dumps({
210+
"variables": {
211+
"file": None,
212+
"contentLength": len(data),
213+
"sign": False
214+
},
215+
"query":
216+
"""mutation UploadFile($file: Upload!, $contentLength: Int!,
207217
$sign: Boolean) {
208218
uploadFile(file: $file, contentLength: $contentLength,
209-
sign: $sign) {url filename} } """,}),
219+
sign: $sign) {url filename} } """,
220+
}),
210221
"map": (None, json.dumps({"1": ["variables.file"]})),
211-
}
222+
}
212223
response = requests.post(
213224
self.endpoint,
214225
headers={"authorization": "Bearer %s" % self.api_key},
215226
data=request_data,
216-
files={"1": data}
217-
)
227+
files={"1": data})
218228

219229
try:
220230
file_data = response.json().get("data", None)
221-
except ValueError as e: # response is not valid JSON
231+
except ValueError as e: # response is not valid JSON
222232
raise labelbox.exceptions.LabelboxError(
223233
"Failed to upload, unknown cause", e)
224234

@@ -350,9 +360,11 @@ def _create(self, db_object_type, data):
350360
"""
351361
# Convert string attribute names to Field or Relationship objects.
352362
# Also convert Labelbox object values to their UIDs.
353-
data = {db_object_type.attribute(attr) if isinstance(attr, str) else attr:
354-
value.uid if isinstance(value, DbObject) else value
355-
for attr, value in data.items()}
363+
data = {
364+
db_object_type.attribute(attr) if isinstance(attr, str) else attr:
365+
value.uid if isinstance(value, DbObject) else value
366+
for attr, value in data.items()
367+
}
356368

357369
query_string, params = query.create(db_object_type, data)
358370
res = self.execute(query_string, params)

labelbox/exceptions.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
class LabelboxError(Exception):
22
"""Base class for exceptions."""
3+
34
def __init__(self, message, cause=None):
45
"""
56
Args:
@@ -34,8 +35,8 @@ def __init__(self, db_object_type, params):
3435
db_object_type (type): A labelbox.schema.DbObject subtype.
3536
params (dict): Dict of params identifying the sought resource.
3637
"""
37-
super().__init__("Resouce '%s' not found for params: %r" % (
38-
db_object_type.type_name(), params))
38+
super().__init__("Resouce '%s' not found for params: %r" %
39+
(db_object_type.type_name(), params))
3940
self.db_object_type = db_object_type
4041
self.params = params
4142

@@ -56,6 +57,7 @@ class InvalidQueryError(LabelboxError):
5657

5758
class NetworkError(LabelboxError):
5859
"""Raised when an HTTPError occurs."""
60+
5961
def __init__(self, cause):
6062
super().__init__(str(cause), cause)
6163
self.cause = cause
@@ -69,9 +71,10 @@ class TimeoutError(LabelboxError):
6971
class InvalidAttributeError(LabelboxError):
7072
""" Raised when a field (name or Field instance) is not valid or found
7173
for a specific DB object type. """
74+
7275
def __init__(self, db_object_type, field):
73-
super().__init__("Field(s) '%r' not valid on DB type '%s'" % (
74-
field, db_object_type.type_name()))
76+
super().__init__("Field(s) '%r' not valid on DB type '%s'" %
77+
(field, db_object_type.type_name()))
7578
self.db_object_type = db_object_type
7679
self.field = field
7780

labelbox/orm/comparison.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
from enum import Enum, auto
2-
3-
42
""" Classes for defining the client-side comparison operations used
53
for filtering data in fetches. Intended for use by library internals
64
and not by the end user.
@@ -60,7 +58,8 @@ def __eq__(self, other):
6058
(self.first == other.second and self.second == other.first))
6159

6260
def __hash__(self):
63-
return hash(self.op) + 2833 * hash(self.first) + 2837 * hash(self.second)
61+
return hash(
62+
self.op) + 2833 * hash(self.first) + 2837 * hash(self.second)
6463

6564
def __repr__(self):
6665
return "%r %s %r" % (self.first, self.op.name, self.second)

labelbox/orm/db_object.py

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from labelbox.orm.model import Field, Relationship, Entity
88
from labelbox.pagination import PaginatedCollection
99

10-
1110
logger = logging.getLogger(__name__)
1211

1312

@@ -62,8 +61,9 @@ def _set_field_values(self, field_values):
6261
value = datetime.strptime(value, "%Y-%m-%dT%H:%M:%S.%fZ")
6362
value = value.replace(tzinfo=timezone.utc)
6463
except ValueError:
65-
logger.warning("Failed to convert value '%s' to datetime for "
66-
"field %s", value, field)
64+
logger.warning(
65+
"Failed to convert value '%s' to datetime for "
66+
"field %s", value, field)
6767
setattr(self, field.name, value)
6868

6969
def __repr__(self):
@@ -74,10 +74,10 @@ def __repr__(self):
7474
return "<%s>" % type_name
7575

7676
def __str__(self):
77-
attribute_values = {field.name: getattr(self, field.name)
78-
for field in self.fields()}
79-
return "<%s %s>" % (self.type_name().split(".")[-1],
80-
attribute_values)
77+
attribute_values = {
78+
field.name: getattr(self, field.name) for field in self.fields()
79+
}
80+
return "<%s %s>" % (self.type_name().split(".")[-1], attribute_values)
8181

8282
def __eq__(self, other):
8383
return self.type_name() == other.type_name() and self.uid == other.uid
@@ -105,7 +105,7 @@ def __init__(self, source, relationship):
105105
self.supports_sorting = True
106106
self.filter_on_id = True
107107

108-
def __call__(self, *args, **kwargs ):
108+
def __call__(self, *args, **kwargs):
109109
""" Forwards the call to either `_to_many` or `_to_one` methods,
110110
depending on relationship type. """
111111
if self.relationship.relationship_type == Relationship.Type.ToMany:
@@ -125,32 +125,30 @@ def _to_many(self, where=None, order_by=None):
125125

126126
if where is not None and not self.supports_filtering:
127127
raise InvalidQueryError(
128-
"Relationship %s.%s doesn't support filtering" % (
129-
self.source.type_name(), rel.name))
128+
"Relationship %s.%s doesn't support filtering" %
129+
(self.source.type_name(), rel.name))
130130
if order_by is not None and not self.supports_sorting:
131131
raise InvalidQueryError(
132-
"Relationship %s.%s doesn't support sorting" % (
133-
self.source.type_name(), rel.name))
132+
"Relationship %s.%s doesn't support sorting" %
133+
(self.source.type_name(), rel.name))
134134

135135
if rel.filter_deleted:
136136
not_deleted = rel.destination_type.deleted == False
137137
where = not_deleted if where is None else where & not_deleted
138138

139139
query_string, params = query.relationship(
140-
self.source if self.filter_on_id else type(self.source),
141-
rel, where, order_by)
140+
self.source if self.filter_on_id else type(self.source), rel, where,
141+
order_by)
142142
return PaginatedCollection(
143143
self.source.client, query_string, params,
144-
[utils.camel_case(self.source.type_name()),
145-
rel.graphql_name],
144+
[utils.camel_case(self.source.type_name()), rel.graphql_name],
146145
rel.destination_type)
147146

148147
def _to_one(self):
149148
""" Returns the relationship destination object. """
150149
rel = self.relationship
151150

152-
query_string, params = query.relationship(
153-
self.source, rel, None, None)
151+
query_string, params = query.relationship(self.source, rel, None, None)
154152
result = self.source.client.execute(query_string, params)
155153
result = result[utils.camel_case(type(self.source).type_name())]
156154
result = result[rel.graphql_name]
@@ -172,6 +170,7 @@ def disconnect(self, other):
172170

173171

174172
class Updateable:
173+
175174
def update(self, **kwargs):
176175
""" Updates this DB object with new values. Values should be
177176
passed as key-value arguments with field names as keys:
@@ -216,6 +215,7 @@ class BulkDeletable:
216215
with the appropriate `use_where_clause` argument for that particular
217216
type.
218217
"""
218+
219219
@staticmethod
220220
def _bulk_delete(objects, use_where_clause):
221221
"""
@@ -235,7 +235,6 @@ def _bulk_delete(objects, use_where_clause):
235235
query_str, params = query.bulk_delete(objects, use_where_clause)
236236
objects[0].client.execute(query_str, params)
237237

238-
239238
def delete(self):
240239
""" Deletes this DB object from the DB (server side). After
241240
a call to this you should not use this DB object anymore.

0 commit comments

Comments
 (0)