json-database 0.10.2a1__tar.gz → 1.0.2a1__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.
Files changed (31) hide show
  1. {json_database-0.10.2a1 → json_database-1.0.2a1}/PKG-INFO +13 -13
  2. {json_database-0.10.2a1 → json_database-1.0.2a1}/README.md +11 -10
  3. json_database-1.0.2a1/json_database/version.py +8 -0
  4. {json_database-0.10.2a1 → json_database-1.0.2a1}/json_database.egg-info/PKG-INFO +13 -13
  5. {json_database-0.10.2a1 → json_database-1.0.2a1}/json_database.egg-info/SOURCES.txt +0 -3
  6. {json_database-0.10.2a1 → json_database-1.0.2a1}/json_database.egg-info/requires.txt +1 -2
  7. {json_database-0.10.2a1 → json_database-1.0.2a1}/pyproject.toml +14 -6
  8. json_database-0.10.2a1/json_database/hpm.py +0 -105
  9. json_database-0.10.2a1/json_database/version.py +0 -6
  10. json_database-0.10.2a1/json_database.egg-info/entry_points.txt +0 -2
  11. json_database-0.10.2a1/test/test_hpm.py +0 -176
  12. {json_database-0.10.2a1 → json_database-1.0.2a1}/LICENSE +0 -0
  13. {json_database-0.10.2a1 → json_database-1.0.2a1}/json_database/__init__.py +0 -0
  14. {json_database-0.10.2a1 → json_database-1.0.2a1}/json_database/crypto.py +0 -0
  15. {json_database-0.10.2a1 → json_database-1.0.2a1}/json_database/exceptions.py +0 -0
  16. {json_database-0.10.2a1 → json_database-1.0.2a1}/json_database/search.py +0 -0
  17. {json_database-0.10.2a1 → json_database-1.0.2a1}/json_database/utils.py +0 -0
  18. {json_database-0.10.2a1 → json_database-1.0.2a1}/json_database/xdg_utils.py +0 -0
  19. {json_database-0.10.2a1 → json_database-1.0.2a1}/json_database.egg-info/dependency_links.txt +0 -0
  20. {json_database-0.10.2a1 → json_database-1.0.2a1}/json_database.egg-info/top_level.txt +0 -0
  21. {json_database-0.10.2a1 → json_database-1.0.2a1}/setup.cfg +0 -0
  22. {json_database-0.10.2a1 → json_database-1.0.2a1}/test/test_crypto.py +0 -0
  23. {json_database-0.10.2a1 → json_database-1.0.2a1}/test/test_database.py +0 -0
  24. {json_database-0.10.2a1 → json_database-1.0.2a1}/test/test_e2e_user_database.py +0 -0
  25. {json_database-0.10.2a1 → json_database-1.0.2a1}/test/test_encrypted_storage.py +0 -0
  26. {json_database-0.10.2a1 → json_database-1.0.2a1}/test/test_exceptions.py +0 -0
  27. {json_database-0.10.2a1 → json_database-1.0.2a1}/test/test_query.py +0 -0
  28. {json_database-0.10.2a1 → json_database-1.0.2a1}/test/test_search.py +0 -0
  29. {json_database-0.10.2a1 → json_database-1.0.2a1}/test/test_storage.py +0 -0
  30. {json_database-0.10.2a1 → json_database-1.0.2a1}/test/test_xdg.py +0 -0
  31. {json_database-0.10.2a1 → json_database-1.0.2a1}/test/test_xdg_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: json_database
3
- Version: 0.10.2a1
3
+ Version: 1.0.2a1
4
4
  Summary: searchable json database with persistence
5
5
  Author-email: jarbasAI <jarbasai@mailfence.com>
6
6
  License: MIT
@@ -12,7 +12,7 @@ Requires-Dist: combo_lock<1.0.0,>=0.2.1
12
12
  Provides-Extra: crypto
13
13
  Requires-Dist: pycryptodomex; extra == "crypto"
14
14
  Provides-Extra: hpm
15
- Requires-Dist: hivemind-plugin-manager<1.0.0,>=0.5.0; extra == "hpm"
15
+ Requires-Dist: hivemind-json-db-plugin>=0.0.3a2; extra == "hpm"
16
16
  Provides-Extra: test
17
17
  Requires-Dist: coveralls>=1.8.2; extra == "test"
18
18
  Requires-Dist: flake8>=3.7.9; extra == "test"
@@ -20,7 +20,6 @@ Requires-Dist: pytest>=5.2.4; extra == "test"
20
20
  Requires-Dist: pytest-cov>=2.8.1; extra == "test"
21
21
  Requires-Dist: cov-core>=1.15.0; extra == "test"
22
22
  Requires-Dist: pycryptodomex; extra == "test"
23
- Requires-Dist: hivemind-plugin-manager<1.0.0,>=0.5.0; extra == "test"
24
23
  Dynamic: license-file
25
24
 
26
25
  # json_database
@@ -80,7 +79,6 @@ results = Query(db).equal("role", "user").build()
80
79
  - File locking via `combo_lock` for safe concurrent access
81
80
  - Supports commented JSON files (`//` and `#` line comments)
82
81
  - Arbitrary Python objects stored via automatic `jsonify_recursively` conversion
83
- - HiveMind plugin (`hivemind-json-db-plugin`) for voice assistant integration
84
82
 
85
83
  ## Configuration / Key Options
86
84
 
@@ -116,15 +114,17 @@ results = Query(db).equal("role", "user").build()
116
114
 
117
115
  ## HiveMind Integration
118
116
 
119
- This project includes a native [hivemind-plugin-manager](https://github.com/JarbasHiveMind/hivemind-plugin-manager)
120
- integration (`>=0.5.0`), providing JSON-backed storage for HiveMind client
121
- credentials and permissions via the `hivemind-json-db-plugin` entry point.
122
-
123
- The storage layer is schema-less: the entire `Client.__dict__` is persisted
124
- per record, so new `Client` fields (e.g. the `metadata` dict added in
125
- plugin-manager 0.5.0) round-trip transparently without changes here. See
126
- [Architecture → HiveMind Plugin](docs/ARCHITECTURE.md#hivemind-plugin) for
127
- the storage shape and the deep-copy aliasing contract.
117
+ The HiveMind database-plugin adapter that used to ship as
118
+ `json_database.hpm:JsonDB` has been extracted into its own package,
119
+ [`hivemind-json-db-plugin`](https://github.com/JarbasHiveMind/hivemind-json-db-plugin),
120
+ so it can release on a HiveMind-aligned cadence and `json_database` doesn't pull
121
+ in `hivemind-plugin-manager` for users who don't need it.
122
+
123
+ For the 1.x line, `pip install json_database[hpm]` continues to work — it now
124
+ transitively installs `hivemind-json-db-plugin` so the `hivemind.database`
125
+ entry point remains available without code changes. **The `[hpm]` extra will
126
+ be removed in 2.0.0;** users should migrate to
127
+ `pip install hivemind-json-db-plugin` directly.
128
128
 
129
129
  ## License
130
130
 
@@ -55,7 +55,6 @@ results = Query(db).equal("role", "user").build()
55
55
  - File locking via `combo_lock` for safe concurrent access
56
56
  - Supports commented JSON files (`//` and `#` line comments)
57
57
  - Arbitrary Python objects stored via automatic `jsonify_recursively` conversion
58
- - HiveMind plugin (`hivemind-json-db-plugin`) for voice assistant integration
59
58
 
60
59
  ## Configuration / Key Options
61
60
 
@@ -91,15 +90,17 @@ results = Query(db).equal("role", "user").build()
91
90
 
92
91
  ## HiveMind Integration
93
92
 
94
- This project includes a native [hivemind-plugin-manager](https://github.com/JarbasHiveMind/hivemind-plugin-manager)
95
- integration (`>=0.5.0`), providing JSON-backed storage for HiveMind client
96
- credentials and permissions via the `hivemind-json-db-plugin` entry point.
97
-
98
- The storage layer is schema-less: the entire `Client.__dict__` is persisted
99
- per record, so new `Client` fields (e.g. the `metadata` dict added in
100
- plugin-manager 0.5.0) round-trip transparently without changes here. See
101
- [Architecture → HiveMind Plugin](docs/ARCHITECTURE.md#hivemind-plugin) for
102
- the storage shape and the deep-copy aliasing contract.
93
+ The HiveMind database-plugin adapter that used to ship as
94
+ `json_database.hpm:JsonDB` has been extracted into its own package,
95
+ [`hivemind-json-db-plugin`](https://github.com/JarbasHiveMind/hivemind-json-db-plugin),
96
+ so it can release on a HiveMind-aligned cadence and `json_database` doesn't pull
97
+ in `hivemind-plugin-manager` for users who don't need it.
98
+
99
+ For the 1.x line, `pip install json_database[hpm]` continues to work — it now
100
+ transitively installs `hivemind-json-db-plugin` so the `hivemind.database`
101
+ entry point remains available without code changes. **The `[hpm]` extra will
102
+ be removed in 2.0.0;** users should migrate to
103
+ `pip install hivemind-json-db-plugin` directly.
103
104
 
104
105
  ## License
105
106
 
@@ -0,0 +1,8 @@
1
+ # START_VERSION_BLOCK
2
+ VERSION_MAJOR = 1
3
+ VERSION_MINOR = 0
4
+ VERSION_BUILD = 2
5
+ VERSION_ALPHA = 1
6
+ # END_VERSION_BLOCK
7
+
8
+ __version__ = f"{VERSION_MAJOR}.{VERSION_MINOR}.{VERSION_BUILD}" + (f"a{VERSION_ALPHA}" if VERSION_ALPHA else "")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: json_database
3
- Version: 0.10.2a1
3
+ Version: 1.0.2a1
4
4
  Summary: searchable json database with persistence
5
5
  Author-email: jarbasAI <jarbasai@mailfence.com>
6
6
  License: MIT
@@ -12,7 +12,7 @@ Requires-Dist: combo_lock<1.0.0,>=0.2.1
12
12
  Provides-Extra: crypto
13
13
  Requires-Dist: pycryptodomex; extra == "crypto"
14
14
  Provides-Extra: hpm
15
- Requires-Dist: hivemind-plugin-manager<1.0.0,>=0.5.0; extra == "hpm"
15
+ Requires-Dist: hivemind-json-db-plugin>=0.0.3a2; extra == "hpm"
16
16
  Provides-Extra: test
17
17
  Requires-Dist: coveralls>=1.8.2; extra == "test"
18
18
  Requires-Dist: flake8>=3.7.9; extra == "test"
@@ -20,7 +20,6 @@ Requires-Dist: pytest>=5.2.4; extra == "test"
20
20
  Requires-Dist: pytest-cov>=2.8.1; extra == "test"
21
21
  Requires-Dist: cov-core>=1.15.0; extra == "test"
22
22
  Requires-Dist: pycryptodomex; extra == "test"
23
- Requires-Dist: hivemind-plugin-manager<1.0.0,>=0.5.0; extra == "test"
24
23
  Dynamic: license-file
25
24
 
26
25
  # json_database
@@ -80,7 +79,6 @@ results = Query(db).equal("role", "user").build()
80
79
  - File locking via `combo_lock` for safe concurrent access
81
80
  - Supports commented JSON files (`//` and `#` line comments)
82
81
  - Arbitrary Python objects stored via automatic `jsonify_recursively` conversion
83
- - HiveMind plugin (`hivemind-json-db-plugin`) for voice assistant integration
84
82
 
85
83
  ## Configuration / Key Options
86
84
 
@@ -116,15 +114,17 @@ results = Query(db).equal("role", "user").build()
116
114
 
117
115
  ## HiveMind Integration
118
116
 
119
- This project includes a native [hivemind-plugin-manager](https://github.com/JarbasHiveMind/hivemind-plugin-manager)
120
- integration (`>=0.5.0`), providing JSON-backed storage for HiveMind client
121
- credentials and permissions via the `hivemind-json-db-plugin` entry point.
122
-
123
- The storage layer is schema-less: the entire `Client.__dict__` is persisted
124
- per record, so new `Client` fields (e.g. the `metadata` dict added in
125
- plugin-manager 0.5.0) round-trip transparently without changes here. See
126
- [Architecture → HiveMind Plugin](docs/ARCHITECTURE.md#hivemind-plugin) for
127
- the storage shape and the deep-copy aliasing contract.
117
+ The HiveMind database-plugin adapter that used to ship as
118
+ `json_database.hpm:JsonDB` has been extracted into its own package,
119
+ [`hivemind-json-db-plugin`](https://github.com/JarbasHiveMind/hivemind-json-db-plugin),
120
+ so it can release on a HiveMind-aligned cadence and `json_database` doesn't pull
121
+ in `hivemind-plugin-manager` for users who don't need it.
122
+
123
+ For the 1.x line, `pip install json_database[hpm]` continues to work — it now
124
+ transitively installs `hivemind-json-db-plugin` so the `hivemind.database`
125
+ entry point remains available without code changes. **The `[hpm]` extra will
126
+ be removed in 2.0.0;** users should migrate to
127
+ `pip install hivemind-json-db-plugin` directly.
128
128
 
129
129
  ## License
130
130
 
@@ -4,7 +4,6 @@ pyproject.toml
4
4
  json_database/__init__.py
5
5
  json_database/crypto.py
6
6
  json_database/exceptions.py
7
- json_database/hpm.py
8
7
  json_database/search.py
9
8
  json_database/utils.py
10
9
  json_database/version.py
@@ -12,7 +11,6 @@ json_database/xdg_utils.py
12
11
  json_database.egg-info/PKG-INFO
13
12
  json_database.egg-info/SOURCES.txt
14
13
  json_database.egg-info/dependency_links.txt
15
- json_database.egg-info/entry_points.txt
16
14
  json_database.egg-info/requires.txt
17
15
  json_database.egg-info/top_level.txt
18
16
  test/test_crypto.py
@@ -20,7 +18,6 @@ test/test_database.py
20
18
  test/test_e2e_user_database.py
21
19
  test/test_encrypted_storage.py
22
20
  test/test_exceptions.py
23
- test/test_hpm.py
24
21
  test/test_query.py
25
22
  test/test_search.py
26
23
  test/test_storage.py
@@ -4,7 +4,7 @@ combo_lock<1.0.0,>=0.2.1
4
4
  pycryptodomex
5
5
 
6
6
  [hpm]
7
- hivemind-plugin-manager<1.0.0,>=0.5.0
7
+ hivemind-json-db-plugin>=0.0.3a2
8
8
 
9
9
  [test]
10
10
  coveralls>=1.8.2
@@ -13,4 +13,3 @@ pytest>=5.2.4
13
13
  pytest-cov>=2.8.1
14
14
  cov-core>=1.15.0
15
15
  pycryptodomex
16
- hivemind-plugin-manager<1.0.0,>=0.5.0
@@ -1,10 +1,10 @@
1
1
  [build-system]
2
- requires = ["setuptools>=42", "wheel"]
2
+ requires = ["setuptools>=61", "wheel"]
3
3
  build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "json_database"
7
- version = "0.10.2a1"
7
+ dynamic = ["version"]
8
8
  description = "searchable json database with persistence"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -16,7 +16,16 @@ dependencies = [
16
16
 
17
17
  [project.optional-dependencies]
18
18
  crypto = ["pycryptodomex"]
19
- hpm = ["hivemind-plugin-manager>=0.5.0,<1.0.0"]
19
+ # Back-compat shim for the 1.x line — ``json_database[hpm]`` keeps
20
+ # resolving to a working install of the HiveMind database plugin so
21
+ # existing ``pip install json_database[hpm]`` users don't break on
22
+ # upgrade. The adapter itself was extracted into
23
+ # https://github.com/JarbasHiveMind/hivemind-json-db-plugin; this
24
+ # extra simply pulls it in transitively so the
25
+ # ``hivemind-json-db-plugin`` entry point remains available.
26
+ # This extra will be REMOVED in 2.0.0 — migrate to
27
+ # ``pip install hivemind-json-db-plugin`` directly.
28
+ hpm = ["hivemind-json-db-plugin>=0.0.3a2"]
20
29
  test = [
21
30
  "coveralls>=1.8.2",
22
31
  "flake8>=3.7.9",
@@ -24,14 +33,13 @@ test = [
24
33
  "pytest-cov>=2.8.1",
25
34
  "cov-core>=1.15.0",
26
35
  "pycryptodomex",
27
- "hivemind-plugin-manager>=0.5.0,<1.0.0",
28
36
  ]
29
37
 
30
38
  [project.urls]
31
39
  Homepage = "https://github.com/TigreGotico/json_database"
32
40
 
33
- [project.entry-points."hivemind.database"]
34
- "hivemind-json-db-plugin" = "json_database.hpm:JsonDB"
41
+ [tool.setuptools.dynamic]
42
+ version = {attr = "json_database.version.__version__"}
35
43
 
36
44
  [tool.setuptools.packages.find]
37
45
  where = ["."]
@@ -1,105 +0,0 @@
1
- import copy
2
- from hivemind_plugin_manager.database import Client, AbstractDB, cast2client
3
- from ovos_utils.log import LOG
4
- from ovos_utils.xdg_utils import xdg_data_home
5
- from typing import Union, Iterable, List, Optional
6
- from json_database import JsonStorageXDG, EncryptedJsonStorageXDG
7
- from dataclasses import dataclass
8
-
9
-
10
- @dataclass
11
- class JsonDB(AbstractDB):
12
- """HiveMind Database implementation using JSON files."""
13
- name: str = "clients"
14
- subfolder: str = "hivemind-core"
15
- password: Optional[str] = None
16
-
17
- def __post_init__(self):
18
- if self.password:
19
- self._db = EncryptedJsonStorageXDG(encrypt_key=self.password,
20
- name=self.name,
21
- subfolder=self.subfolder,
22
- xdg_folder=xdg_data_home())
23
- else:
24
- self._db = JsonStorageXDG(self.name,
25
- subfolder=self.subfolder,
26
- xdg_folder=xdg_data_home())
27
- LOG.debug(f"json database path: {self._db.path}")
28
-
29
- def sync(self):
30
- """update db from disk if needed"""
31
- self._db.reload()
32
-
33
- def add_item(self, client: Client) -> bool:
34
- """
35
- Add a client to the JSON database.
36
-
37
- Args:
38
- client: The client to be added.
39
-
40
- Returns:
41
- True if the addition was successful, False otherwise.
42
- """
43
- # Deep copy to break aliasing: dict(client.__dict__) is shallow, so
44
- # mutable fields (metadata dict, intent/skill/message/allowed lists)
45
- # would otherwise reference caller state and pick up later mutations
46
- # on the next commit. Snapshot once on insert.
47
- client_data = copy.deepcopy(client.__dict__)
48
- self._db[client.client_id] = client_data
49
- return True
50
-
51
- def search_by_value(self, key: str, val: Union[str, bool, int, float]) -> List[Client]:
52
- """
53
- Search for clients by a specific key-value pair in the JSON database.
54
-
55
- Args:
56
- key: The key to search by.
57
- val: The value to search for.
58
-
59
- Returns:
60
- A list of clients that match the search criteria.
61
- """
62
- res = []
63
- if key == "client_id":
64
- v = self._db.get(val)
65
- if v:
66
- res.append(cast2client(v))
67
- else:
68
- for client in self._db.values():
69
- v = client.get(key)
70
- if v == val:
71
- res.append(cast2client(client))
72
- return res
73
-
74
- def __len__(self) -> int:
75
- """
76
- Get the number of clients in the database.
77
-
78
- Returns:
79
- The number of clients in the database.
80
- """
81
- return len(self._db)
82
-
83
- def __iter__(self) -> Iterable['Client']:
84
- """
85
- Iterate over all clients in the JSON database.
86
-
87
- Returns:
88
- An iterator over the clients in the database.
89
- """
90
- for item in self._db.values():
91
- yield cast2client(item)
92
-
93
- def commit(self) -> bool:
94
- """
95
- Commit changes to the JSON database.
96
-
97
- Returns:
98
- True if the commit was successful, False otherwise.
99
- """
100
- try:
101
- self._db.store()
102
- return True
103
- except Exception as e:
104
- LOG.error(f"Failed to save {self._db.path} - {e}")
105
- return False
@@ -1,6 +0,0 @@
1
- # START_VERSION_BLOCK
2
- VERSION_MAJOR = 0
3
- VERSION_MINOR = 10
4
- VERSION_BUILD = 4
5
- VERSION_ALPHA = 2
6
- # END_VERSION_BLOCK
@@ -1,2 +0,0 @@
1
- [hivemind.database]
2
- hivemind-json-db-plugin = json_database.hpm:JsonDB
@@ -1,176 +0,0 @@
1
- from hivemind_plugin_manager.database import Client
2
-
3
- import json_database.hpm as hpm
4
- from json_database.hpm import JsonDB
5
-
6
-
7
- def make_db(tmp_path, monkeypatch) -> JsonDB:
8
- """Return an initialized JsonDB backed by a temp XDG data path."""
9
- monkeypatch.setattr(hpm, "xdg_data_home", lambda: str(tmp_path))
10
- return JsonDB()
11
-
12
-
13
- def make_client(*, metadata=None, **kwargs) -> Client:
14
- """Build a Client with optional metadata."""
15
- client = Client(**kwargs)
16
- if metadata is not None:
17
- client.metadata = metadata
18
- return client
19
-
20
-
21
- def test_hivemind_client_metadata_survives_search_round_trip(tmp_path, monkeypatch):
22
- """Client metadata survives add and search in JsonDB."""
23
- db = make_db(tmp_path, monkeypatch)
24
- client = make_client(
25
- client_id=1,
26
- api_key="alpha-key",
27
- name="alpha",
28
- metadata={"owner_id": "owner-123"},
29
- )
30
-
31
- assert db.add_item(client)
32
- found = db.search_by_value("api_key", "alpha-key")
33
-
34
- assert len(found) == 1
35
- assert found[0].metadata == {"owner_id": "owner-123"}
36
-
37
-
38
- def test_hivemind_client_metadata_survives_iteration(tmp_path, monkeypatch):
39
- """Client metadata survives iteration in JsonDB."""
40
- db = make_db(tmp_path, monkeypatch)
41
- client = make_client(
42
- client_id=1,
43
- api_key="alpha-key",
44
- name="alpha",
45
- metadata={"owner_id": "owner-123"},
46
- )
47
-
48
- assert db.add_item(client)
49
- found = list(db)
50
-
51
- assert len(found) == 1
52
- assert found[0].metadata == {"owner_id": "owner-123"}
53
-
54
-
55
- def test_hivemind_client_metadata_record_round_trips(tmp_path, monkeypatch):
56
- """Stored metadata round-trips through search_by_value."""
57
- db = make_db(tmp_path, monkeypatch)
58
- db._db[1] = {
59
- "client_id": 1,
60
- "api_key": "alpha-key",
61
- "name": "alpha",
62
- "metadata": {"owner_id": "owner-123"},
63
- }
64
-
65
- found = db.search_by_value("api_key", "alpha-key")
66
-
67
- assert len(found) == 1
68
- assert found[0].api_key == "alpha-key"
69
- assert found[0].metadata == {"owner_id": "owner-123"}
70
-
71
-
72
- def test_metadata_defaults_to_empty_when_missing(tmp_path, monkeypatch):
73
- """Clients added without a metadata dict get persisted with metadata={}."""
74
- db = make_db(tmp_path, monkeypatch)
75
- db.add_item(Client(client_id=1, api_key="k", name="a"))
76
- assert db._db[1]["metadata"] == {}
77
- found = db.search_by_value("api_key", "k")
78
- assert found[0].metadata == {}
79
-
80
-
81
- def test_search_by_client_id_returns_metadata(tmp_path, monkeypatch):
82
- """The client_id search path also preserves metadata."""
83
- db = make_db(tmp_path, monkeypatch)
84
- db.add_item(make_client(client_id=1, api_key="k", name="a",
85
- metadata={"tier": "gold"}))
86
- found = db.search_by_value("client_id", 1)
87
- assert len(found) == 1
88
- assert found[0].metadata == {"tier": "gold"}
89
-
90
-
91
- def test_nested_and_non_ascii_metadata_round_trip(tmp_path, monkeypatch):
92
- """Nested structures and non-ASCII characters survive add → iterate."""
93
- db = make_db(tmp_path, monkeypatch)
94
- meta = {
95
- "owner": {"id": "owner-1", "tags": ["a", "b"]},
96
- "name": "Zé Ninguém",
97
- "emoji": "🚀",
98
- }
99
- db.add_item(make_client(client_id=1, api_key="k", name="a", metadata=meta))
100
- found = list(db)
101
- assert found[0].metadata == meta
102
-
103
-
104
- def test_metadata_survives_commit_and_reload(tmp_path, monkeypatch):
105
- """add_item → commit → new JsonDB pointed at the same path reads metadata back."""
106
- db = make_db(tmp_path, monkeypatch)
107
- db.add_item(make_client(client_id=1, api_key="k", name="a",
108
- metadata={"owner": "owner-1"}))
109
- assert db.commit()
110
-
111
- # Fresh JsonDB instance against the same xdg_data_home path
112
- fresh = make_db(tmp_path, monkeypatch)
113
- found = fresh.search_by_value("api_key", "k")
114
- assert len(found) == 1
115
- assert found[0].metadata == {"owner": "owner-1"}
116
-
117
-
118
- def test_add_item_snapshots_metadata_against_caller_mutation(tmp_path, monkeypatch):
119
- """Caller mutations to client.metadata after add_item must not leak into
120
- the stored record — including mutations of nested dicts."""
121
- db = make_db(tmp_path, monkeypatch)
122
- meta = {"v": "original", "nested": {"k": "n_original"}}
123
- client = make_client(client_id=1, api_key="k", name="a", metadata=meta)
124
- db.add_item(client)
125
-
126
- meta["v"] = "mutated"
127
- meta["nested"]["k"] = "n_mutated"
128
- client.metadata["added"] = "later"
129
-
130
- found = db.search_by_value("api_key", "k")
131
- assert found[0].metadata == {"v": "original", "nested": {"k": "n_original"}}
132
-
133
-
134
- def test_add_item_snapshots_list_fields_against_caller_mutation(tmp_path, monkeypatch):
135
- """Same aliasing bug applied to all mutable list fields: caller mutation
136
- of intent_blacklist / skill_blacklist / message_blacklist / allowed_types
137
- after add_item must not leak into the stored record."""
138
- db = make_db(tmp_path, monkeypatch)
139
- intents = ["skill:a"]
140
- skills = ["skill:b"]
141
- messages = ["msg:c"]
142
- allowed = ["recognizer_loop:utterance", "speak:b64_audio"]
143
- client = Client(
144
- client_id=1, api_key="k", name="a",
145
- intent_blacklist=intents,
146
- skill_blacklist=skills,
147
- message_blacklist=messages,
148
- allowed_types=allowed,
149
- )
150
- db.add_item(client)
151
-
152
- # mutate the caller-side lists and the lists still on the client
153
- intents.append("skill:leaked")
154
- client.skill_blacklist.append("skill:leaked")
155
- messages.append("msg:leaked")
156
- client.allowed_types.append("speak:leaked")
157
-
158
- found = db.search_by_value("api_key", "k")
159
- assert found[0].intent_blacklist == ["skill:a"]
160
- assert found[0].skill_blacklist == ["skill:b"]
161
- assert found[0].message_blacklist == ["msg:c"]
162
- # allowed_types: __post_init__ guarantees "recognizer_loop:utterance" is
163
- # in the list, so verify the leaked entry isn't there.
164
- assert "speak:leaked" not in found[0].allowed_types
165
-
166
-
167
- def test_add_item_overwrites_metadata_for_same_client_id(tmp_path, monkeypatch):
168
- """Re-adding a client with the same client_id replaces stored metadata."""
169
- db = make_db(tmp_path, monkeypatch)
170
- db.add_item(make_client(client_id=1, api_key="k", name="a",
171
- metadata={"v": "old"}))
172
- db.add_item(make_client(client_id=1, api_key="k", name="a",
173
- metadata={"v": "new", "extra": "x"}))
174
- found = db.search_by_value("api_key", "k")
175
- assert len(found) == 1
176
- assert found[0].metadata == {"v": "new", "extra": "x"}