Skip to content

Commit 5a50e3d

Browse files
authored
Merge pull request #179 from aperture-data/release-0.3.6
Release 0.3.6
2 parents cfece05 + 1696cc3 commit 5a50e3d

File tree

20 files changed

+179
-183
lines changed

20 files changed

+179
-183
lines changed

.github/workflows/checks.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
- uses: actions/checkout@v2
1313
- uses: actions/setup-python@v3
1414
with:
15-
python-version: '3.8.10'
15+
python-version: '3.10'
1616
- uses: pre-commit/[email protected]
1717
- uses: actions/checkout@v2
1818
- uses: luisremis/find-trailing-whitespace@master

aperturedb/Blobs.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,7 @@
11
from __future__ import annotations
2-
from typing import Dict
32

4-
from aperturedb.Connector import Connector
53
from aperturedb.Entities import Entities
6-
from aperturedb.Query import Query
74

85

96
class Blobs(Entities):
107
db_object = "_Blob"
11-
12-
@classmethod
13-
def retrieve(cls,
14-
db: Connector,
15-
spec: Query,
16-
with_adjacent: Dict[str, Query] = None) -> Blobs:
17-
spec.with_class = cls.db_object
18-
19-
results = Entities.retrieve(
20-
db=db, spec=spec, with_adjacent=with_adjacent)
21-
22-
blobs = results[-1]
23-
return blobs

aperturedb/BoundingBoxes.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,7 @@
11
from __future__ import annotations
2-
from typing import Dict
32

4-
from aperturedb.Connector import Connector
53
from aperturedb.Entities import Entities
6-
from aperturedb.Query import Query
74

85

96
class BoundingBoxes(Entities):
107
db_object = "_BoundingBox"
11-
12-
@classmethod
13-
def retrieve(cls,
14-
db: Connector,
15-
spec: Query,
16-
with_adjacent: Dict[str, Query] = None) -> BoundingBoxes:
17-
spec.with_class = cls.db_object
18-
19-
results = Entities.retrieve(
20-
db=db, spec=spec, with_adjacent=with_adjacent)
21-
22-
bboxes = results[-1]
23-
return bboxes

aperturedb/Connector.py

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ def valid(self) -> bool:
6363
session_age = time.time() - self.session_started
6464

6565
# This triggers refresh if the session is about to expire.
66-
if session_age > self.session_token_ttl - os.getenv("SESSION_EXPIRTY_OFFSET_SEC", 10):
66+
if session_age > self.session_token_ttl - \
67+
int(os.getenv("SESSION_EXPIRTY_OFFSET_SEC", 10)):
6768
return False
6869

6970
return True
@@ -160,12 +161,12 @@ def _authenticate(self, user, password="", token=""):
160161
if session_info["status"] != 0:
161162
raise Exception(session_info["info"])
162163

163-
self.shared_data.session = Session(session_info["session_token"],
164-
session_info["refresh_token"],
165-
session_info["session_token_expires_in"],
166-
session_info["refresh_token_expires_in"],
167-
time.time()
168-
)
164+
self.shared_data.session = Session(
165+
session_info["session_token"],
166+
session_info["refresh_token"],
167+
session_info["session_token_expires_in"],
168+
session_info["refresh_token_expires_in"],
169+
time.time())
169170

170171
def _check_session_status(self):
171172
if not self.shared_data.session:
@@ -190,12 +191,12 @@ def _refresh_token(self):
190191
if session_info["status"] != 0:
191192
raise UnauthorizedException(response)
192193

193-
self.shared_data.session = Session(session_info["session_token"],
194-
session_info["refresh_token"],
195-
session_info["session_token_expires_in"],
196-
session_info["refresh_token_expires_in"],
197-
time.time()
198-
)
194+
self.shared_data.session = Session(
195+
session_info["session_token"],
196+
session_info["refresh_token"],
197+
session_info["session_token_expires_in"],
198+
session_info["refresh_token_expires_in"],
199+
time.time())
199200
else:
200201
raise UnauthorizedException(response)
201202

@@ -312,10 +313,13 @@ def query(self, q, blobs=[]):
312313
try:
313314
start = time.time()
314315
self.response, self.blobs = self._query(q, blobs)
315-
if not isinstance(self.response, list) and self.response["info"] == "Not Authenticated!":
316+
if not isinstance(
317+
self.response,
318+
list) and self.response["info"] == "Not Authenticated!":
316319
# The case where session is valid, but expires while query is sent.
317-
# Hope is that the query send won't be longer than the session ttl.
318-
logger.warn(
320+
# Hope is that the query send won't be longer than the session
321+
# ttl.
322+
logger.warning(
319323
f"Session expired while query was sent. Retrying... \r\n{traceback.format_stack(limit=5)}")
320324
self._renew_session()
321325
start = time.time()
@@ -333,7 +337,7 @@ def _renew_session(self):
333337
self._check_session_status()
334338
break
335339
except UnauthorizedException as e:
336-
logger.warn(
340+
logger.warning(
337341
f"[Attempt {count + 1} of 3] Failed to refresh token. Details: \r\n{traceback.format_exc(limit=5)}")
338342
time.sleep(1)
339343
count += 1

aperturedb/Entities.py

Lines changed: 57 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from aperturedb.Constraints import Constraints
77
from aperturedb.Connector import Connector
88
from aperturedb.ParallelQuery import execute_batch
9+
from aperturedb.Query import QueryBuilder
910
import pandas as pd
1011

1112

@@ -21,13 +22,13 @@ class Entities(Subscriptable):
2122
update_command = f"Update{db_object}"
2223

2324
@classmethod
24-
def retrieve(cls,
25-
db: Connector,
26-
spec: Query,
27-
with_adjacent: Dict[str, Query] = None
28-
) -> List[Entities]:
25+
def retrieve_entities(cls,
26+
db: Connector,
27+
spec: Query,
28+
with_adjacent: Dict[str, Query] = None
29+
) -> List[Entities]:
2930
"""
30-
Using the Entities.retrieve method, is a simpple layer, with typical native queries converted
31+
Using the Entities.retrieve method, is a simple layer, with typical native queries converted
3132
using :class:`~aperturedb.Query.Query`
3233
3334
Args:
@@ -85,8 +86,7 @@ def retrieve(cls,
8586
entities = cls.known_entities[wc](
8687
db=db, response=subresponse, type=wc)
8788
entities.blobs = blobs
88-
if wc[0] == "_":
89-
entities.find_command = f"Find{wc[1:]}"
89+
9090
results.append(entities)
9191
except Exception as e:
9292
print(e)
@@ -96,8 +96,25 @@ def retrieve(cls,
9696
cls.__postprocess__(entities=results[-1], with_adjacent=with_adjacent)
9797
return results
9898

99+
@classmethod
100+
def retrieve(cls,
101+
db: Connector,
102+
spec: Query,
103+
with_adjacent: Dict[str, Query] = None) -> Entities:
104+
spec.db_object = cls.db_object
105+
106+
results = Entities.retrieve_entities(
107+
db=db, spec=spec, with_adjacent=with_adjacent)
108+
109+
# This is a very naive assumption, we will stop querying once
110+
# the object of interest is the in the resopnses.
111+
objects = results[-1]
112+
113+
return objects
114+
99115
# This needs to be defined so that the application can access the adjacent items,
100116
# with every item of this iterable.
117+
101118
@classmethod
102119
def __decorator(cls, index, adjacent):
103120
item = {}
@@ -180,27 +197,28 @@ def get_connected_entities(self, etype: Union[ObjectType, str], constraints: Co
180197
result = []
181198
entity_class = etype.value if isinstance(etype, ObjectType) else etype
182199
for entity in self:
183-
query = [
184-
{
185-
self.find_command: {
186-
"_ref": 1,
187-
"unique": False,
188-
"constraints": {
189-
"_uniqueid": ["==", entity["_uniqueid"]]
190-
}
191-
}
192-
}, {
193-
"FindEntity": {
194-
"is_connected_to": {
195-
"ref": 1
196-
},
197-
"with_class": entity_class,
198-
"constraints": constraints.constraints,
199-
"results": {
200-
"all_properties": True
201-
}
202-
}
200+
params_src = {
201+
"_ref": 1,
202+
"unique": False,
203+
"constraints": {
204+
"_uniqueid": ["==", entity["_uniqueid"]]
205+
}
206+
}
207+
params_dst = {
208+
"is_connected_to": {
209+
"ref": 1
210+
},
211+
"with_class": entity_class,
212+
"constraints": constraints.constraints,
213+
"results": {
214+
"all_properties": True
203215
}
216+
}
217+
218+
query = [
219+
QueryBuilder.find_command(self.db_object, params=params_src),
220+
QueryBuilder.find_command(
221+
oclass=entity_class, params=params_dst)
204222
]
205223
res, r, b = execute_batch(query, [], self.db)
206224
cl = Entities
@@ -214,19 +232,18 @@ def get_blob(self, entity) -> Any:
214232
"""
215233
Helper to get blobs for FindImage, FindVideo and FindBlob commands.
216234
"""
217-
query = [
218-
{
219-
self.find_command: {
220-
"constraints": {
221-
"_uniqueid": ["==", entity["_uniqueid"]]
222-
},
223-
"blobs": True,
224-
"uniqueids": True,
225-
"results": {
226-
"count": True
227-
}
228-
}
235+
cmd_params = {
236+
"constraints": {
237+
"_uniqueid": ["==", entity["_uniqueid"]]
238+
},
239+
"blobs": True,
240+
"uniqueids": True,
241+
"results": {
242+
"count": True
229243
}
244+
}
245+
query = [
246+
QueryBuilder().find_command(self.db_object, params=cmd_params)
230247
]
231248
res, r, b = execute_batch(query, [], self.db)
232249
return b[0]

aperturedb/Images.py

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
from __future__ import annotations
2-
from typing import Dict, Tuple, Union
2+
from typing import Tuple, Union
33
import cv2
44
import math
55
import numpy as np
66

77
import matplotlib.pyplot as plt
88

99
from aperturedb import Utils
10-
from aperturedb.Entities import Entities, ObjectType, Query
11-
from aperturedb.Connector import Connector
10+
from aperturedb.Entities import Entities
1211
from aperturedb.Constraints import Constraints
1312
from ipywidgets import widgets
1413
from IPython.display import display, HTML
@@ -23,23 +22,6 @@
2322
class Images(Entities):
2423
db_object = "_Image"
2524

26-
@classmethod
27-
def retrieve(cls,
28-
db: Connector,
29-
spec: Query,
30-
with_adjacent: Dict[str, Query] = None) -> Images:
31-
spec.with_class = cls.db_object
32-
33-
results = Entities.retrieve(
34-
db=db, spec=spec, with_adjacent=with_adjacent)
35-
36-
# A Polygon is only connected to 1 image, and our query is filtered with
37-
# meta info from polygon, so connect the right image to the polygon
38-
# That being said, the ordering should be same as that of the first command in the query
39-
images = results[-1]
40-
41-
return images
42-
4325
def inspect(self, use_thumbnails=True) -> Union[Tuple[widgets.IntSlider, widgets.Output], DataFrame]:
4426
df = super(Images, self).inspect()
4527
if use_thumbnails:

aperturedb/Polygons.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,11 @@
11
from __future__ import annotations
2-
from aperturedb.Connector import Connector
32
from aperturedb.Entities import Entities
4-
from aperturedb.Query import Query
53
from aperturedb.ParallelQuery import execute_batch
64

75

86
class Polygons(Entities):
97
db_object = "_Polygon"
108

11-
@classmethod
12-
def retrieve(cls,
13-
db: Connector,
14-
spec: Query) -> Polygons:
15-
polygons = Entities.retrieve(
16-
db=db,
17-
spec=spec)
18-
return polygons[-1]
19-
209
def intersection(self, other: Polygons, threshold: float) -> Polygons:
2110
"""
2211
Find a set of polygons that intersect with another set of polygons.

aperturedb/Query.py

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,6 @@ class Query():
4949
This is the underlying class to generate a query using python code.
5050
"""
5151
db_object = "Entity"
52-
find_command = f"Find{db_object}"
53-
update_command = f"Update{db_object}"
5452
next = None
5553

5654
def connected_to(self,
@@ -142,33 +140,27 @@ def __init__(self,
142140

143141
def query(self) -> List[dict]:
144142
results_section = "results"
145-
cmd = {
146-
self.find_command: {
147-
"_ref": self.adj_to,
148-
results_section: {
149-
150-
}
151-
}
152-
}
153-
if self.db_object == "Entity":
154-
cmd[self.find_command]["with_class"] = self.with_class
143+
cmd_params = {results_section: {}}
155144
if self.limit != -1:
156-
cmd[self.find_command][results_section]["limit"] = self.limit
145+
cmd_params[results_section]["limit"] = self.limit
157146
if self.sort:
158-
cmd[self.find_command][results_section]["sort"] = self.sort._sort
147+
cmd_params[results_section]["sort"] = self.sort._sort
159148
if self.list is not None and len(self.list) > 0:
160-
cmd[self.find_command][results_section]["list"] = self.list
149+
cmd_params[results_section]["list"] = self.list
161150
else:
162-
cmd[self.find_command][results_section]["all_properties"] = True
163-
cmd[self.find_command][results_section]["group_by_source"] = self.group_by_src
151+
cmd_params[results_section]["all_properties"] = True
152+
cmd_params[results_section]["group_by_source"] = self.group_by_src
164153

165154
if self.constraints:
166-
cmd[self.find_command]["constraints"] = self.constraints.constraints
167-
155+
cmd_params["constraints"] = self.constraints.constraints
156+
self.with_class = self.with_class if self.db_object == "Entity" else self.db_object
157+
cmd = QueryBuilder.find_command(
158+
oclass=self.with_class, params=cmd_params)
159+
self.find_command = list(cmd.keys())[0]
168160
query = [cmd]
169161
if self.next:
170162
next_commands = self.next.query()
171-
next_commands[0][self.next.find_command]["is_connected_to"] = {
163+
list(next_commands[0].values())[0]["is_connected_to"] = {
172164
"ref": self.adj_to
173165
}
174166
query.extend(next_commands)

0 commit comments

Comments
 (0)