pyneoinstance 4.0.0__tar.gz → 4.0.2__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.
- {pyneoinstance-4.0.0/pyneoinstance.egg-info → pyneoinstance-4.0.2}/PKG-INFO +6 -4
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/README.md +3 -2
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance/__init__.py +1 -1
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance/database/neo4jdbms.py +16 -19
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2/pyneoinstance.egg-info}/PKG-INFO +6 -4
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance.egg-info/requires.txt +2 -1
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyproject.toml +3 -3
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/test/cypher_queries.yaml +3 -3
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/test/test_neo4jdb.py +14 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/test/test_util_functions.py +1 -1
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/LICENSE +0 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/MANIFEST.in +0 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance/database/__init__.py +0 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance/database/context.py +0 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance/fileload/__init__.py +0 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance/fileload/helpers.py +0 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance/fileload/loadyaml.py +0 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance/py.typed +0 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance/util/__init__.py +0 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance/util/functions.py +0 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance.egg-info/SOURCES.txt +0 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance.egg-info/dependency_links.txt +0 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance.egg-info/top_level.txt +0 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/setup.cfg +0 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/setup.py +0 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/test/__init__.py +0 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/test/age_data.csv +0 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/test/context.py +0 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/test/load_files.yaml +0 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/test/movies.csv +0 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/test/people.csv +0 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/test/roles.csv +0 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/test/test.py +0 -0
- {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/test/test_fileload.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyneoinstance
|
|
3
|
-
Version: 4.0.
|
|
3
|
+
Version: 4.0.2
|
|
4
4
|
Summary: Handle Neo4j read and write transactions and provide methods for performing graph EDA
|
|
5
5
|
Author-email: "Jose A. Alvarado-Guzman" <jose.alvarado-guzman@neo4j.com>
|
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
|
@@ -694,9 +694,10 @@ Requires-Dist: neo4j-rust-ext>=5.0.0
|
|
|
694
694
|
Requires-Dist: pandas>=1.3.0
|
|
695
695
|
Requires-Dist: PyYAML>=5.1
|
|
696
696
|
Requires-Dist: pyvis>=0.3.0
|
|
697
|
-
Requires-Dist: neo4j-viz>=0.
|
|
697
|
+
Requires-Dist: neo4j-viz>=1.0.0
|
|
698
698
|
Provides-Extra: docs
|
|
699
699
|
Requires-Dist: mkdocs-material>=9.0.0; extra == "docs"
|
|
700
|
+
Requires-Dist: mkdocstrings[python]>=0.24.0; extra == "docs"
|
|
700
701
|
Dynamic: license-file
|
|
701
702
|
|
|
702
703
|
# PyNeoInstance Package
|
|
@@ -794,7 +795,7 @@ This YAML file can then be loaded in Python and this information can be retrieve
|
|
|
794
795
|
```python
|
|
795
796
|
from pyneoinstance import load_yaml_file
|
|
796
797
|
|
|
797
|
-
config = load_yaml_file(configuration.yaml)
|
|
798
|
+
config = load_yaml_file('configuration.yaml')
|
|
798
799
|
db_info = config['db_info']
|
|
799
800
|
graph = Neo4jInstance(db_info['uri'], db_info['user'], db_info['password'])
|
|
800
801
|
```
|
|
@@ -1037,5 +1038,6 @@ Open `schema.html` in your browser to explore the schema interactively.
|
|
|
1037
1038
|
## More detailed examples
|
|
1038
1039
|
|
|
1039
1040
|
For more detailed examples please refer to the following articles:
|
|
1040
|
-
* Data
|
|
1041
|
+
* Data Ingestion: [PyNeoInstance: A User-Friendly Python Library for Neo4j](https://medium.com/@a-gilmore/pyneoinstance-a-user-friendly-python-library-for-neo4j-dbefa3117bb2).
|
|
1041
1042
|
* Graph EDA: [Performing graph EDA with the PyNeoInstance Python Package](https://medium.com/@jose.alvarado-guzman/0c0f6f230aa9)
|
|
1043
|
+
* ETL Best Practices: [Python & Neo4j: ETL Best Practices](https://medium.com/@jose.alvarado-guzman/python-neo4j-etl-best-practices-83265ee201d6)
|
|
@@ -93,7 +93,7 @@ This YAML file can then be loaded in Python and this information can be retrieve
|
|
|
93
93
|
```python
|
|
94
94
|
from pyneoinstance import load_yaml_file
|
|
95
95
|
|
|
96
|
-
config = load_yaml_file(configuration.yaml)
|
|
96
|
+
config = load_yaml_file('configuration.yaml')
|
|
97
97
|
db_info = config['db_info']
|
|
98
98
|
graph = Neo4jInstance(db_info['uri'], db_info['user'], db_info['password'])
|
|
99
99
|
```
|
|
@@ -336,5 +336,6 @@ Open `schema.html` in your browser to explore the schema interactively.
|
|
|
336
336
|
## More detailed examples
|
|
337
337
|
|
|
338
338
|
For more detailed examples please refer to the following articles:
|
|
339
|
-
* Data
|
|
339
|
+
* Data Ingestion: [PyNeoInstance: A User-Friendly Python Library for Neo4j](https://medium.com/@a-gilmore/pyneoinstance-a-user-friendly-python-library-for-neo4j-dbefa3117bb2).
|
|
340
340
|
* Graph EDA: [Performing graph EDA with the PyNeoInstance Python Package](https://medium.com/@jose.alvarado-guzman/0c0f6f230aa9)
|
|
341
|
+
* ETL Best Practices: [Python & Neo4j: ETL Best Practices](https://medium.com/@jose.alvarado-guzman/python-neo4j-etl-best-practices-83265ee201d6)
|
|
@@ -28,6 +28,7 @@ from .context import get_logger, get_batches, get_columns_diff
|
|
|
28
28
|
|
|
29
29
|
_NODE_LABEL_RE = re.compile(r"\(:?(\w*)\)")
|
|
30
30
|
_REL_TYPE_RE = re.compile(r"\[:?(\w*)\]")
|
|
31
|
+
_IMPLICIT_TX_RE = re.compile(r"\bIN\s+TRANSACTIONS\b", re.IGNORECASE)
|
|
31
32
|
|
|
32
33
|
def _get_driver(neo_info : Dict[str, str]):
|
|
33
34
|
try:
|
|
@@ -84,8 +85,8 @@ class Neo4jInstance:
|
|
|
84
85
|
kwargs: Optional[Dict[str, Any]]) -> None
|
|
85
86
|
Execute a write query to a specific database.
|
|
86
87
|
get_query_visualization(query: str, database: Optional[str],
|
|
87
|
-
parameters: Optional[Dict[str, Any]]) ->
|
|
88
|
-
Execute a read query and return the result as a
|
|
88
|
+
parameters: Optional[Dict[str, Any]]) -> VisualizationGraph
|
|
89
|
+
Execute a read query and return the result as a neo4j-viz graph visualization.
|
|
89
90
|
execute_write_query_with_data(self, query: str, data: DataFrame,
|
|
90
91
|
database: Optional[str] = None,
|
|
91
92
|
partitions: Optional[int] = 1,
|
|
@@ -110,7 +111,7 @@ class Neo4jInstance:
|
|
|
110
111
|
Parameters
|
|
111
112
|
----------
|
|
112
113
|
uri : str
|
|
113
|
-
|
|
114
|
+
The Uniform Resource Identifier of the database.
|
|
114
115
|
user : str
|
|
115
116
|
The Neo4j username.
|
|
116
117
|
password : str
|
|
@@ -206,9 +207,7 @@ class Neo4jInstance:
|
|
|
206
207
|
|
|
207
208
|
def get_query_visualization(self, query: str,
|
|
208
209
|
database: Optional[str] = None,
|
|
209
|
-
parameters: Optional[Dict[str, Any]] = None
|
|
210
|
-
node_caption: Optional[str] = 'labels',
|
|
211
|
-
relationship_caption: Optional[str] = 'type'
|
|
210
|
+
parameters: Optional[Dict[str, Any]] = None
|
|
212
211
|
) -> VisualizationGraph:
|
|
213
212
|
"""Execute a read query and return the result as a graph visualization.
|
|
214
213
|
|
|
@@ -221,15 +220,12 @@ class Neo4jInstance:
|
|
|
221
220
|
If not provided the default database is used.
|
|
222
221
|
parameters : Dict[str, Any], optional
|
|
223
222
|
Extra arguments containing optional Cypher parameters.
|
|
224
|
-
node_caption : str, optional
|
|
225
|
-
Node property to use as the caption. Defaults to 'labels'.
|
|
226
|
-
relationship_caption : str, optional
|
|
227
|
-
Relationship property to use as the caption. Defaults to 'type'.
|
|
228
223
|
|
|
229
224
|
Returns
|
|
230
225
|
-------
|
|
231
226
|
VisualizationGraph
|
|
232
|
-
neo4j-viz VisualizationGraph object.
|
|
227
|
+
neo4j-viz VisualizationGraph object. Node captions are derived
|
|
228
|
+
from node labels; relationship captions from relationship type.
|
|
233
229
|
In a Jupyter notebook call ``vg.render()`` to display it inline.
|
|
234
230
|
To save as a standalone HTML file, wrap the fragment in a full document::
|
|
235
231
|
|
|
@@ -253,9 +249,7 @@ class Neo4jInstance:
|
|
|
253
249
|
raise ServiceUnavailable() from exception
|
|
254
250
|
except ClientError as exception:
|
|
255
251
|
raise ClientError(str(exception)) from exception
|
|
256
|
-
return from_neo4j(graph
|
|
257
|
-
node_caption=node_caption,
|
|
258
|
-
relationship_caption=relationship_caption)
|
|
252
|
+
return from_neo4j(graph)
|
|
259
253
|
|
|
260
254
|
def execute_write_queries(self, queries: List[str],
|
|
261
255
|
database: Optional[str] = None,
|
|
@@ -757,15 +751,18 @@ class Neo4jInstance:
|
|
|
757
751
|
parameters: Optional[Dict[str, Any]] = None
|
|
758
752
|
):
|
|
759
753
|
params = parameters or {}
|
|
754
|
+
kwargs = dict(params)
|
|
755
|
+
if rows is not None:
|
|
756
|
+
kwargs['rows'] = rows
|
|
760
757
|
try:
|
|
761
|
-
if
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
758
|
+
if _IMPLICIT_TX_RE.search(query):
|
|
759
|
+
# 'CALL { ... } IN TRANSACTIONS' is only valid in an implicit
|
|
760
|
+
# (auto-commit) transaction, so it can't go through execute_write.
|
|
761
|
+
results = session.run(query, **kwargs).consume().counters.__dict__
|
|
765
762
|
else:
|
|
766
763
|
results = session.execute_write(
|
|
767
764
|
_write_transaction_function, query,
|
|
768
|
-
**
|
|
765
|
+
**kwargs).counters.__dict__
|
|
769
766
|
except ServiceUnavailable as exception:
|
|
770
767
|
raise ServiceUnavailable() from exception
|
|
771
768
|
except ClientError as exception:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyneoinstance
|
|
3
|
-
Version: 4.0.
|
|
3
|
+
Version: 4.0.2
|
|
4
4
|
Summary: Handle Neo4j read and write transactions and provide methods for performing graph EDA
|
|
5
5
|
Author-email: "Jose A. Alvarado-Guzman" <jose.alvarado-guzman@neo4j.com>
|
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
|
@@ -694,9 +694,10 @@ Requires-Dist: neo4j-rust-ext>=5.0.0
|
|
|
694
694
|
Requires-Dist: pandas>=1.3.0
|
|
695
695
|
Requires-Dist: PyYAML>=5.1
|
|
696
696
|
Requires-Dist: pyvis>=0.3.0
|
|
697
|
-
Requires-Dist: neo4j-viz>=0.
|
|
697
|
+
Requires-Dist: neo4j-viz>=1.0.0
|
|
698
698
|
Provides-Extra: docs
|
|
699
699
|
Requires-Dist: mkdocs-material>=9.0.0; extra == "docs"
|
|
700
|
+
Requires-Dist: mkdocstrings[python]>=0.24.0; extra == "docs"
|
|
700
701
|
Dynamic: license-file
|
|
701
702
|
|
|
702
703
|
# PyNeoInstance Package
|
|
@@ -794,7 +795,7 @@ This YAML file can then be loaded in Python and this information can be retrieve
|
|
|
794
795
|
```python
|
|
795
796
|
from pyneoinstance import load_yaml_file
|
|
796
797
|
|
|
797
|
-
config = load_yaml_file(configuration.yaml)
|
|
798
|
+
config = load_yaml_file('configuration.yaml')
|
|
798
799
|
db_info = config['db_info']
|
|
799
800
|
graph = Neo4jInstance(db_info['uri'], db_info['user'], db_info['password'])
|
|
800
801
|
```
|
|
@@ -1037,5 +1038,6 @@ Open `schema.html` in your browser to explore the schema interactively.
|
|
|
1037
1038
|
## More detailed examples
|
|
1038
1039
|
|
|
1039
1040
|
For more detailed examples please refer to the following articles:
|
|
1040
|
-
* Data
|
|
1041
|
+
* Data Ingestion: [PyNeoInstance: A User-Friendly Python Library for Neo4j](https://medium.com/@a-gilmore/pyneoinstance-a-user-friendly-python-library-for-neo4j-dbefa3117bb2).
|
|
1041
1042
|
* Graph EDA: [Performing graph EDA with the PyNeoInstance Python Package](https://medium.com/@jose.alvarado-guzman/0c0f6f230aa9)
|
|
1043
|
+
* ETL Best Practices: [Python & Neo4j: ETL Best Practices](https://medium.com/@jose.alvarado-guzman/python-neo4j-etl-best-practices-83265ee201d6)
|
|
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "pyneoinstance"
|
|
9
|
-
version = "4.0.
|
|
9
|
+
version = "4.0.2"
|
|
10
10
|
description = "Handle Neo4j read and write transactions and provide methods for performing graph EDA"
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
authors = [{ name = "Jose A. Alvarado-Guzman",email = "jose.alvarado-guzman@neo4j.com" }]
|
|
@@ -25,12 +25,12 @@ dependencies = [
|
|
|
25
25
|
"pandas>=1.3.0",
|
|
26
26
|
"PyYAML>=5.1",
|
|
27
27
|
"pyvis>=0.3.0",
|
|
28
|
-
"neo4j-viz>=0.
|
|
28
|
+
"neo4j-viz>=1.0.0"
|
|
29
29
|
]
|
|
30
30
|
requires-python = ">=3.10"
|
|
31
31
|
|
|
32
32
|
[project.optional-dependencies]
|
|
33
|
-
docs = ["mkdocs-material>=9.0.0"]
|
|
33
|
+
docs = ["mkdocs-material>=9.0.0", "mkdocstrings[python]>=0.24.0"]
|
|
34
34
|
|
|
35
35
|
[tool.setuptools.packages.find]
|
|
36
36
|
exclude = ["test*"]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
database:
|
|
1
|
+
database: neo4j
|
|
2
2
|
pre_ingest:
|
|
3
|
-
- CREATE CONSTRAINT nkPerson IF NOT EXISTS FOR(n:Person) REQUIRE (n.personId) IS
|
|
4
|
-
- CREATE CONSTRAINT nkMovie IF NOT EXISTS FOR(n:Movie) REQUIRE (n.movieId) IS
|
|
3
|
+
- CREATE CONSTRAINT nkPerson IF NOT EXISTS FOR(n:Person) REQUIRE (n.personId) IS UNIQUE;
|
|
4
|
+
- CREATE CONSTRAINT nkMovie IF NOT EXISTS FOR(n:Movie) REQUIRE (n.movieId) IS UNIQUE;
|
|
5
5
|
|
|
6
6
|
queries:
|
|
7
7
|
load_person: |
|
|
@@ -97,6 +97,20 @@ class TestWriteMethods(unittest.TestCase):
|
|
|
97
97
|
self.assertEqual(
|
|
98
98
|
{'nodes_created': 1, 'labels_added': 2, 'properties_set': 4}, result)
|
|
99
99
|
|
|
100
|
+
def test_execute_write_query_in_transactions(self):
|
|
101
|
+
"""Test a query with 'CALL { ... } IN TRANSACTIONS', which requires
|
|
102
|
+
an implicit transaction rather than the managed transaction used by
|
|
103
|
+
execute_write_query for regular queries."""
|
|
104
|
+
query = """
|
|
105
|
+
UNWIND range(1, 3) AS i
|
|
106
|
+
CALL (i) {
|
|
107
|
+
CREATE (:Actor {id: i})
|
|
108
|
+
} IN TRANSACTIONS OF 1 ROWS
|
|
109
|
+
"""
|
|
110
|
+
result = self.graph.execute_write_query(query, self.db)
|
|
111
|
+
self.assertEqual(
|
|
112
|
+
{'nodes_created': 3, 'labels_added': 3, 'properties_set': 3}, result)
|
|
113
|
+
|
|
100
114
|
|
|
101
115
|
class TestReadAndEdaMethods(unittest.TestCase):
|
|
102
116
|
"""Test read and EDA methods. Data is loaded once for the entire class."""
|
|
@@ -65,7 +65,7 @@ class TestUtilFunctions(unittest.TestCase):
|
|
|
65
65
|
|
|
66
66
|
def test_get_batches(self):
|
|
67
67
|
batch_size = 100_000
|
|
68
|
-
data = pd.read_csv(os.path.join(test_dir,'
|
|
68
|
+
data = pd.read_csv(os.path.join(test_dir,'people.csv'))
|
|
69
69
|
batches = util.get_batches(data, batch_size)
|
|
70
70
|
records = data.shape[0]
|
|
71
71
|
remainder = records % batch_size
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|