Skip to content

Commit 1fae138

Browse files
authored
Merge pull request #643 from aperture-data/release-0.4.54
Release 0.4.54
2 parents 2a29b18 + 5d6c0f1 commit 1fae138

13 files changed

Lines changed: 121 additions & 27 deletions

File tree

.github/workflows/pr.yaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ jobs:
99
run_test:
1010

1111
runs-on:
12-
- self-hosted
13-
- deployer
12+
- gcp
1413

1514
steps:
1615

aperturedb/CSVParser.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,17 @@ def __init__(self,
6262
self.df = pd.read_csv(filename)
6363
else:
6464
self.df = df
65+
66+
# we expect the df index to have 'start', which means RangeIndex.
67+
# most users don't supply their own df, so this is mostly a sanity check
68+
# for when an advanced user has done filtering and have a IntervalIndex.
69+
if not isinstance(self.df.index, pd.RangeIndex):
70+
raise TypeError(
71+
f"CSVParser requires a RangeIndex. the supplied DataFrame has a {type(self.df.index)} index.")
6572
else:
73+
if df is not None:
74+
raise ValueError(
75+
"Dask mode requires a CSV filename; DataFrame inputs are not supported.")
6676
# It'll impact the number of partitions, and memory usage.
6777
# TODO: tune this for the best performance.
6878
cores_used = int(CORES_USED_FOR_PARALLELIZATION * mp.cpu_count())

aperturedb/Configuration.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ def create_aperturedb_key(
116116

117117
if host.endswith(APERTUREDB_CLOUD):
118118
host = host[:-1 * len(APERTUREDB_CLOUD)]
119-
m = re.match("(.*)\.farm(\d+)$", host)
119+
m = re.match(r"(.*)\.farm(\d+)$", host)
120120
if m is not None:
121121
host = "{}.{}".format(m.group(1), int(m.group(2)))
122122
compressed = True
@@ -170,7 +170,7 @@ def reinflate(cls, encoded_str: list) -> object:
170170
else:
171171
raise ValueError("Bad format for key list")
172172

173-
port_match = re.match(".*:(\d+)$", host)
173+
port_match = re.match(r".*:(\d+)$", host)
174174
if port_match is not None:
175175
port = int(port_match.group(1))
176176
host = host[:-1 * (len(port_match.group(1)) + 1)]

aperturedb/DaskManager.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def __del__(self):
4242
self._cluster.close()
4343

4444
def run(self, QueryClass: type[ParallelQuery], client: Connector, generator, batchsize, stats):
45-
def process(df, host, port, use_ssl, ca_cert, session, connnector_type):
45+
def process(df, host, port, use_ssl, ca_cert, verify_hostname, session, connnector_type):
4646
metrics = Stats()
4747
# Dask reads data in partitions, and the first partition is of 2 rows, with all
4848
# values as 'foo'. This is for sampling the column names and types. Should not process
@@ -55,8 +55,12 @@ def process(df, host, port, use_ssl, ca_cert, session, connnector_type):
5555
shared_data = SimpleNamespace()
5656
shared_data.session = session
5757
shared_data.lock = Lock()
58-
client = connnector_type(host=host, port=port,
59-
use_ssl=use_ssl, ca_cert=ca_cert, shared_data=shared_data)
58+
client = connnector_type(
59+
host=host, port=port,
60+
use_ssl=use_ssl,
61+
ca_cert=ca_cert,
62+
verify_hostname=verify_hostname,
63+
shared_data=shared_data)
6064
except Exception as e:
6165
logger.exception(e)
6266
#from aperturedb.ParallelLoader import ParallelLoader
@@ -88,6 +92,7 @@ def process(df, host, port, use_ssl, ca_cert, session, connnector_type):
8892
client.port,
8993
client.use_ssl,
9094
client.config.ca_cert,
95+
client.config.verify_hostname,
9196
client.shared_data.session,
9297
type(client))
9398
computation = computation.persist()

aperturedb/Query.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ def get_specific(obj: BaseModel) -> dict:
8787
start, stop = obj.start, obj.stop
8888
if obj.range_type == RangeType.TIME:
8989
start, stop = int(start), int(stop)
90-
start = f"{start//60}:{start%60}"
91-
stop = f"{stop//60}:{stop%60}"
90+
start = f"{start//3600:0>2}:{start//60:0>2}:{start%60:0>2}"
91+
stop = f"{stop//3600:0>2}:{stop//60:0>2}:{stop%60:0>2}"
9292
elif obj.range_type == RangeType.FRAME:
9393
start = int(obj.start)
9494
stop = int(obj.stop)
@@ -169,6 +169,8 @@ def generate_add_query(
169169
cindex = index
170170
specific_params = {}
171171
specific_blobs = []
172+
if obj is None:
173+
return query, blobs, index
172174
if obj.id not in cached:
173175
for p in obj.__dict__.keys():
174176
if "_" == p[0]:

aperturedb/SPARQL.py

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
from aperturedb.CommonLibrary import create_connector, execute_query
1414
from aperturedb.Utils import Utils
1515

16+
SAFE_PREFIX = "adb_"
17+
1618

1719
class SPARQL:
1820
def __init__(self, client=None, debug=False, log_level=None):
@@ -93,6 +95,12 @@ def _format_triple(self, triple):
9395
def _format_triples(self, triples):
9496
return " .\n".join([self._format_triple(triple) for triple in triples])
9597

98+
def _make_safe_prefix(self, suffix):
99+
return f"{SAFE_PREFIX}{suffix[1:]}" if suffix.startswith("_") else suffix
100+
101+
def _make_command_name(self, t):
102+
return "Find" + t[len(SAFE_PREFIX):] if t.startswith(f"{SAFE_PREFIX}") else "FindEntity"
103+
96104
def _load_schema(self):
97105
self.schema = self._utils.get_schema()
98106
self.connections = {}
@@ -109,14 +117,17 @@ def _load_schema(self):
109117
d_list = [d] if isinstance(d, dict) else d
110118

111119
for d in d_list:
112-
self.connections[uri][0].add(d["src"])
113-
self.connections[uri][1].add(d["dst"])
120+
self.connections[uri][0].add(
121+
self._make_safe_prefix(d["src"]))
122+
self.connections[uri][1].add(
123+
self._make_safe_prefix(d["dst"]))
114124
if not self.connections:
115125
self.logger.warning("No connections found in schema")
116126

117127
self.properties = {}
118128
if "entities" in self.schema and self.schema["entities"] is not None and "classes" in self.schema["entities"]:
119129
for e, d in self.schema["entities"]["classes"].items():
130+
e = self._make_safe_prefix(e)
120131
for p in d["properties"]:
121132
uri = self._make_uri("p", p)
122133
if uri not in self.properties:
@@ -166,9 +177,9 @@ def evalBGP(self, ctx: "QueryContext",
166177
def add_find(v, t):
167178
"""Create new Find* command for variable v with type t"""
168179
from rdflib.term import Variable
169-
command_name = "FindEntity" if t[0] != "_" else "Find" + t[1:]
170180
body = {}
171-
if t[0] != "_":
181+
command_name = self._make_command_name(t)
182+
if command_name == "FindEntity":
172183
body["with_class"] = t
173184
body["_ref"] = len(query) + 1
174185
body["uniqueids"] = True
@@ -445,7 +456,7 @@ def add_types(k, tt):
445456
add_types(s, [self._parse_uri_with_ns('t', o)])
446457
elif p in self.knn_properties:
447458
if p == self.namespaces["knn"] + "similarTo":
448-
add_types(s, {"_Descriptor"})
459+
add_types(s, {self._make_safe_prefix("_Descriptor")})
449460
elif p == self.namespaces["c"] + "ANY":
450461
pass
451462
else:
@@ -509,9 +520,10 @@ def get_blob(self, uri: Union[str, "URIRef"], type: Optional[str] = None) -> byt
509520
assert type == self._deduce_type(
510521
uri), f"Type {type} does not match deduced type {self._deduce_type(uri)}"
511522
assert type is not None, f"Cannot get blob for entity URI: {uri}"
512-
assert type[0] == "_", f"Cannot get blob for entity URI: {uri} with type {type}"
523+
assert type.startswith(
524+
f"{SAFE_PREFIX}"), f"Cannot get blob for entity URI: {uri} with type {type}"
513525
uniqueid = self._deduce_uniqueid(uri)
514-
command_name = "Find" + type[1:]
526+
command_name = self._make_command_name(type)
515527
query = [
516528
{command_name: {
517529
"constraints": {
@@ -539,9 +551,10 @@ def get_blobs(self, uris: List[Union[str, "URIRef"]], type: Optional[str] = None
539551
t == type for t in types), f"Types do not match: {types}"
540552

541553
assert type is not None, f"Cannot get blob for entity URI: {uri}"
542-
assert type[0] == "_", f"Cannot get blob for entity URI: {uri} with type {type}"
554+
assert type.startswith(
555+
f"{SAFE_PREFIX}"), f"Cannot get blob for entity URI: {uri} with type {type}"
543556
uniqueids = [self._deduce_uniqueid(uri) for uri in uris]
544-
command_name = "Find" + type[1:]
557+
command_name = self._make_command_name(type)
545558
query = [
546559
{command_name: {
547560
"results": {"list": ["_uniqueid"]},
@@ -568,7 +581,7 @@ def get_image(self, uri: Union[str, "URIRef"]) -> "np.ndarray":
568581
import numpy as np
569582
import cv2
570583

571-
blob = self.get_blob(uri, type="_Image")
584+
blob = self.get_blob(uri, type=self._make_safe_prefix("_Image"))
572585
nparr = np.fromstring(blob, np.uint8)
573586
image = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
574587
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
@@ -581,7 +594,7 @@ def get_images(self, uris: List[Union[str, "URIRef"]]) -> List["np.ndarray"]:
581594
import numpy as np
582595
import cv2
583596

584-
blobs = self.get_blobs(uris, type="_Image")
597+
blobs = self.get_blobs(uris, type=self._make_safe_prefix("_Image"))
585598
images = []
586599
for blob in blobs:
587600
if blob is not None:
@@ -616,13 +629,14 @@ def get_descriptor(self, uri: Union[str, "URIRef"]) -> "np.ndarray":
616629
Get the descriptor associated with a URI or QName
617630
"""
618631
import numpy as np
619-
blob = self.get_blob(uri, type="_Descriptor")
632+
blob = self.get_blob(uri, type=self._make_safe_prefix("_Descriptor"))
620633
return np.frombuffer(blob, dtype=np.float32)
621634

622635
def get_descriptors(self, uris: List[Union[str, "URIRef"]]) -> List["np.ndarray"]:
623636
"""
624637
Get the descriptors associated with a list of URI or QName
625638
"""
626639
import numpy as np
627-
blobs = self.get_blobs(uris, type="_Descriptor")
640+
blobs = self.get_blobs(
641+
uris, type=self._make_safe_prefix("_Descriptor"))
628642
return [np.frombuffer(blob, dtype=np.float32) for blob in blobs]

aperturedb/__init__.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import signal
1111
import sys
1212

13-
__version__ = "0.4.53"
13+
__version__ = "0.4.54"
1414

1515
logger = logging.getLogger(__name__)
1616

@@ -47,13 +47,30 @@
4747
os.environ["ADB_LOG_FILE"]) == 0 else os.environ["ADB_LOG_FILE"]
4848

4949
if error_file_name is not None:
50+
# detachable file handler allows program to run from working directory
51+
# without write access; adb is a use case for this.
52+
class DetachableFileHandler(logging.FileHandler):
53+
def __init__(self, file_path, delay=False):
54+
super().__init__(file_path, delay=delay)
55+
56+
def emit(self, record):
57+
try:
58+
super().emit(record)
59+
except PermissionError as pErr:
60+
for h in logger.handlers[:]:
61+
if h == self:
62+
logger.removeHandler(h)
63+
break
64+
logging.warning(
65+
f"Unable to write to {self.baseFilename}, removing file logging")
66+
5067
error_file_tmpl = Template(error_file_name)
5168
template_items = {
5269
# python isodate has ':', not valid in files in windows.
5370
"now": str(datetime.datetime.now().isoformat()).replace(':', ''),
5471
"node": str(platform.node())
5572
}
56-
error_file_handler = logging.FileHandler(error_file_tmpl.safe_substitute(
73+
error_file_handler = DetachableFileHandler(error_file_tmpl.safe_substitute(
5774
**template_items), delay=True)
5875
error_file_handler.setFormatter(formatter)
5976
error_file_handler.setLevel(log_file_level)

aperturedb/queryMessage.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ def ParseFromString(msg, data):
2424
def queryMessage():
2525
return queryMessage5_pb2.queryMessage()
2626

27+
def ParseFromString(msg, data):
28+
return msg.ParseFromString(data)
29+
elif google.protobuf.__version__.split(".")[0] == "6":
30+
from . import queryMessage6_pb2
31+
32+
def queryMessage():
33+
return queryMessage6_pb2.queryMessage()
34+
2735
def ParseFromString(msg, data):
2836
return msg.ParseFromString(data)
2937
else:

aperturedb/queryMessage6_pb2.py

Lines changed: 36 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ dynamic = ["version"]
44
description = "ApertureDB Python SDK"
55

66
readme = "README.md"
7-
requires-python = ">=3.8"
7+
requires-python = ">=3.10"
88
license = {file = "LICENSE"}
99
keywords = ["aperturedb", "graph", "database",
1010
"image", "video", "metadata", "search", "indexing"]
@@ -16,7 +16,7 @@ authors = [
1616
dependencies = [
1717
# Pin to the bridge version.
1818
# https://github.com/tensorflow/tensorflow/issues/60320
19-
'protobuf >=3.20.3,<6.0.0',
19+
'protobuf >=3.20.3,<7.0.0',
2020
#Folllowing is needed parallel loaders, and basic things for
2121
# making the notebooks.
2222
'requests', 'boto3',

0 commit comments

Comments
 (0)