Skip to content

Commit 304cfdd

Browse files
committed
Merge branch '44-deprecate-Builder-enrich-Store-constructor' into 'dev'
Deprecate Builder / Store constructor with optional parameters Closes #44 See merge request objectbox/objectbox-python!33
2 parents 68fadd9 + 1199893 commit 304cfdd

20 files changed

Lines changed: 300 additions & 127 deletions

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,23 +61,23 @@ class Person:
6161

6262
### Using ObjectBox
6363

64-
To actually use the database, you launch (or "build") it with the model you've just defined.
65-
Afterwards, you can reuse the instance (`ob` in the example below) and use it to access "Entity Boxes" which hold your objects.
64+
To actually use the database, you create a Store with the model you've just defined.
65+
Afterwards, you can reuse the instance (`store` in the example below) and use it to access "Entity Boxes" which hold your objects.
6666

6767
#### program.py
6868

6969
```python
7070
import objectbox
7171
# from mypackage.model import Person
7272

73-
# Configure ObjectBox: should be done only once in the whole program and the "ob" variable should be kept around
73+
# Configure ObjectBox: should be done only once in the whole program and the "store" variable should be kept around
7474
model = objectbox.Model()
7575
model.entity(Person, last_property_id=objectbox.model.IdUid(10, 1010))
7676
model.last_entity_id = objectbox.model.IdUid(1, 1)
77-
ob = objectbox.Builder().model(model).directory("db").build()
77+
store = objectbox.Store(model=model)
7878

7979
# Open the box of "Person" entity. This can be called many times but you can also pass the variable around
80-
box = objectbox.Box(ob, Person)
80+
box = store.box(Person)
8181

8282
person = Person()
8383
person.name = "Joe Green"

benchmark.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ class ObjectBoxPerf:
1010
"""
1111

1212
def __init__(self):
13-
self.ob = load_empty_test_default_store()
14-
self.box = objectbox.Box(self.ob, TestEntity)
13+
self.store = load_empty_test_default_store()
14+
self.box = store.box(TestEntity)
1515

1616
def remove_all(self):
1717
self.box.remove_all()

example/tasks/__main__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ def format_date(timestamp_ms: int) -> str:
1515

1616
class TasklistCmd(Cmd):
1717
prompt = "> "
18-
_ob = objectbox.Builder().model(get_objectbox_model()).directory("tasklist-db").build()
19-
_box = objectbox.Box(_ob, Task)
18+
_store = objectbox.Store(model=get_objectbox_model(), directory="tasklist-db")
19+
_box = _store.box(Task)
2020

2121
def do_ls(self, _):
2222
"""list tasks"""

example/vectorsearch-cities/__main__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ def __init__(self, *args):
2323
Cmd.__init__(self, *args)
2424
dbdir = "cities-db"
2525
new_db = not os.path.exists(dbdir)
26-
self._ob = objectbox.Builder().model(get_objectbox_model()).directory(dbdir).build()
27-
self._box = objectbox.Box(self._ob, City)
26+
self._store = objectbox.Store(model=get_objectbox_model(),directory=dbdir)
27+
self._box = _store.box(City)
2828
self._name_prop: Property = City.get_property("name")
2929
self._location_prop: Property = City.get_property("location")
3030
if new_db:

objectbox/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from objectbox.model import Model
1919
from objectbox.store import Store
2020
from objectbox.objectbox import ObjectBox
21-
from objectbox.c import NotFoundException, version_core
21+
from objectbox.c import NotFoundException, version_core, DebugFlags
2222
from objectbox.version import Version
2323

2424
__all__ = [
@@ -30,6 +30,7 @@
3030
'NotFoundException',
3131
'version',
3232
'version_info',
33+
'DebugFlags'
3334
]
3435

3536
# Python binding version

objectbox/builder.py

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,37 +17,25 @@
1717
from objectbox.model import Model
1818
from objectbox.store import Store
1919
from objectbox.store_options import StoreOptions
20-
20+
from warnings import warn
2121

2222
class Builder:
2323
def __init__(self):
24-
self._model = Model()
25-
self._directory = None
26-
self._max_db_size_in_kb = None
24+
"""This throws a deprecation warning on initialization."""
25+
warn(f'Using {self.__class__.__name__} is deprecated, please use Store(model=, directory= ...) from objectbox.store.', DeprecationWarning, stacklevel=2)
26+
self._kwargs = { }
2727

2828
def directory(self, path: str) -> 'Builder':
29-
self._directory = path
29+
self._kwargs['directory'] = path
3030
return self
3131

3232
def max_db_size_in_kb(self, size_in_kb: int) -> 'Builder':
33-
self._max_db_size_in_kb = size_in_kb
33+
self._kwargs['max_db_size_in_kb'] = size_in_kb
3434
return self
3535

3636
def model(self, model: Model) -> 'Builder':
37-
self._model = model
38-
self._model._finish()
37+
self._kwargs['model'] = model
3938
return self
4039

4140
def build(self) -> 'Store':
42-
options = StoreOptions()
43-
try:
44-
if self._directory:
45-
options.directory(self._directory)
46-
if self._max_db_size_in_kb:
47-
options.max_db_size_in_kb(self._max_db_size_in_kb)
48-
options.model(self._model)
49-
except CoreException:
50-
options._free()
51-
raise
52-
c_store = obx_store_open(options._c_handle)
53-
return Store(c_store)
41+
return Store(**self._kwargs)

objectbox/c.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from objectbox.version import Version
2020
from typing import *
2121
import numpy as np
22+
from enum import IntEnum
2223

2324
# This file contains C-API bindings based on lib/objectbox.h, linking to the 'objectbox' shared library.
2425
# The bindings are implementing using ctypes, see https://docs.python.org/dev/library/ctypes.html for introduction.
@@ -84,6 +85,17 @@ def shlib_name(library: str) -> str:
8485
OBXValidateOnOpenKvFlags = ctypes.c_int
8586
OBXBackupRestoreFlags = ctypes.c_int
8687

88+
class DebugFlags(IntEnum):
89+
NONE = 0,
90+
LOG_TRANSACTIONS_READ = 1,
91+
LOG_TRANSACTIONS_WRITE = 2,
92+
LOG_QUERIES = 3,
93+
LOG_QUERY_PARAMETERS = 8,
94+
LOG_ASYNC_QUEUE = 16,
95+
LOG_CACHE_HITS = 32,
96+
LOG_CACHE_ALL = 64,
97+
LOG_TREE = 128
98+
8799

88100
class OBX_model(ctypes.Structure):
89101
pass

objectbox/objectbox.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from warnings import warn
1818

1919
class ObjectBox(objectbox.store.Store):
20-
def __init__(self, *args, **kwargs):
20+
def __init__(self, c_store):
2121
"""This throws a deprecation warning on initialization."""
2222
warn(f'{self.__class__.__name__} will be deprecated, use Store from objectbox.store.', DeprecationWarning, stacklevel=2)
23-
super().__init__(*args, **kwargs)
23+
super().__init__(c_store=c_store)

objectbox/store.py

Lines changed: 171 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,173 @@
1313
# limitations under the License.
1414

1515

16-
from objectbox.c import *
16+
import objectbox.c as c
1717
import objectbox.transaction
18-
18+
from objectbox.store_options import StoreOptions
19+
import objectbox
20+
from objectbox.model.entity import _Entity
21+
from typing import *
1922

2023
class Store:
21-
def __init__(self, c_store: OBX_store_p):
22-
self._c_store = c_store
24+
def __init__(self,
25+
model : Optional[objectbox.model.Model] = None,
26+
directory : Optional[str] = None,
27+
max_db_size_in_kb : Optional[int] = None,
28+
max_data_size_in_kb: Optional[int] = None,
29+
file_mode: Optional[int] = None,
30+
max_readers: Optional[int] = None,
31+
no_reader_thread_locals: Optional[bool] = None,
32+
model_bytes: Optional[bytes] = None,
33+
model_bytes_direct: Optional[bytes] = None,
34+
read_schema: Optional[bool] = None,
35+
use_previous_commit: Optional[bool] = None,
36+
read_only: Optional[bool] = None,
37+
debug_flags: Optional[c.DebugFlags] = None,
38+
async_max_queue_length: Optional[int] = None,
39+
async_throttle_at_queue_length: Optional[int] = None,
40+
async_throttle_micros: Optional[int] = None,
41+
async_max_in_tx_duration: Optional[int] = None,
42+
async_max_in_tx_operations: Optional[int] = None,
43+
async_pre_txn_delay: Optional[int] = None,
44+
async_post_txn_delay: Optional[int] = None,
45+
async_minor_refill_threshold: Optional[int] = None,
46+
async_minor_refill_max_count: Optional[int] = None,
47+
async_object_bytes_max_cache_size: Optional[int] = None,
48+
async_object_bytes_max_size_to_cache: Optional[int] = None,
49+
c_store : Optional[c.OBX_store_p] = None):
50+
51+
"""Opens an ObjectBox database Store
52+
53+
:param model:
54+
Database schema model.
55+
:param directory:
56+
Store directory. Defaults to "objectbox".
57+
Use prefix "memory:" to open an in-memory database, e.g. "memory:myapp"
58+
:param max_db_size_in_kb:
59+
Maximum database size. Defaults to one gigabyte.
60+
:param max_data_size_in_kb:
61+
Maximum data in database size tracking. Defaults to being disabled.
62+
This is a more involved size tacking.
63+
Recommended only if stricter accurate limit is required.
64+
Data size must be below database size.
65+
:param file_mode:
66+
Unix-style file mode options. Defaults to "int('644',8)".
67+
This option is ignored on Windows platforms.
68+
:param max_readers:
69+
Maximum number of readers (related to read transactions).
70+
Default value (currently 126) is suitable for most applications.
71+
:param no_reader_thread_locals:
72+
Disables the usage of thread locals for "readers" related to read transactions.
73+
This can make sense if you are using a lot of threads that are kept alive.
74+
:param model_bytes:
75+
Database schema model given by flatbuffers bytes serialized model.
76+
:param model_bytes_direct:
77+
Database schema model given by flatbuffers bytes serialized model without copying.
78+
:param read_schema:
79+
Advanced settings.
80+
:param use_previous_commit:
81+
Advanced setting recommended to set with read_only to ensure no data is lost.
82+
:param read_only:
83+
Open store in read-only mode: no schema update, no write transactions. Defaults to false.
84+
:param debug_flags:
85+
Set debug flags. Defaults to DebugFlags.NONE.
86+
:param async_max_queue_length:
87+
Maximum size of the queue before new transactions will be rejected.
88+
:param async_throttle_at_queue_length:
89+
Throttle queue submitter when hitting this water mark.
90+
:param async_throttle_micros:
91+
Sleeping time for throttled queue submitter.
92+
:param async_max_in_tx_duration:
93+
Maximum duration spent in a transaction before queue enforces a commit.
94+
:param async_max_in_tx_operations:
95+
Maximum number of operations performed in a transaction before queye enforces a commit.
96+
:param async_pre_txn_delay:
97+
Delay (in micro seconds) before queue is triggered by new element.
98+
:param async_post_txn_delay:
99+
Delay (in micro seconds) after a transaction was committed.
100+
:param async_minor_refill_threshold:
101+
Number of operations to be considered a "minor refill".
102+
:param async_minor_refill_max_count:
103+
If set, allows "minor refills" with small batches that came in (off by default).
104+
:param async_object_bytes_max_cache_size:
105+
Total cache size. Defaults to 0.5 mega bytes.
106+
:param async_object_bytes_max_size_to_cache:
107+
Maximum size for an object to be cached.
108+
:param c_store:
109+
Internal parameter for deprecated ObjectBox interface. Do not use it; other options would be ignored if passed.
110+
"""
111+
112+
self._c_store = None
113+
if not c_store:
114+
options = StoreOptions()
115+
try:
116+
if model is not None:
117+
options.model(model)
118+
if directory is not None:
119+
options.directory(directory)
120+
if max_db_size_in_kb is not None:
121+
options.max_db_size_in_kb(max_db_size_in_kb)
122+
if max_data_size_in_kb is not None:
123+
options.max_data_size_in_kb(max_data_size_in_kb)
124+
if file_mode is not None:
125+
options.file_mode(file_mode)
126+
if max_readers is not None:
127+
options.max_readers(max_readers)
128+
if no_reader_thread_locals is not None:
129+
options.no_reader_thread_locals(no_reader_thread_locals)
130+
if model_bytes is not None:
131+
options.model_bytes(model_bytes)
132+
if model_bytes_direct is not None:
133+
options.model_bytes_direct(model_bytes_direct)
134+
if read_schema is not None:
135+
options.read_schema(read_schema)
136+
if use_previous_commit is not None:
137+
options.use_previous_commit(use_previous_commit)
138+
if read_only is not None:
139+
options.read_only(read_only)
140+
if debug_flags is not None:
141+
options.debug_flags(debug_flags)
142+
if async_max_queue_length is not None:
143+
options.async_max_queue_length(async_max_queue_length)
144+
if async_throttle_at_queue_length is not None:
145+
options.async_throttle_at_queue_length(async_throttle_at_queue_length)
146+
if async_throttle_micros is not None:
147+
options.async_throttle_micros(async_throttle_micros)
148+
if async_max_in_tx_duration is not None:
149+
options.async_max_in_tx_duration(async_max_in_tx_duration)
150+
if async_max_in_tx_operations is not None:
151+
options.async_max_in_tx_operations(async_max_in_tx_operations)
152+
if async_pre_txn_delay is not None:
153+
options.async_pre_txn_delay(async_pre_txn_delay)
154+
if async_post_txn_delay is not None:
155+
options.async_post_txn_delay(async_post_txn_delay)
156+
if async_minor_refill_threshold is not None:
157+
options.async_minor_refill_threshold(async_minor_refill_threshold)
158+
if async_minor_refill_max_count is not None:
159+
options.async_minor_refill_max_count(async_minor_refill_max_count)
160+
if async_object_bytes_max_cache_size is not None:
161+
options.async_object_bytes_max_cache_size(async_object_bytes_max_cache_size)
162+
if async_object_bytes_max_size_to_cache is not None:
163+
options.async_object_bytes_max_size_to_cache(async_object_bytes_max_size_to_cache)
164+
165+
except c.CoreException:
166+
options._free()
167+
raise
168+
self._c_store = c.obx_store_open(options._c_handle)
169+
else:
170+
self._c_store = c_store
23171

24172
def __del__(self):
25173
self.close()
174+
175+
def box(self, entity: _Entity) -> 'objectbox.Box':
176+
"""
177+
Open a box for an entity.
178+
179+
:param entity:
180+
Entity type of the model
181+
"""
182+
return objectbox.Box(self, entity)
26183

27184
def read_tx(self):
28185
return objectbox.transaction.read(self)
@@ -34,4 +191,13 @@ def close(self):
34191
c_store_to_close = self._c_store
35192
if c_store_to_close:
36193
self._c_store = None
37-
obx_store_close(c_store_to_close)
194+
c.obx_store_close(c_store_to_close)
195+
196+
def remove_db_files(dir):
197+
"""
198+
Remove Database files
199+
200+
:param dir:
201+
Path to directory.
202+
"""
203+
c.obx_remove_db_files(c.c_str(dir))

0 commit comments

Comments
 (0)