biocypher 0.9.2__py3-none-any.whl → 0.12.3__py3-none-any.whl

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.
@@ -1,6 +1,5 @@
1
1
  import pandas as pd
2
2
 
3
- from biocypher._create import BioCypherEdge, BioCypherNode, BioCypherRelAsNode
4
3
  from biocypher.output.in_memory._in_memory_kg import _InMemoryKG
5
4
 
6
5
 
@@ -20,65 +19,8 @@ class PandasKG(_InMemoryKG):
20
19
  def add_edges(self, edges):
21
20
  self.add_tables(edges)
22
21
 
23
- def _separate_entity_types(self, entities):
24
- """
25
- Given mixed iterable of BioCypher objects, separate them into lists by
26
- type. Also deduplicates using the `Deduplicator` instance.
27
- """
28
- lists = {}
29
- for entity in entities:
30
- if (
31
- not isinstance(entity, BioCypherNode)
32
- and not isinstance(entity, BioCypherEdge)
33
- and not isinstance(entity, BioCypherRelAsNode)
34
- ):
35
- raise TypeError(
36
- "Expected a BioCypherNode / BioCypherEdge / " f"BioCypherRelAsNode, got {type(entity)}."
37
- )
38
-
39
- if isinstance(entity, BioCypherNode):
40
- seen = self.deduplicator.node_seen(entity)
41
- elif isinstance(entity, BioCypherEdge):
42
- seen = self.deduplicator.edge_seen(entity)
43
- elif isinstance(entity, BioCypherRelAsNode):
44
- seen = self.deduplicator.rel_as_node_seen(entity)
45
-
46
- if seen:
47
- continue
48
-
49
- if isinstance(entity, BioCypherRelAsNode):
50
- node = entity.get_node()
51
- source_edge = entity.get_source_edge()
52
- target_edge = entity.get_target_edge()
53
-
54
- _type = node.get_type()
55
- if _type not in lists:
56
- lists[_type] = []
57
- lists[_type].append(node)
58
-
59
- _source_type = source_edge.get_type()
60
- if _source_type not in lists:
61
- lists[_source_type] = []
62
- lists[_source_type].append(source_edge)
63
-
64
- _target_type = target_edge.get_type()
65
- if _target_type not in lists:
66
- lists[_target_type] = []
67
- lists[_target_type].append(target_edge)
68
- continue
69
-
70
- _type = entity.get_type()
71
- if _type not in lists:
72
- lists[_type] = []
73
- lists[_type].append(entity)
74
-
75
- return lists
76
-
77
22
  def add_tables(self, entities):
78
- """
79
- Add Pandas dataframes for each node and edge type in the input.
80
- """
81
-
23
+ """Add Pandas dataframes for each node and edge type in the input."""
82
24
  lists = self._separate_entity_types(entities)
83
25
 
84
26
  for _type, _entities in lists.items():
@@ -0,0 +1,60 @@
1
+ $banner = @"
2
+ # ============================================================================== #
3
+ # ======== Import Script for Powershell ======== #
4
+ # ============================================================================== #
5
+ "@
6
+ Write-Host $banner -ForegroundColor Cyan
7
+ Write-Host "[$(Get-Date -Format 'u')] Starting Neo4j import process..." -ForegroundColor Cyan
8
+
9
+ # ================================ #
10
+ # Neo4j Binary Settings #
11
+ # ================================ #
12
+ {neo4j_bin_path}
13
+ Write-Host "[$(Get-Date -Format 'u')] Neo4j bin path set to: $NEO4J_BIN_PATH_WINDOWS"
14
+
15
+ {neo4j_version_check}
16
+ Write-Host "[$(Get-Date -Format 'u')] Detected Neo4j version: $version"
17
+
18
+ $major_version = $version.Trim().Split('.')[0]
19
+ $major = [int]$major_version
20
+
21
+
22
+ # ================================ #
23
+ # Neo4j import arguments #
24
+ # ================================ #
25
+
26
+ if ( $major -lt 5 )
27
+ {{
28
+ $args_neo4j=@(
29
+ @'
30
+ {args_neo4j_v4}
31
+ '@
32
+ )
33
+ Write-Host "[$(Get-Date -Format 'u')] Detected Neo4j v4 - using legacy import command." -ForegroundColor Yellow
34
+ Write-Host "[$(Get-Date -Format 'u')] Args for Neo4j v4:"
35
+ $args_neo4j -split ' ' | ForEach-Object {{ Write-Host "`t$_" }}
36
+ }}
37
+ else
38
+ {{
39
+ $args_neo4j = @(
40
+ @'
41
+ {args_neo4j_v5}
42
+ '@
43
+ )
44
+ Write-Host "[$(Get-Date -Format 'u')] Detected Neo4j v5 or newer - using modern import command." -ForegroundColor Yellow
45
+ Write-Host "[$(Get-Date -Format 'u')] Args for Neo4j >= v5:"
46
+ $args_neo4j -split ' ' | ForEach-Object {{ Write-Host "`t$_" }}
47
+ }}
48
+
49
+ # ================================ #
50
+ # Neo4j-admin import call #
51
+ # ================================ #
52
+ Write-Host "[$(Get-Date -Format 'u')] Running import command..." -ForegroundColor Cyan
53
+
54
+ Invoke-Expression "$NEO4J_BIN_PATH_WINDOWS $args_neo4j"
55
+ if ($LASTEXITCODE -eq 0) {{
56
+ Write-Host "[$(Get-Date -Format 'u')] Import completed successfully!" -ForegroundColor Green
57
+ }} else {{
58
+ Write-Host "[$(Get-Date -Format 'u')] Import failed with exit code $LASTEXITCODE." -ForegroundColor Red
59
+ }}
60
+ Write-Host "[$(Get-Date -Format 'u')] Script finished." -ForegroundColor Cyan
@@ -162,8 +162,8 @@ class _BatchWriter(_Writer, ABC):
162
162
  which need to be overwritten by the child classes.
163
163
 
164
164
  Each batch writer instance has a fixed representation that needs to be
165
- passed at instantiation via the :py:attr:`schema` argument. The instance
166
- also expects an ontology adapter via :py:attr:`ontology_adapter` to be
165
+ passed at instantiation via the `schema` argument. The instance
166
+ also expects an ontology adapter via `ontology_adapter` to be
167
167
  able to convert and extend the hierarchy.
168
168
 
169
169
  Requires the following methods to be overwritten by database-specific
@@ -289,7 +289,7 @@ class _BatchWriter(_Writer, ABC):
289
289
  self._labels_orders = ["Alphabetical", "Ascending", "Descending", "Leaves"]
290
290
  if labels_order not in self._labels_orders:
291
291
  msg = (
292
- f"neo4j's 'labels_order' parameter cannot be '{labels_order}',"
292
+ f"A batch writer 'labels_order' parameter cannot be '{labels_order}',"
293
293
  "must be one of: {' ,'.join(self._labels_orders)}",
294
294
  )
295
295
  raise ValueError(msg)
@@ -545,7 +545,7 @@ class _BatchWriter(_Writer, ABC):
545
545
  f"Must be one of {self._labels_orders}"
546
546
  )
547
547
  raise ValueError(msg)
548
- # concatenate with array delimiter
548
+ # concatenate with array delimiters
549
549
  all_labels = self._write_array_string(all_labels)
550
550
  else:
551
551
  all_labels = self.translator.name_sentence_to_pascal(label)
@@ -9,6 +9,7 @@ from typing import TYPE_CHECKING
9
9
  from biocypher._config import config as _config
10
10
  from biocypher._logger import logger
11
11
  from biocypher.output.write._batch_writer import _BatchWriter
12
+ from biocypher.output.write.graph._airr import _AirrWriter
12
13
  from biocypher.output.write.graph._arangodb import _ArangoDBBatchWriter
13
14
  from biocypher.output.write.graph._neo4j import _Neo4jBatchWriter
14
15
  from biocypher.output.write.graph._networkx import _NetworkXWriter
@@ -50,6 +51,7 @@ DBMS_TO_CLASS = {
50
51
  "Tabular": _PandasCSVWriter,
51
52
  "networkx": _NetworkXWriter,
52
53
  "NetworkX": _NetworkXWriter,
54
+ "airr": _AirrWriter,
53
55
  }
54
56
 
55
57
 
@@ -93,6 +95,8 @@ def get_writer(
93
95
  raise ValueError(msg)
94
96
 
95
97
  if writer is not None:
98
+ # FIXME: passing dbms_config as kwargs would ensure that we pass all config by default.
99
+ # TODO: to do that, config options names need to be aligned first.
96
100
  return writer(
97
101
  translator=translator,
98
102
  deduplicator=deduplicator,
@@ -105,6 +109,7 @@ def get_writer(
105
109
  import_call_file_prefix=dbms_config.get("import_call_file_prefix"),
106
110
  wipe=dbms_config.get("wipe"),
107
111
  strict_mode=strict_mode,
112
+ labels_order=dbms_config.get("labels_order"), # batch writer
108
113
  skip_bad_relationships=dbms_config.get("skip_bad_relationships"), # neo4j
109
114
  skip_duplicate_nodes=dbms_config.get("skip_duplicate_nodes"), # neo4j
110
115
  db_user=dbms_config.get("user"), # psql
@@ -0,0 +1,32 @@
1
+ """Module to provide the AnnData writer class for BioCypher."""
2
+
3
+ from biocypher._logger import logger
4
+ from biocypher.output.write._writer import _Writer
5
+
6
+
7
+ class _AirrWriter(_Writer):
8
+ """A minimal placeholder writer class that implements the required methods
9
+ but performs no actual writing operations, since there is an existing anndata native writer functionality
10
+ """
11
+
12
+ def __init__(self, *args, **kwargs):
13
+ super().__init__(*args, **kwargs)
14
+ logger.info("Placeholder writer initialized")
15
+
16
+ def _write_node_data(self, nodes) -> bool:
17
+ """Required implementation that does nothing with nodes."""
18
+ logger.info("Placeholder: Node data received but not processed")
19
+ return True
20
+
21
+ def _write_edge_data(self, edges) -> bool:
22
+ """Required implementation that does nothing with edges."""
23
+ logger.info("Placeholder: Edge data received but not processed")
24
+ return True
25
+
26
+ def _construct_import_call(self) -> str:
27
+ """Return a placeholder import script."""
28
+ return "# This is a placeholder import script\nprint('No actual import functionality implemented')"
29
+
30
+ def _get_import_script_name(self) -> str:
31
+ """Return a placeholder script name."""
32
+ return "placeholder_import.py"
@@ -1,6 +1,7 @@
1
1
  """Module to provide the Neo4j writer class."""
2
2
 
3
3
  import os
4
+ import sys
4
5
 
5
6
  from biocypher._logger import logger
6
7
  from biocypher.output.write._batch_writer import _BatchWriter, parse_label
@@ -226,7 +227,7 @@ class _Neo4jBatchWriter(_BatchWriter):
226
227
  self.translator.ontology.mapping.extended_schema.get( # (seems to not work with 'not')
227
228
  schema_label,
228
229
  ).get("use_id")
229
- == False # noqa: E712 (seems to not work with 'not')
230
+ is False
230
231
  ):
231
232
  skip_id = True
232
233
 
@@ -260,12 +261,26 @@ class _Neo4jBatchWriter(_BatchWriter):
260
261
 
261
262
  Returns
262
263
  -------
263
- str: The name of the import script (ending in .sh)
264
+ str: The name of the import script (ending in .sh or .ps1 depending on OS)
264
265
 
265
266
  """
267
+ if sys.platform.startswith("win"):
268
+ return "neo4j-admin-import-call.ps1"
266
269
  return "neo4j-admin-import-call.sh"
267
270
 
268
271
  def _construct_import_call(self) -> str:
272
+ """Construct the import call script for Neo4j admin import.
273
+
274
+ Returns
275
+ -------
276
+ str: The import call script.
277
+
278
+ """
279
+ if sys.platform.startswith("win"):
280
+ return self._construct_import_call_powershell()
281
+ return self._construct_import_call_bash()
282
+
283
+ def _construct_import_call_bash(self) -> str:
269
284
  """Function to construct the import call detailing folder and
270
285
  individual node and edge headers and data files, as well as
271
286
  delimiters and database name. Built after all data has been
@@ -278,9 +293,7 @@ class _Neo4jBatchWriter(_BatchWriter):
278
293
  """
279
294
  import_call_neo4j_v4 = self._get_import_call("import", "--database=", "--force=")
280
295
  import_call_neo4j_v5 = self._get_import_call("database import full", "", "--overwrite-destination=")
281
- neo4j_version_check = (
282
- f"version=$({self._get_default_import_call_bin_prefix()}neo4j-admin --version | cut -d '.' -f 1)"
283
- )
296
+ neo4j_version_check = f"version=$({self.import_call_bin_prefix}neo4j-admin --version | cut -d '.' -f 1)"
284
297
 
285
298
  import_script = (
286
299
  f"#!/bin/bash\n{neo4j_version_check}\nif [[ $version -ge 5 ]]; "
@@ -288,6 +301,47 @@ class _Neo4jBatchWriter(_BatchWriter):
288
301
  )
289
302
  return import_script
290
303
 
304
+ def _construct_import_call_powershell(self) -> str:
305
+ """Construct the import call script for Neo4j admin import (PowerShell).
306
+
307
+ Returns
308
+ -------
309
+ str: PowerShell script for Neo4j admin import.
310
+
311
+ """
312
+ # Path to the PowerShell template
313
+ template_path = os.path.join(
314
+ os.path.dirname(os.path.abspath(__file__)),
315
+ "..",
316
+ "..",
317
+ "templates",
318
+ "powershell_template.ps1",
319
+ )
320
+
321
+ # Read the template file
322
+ with open(template_path, encoding="utf-8") as f:
323
+ template = f.read()
324
+
325
+ # Prepare the dynamic components for the template
326
+ import_call_neo4j_v4 = self._get_import_call_windows("import", "--database=", "--force=")
327
+ import_call_neo4j_v5 = self._get_import_call_windows("database import full", "", "--overwrite-destination=")
328
+
329
+ # Prepare the version check command
330
+ neo4j_version_check = (
331
+ f"$version = & powershell -NoProfile -ExecutionPolicy Bypass -File "
332
+ f'"{self.import_call_bin_prefix}neo4j-admin.ps1" --version'
333
+ )
334
+
335
+ # Fill in the template with the dynamic components
336
+ import_script = template.format(
337
+ neo4j_bin_path=f'$NEO4J_BIN_PATH_WINDOWS = "{self.import_call_bin_prefix}neo4j-admin.ps1"',
338
+ neo4j_version_check=neo4j_version_check,
339
+ args_neo4j_v4=import_call_neo4j_v4,
340
+ args_neo4j_v5=import_call_neo4j_v5,
341
+ )
342
+
343
+ return import_script
344
+
291
345
  def _get_import_call(self, import_cmd: str, database_cmd: str, wipe_cmd: str) -> str:
292
346
  """Get parametrized import call for Neo4j 4 or 5+.
293
347
 
@@ -331,3 +385,35 @@ class _Neo4jBatchWriter(_BatchWriter):
331
385
  import_call += f'--relationships="{header_path},{parts_path}" '
332
386
 
333
387
  return import_call
388
+
389
+ def _get_import_call_windows(self, import_cmd: str, database_cmd: str, wipe_cmd: str) -> str:
390
+ """Get parametrized import call for Neo4j 4 or 5+ (Windows).
391
+
392
+ Args:
393
+ ----
394
+ import_cmd (str): The import command to use.
395
+ database_cmd (str): The database command to use.
396
+ wipe_cmd (str): The wipe command to use.
397
+
398
+ Returns:
399
+ -------
400
+ str: The import call for Windows.
401
+
402
+ """
403
+ import_call = []
404
+ import_call.append(f"{import_cmd} ")
405
+ import_call.append(f"{database_cmd}{self.db_name} ")
406
+ import_call.append(f'--delimiter="{self.escaped_delim}" ')
407
+ import_call.append(f'--array-delimiter="{self.escaped_adelim}" ')
408
+ import_call.append(f'--quote="{self.quote}" ' if self.quote == "'" else f"--quote='{self.quote}' ")
409
+ import_call.append(f"{wipe_cmd}true " if self.wipe else "")
410
+ import_call.append("--skip-bad-relationships=true " if self.skip_bad_relationships else "")
411
+ import_call.append("--skip-duplicate-nodes=true " if self.skip_duplicate_nodes else "")
412
+ import_call.extend(
413
+ f'--nodes="{header_path},{parts_path}" ' for header_path, parts_path in self.import_call_nodes
414
+ )
415
+ import_call.extend(
416
+ f'--relationships="{header_path},{parts_path}" ' for header_path, parts_path in self.import_call_edges
417
+ )
418
+
419
+ return "".join(import_call)
@@ -6,7 +6,8 @@ from biocypher.output.write._batch_writer import _BatchWriter
6
6
 
7
7
 
8
8
  class _PostgreSQLBatchWriter(_BatchWriter):
9
- """
9
+ """Write node and edge representations for PostgreSQL.
10
+
10
11
  Class for writing node and edge representations to disk using the
11
12
  format specified by PostgreSQL for the use of "COPY FROM...". Each batch
12
13
  writer instance has a fixed representation that needs to be passed
@@ -39,12 +40,13 @@ class _PostgreSQLBatchWriter(_BatchWriter):
39
40
  self._copy_from_csv_commands = set()
40
41
  super().__init__(*args, **kwargs)
41
42
 
42
- def _get_default_import_call_bin_prefix(self):
43
- """
44
- Method to provide the default string for the import call bin prefix.
43
+ def _get_default_import_call_bin_prefix(self) -> str:
44
+ """Provide the default string for the import call bin prefix.
45
45
 
46
- Returns:
46
+ Returns
47
+ -------
47
48
  str: The default location for the psql command
49
+
48
50
  """
49
51
  return ""
50
52
 
@@ -56,33 +58,36 @@ class _PostgreSQLBatchWriter(_BatchWriter):
56
58
  return "VARCHAR"
57
59
 
58
60
  def _quote_string(self, value: str) -> str:
59
- """
60
- Quote a string.
61
- """
62
-
61
+ """Quote a string."""
63
62
  return f"{self.quote}{value}{self.quote}"
64
63
 
65
64
  def _write_array_string(self, string_list) -> str:
66
- """
67
- Abstract method to output.write the string representation of an array into a .csv file
68
- as required by the postgresql COPY command, with '{','}' brackets and ',' separation.
65
+ """Write the string representation of an array into a .csv file.
66
+
67
+ Abstract method to output.write the string representation of an array
68
+ into a .csv file as required by the postgresql COPY command, with
69
+ '{','}' brackets and ',' separation.
69
70
 
70
71
  Args:
72
+ ----
71
73
  string_list (list): list of ontology strings
72
74
 
73
75
  Returns:
76
+ -------
74
77
  str: The string representation of an array for postgres COPY
78
+
75
79
  """
76
80
  string = ",".join(string_list)
77
81
  string = f'"{{{string}}}"'
78
82
  return string
79
83
 
80
84
  def _get_import_script_name(self) -> str:
81
- """
82
- Returns the name of the psql import script
85
+ """Return the name of the psql import script.
83
86
 
84
- Returns:
87
+ Returns
88
+ -------
85
89
  str: The name of the import script (ending in .sh)
90
+
86
91
  """
87
92
  return f"{self.db_name}-import-call.sh"
88
93
 
@@ -91,14 +96,17 @@ class _PostgreSQLBatchWriter(_BatchWriter):
91
96
  string = string.lower()
92
97
  return string
93
98
 
94
- def _write_node_headers(self):
95
- """
99
+ def _write_node_headers(self) -> bool:
100
+ """Write node header files for PostgreSQL.
101
+
96
102
  Writes single CSV file for a graph entity that is represented
97
103
  as a node as per the definition in the `schema_config.yaml`,
98
104
  containing only the header for this type of node.
99
105
 
100
- Returns:
106
+ Returns
107
+ -------
101
108
  bool: The return value. True for success, False otherwise.
109
+
102
110
  """
103
111
  # load headers from data parse
104
112
  if not self.node_property_dict:
@@ -158,7 +166,7 @@ class _PostgreSQLBatchWriter(_BatchWriter):
158
166
  )
159
167
 
160
168
  self._copy_from_csv_commands.add(
161
- f"\\copy {pascal_label} FROM '{parts_path}' DELIMITER E'{self.delim}' CSV;"
169
+ f"\\copy {pascal_label} FROM '{parts_path}' DELIMITER E'{self.delim}' CSV;",
162
170
  )
163
171
 
164
172
  # add file path to import statement
@@ -175,13 +183,14 @@ class _PostgreSQLBatchWriter(_BatchWriter):
175
183
  return True
176
184
 
177
185
  def _write_edge_headers(self):
178
- """
179
- Writes single CSV file for a graph entity that is represented
186
+ """Writes single CSV file for a graph entity that is represented
180
187
  as an edge as per the definition in the `schema_config.yaml`,
181
188
  containing only the header for this type of edge.
182
189
 
183
- Returns:
190
+ Returns
191
+ -------
184
192
  bool: The return value. True for success, False otherwise.
193
+
185
194
  """
186
195
  # load headers from data parse
187
196
  if not self.edge_property_dict:
@@ -221,7 +230,7 @@ class _PostgreSQLBatchWriter(_BatchWriter):
221
230
  raise ValueError(
222
231
  "Column name '_ID' is reserved for internal use, "
223
232
  "denoting the relationship ID. Please choose a "
224
- "different name for your column."
233
+ "different name for your column.",
225
234
  )
226
235
 
227
236
  columns.append(f"{col_name} {col_type}")
@@ -255,7 +264,7 @@ class _PostgreSQLBatchWriter(_BatchWriter):
255
264
  )
256
265
 
257
266
  self._copy_from_csv_commands.add(
258
- f"\\copy {pascal_label} FROM '{parts_path}' DELIMITER E'{self.delim}' CSV;"
267
+ f"\\copy {pascal_label} FROM '{parts_path}' DELIMITER E'{self.delim}' CSV;",
259
268
  )
260
269
 
261
270
  # add file path to import statement
@@ -272,14 +281,15 @@ class _PostgreSQLBatchWriter(_BatchWriter):
272
281
  return True
273
282
 
274
283
  def _construct_import_call(self) -> str:
275
- """
276
- Function to construct the import call detailing folder and
284
+ """Function to construct the import call detailing folder and
277
285
  individual node and edge headers and data files, as well as
278
286
  delimiters and database name. Built after all data has been
279
287
  processed to ensure that nodes are called before any edges.
280
288
 
281
- Returns:
289
+ Returns
290
+ -------
282
291
  str: a bash command for postgresql import
292
+
283
293
  """
284
294
  import_call = ""
285
295
 
@@ -1,43 +1,47 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: biocypher
3
- Version: 0.9.2
3
+ Version: 0.12.3
4
4
  Summary: A unifying framework for biomedical research knowledge graphs
5
- Home-page: https://github.com/biocypher/biocypher
6
- License: MIT
7
- Author: Sebastian Lobentanzer
8
- Author-email: sebastian.lobentanzer@gmail.com
9
- Requires-Python: >=3.10,<4.0
5
+ Project-URL: Homepage, https://biocypher.org
6
+ Project-URL: Documentation, https://biocypher.org
7
+ Project-URL: Repository, https://github.com/biocypher/biocypher
8
+ Project-URL: Issues, https://github.com/biocypher/biocypher/issues
9
+ Project-URL: Bug Tracker, https://github.com/biocypher/biocypher/issues
10
+ Author-email: Sebastian Lobentanzer <sebastian.lobentanzer@gmail.com>, Denes Turei <turei.denes@gmail.com>
11
+ License: Apache-2.0
12
+ License-File: LICENSE
13
+ License-File: NOTICE
14
+ Keywords: bioinformatics,biomedical-data,graph-database,knowledge-graph
10
15
  Classifier: Development Status :: 3 - Alpha
11
16
  Classifier: Intended Audience :: Developers
12
17
  Classifier: Intended Audience :: Science/Research
13
- Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: License :: OSI Approved :: Apache Software License
14
19
  Classifier: Natural Language :: English
15
20
  Classifier: Operating System :: OS Independent
16
21
  Classifier: Programming Language :: Python
17
- Classifier: Programming Language :: Python :: 3
18
- Classifier: Programming Language :: Python :: 3.10
19
- Classifier: Programming Language :: Python :: 3.11
20
- Classifier: Programming Language :: Python :: 3.12
21
22
  Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
22
- Requires-Dist: PyYAML (>=5.0)
23
+ Requires-Python: >=3.10
23
24
  Requires-Dist: appdirs
24
- Requires-Dist: more_itertools
25
- Requires-Dist: neo4j-utils (==0.0.7)
26
- Requires-Dist: networkx (>=3.0,<4.0)
27
- Requires-Dist: pandas (>=2.0.1,<3.0.0)
28
- Requires-Dist: pooch (>=1.7.0,<2.0.0)
29
- Requires-Dist: rdflib (>=6.2.0,<7.0.0)
30
- Requires-Dist: tqdm (>=4.65.0,<5.0.0)
31
- Requires-Dist: treelib (==1.6.4)
32
- Project-URL: Bug Tracker, https://github.com/biocypher/biocypher/issues
33
- Project-URL: Repository, https://github.com/biocypher/biocypher
25
+ Requires-Dist: more-itertools
26
+ Requires-Dist: networkx>=3.0
27
+ Requires-Dist: pandas>=2.0.1
28
+ Requires-Dist: pooch>=1.7.0
29
+ Requires-Dist: pyyaml>=5.0
30
+ Requires-Dist: rdflib>=6.2.0
31
+ Requires-Dist: toml>=0.10.2
32
+ Requires-Dist: tqdm>=4.65.0
33
+ Requires-Dist: treelib==1.6.4
34
+ Provides-Extra: neo4j
35
+ Requires-Dist: neo4j>=5.0; extra == 'neo4j'
36
+ Provides-Extra: scirpy
37
+ Requires-Dist: scirpy>=0.22.0; extra == 'scirpy'
34
38
  Description-Content-Type: text/markdown
35
39
 
36
40
  # BioCypher
37
41
 
38
42
  | | | | |
39
43
  | --- | --- | --- | --- |
40
- | __License__ | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) | __Python__ | [![Python](https://img.shields.io/pypi/pyversions/biocypher)](https://www.python.org) |
44
+ | __License__ | [![License: Apache 2.0](https://img.shields.io/badge/license-Apache%202-blue)](https://opensource.org/license/apache-2-0) | __Python__ | [![Python](https://img.shields.io/pypi/pyversions/biocypher)](https://www.python.org) |
41
45
  | __Package__ | [![PyPI version](https://img.shields.io/pypi/v/biocypher)](https://pypi.org/project/biocypher/) [![Downloads](https://static.pepy.tech/badge/biocypher)](https://pepy.tech/project/biocypher) [![DOI](https://zenodo.org/badge/405143648.svg)](https://zenodo.org/doi/10.5281/zenodo.10158203) | __Build status__ | [![CI](https://github.com/biocypher/biocypher/actions/workflows/tests_and_code_quality.yaml/badge.svg)](https://github.com/biocypher/biocypher/actions/workflows/tests_and_code_quality.yaml) [![Docs build](https://github.com/biocypher/biocypher/actions/workflows/docs.yaml/badge.svg)](https://github.com/biocypher/biocypher/actions/workflows/docs.yaml) |
42
46
  | __Tests__ | [![Coverage](https://raw.githubusercontent.com/biocypher/biocypher/coverage/coverage.svg)](https://github.com/biocypher/biocypher/actions/workflows/tests_and_code_quality.yaml) | __Docker__ | [![Latest image](https://img.shields.io/docker/v/biocypher/base)](https://hub.docker.com/repository/docker/biocypher/base/general) [![Image size](https://img.shields.io/docker/image-size/biocypher/base/latest)](https://hub.docker.com/repository/docker/biocypher/base/general) |
43
47
  | __Development__ | [![pyOpenSci](https://tinyurl.com/y22nb8up)](https://github.com/pyOpenSci/software-review/issues/110) [![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active) [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://github.com/pre-commit/pre-commit) [![Code style](https://img.shields.io/badge/code%20style-black-000000.svg)](https://black.readthedocs.io/en/stable/) | __Contributions__ | [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](CONTRIBUTING.md) [![Powered by the Bioregistry](https://img.shields.io/static/v1?label=Powered%20by&message=Bioregistry&color=BA274A&style=flat&logo=image/png;base64,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)](https://github.com/biopragmatics/bioregistry) |
@@ -62,7 +66,7 @@ the docs [here](https://biocypher.org).
62
66
  margin-left: auto;
63
67
  margin-right: auto;
64
68
  width: 70%;"
65
- src="docs/graphical_abstract.png"
69
+ src="docs/assets/img/graphical-abstract-biocypher.png"
66
70
  alt="Graphical Abstract">
67
71
  </img>
68
72
 
@@ -77,9 +81,10 @@ Board](https://github.com/orgs/biocypher/projects/3/views/2).
77
81
 
78
82
  ## ⚙️ Installation / Usage
79
83
 
80
- Install the package from PyPI using `pip install biocypher`. More comprehensive
84
+ Install the package from PyPI using `pip install biocypher`. For Neo4j online mode
85
+ support, install with `pip install biocypher[neo4j]`. More comprehensive
81
86
  installation and configuration instructions can be found
82
- [here](https://biocypher.org/installation.html).
87
+ [here](https://biocypher.org/BioCypher/installation/).
83
88
 
84
89
  Exemplary usage of BioCypher to build a graph database is shown in our tutorial
85
90
  and the various pipelines we have created. You can find these on the [Components
@@ -112,4 +117,3 @@ as a preprint at https://arxiv.org/abs/2212.13543.
112
117
  This project has received funding from the European Union’s Horizon 2020
113
118
  research and innovation programme under grant agreement No 965193 for DECIDER
114
119
  and No 116030 for TransQST.
115
-