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.
Files changed (34) hide show
  1. {pyneoinstance-4.0.0/pyneoinstance.egg-info → pyneoinstance-4.0.2}/PKG-INFO +6 -4
  2. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/README.md +3 -2
  3. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance/__init__.py +1 -1
  4. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance/database/neo4jdbms.py +16 -19
  5. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2/pyneoinstance.egg-info}/PKG-INFO +6 -4
  6. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance.egg-info/requires.txt +2 -1
  7. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyproject.toml +3 -3
  8. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/test/cypher_queries.yaml +3 -3
  9. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/test/test_neo4jdb.py +14 -0
  10. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/test/test_util_functions.py +1 -1
  11. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/LICENSE +0 -0
  12. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/MANIFEST.in +0 -0
  13. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance/database/__init__.py +0 -0
  14. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance/database/context.py +0 -0
  15. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance/fileload/__init__.py +0 -0
  16. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance/fileload/helpers.py +0 -0
  17. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance/fileload/loadyaml.py +0 -0
  18. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance/py.typed +0 -0
  19. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance/util/__init__.py +0 -0
  20. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance/util/functions.py +0 -0
  21. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance.egg-info/SOURCES.txt +0 -0
  22. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance.egg-info/dependency_links.txt +0 -0
  23. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/pyneoinstance.egg-info/top_level.txt +0 -0
  24. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/setup.cfg +0 -0
  25. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/setup.py +0 -0
  26. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/test/__init__.py +0 -0
  27. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/test/age_data.csv +0 -0
  28. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/test/context.py +0 -0
  29. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/test/load_files.yaml +0 -0
  30. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/test/movies.csv +0 -0
  31. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/test/people.csv +0 -0
  32. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/test/roles.csv +0 -0
  33. {pyneoinstance-4.0.0 → pyneoinstance-4.0.2}/test/test.py +0 -0
  34. {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.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.5.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 ingestion: [PyNeoInstance: A User-Friendly Python Library for Neo4j](https://medium.com/@a-gilmore/pyneoinstance-a-user-friendly-python-library-for-neo4j-dbefa3117bb2).
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 ingestion: [PyNeoInstance: A User-Friendly Python Library for Neo4j](https://medium.com/@a-gilmore/pyneoinstance-a-user-friendly-python-library-for-neo4j-dbefa3117bb2).
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)
@@ -1,5 +1,5 @@
1
1
  from .database.neo4jdbms import Neo4jInstance
2
2
  from .fileload.loadyaml import load_yaml_file
3
3
 
4
- __version__ = '4.0.0'
4
+ __version__ = '4.0.2'
5
5
  __all__ = ['Neo4jInstance', 'load_yaml_file']
@@ -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]]) -> Network
88
- Execute a read query and return the result as a pyvis graph visualization.
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
- The Uniform Resource Identifier of the database.
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 rows is not None:
762
- results = session.execute_write(
763
- _write_transaction_function, query,
764
- rows = rows, **params).counters.__dict__
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
- **params).counters.__dict__
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.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.5.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 ingestion: [PyNeoInstance: A User-Friendly Python Library for Neo4j](https://medium.com/@a-gilmore/pyneoinstance-a-user-friendly-python-library-for-neo4j-dbefa3117bb2).
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)
@@ -2,7 +2,8 @@ neo4j-rust-ext>=5.0.0
2
2
  pandas>=1.3.0
3
3
  PyYAML>=5.1
4
4
  pyvis>=0.3.0
5
- neo4j-viz>=0.5.0
5
+ neo4j-viz>=1.0.0
6
6
 
7
7
  [docs]
8
8
  mkdocs-material>=9.0.0
9
+ mkdocstrings[python]>=0.24.0
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
 
7
7
  [project]
8
8
  name = "pyneoinstance"
9
- version = "4.0.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.5.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: test
1
+ database: neo4j
2
2
  pre_ingest:
3
- - CREATE CONSTRAINT nkPerson IF NOT EXISTS FOR(n:Person) REQUIRE (n.personId) IS NODE KEY;
4
- - CREATE CONSTRAINT nkMovie IF NOT EXISTS FOR(n:Movie) REQUIRE (n.movieId) IS NODE KEY;
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,'age_data.csv'))
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