Skip to content

Commit 1464a0d

Browse files
authored
#212 Why Search (#223)
* #212 Savepoint * #212 Savepoint * #212 Prepare for versioned release * #212 Savepoint * #212 Update dependencies * #212 Savepoint * #212 Fix spacing * Force re-test
1 parent 126548f commit 1464a0d

15 files changed

+420
-195
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning].
77

88
## [Unreleased]
99

10+
## [0.3.5] - 2025-04-16
11+
12+
### Added in 0.3.5
13+
14+
- `SzEngine.why_search`
15+
1016
## [0.3.4] - 2025-04-11
1117

1218
### Changed in 0.3.4

development-requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ sphinx-autodoc-typehints==3.1.0
1515
sphinx-gallery==0.19.0
1616
sphinx-jinja2-compat==0.3.0
1717
sphinx-prompt==1.9.0
18-
sphinxext-remoteliteralinclude==0.5.0
1918
sphinx-rtd-theme==3.0.2
2019
sphinx-tabs==3.4.7
2120
sphinx-toolbox==3.8.0
@@ -27,6 +26,7 @@ sphinxcontrib-jquery==4.1
2726
sphinxcontrib-jsmath==1.0.1
2827
sphinxcontrib-qthelp==2.0.0
2928
sphinxcontrib-serializinghtml==2.0.0
29+
sphinxext-remoteliteralinclude==0.5.0
3030
twine==6.1.0
3131
virtualenv==20.30.0
3232
wheel==0.46.1

examples/szengine/why_search.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#! /usr/bin/env python3
2+
3+
import json
4+
5+
from senzing import SzEngineFlags, SzError
6+
7+
from senzing_core import SzAbstractFactoryCore
8+
9+
ATTRIBUTES = json.dumps({"NAME_FULL": "BOB SMITH", "EMAIL_ADDRESS": "bsmith@work.com"})
10+
ENTITY_ID = 1
11+
FLAGS = SzEngineFlags.SZ_SEARCH_BY_ATTRIBUTES_DEFAULT_FLAGS
12+
INSTANCE_NAME = "Example"
13+
SEARCH_PROFILE = ""
14+
SETTINGS = {
15+
"PIPELINE": {
16+
"CONFIGPATH": "/etc/opt/senzing",
17+
"RESOURCEPATH": "/opt/senzing/er/resources",
18+
"SUPPORTPATH": "/opt/senzing/data",
19+
},
20+
"SQL": {"CONNECTION": "sqlite3://na:na@/tmp/sqlite/G2C.db"},
21+
}
22+
23+
try:
24+
sz_abstract_factory = SzAbstractFactoryCore(INSTANCE_NAME, SETTINGS)
25+
sz_engine = sz_abstract_factory.create_engine()
26+
RESULT = sz_engine.why_search(ATTRIBUTES, ENTITY_ID, FLAGS, SEARCH_PROFILE)
27+
print(f"\n{RESULT}\n")
28+
except SzError as err:
29+
print(f"\nERROR: {err}\n")

examples/szengine/why_search.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Output has been formatted for easier reading.
2+
{
3+
"WHY_RESULTS": [
4+
{
5+
"ENTITY_ID": 1,
6+
"MATCH_INFO": {
7+
"WHY_KEY": "+PNAME+EMAIL",
8+
"WHY_ERRULE_CODE": "SF1",
9+
"MATCH_LEVEL_CODE": "POSSIBLY_RELATED"
10+
}
11+
}
12+
],
13+
"ENTITIES": [
14+
{
15+
"RESOLVED_ENTITY": {
16+
"ENTITY_ID": 1
17+
}
18+
}
19+
]
20+
}

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
orjson==3.10.16
2-
senzing==0.2.5
2+
senzing==0.2.6

setup.cfg

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = senzing_core
3-
version = 0.3.4
3+
version = 0.3.5
44
author = senzing
55
author_email = support@senzing.com
66
description = Senzing Python SDK
@@ -21,7 +21,7 @@ package_dir =
2121
packages = find:
2222
python_requires = >=3.9
2323
install_requires =
24-
senzing >= 0.2.2,<1.0.0
24+
senzing >= 0.2.6,<1.0.0
2525

2626
[options.packages.find]
2727
where = src

src/senzing_core/szabstractfactory.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -187,15 +187,15 @@ def reinitialize(self, config_id: int) -> None:
187187

188188
if self.is_szengine_initialized:
189189
sz_engine = SzEngineCore()
190-
sz_engine._reinitialize(config_id=config_id) # pylint: disable=W0212
190+
sz_engine.reinitialize(config_id=config_id) # pylint: disable=W0212
191191

192192
if self.is_szdiagnostic_initialized:
193193
sz_diagnostic = SzDiagnosticCore()
194-
sz_diagnostic._reinitialize(config_id=config_id) # pylint: disable=W0212
194+
sz_diagnostic.reinitialize(config_id=config_id) # pylint: disable=W0212
195195
if self.is_szengine_initialized:
196196
sz_engine = SzEngineCore()
197-
sz_engine._reinitialize(config_id=config_id) # pylint: disable=W0212
197+
sz_engine.reinitialize(config_id=config_id) # pylint: disable=W0212
198198

199199
if self.is_szdiagnostic_initialized:
200200
sz_diagnostic = SzDiagnosticCore()
201-
sz_diagnostic._reinitialize(config_id=config_id) # pylint: disable=W0212
201+
sz_diagnostic.reinitialize(config_id=config_id) # pylint: disable=W0212

src/senzing_core/szdiagnostic.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,11 @@ def purge_repository(self) -> None:
216216
self.check_result(result)
217217

218218
@catch_non_sz_exceptions
219-
def _reinitialize(self, config_id: int) -> None:
219+
def reinitialize(self, config_id: int) -> None:
220+
"""
221+
The `reinitialize` method reinitializes the Senzing object using a specific configuration
222+
identifier. A list of available configuration identifiers can be retrieved using
223+
`szconfigmanager.get_configs`.
224+
"""
220225
result = self.library_handle.SzDiagnostic_reinit(config_id)
221226
self.check_result(result)

src/senzing_core/szengine.py

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,14 @@ class SzWhyRecordsV2Result(SzResponseReturnCodeResult):
215215
"""In SzLang_helpers.h Sz_whyRecords_V2_result"""
216216

217217

218+
class SzWhySearchResult(SzResponseReturnCodeResult):
219+
"""In SzLang_helpers.h Sz_whyEntities_result"""
220+
221+
222+
class SzWhySearchV2Result(SzResponseReturnCodeResult):
223+
"""In SzLang_helpers.h Sz_whyEntities_V2_result"""
224+
225+
218226
# -----------------------------------------------------------------------------
219227
# SzEngineCore class
220228
# -----------------------------------------------------------------------------
@@ -503,6 +511,7 @@ def __init__(self, **kwargs: Any) -> None:
503511
c_char_p,
504512
c_longlong,
505513
]
514+
self.library_handle.Sz_whyRecords_V2_helper.restype = SzWhyRecordsV2Result
506515
self.library_handle.Sz_whyRecordInEntity_V2_helper.restype = SzWhyRecordInEntityV2Result
507516
self.library_handle.Sz_whyRecords_V2_helper.argtypes = [
508517
c_char_p,
@@ -511,7 +520,19 @@ def __init__(self, **kwargs: Any) -> None:
511520
c_char_p,
512521
c_longlong,
513522
]
514-
self.library_handle.Sz_whyRecords_V2_helper.restype = SzWhyRecordsV2Result
523+
self.library_handle.Sz_whySearch_helper.restype = SzWhySearchResult
524+
self.library_handle.Sz_whySearch_helper.argtypes = [
525+
c_char_p,
526+
c_longlong,
527+
c_char_p,
528+
]
529+
self.library_handle.Sz_whySearch_V2_helper.restype = SzWhySearchV2Result
530+
self.library_handle.Sz_whySearch_V2_helper.argtypes = [
531+
c_char_p,
532+
c_longlong,
533+
c_char_p,
534+
c_longlong,
535+
]
515536
self.library_handle.SzHelper_free.argtypes = [c_void_p]
516537

517538
def __del__(self) -> None:
@@ -976,7 +997,12 @@ def reevaluate_record(
976997
return self.no_info
977998

978999
@catch_non_sz_exceptions
979-
def _reinitialize(self, config_id: int) -> None:
1000+
def reinitialize(self, config_id: int) -> None:
1001+
"""
1002+
The `reinitialize` method reinitializes the Senzing object using a specific configuration
1003+
identifier. A list of available configuration identifiers can be retrieved using
1004+
`szconfigmanager.get_configs`.
1005+
"""
9801006
result = self.library_handle.Sz_reinit(config_id)
9811007
self.check_result(result)
9821008

@@ -1047,3 +1073,21 @@ def why_record_in_entity(
10471073
with FreeCResources(self.library_handle, result.response):
10481074
self.check_result(result.return_code)
10491075
return as_python_str(result.response)
1076+
1077+
@catch_non_sz_exceptions
1078+
def why_search(
1079+
self,
1080+
attributes: str,
1081+
entity_id: int,
1082+
flags: int = SzEngineFlags.SZ_ENTITY_DEFAULT_FLAGS,
1083+
search_profile: str = "",
1084+
) -> str:
1085+
result = self.library_handle.Sz_whySearch_V2_helper(
1086+
as_c_char_p(attributes),
1087+
entity_id,
1088+
as_c_char_p(search_profile),
1089+
flags,
1090+
)
1091+
with FreeCResources(self.library_handle, result.response):
1092+
self.check_result(result.return_code)
1093+
return as_python_str(result.response)

tests/szabstractfactory_test.py

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
#! /usr/bin/env python3
2+
3+
"""
4+
TODO: szabstractfactory_test.py
5+
"""
6+
7+
18
from datetime import datetime
29
from typing import Any, Dict
310

@@ -13,42 +20,51 @@
1320
from senzing_core import SzAbstractFactoryCore
1421

1522
# -----------------------------------------------------------------------------
16-
# Testcases
23+
# Test cases
1724
# -----------------------------------------------------------------------------
1825

1926

20-
def test_create_configmanager(sz_abstract_factory: SzAbstractFactory) -> None:
21-
"""Create SzConfigManager."""
22-
actual = sz_abstract_factory.create_configmanager()
27+
def test_create_configmanager(sz_abstractfactory: SzAbstractFactory) -> None:
28+
"""Test SzAbstractFactory.create_configmanager()."""
29+
actual = sz_abstractfactory.create_configmanager()
2330
assert isinstance(actual, SzConfigManager)
2431

2532

26-
def test_create_diagnostic(sz_abstract_factory: SzAbstractFactory) -> None:
27-
"""Create SzDiagnostic."""
28-
actual = sz_abstract_factory.create_diagnostic()
33+
def test_create_diagnostic(sz_abstractfactory: SzAbstractFactory) -> None:
34+
"""Test SzAbstractFactory.create_diagnostic()."""
35+
actual = sz_abstractfactory.create_diagnostic()
2936
assert isinstance(actual, SzDiagnostic)
3037

3138

32-
def test_create_engine(sz_abstract_factory: SzAbstractFactory) -> None:
33-
"""Create SzEngine."""
34-
actual = sz_abstract_factory.create_engine()
39+
def test_create_engine(sz_abstractfactory: SzAbstractFactory) -> None:
40+
"""Test SzAbstractFactory.create_engine()."""
41+
actual = sz_abstractfactory.create_engine()
3542
assert isinstance(actual, SzEngine)
3643

3744

38-
def test_create_product(sz_abstract_factory: SzAbstractFactory) -> None:
39-
"""Create SzProduct."""
40-
actual = sz_abstract_factory.create_product()
45+
def test_create_product(sz_abstractfactory: SzAbstractFactory) -> None:
46+
"""Test SzAbstractFactory.create_product()."""
47+
actual = sz_abstractfactory.create_product()
4148
assert isinstance(actual, SzProduct)
4249

4350

44-
def test_reinitialize(sz_abstract_factory: SzAbstractFactory) -> None:
45-
"""Create SzConfig."""
51+
def test_help_1(sz_abstractfactory: SzAbstractFactory) -> None:
52+
"""Test SzAbstractFactory.help()."""
53+
sz_abstractfactory.help()
54+
55+
56+
def test_help_2(sz_abstractfactory: SzAbstractFactory) -> None:
57+
"""Test SzAbstractFactory.help(...)."""
58+
sz_abstractfactory.help("create_configmanager")
59+
4660

61+
def test_reinitialize(sz_abstractfactory: SzAbstractFactory) -> None:
62+
"""Test SzAbstractFactory.reinitialize()."""
4763
datasources = [f"TEST_DATASOURCE_{datetime.now().timestamp()}"]
4864

4965
# Create Senzing objects.
5066

51-
sz_configmanager = sz_abstract_factory.create_configmanager()
67+
sz_configmanager = sz_abstractfactory.create_configmanager()
5268
sz_config = sz_configmanager.create_config_from_template()
5369

5470
# Add DataSources to Senzing configuration.
@@ -63,7 +79,7 @@ def test_reinitialize(sz_abstract_factory: SzAbstractFactory) -> None:
6379

6480
# Update other Senzing objects.
6581

66-
sz_abstract_factory.reinitialize(config_id)
82+
sz_abstractfactory.reinitialize(config_id)
6783

6884

6985
# -----------------------------------------------------------------------------
@@ -76,10 +92,10 @@ def test_reinitialize(sz_abstract_factory: SzAbstractFactory) -> None:
7692
# -----------------------------------------------------------------------------
7793

7894

79-
@pytest.fixture(name="sz_abstract_factory", scope="function")
80-
def sz_abstract_factory_fixture(engine_vars: Dict[Any, Any]) -> SzAbstractFactory:
95+
@pytest.fixture(name="sz_abstractfactory", scope="function")
96+
def szabstractfactory_fixture(engine_vars: Dict[Any, Any]) -> SzAbstractFactory:
8197
"""
82-
Single SzAbstractFactoryCore object to use for all tests.
98+
SzAbstractFactory object to use for all tests.
8399
"""
84100

85101
factory_parameters = {

0 commit comments

Comments
 (0)