ricgraph 2.7__tar.gz → 2.9__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.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: ricgraph
3
- Version: 2.7
3
+ Version: 2.9
4
4
  Summary: Ricgraph - Research in context graph
5
5
  Author: Rik D.T. Janssen
6
6
  Project-URL: Website, https://www.ricgraph.eu
@@ -25,19 +25,25 @@ Requires-Dist: requests
25
25
  [![DOI software](https://img.shields.io/badge/DOI%20%20software-10.5281/zenodo.7524314-blue)](https://doi.org/10.5281/zenodo.7524314)
26
26
  [![DOI reference publication](https://img.shields.io/badge/DOI%20reference%20publication-10.1016%2Fj.softx.2024.101736-blue)](https://doi.org/10.1016/j.softx.2024.101736)
27
27
  [![website](https://img.shields.io/badge/website-www.ricgraph.eu-blue)](https://www.ricgraph.eu)
28
- ![GitHub release date](https://img.shields.io/github/release-date/UtrechtUniversity/ricgraph?color=green)
29
- [![GitHub latest release](https://img.shields.io/github/release/UtrechtUniversity/ricgraph?color=green)](https://github.com/UtrechtUniversity/ricgraph/releases)
30
- ![GitHub commits since latest release](https://img.shields.io/github/commits-since/UtrechtUniversity/ricgraph/latest?color=green)
31
- ![GitHub last commit](https://img.shields.io/github/last-commit/UtrechtUniversity/ricgraph?color=green)
32
- [![PyPI version](https://img.shields.io/pypi/v/ricgraph?label=PyPI%20version&color=green)](https://pypi.org/project/ricgraph)
33
- [![PyPI downloads](https://img.shields.io/pypi/dm/ricgraph?label=PyPI%20downloads&color=green)](https://pypistats.org/packages/ricgraph)
34
- [![GitHub license](https://img.shields.io/github/license/UtrechtUniversity/ricgraph?color=green)](LICENSE)
28
+ ![GitHub release date](https://img.shields.io/github/release-date/UtrechtUniversity/ricgraph?color=%234c1)
29
+ [![GitHub latest release](https://img.shields.io/github/release/UtrechtUniversity/ricgraph?color=%234c1)](https://github.com/UtrechtUniversity/ricgraph/releases)
30
+ ![GitHub commits since latest release](https://img.shields.io/github/commits-since/UtrechtUniversity/ricgraph/latest?color=%234c1)
31
+ ![GitHub last commit](https://img.shields.io/github/last-commit/UtrechtUniversity/ricgraph?color=%234c1)
32
+ [![PyPI version](https://img.shields.io/pypi/v/ricgraph?label=PyPI%20version&color=%234c1)](https://pypi.org/project/ricgraph)
33
+ [![PyPI downloads](https://img.shields.io/pypi/dm/ricgraph?label=PyPI%20downloads&color=%234c1)](https://pypistats.org/packages/ricgraph)
34
+ [![Ricgraph container doc](https://img.shields.io/badge/Ricgraph_container_doc-click_here-%234c1)](https://github.com/UtrechtUniversity/ricgraph/blob/main/docs/ricgraph_containerized.md)
35
+ [![Podman container version](https://ghcr-badge.egpl.dev/utrechtuniversity/ricgraph/latest_tag?color=%234c1&label=container+version)](https://github.com/utrechtuniversity/ricgraph/pkgs/container/ricgraph)
36
+ [![GitHub license](https://img.shields.io/github/license/UtrechtUniversity/ricgraph?color=%234c1)](LICENSE)
35
37
  [![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)
36
38
  [![Technology Readiness Level 7/9 - Release Candidate - Technology ready enough and in initial use by end-users in intended scholarly environments](https://w3id.org/research-technology-readiness-levels/Level7ReleaseCandidate.svg)](https://github.com/CLARIAH/clariah-plus/blob/main/requirements/software-metadata-requirements.md#15--you-should-express-a-technology-readiness-level)
37
39
  [![FAIR checklist badge](https://fairsoftwarechecklist.net/badge.svg)](https://fairsoftwarechecklist.net/v0.2?f=31&a=32113&i=32110&r=123)
40
+
38
41
  <!---
39
42
  Note, the lines 'Website' and
40
43
  'PyPI downloads' end in two spaces, to force a line break but not a paragraph break.
44
+ Similar for others.
45
+ We use color=#4c1 (green), that color is used by the 'repo status' badge.
46
+ Documentation about the Podman badges can be found here: https://github.com/eggplants/ghcr-badge.
41
47
  --->
42
48
 
43
49
  <img alt="Ricgraph logo" src="https://raw.githubusercontent.com/UtrechtUniversity/ricgraph/refs/heads/main/docs/images/ricgraph_logo.png" height="30">
@@ -1,19 +1,25 @@
1
1
  [![DOI software](https://img.shields.io/badge/DOI%20%20software-10.5281/zenodo.7524314-blue)](https://doi.org/10.5281/zenodo.7524314)
2
2
  [![DOI reference publication](https://img.shields.io/badge/DOI%20reference%20publication-10.1016%2Fj.softx.2024.101736-blue)](https://doi.org/10.1016/j.softx.2024.101736)
3
3
  [![website](https://img.shields.io/badge/website-www.ricgraph.eu-blue)](https://www.ricgraph.eu)
4
- ![GitHub release date](https://img.shields.io/github/release-date/UtrechtUniversity/ricgraph?color=green)
5
- [![GitHub latest release](https://img.shields.io/github/release/UtrechtUniversity/ricgraph?color=green)](https://github.com/UtrechtUniversity/ricgraph/releases)
6
- ![GitHub commits since latest release](https://img.shields.io/github/commits-since/UtrechtUniversity/ricgraph/latest?color=green)
7
- ![GitHub last commit](https://img.shields.io/github/last-commit/UtrechtUniversity/ricgraph?color=green)
8
- [![PyPI version](https://img.shields.io/pypi/v/ricgraph?label=PyPI%20version&color=green)](https://pypi.org/project/ricgraph)
9
- [![PyPI downloads](https://img.shields.io/pypi/dm/ricgraph?label=PyPI%20downloads&color=green)](https://pypistats.org/packages/ricgraph)
10
- [![GitHub license](https://img.shields.io/github/license/UtrechtUniversity/ricgraph?color=green)](LICENSE)
4
+ ![GitHub release date](https://img.shields.io/github/release-date/UtrechtUniversity/ricgraph?color=%234c1)
5
+ [![GitHub latest release](https://img.shields.io/github/release/UtrechtUniversity/ricgraph?color=%234c1)](https://github.com/UtrechtUniversity/ricgraph/releases)
6
+ ![GitHub commits since latest release](https://img.shields.io/github/commits-since/UtrechtUniversity/ricgraph/latest?color=%234c1)
7
+ ![GitHub last commit](https://img.shields.io/github/last-commit/UtrechtUniversity/ricgraph?color=%234c1)
8
+ [![PyPI version](https://img.shields.io/pypi/v/ricgraph?label=PyPI%20version&color=%234c1)](https://pypi.org/project/ricgraph)
9
+ [![PyPI downloads](https://img.shields.io/pypi/dm/ricgraph?label=PyPI%20downloads&color=%234c1)](https://pypistats.org/packages/ricgraph)
10
+ [![Ricgraph container doc](https://img.shields.io/badge/Ricgraph_container_doc-click_here-%234c1)](https://github.com/UtrechtUniversity/ricgraph/blob/main/docs/ricgraph_containerized.md)
11
+ [![Podman container version](https://ghcr-badge.egpl.dev/utrechtuniversity/ricgraph/latest_tag?color=%234c1&label=container+version)](https://github.com/utrechtuniversity/ricgraph/pkgs/container/ricgraph)
12
+ [![GitHub license](https://img.shields.io/github/license/UtrechtUniversity/ricgraph?color=%234c1)](LICENSE)
11
13
  [![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)
12
14
  [![Technology Readiness Level 7/9 - Release Candidate - Technology ready enough and in initial use by end-users in intended scholarly environments](https://w3id.org/research-technology-readiness-levels/Level7ReleaseCandidate.svg)](https://github.com/CLARIAH/clariah-plus/blob/main/requirements/software-metadata-requirements.md#15--you-should-express-a-technology-readiness-level)
13
15
  [![FAIR checklist badge](https://fairsoftwarechecklist.net/badge.svg)](https://fairsoftwarechecklist.net/v0.2?f=31&a=32113&i=32110&r=123)
16
+
14
17
  <!---
15
18
  Note, the lines 'Website' and
16
19
  'PyPI downloads' end in two spaces, to force a line break but not a paragraph break.
20
+ Similar for others.
21
+ We use color=#4c1 (green), that color is used by the 'repo status' badge.
22
+ Documentation about the Podman badges can be found here: https://github.com/eggplants/ghcr-badge.
17
23
  --->
18
24
 
19
25
  <img alt="Ricgraph logo" src="https://raw.githubusercontent.com/UtrechtUniversity/ricgraph/refs/heads/main/docs/images/ricgraph_logo.png" height="30">
@@ -1,19 +1,25 @@
1
1
  [![DOI software](https://img.shields.io/badge/DOI%20%20software-10.5281/zenodo.7524314-blue)](https://doi.org/10.5281/zenodo.7524314)
2
2
  [![DOI reference publication](https://img.shields.io/badge/DOI%20reference%20publication-10.1016%2Fj.softx.2024.101736-blue)](https://doi.org/10.1016/j.softx.2024.101736)
3
3
  [![website](https://img.shields.io/badge/website-www.ricgraph.eu-blue)](https://www.ricgraph.eu)
4
- ![GitHub release date](https://img.shields.io/github/release-date/UtrechtUniversity/ricgraph?color=green)
5
- [![GitHub latest release](https://img.shields.io/github/release/UtrechtUniversity/ricgraph?color=green)](https://github.com/UtrechtUniversity/ricgraph/releases)
6
- ![GitHub commits since latest release](https://img.shields.io/github/commits-since/UtrechtUniversity/ricgraph/latest?color=green)
7
- ![GitHub last commit](https://img.shields.io/github/last-commit/UtrechtUniversity/ricgraph?color=green)
8
- [![PyPI version](https://img.shields.io/pypi/v/ricgraph?label=PyPI%20version&color=green)](https://pypi.org/project/ricgraph)
9
- [![PyPI downloads](https://img.shields.io/pypi/dm/ricgraph?label=PyPI%20downloads&color=green)](https://pypistats.org/packages/ricgraph)
10
- [![GitHub license](https://img.shields.io/github/license/UtrechtUniversity/ricgraph?color=green)](LICENSE)
4
+ ![GitHub release date](https://img.shields.io/github/release-date/UtrechtUniversity/ricgraph?color=%234c1)
5
+ [![GitHub latest release](https://img.shields.io/github/release/UtrechtUniversity/ricgraph?color=%234c1)](https://github.com/UtrechtUniversity/ricgraph/releases)
6
+ ![GitHub commits since latest release](https://img.shields.io/github/commits-since/UtrechtUniversity/ricgraph/latest?color=%234c1)
7
+ ![GitHub last commit](https://img.shields.io/github/last-commit/UtrechtUniversity/ricgraph?color=%234c1)
8
+ [![PyPI version](https://img.shields.io/pypi/v/ricgraph?label=PyPI%20version&color=%234c1)](https://pypi.org/project/ricgraph)
9
+ [![PyPI downloads](https://img.shields.io/pypi/dm/ricgraph?label=PyPI%20downloads&color=%234c1)](https://pypistats.org/packages/ricgraph)
10
+ [![Ricgraph container doc](https://img.shields.io/badge/Ricgraph_container_doc-click_here-%234c1)](https://github.com/UtrechtUniversity/ricgraph/blob/main/docs/ricgraph_containerized.md)
11
+ [![Podman container version](https://ghcr-badge.egpl.dev/utrechtuniversity/ricgraph/latest_tag?color=%234c1&label=container+version)](https://github.com/utrechtuniversity/ricgraph/pkgs/container/ricgraph)
12
+ [![GitHub license](https://img.shields.io/github/license/UtrechtUniversity/ricgraph?color=%234c1)](LICENSE)
11
13
  [![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)
12
14
  [![Technology Readiness Level 7/9 - Release Candidate - Technology ready enough and in initial use by end-users in intended scholarly environments](https://w3id.org/research-technology-readiness-levels/Level7ReleaseCandidate.svg)](https://github.com/CLARIAH/clariah-plus/blob/main/requirements/software-metadata-requirements.md#15--you-should-express-a-technology-readiness-level)
13
15
  [![FAIR checklist badge](https://fairsoftwarechecklist.net/badge.svg)](https://fairsoftwarechecklist.net/v0.2?f=31&a=32113&i=32110&r=123)
16
+
14
17
  <!---
15
18
  Note, the lines 'Website' and
16
19
  'PyPI downloads' end in two spaces, to force a line break but not a paragraph break.
20
+ Similar for others.
21
+ We use color=#4c1 (green), that color is used by the 'repo status' badge.
22
+ Documentation about the Podman badges can be found here: https://github.com/eggplants/ghcr-badge.
17
23
  --->
18
24
 
19
25
  <img alt="Ricgraph logo" src="docs/images/ricgraph_logo.png" height="30">
@@ -7,7 +7,7 @@ packages = ["ricgraph"]
7
7
 
8
8
  [project]
9
9
  name = "ricgraph"
10
- version = "2.7"
10
+ version = "2.9"
11
11
  authors = [
12
12
  { name="Rik D.T. Janssen" },
13
13
  ]
@@ -33,6 +33,4 @@
33
33
  #
34
34
  # ########################################################################
35
35
 
36
- __version__ = '2.7'
37
-
38
36
  from .ricgraph import *
@@ -6,7 +6,7 @@
6
6
  #
7
7
  # MIT License
8
8
  #
9
- # Copyright (c) 2023, 2024 Rik D.T. Janssen
9
+ # Copyright (c) 2023, 2024, 2025 Rik D.T. Janssen
10
10
  #
11
11
  # Permission is hereby granted, free of charge, to any person obtaining a copy
12
12
  # of this software and associated documentation files (the "Software"), to deal
@@ -31,7 +31,8 @@
31
31
  # This file is the main file for Ricgraph.
32
32
  # Original version Rik D.T. Janssen, December 2022.
33
33
  # Updated Rik D.T. Janssen, February, March, September to December 2023.
34
- # Updated Rik D.T. Janssen, February 2024, March 2024.
34
+ # Updated Rik D.T. Janssen, February, March 2024.
35
+ # Updated Rik D.T. Janssen, January 2025
35
36
  #
36
37
  # ########################################################################
37
38
 
@@ -65,7 +66,7 @@ In RICGRAPH_PROPERTIES_STANDARD:
65
66
  - name: name of the node, e.g. ISNI, ORCID, DOI, etc.
66
67
 
67
68
  - category: category of the node,
68
- e.g. person, person-root, book, journal article, dataset, etc.
69
+ e.g. person, person-root, book, journal article, data set, etc.
69
70
 
70
71
  - value: value of the node.
71
72
 
@@ -99,6 +100,7 @@ In the default configuration of Ricgraph, the following properties are included:
99
100
 
100
101
  import os
101
102
  import sys
103
+ import re
102
104
  from datetime import datetime
103
105
  import numpy
104
106
  import pandas
@@ -113,11 +115,15 @@ from neo4j import GraphDatabase, Driver, Result
113
115
  from neo4j.graph import Node
114
116
 
115
117
  __author__ = 'Rik D.T. Janssen'
116
- __copyright__ = 'Copyright (c) 2023, 2024 Rik D.T. Janssen'
118
+ __copyright__ = 'Copyright (c) 2023, 2024, 2025 Rik D.T. Janssen'
117
119
  __email__ = ''
118
120
  __license__ = 'MIT License'
119
121
  __package__ = 'Ricgraph'
120
- # __version__ is in __init__.py of this module.
122
+
123
+ # __version__ should be placed here instead of in __init__.py.
124
+ # If not here, it cannot be found when executing something like
125
+ # PYTHONPATH=../ricgraph ../bin/python ricgraph_explorer.py
126
+ __version__ = '2.9'
121
127
 
122
128
 
123
129
  # ########################################################################
@@ -167,7 +173,7 @@ graphdb_nr_deletes = 0
167
173
  # An example mapping may look like this:
168
174
  # mapping = {
169
175
  # 'book': ROTYPE_BOOK,
170
- # 'dataset': ROTYPE_DATASET,
176
+ # 'data set': ROTYPE_DATASET,
171
177
  # 'software': ROTYPE_SOFTWARE
172
178
  # }
173
179
  #
@@ -299,17 +305,19 @@ def open_ricgraph() -> Driver:
299
305
  """
300
306
  global _graph
301
307
 
302
- print('Opening ricgraph.\n')
308
+ print('Opening Ricgraph.\n')
303
309
  try:
304
310
  _graph = GraphDatabase.driver(GRAPHDB_URL,
305
311
  auth=(GRAPHDB_USER, GRAPHDB_PASSWORD))
306
312
  _graph.verify_connectivity()
307
- except:
308
- print('open_ricgraph(): Error opening graph database backend using these parameters:')
313
+ except Exception as e:
314
+ print('open_ricgraph(): An exception occurred. Name: ' + type(e).__name__ + ',')
315
+ print(' error message: ' + str(e) + '.')
316
+ print('Error opening graph database backend using these parameters:')
309
317
  print('GRAPHDB_URL: ' + GRAPHDB_URL)
310
318
  print('GRAPHDB_DATABASENAME: ' + ricgraph_databasename())
311
319
  print('GRAPHDB_USER: ' + GRAPHDB_USER)
312
- print('GRAPHDB_PASSWORD: [see ricgraph.ini file]')
320
+ print('GRAPHDB_PASSWORD: [see file ' + get_ricgraph_ini_file() + ']')
313
321
  print('\nAre these parameters correct and did you start your graph database backend "' + GRAPHDB + '"?')
314
322
  print('Exiting.')
315
323
  exit(1)
@@ -322,7 +330,7 @@ def close_ricgraph() -> None:
322
330
  """
323
331
  global _graph
324
332
 
325
- print('Closing ricgraph.\n')
333
+ print('Closing Ricgraph.\n')
326
334
  _graph.close()
327
335
  return
328
336
 
@@ -350,28 +358,16 @@ def empty_ricgraph(answer: str = '') -> None:
350
358
  """
351
359
  global _graph
352
360
 
353
- if answer == 'yes':
354
- print('Emptying Ricgraph: Ricgraph will be emptied.\n')
355
- # Fall through.
356
- elif answer == 'no':
357
- print('Emptying Ricgraph: Ricgraph will not be emptied.\n')
361
+ if answer != 'yes' and answer != 'no':
362
+ print('empty_ricgraph(): invalid answer "' + answer + '" on the question')
363
+ print('to empty Ricgraph, exiting.')
364
+ exit(1)
365
+
366
+ if answer == 'no':
367
+ print('empty_ricgraph(): Ricgraph will not be emptied.\n')
358
368
  return
359
- else:
360
- print('Do you want to empty Ricgraph? You have the following options:')
361
- print('- "yes": Ricgraph will be emptied.')
362
- print('- "no": Ricgraph will not be emptied.')
363
- print('- any other answer: Ricgraph will not be emptied, execution of this script will abort.')
364
- user_input = input('Please make a choice: ')
365
- if user_input.lower() == 'yes':
366
- print('\nRicgraph will be emptied.\n')
367
- # Fall through.
368
- elif user_input.lower() == 'no':
369
- print('\nRicgraph has not been emptied.\n')
370
- return
371
- else:
372
- print('\nRicgraph has not been emptied, exiting.\n')
373
- exit(1)
374
369
 
370
+ print('empty_ricgraph(): Ricgraph will be emptied.\n')
375
371
  graphdb_name = ricgraph_database()
376
372
  graphdb_databasename = ricgraph_databasename()
377
373
 
@@ -560,6 +556,31 @@ def cypher_create_node(node_properties: dict) -> Union[Node, None]:
560
556
  return nodes[0]
561
557
 
562
558
 
559
+ def cypher_delete_node(node_element_id: str) -> None:
560
+ """Delete a node in the graph database.
561
+ If it has any edges, these will also be deleted.
562
+
563
+ :param node_element_id: the element_id of the node.
564
+ :return: None.
565
+ """
566
+ global graphdb_nr_deletes
567
+
568
+ cypher_query = 'MATCH (node:RicgraphNode) '
569
+ if ricgraph_database() == 'neo4j':
570
+ cypher_query += 'WHERE elementId(node)=$node_element_id '
571
+ else:
572
+ cypher_query += 'WHERE id(node)=toInteger($node_element_id) '
573
+ cypher_query += 'DETACH DELETE node'
574
+ _graph.execute_query(cypher_query,
575
+ node_element_id=node_element_id,
576
+ result_transformer_=Result.value,
577
+ database_=ricgraph_databasename())
578
+
579
+ nr_edges = ricgraph_nr_edges_of_node(node_element_id=node_element_id)
580
+ graphdb_nr_deletes += 1 + nr_edges # '1' for node, add all of its edges.
581
+ return
582
+
583
+
563
584
  def cypher_update_node_properties(node_element_id: str, node_properties: dict) -> Union[Node, None]:
564
585
  """
565
586
  Update node properties in a node in the graph database.
@@ -664,16 +685,7 @@ def cypher_merge_nodes(node_merge_from_element_id: str,
664
685
 
665
686
  # If merge_node_from does not have neighbors, it will not be deleted.
666
687
  # Do another Cypher query to be sure it is gone.
667
- cypher_query = 'MATCH (node_from:RicgraphNode) '
668
- if graphdb_name == 'neo4j':
669
- cypher_query += 'WHERE elementId(node_from)=$node_merge_from_element_id '
670
- else:
671
- cypher_query += 'WHERE id(node_from)=toInteger($node_merge_from_element_id) '
672
- cypher_query += 'DETACH DELETE node_from'
673
- _graph.execute_query(cypher_query,
674
- node_merge_from_element_id=node_merge_from_element_id,
675
- result_transformer_=Result.value,
676
- database_=ricgraph_databasename())
688
+ cypher_delete_node(node_element_id=node_merge_from_element_id)
677
689
 
678
690
  nr_edges = ricgraph_nr_edges_of_node(node_element_id=node_merge_to_element_id)
679
691
  graphdb_nr_reads += 2 * nr_edges # Approximation: edges are in two directions.
@@ -736,6 +748,14 @@ def cypher_create_edge_if_not_exists(left_node_element_id: str, right_node_eleme
736
748
  # ##############################################################################
737
749
  # General Ricgraph functions.
738
750
  # ##############################################################################
751
+ def get_ricgraph_version() -> str:
752
+ """Get the version Ricgraph.
753
+
754
+ :return: the version string.
755
+ """
756
+ return __version__
757
+
758
+
739
759
  def get_ricgraph_ini_file() -> str:
740
760
  """Get the location of the ricgraph ini file.
741
761
 
@@ -908,13 +928,191 @@ def create_well_known_url(name: str, value: str) -> str:
908
928
  return ''
909
929
 
910
930
 
931
+ def normalize_doi(identifier: str) -> str:
932
+ """Normalize DOI.
933
+
934
+ :param identifier: identifier to normalize.
935
+ :return: Result of normalizing.
936
+ """
937
+ if identifier == '':
938
+ return ''
939
+ identifier = identifier.lower()
940
+ identifier = re.sub(pattern=r'https|http', repl='', string=identifier)
941
+ identifier = re.sub(pattern=r'://', repl='', string=identifier)
942
+ identifier = re.sub(pattern=r'www.', repl='', string=identifier)
943
+ identifier = re.sub(pattern=r'doi.org/', repl='', string=identifier)
944
+ identifier = re.sub(pattern=r'doi', repl='', string=identifier)
945
+ identifier = re.sub(pattern=r'.proxy.uu.nl/', repl='', string=identifier)
946
+ return identifier
947
+
948
+
949
+ def normalize_ror(identifier: str) -> str:
950
+ """Normalize ROR.
951
+
952
+ :param identifier: identifier to normalize.
953
+ :return: Result of normalizing.
954
+ """
955
+ if identifier == '':
956
+ return ''
957
+ identifier = identifier.lower()
958
+ identifier = re.sub(pattern=r'https|http', repl='', string=identifier)
959
+ identifier = re.sub(pattern=r'://', repl='', string=identifier)
960
+ identifier = re.sub(pattern=r'www.', repl='', string=identifier)
961
+ identifier = re.sub(pattern=r'ror.org/', repl='', string=identifier)
962
+ return identifier
963
+
964
+
965
+ def normalize_orcid(identifier: str) -> str:
966
+ """Normalize ORCID.
967
+
968
+ :param identifier: identifier to normalize.
969
+ :return: Result of normalizing.
970
+ """
971
+ if identifier == '':
972
+ return ''
973
+ identifier = identifier.lower()
974
+ identifier = re.sub(pattern=r'https|http', repl='', string=identifier)
975
+ identifier = re.sub(pattern=r'://', repl='', string=identifier)
976
+ identifier = re.sub(pattern=r'www.', repl='', string=identifier)
977
+ identifier = re.sub(pattern=r'orcid.org/', repl='', string=identifier)
978
+ identifier = identifier.upper()
979
+ return identifier
980
+
981
+
982
+ def normalize_isni(identifier: str) -> str:
983
+ """Normalize ISNI.
984
+
985
+ :param identifier: identifier to normalize.
986
+ :return: Result of normalizing.
987
+ """
988
+ if identifier == '':
989
+ return ''
990
+ identifier = identifier.lower()
991
+ identifier = re.sub(pattern=r'https|http', repl='', string=identifier)
992
+ identifier = re.sub(pattern=r'://', repl='', string=identifier)
993
+ identifier = re.sub(pattern=r'www.', repl='', string=identifier)
994
+ identifier = re.sub(pattern=r'isni.org/isni/', repl='', string=identifier)
995
+ identifier = identifier.upper()
996
+ return identifier
997
+
998
+
999
+ def normalize_openalex(identifier: str) -> str:
1000
+ """Normalize OpenAlex identifier.
1001
+
1002
+ :param identifier: identifier to normalize.
1003
+ :return: Result of normalizing.
1004
+ """
1005
+ if identifier == '':
1006
+ return ''
1007
+ identifier = identifier.lower()
1008
+ identifier = re.sub(pattern=r'https|http', repl='', string=identifier)
1009
+ identifier = re.sub(pattern=r'://', repl='', string=identifier)
1010
+ identifier = re.sub(pattern=r'www.', repl='', string=identifier)
1011
+ identifier = re.sub(pattern=r'openalex.org/', repl='', string=identifier)
1012
+ identifier = identifier.upper()
1013
+ return identifier
1014
+
1015
+
1016
+ def normalize_scopus_author_id(identifier: str) -> str:
1017
+ """Normalize SCOPUS_AUTHOR_ID. Return a uniform value.
1018
+
1019
+ :param identifier: identifier to normalize.
1020
+ :return: Result of normalizing.
1021
+ """
1022
+ if identifier == '':
1023
+ return ''
1024
+ identifier = identifier.lower()
1025
+ identifier = re.sub(pattern=r'https|http', repl='', string=identifier)
1026
+ identifier = re.sub(pattern=r'://', repl='', string=identifier)
1027
+ identifier = re.sub(pattern=r'www.', repl='', string=identifier)
1028
+ identifier = re.sub(pattern=r'scopus.com/authid/detail.uri', repl='', string=identifier)
1029
+ identifier = re.sub(pattern=r'\?authorid\=', repl='', string=identifier)
1030
+ return identifier
1031
+
1032
+
1033
+ def normalize_researcher_id(identifier: str) -> str:
1034
+ """Normalize RESEARCHER_ID.
1035
+
1036
+ :param identifier: identifier to normalize.
1037
+ :return: Result of normalizing.
1038
+ """
1039
+ if identifier == '':
1040
+ return ''
1041
+ identifier = identifier.lower()
1042
+ identifier = re.sub(pattern=r'https|http', repl='', string=identifier)
1043
+ identifier = re.sub(pattern=r'://', repl='', string=identifier)
1044
+ identifier = re.sub(pattern=r'www.', repl='', string=identifier)
1045
+ identifier = re.sub(pattern=r'researcherid.com/rid/', repl='', string=identifier)
1046
+ identifier = identifier.upper()
1047
+ return identifier
1048
+
1049
+
1050
+ def normalize_digital_author_id(identifier: str) -> str:
1051
+ """Normalize DIGITAL_AUTHOR_ID.
1052
+
1053
+ :param identifier: identifier to normalize.
1054
+ :return: Result of normalizing.
1055
+ """
1056
+ if identifier == '':
1057
+ return ''
1058
+ identifier = identifier.lower()
1059
+ identifier = re.sub(pattern=r'urn:nbn:nl:ui:', repl='', string=identifier)
1060
+ identifier = re.sub(pattern=r'info:eu-repo/dai/nl/', repl='', string=identifier)
1061
+ identifier = identifier.upper()
1062
+ return identifier
1063
+
1064
+
1065
+ def normalize_email(identifier: str) -> str:
1066
+ """Normalize email address.
1067
+
1068
+ :param identifier: identifier to normalize.
1069
+ :return: Result of normalizing.
1070
+ """
1071
+ if identifier == '':
1072
+ return ''
1073
+ identifier = identifier.lower()
1074
+ return identifier
1075
+
1076
+
1077
+ def normalize_identifiers(df: pandas.DataFrame) -> pandas.DataFrame:
1078
+ """Normalize selected identifiers in the dataframe.
1079
+ Delete empty rows and duplicates.
1080
+
1081
+ :param df: dataframe with identifiers.
1082
+ :return: Result of normalizing.
1083
+ """
1084
+ df_mod = df.copy(deep=True)
1085
+
1086
+ # Ensure that all '' values are NaN, so that those rows can be easily removed with dropna()
1087
+ df_mod.replace('', numpy.nan, inplace=True)
1088
+ # dropna(how='all'): drop row if all row values contain NaN
1089
+ df_mod.dropna(axis=0, how='all', inplace=True)
1090
+ df_mod.drop_duplicates(keep='first', inplace=True, ignore_index=True)
1091
+
1092
+ # The values in this list correspond to the normalize functions above,
1093
+ # such as normalize_doi(), normalize_ror(), etc.
1094
+ for identifier in ['DOI', 'ROR', 'ORCID', 'ISNI', 'OPENALEX',
1095
+ 'SCOPUS_AUTHOR_ID', 'RESEARCHER_ID', 'DIGITAL_AUTHOR_ID',
1096
+ 'EMAIL']:
1097
+ function_name = f'normalize_{identifier.lower()}'
1098
+ if not callable(globals().get(function_name)):
1099
+ print('normalize_identifiers(): Error, function "' + function_name + '"')
1100
+ print(' does not exist, exiting.')
1101
+ exit(1)
1102
+
1103
+ if identifier in df_mod.columns:
1104
+ df_mod[identifier] = df_mod[identifier].apply(
1105
+ lambda x: globals()[function_name](x) if isinstance(x, str) else x)
1106
+ return df_mod
1107
+
1108
+
911
1109
  def create_history_line(property_name: str, old_value: str, new_value: str) -> str:
912
1110
  """Create a line to be used in the 'history' property of a node.
913
1111
  """
914
1112
  return 'Updated property "' + property_name + '" from "' + old_value + '" to "' + new_value + '". '
915
1113
 
916
1114
 
917
- def create_name_cache_in_personroot(node: Node, personroot: Node):
1115
+ def create_name_cache_in_personroot(node: Node, personroot: Node) -> None:
918
1116
  """This function caches the value of a node with 'name' 'FULL_NAME'
919
1117
  in the 'comment' property of its person-root node 'personroot'.
920
1118
  If the cache is not present, it is created.
@@ -958,7 +1156,7 @@ def create_name_cache_in_personroot(node: Node, personroot: Node):
958
1156
  return
959
1157
 
960
1158
 
961
- def recreate_name_cache_in_personroot(personroot: Node):
1159
+ def recreate_name_cache_in_personroot(personroot: Node) -> None:
962
1160
  """This function recreates the cache of all the nodes with 'name' 'FULL_NAME'
963
1161
  in the 'comment' property of its person-root node 'personroot'.
964
1162
  If the cache is not present, it is created.
@@ -969,26 +1167,28 @@ def recreate_name_cache_in_personroot(personroot: Node):
969
1167
  """
970
1168
  if personroot is None:
971
1169
  return
972
- neighbornodes = get_all_neighbor_nodes(node=personroot)
1170
+ neighbornodes = get_all_neighbor_nodes(node=personroot,
1171
+ name_want='FULL_NAME')
973
1172
  name_cache = []
974
1173
  for node in neighbornodes:
975
- if node['name'] == 'FULL_NAME':
976
- if node['value'] not in name_cache:
977
- name_cache.append(node['value'])
978
-
979
- if len(name_cache) != 0:
980
- if (isinstance(personroot['comment'], str) and personroot['comment'] == '') \
981
- or isinstance(personroot['comment'], list):
982
- time_stamp = datetimestamp()
983
- history_line = create_history_line(property_name='comment',
984
- old_value=str(personroot['comment']),
985
- new_value=str(name_cache))
986
- node_properties = {'comment': name_cache.copy(),
987
- '_history': personroot['_history'].copy()}
988
- node_properties['_history'].append(time_stamp + ': Cleaned and recreated name cache. ' + history_line)
989
- cypher_update_node_properties(node_element_id=personroot.element_id,
990
- node_properties=node_properties)
991
- # In all other cases: leave it as it is: 'comment' seems to be used for something we don't know.
1174
+ if node['value'] not in name_cache:
1175
+ name_cache.append(node['value'])
1176
+
1177
+ # We need to do this irrespective of the length of name_cache.
1178
+ # If the length is 0, we might be deleting FULL_NAME nodes and that
1179
+ # should also be reflected in the name cache.
1180
+ if (isinstance(personroot['comment'], str) and personroot['comment'] == '') \
1181
+ or isinstance(personroot['comment'], list):
1182
+ time_stamp = datetimestamp()
1183
+ history_line = create_history_line(property_name='comment',
1184
+ old_value=str(personroot['comment']),
1185
+ new_value=str(name_cache))
1186
+ node_properties = {'comment': name_cache.copy(),
1187
+ '_history': personroot['_history'].copy()}
1188
+ node_properties['_history'].append(time_stamp + ': Cleaned and recreated name cache. ' + history_line)
1189
+ cypher_update_node_properties(node_element_id=personroot.element_id,
1190
+ node_properties=node_properties)
1191
+ # In all other cases: leave it as it is: 'comment' seems to be used for something we don't know.
992
1192
  return
993
1193
 
994
1194
 
@@ -1327,7 +1527,11 @@ def read_all_values_of_property(node_property: str = '') -> list:
1327
1527
  global _graph
1328
1528
 
1329
1529
  if _graph is None:
1330
- print('\nread_all_values_of_property(): Error: graph has not been initialized or opened.\n\n')
1530
+ print('\nread_all_values_of_property(): Error: graph has not been initialized or opened.')
1531
+ return []
1532
+
1533
+ if ricgraph_nr_nodes() == 0:
1534
+ print('\nread_all_values_of_property(): Warning: graph is empty.')
1331
1535
  return []
1332
1536
 
1333
1537
  if node_property != 'name' \
@@ -1338,7 +1542,6 @@ def read_all_values_of_property(node_property: str = '') -> list:
1338
1542
  + node_property + '".\n\n')
1339
1543
  return []
1340
1544
 
1341
-
1342
1545
  if node_property == 'name_personal':
1343
1546
  # Note that the comment property of 'person-root' contains FULL_NAMEs,
1344
1547
  # so it is also a name property that is a personal identifier.
@@ -1478,6 +1681,37 @@ def update_nodes_df(nodes: pandas.DataFrame) -> None:
1478
1681
  return
1479
1682
 
1480
1683
 
1684
+ def delete_node(node: Node) -> None:
1685
+ """Delete a node in the graph database.
1686
+ If it has any edges, these will also be deleted.
1687
+
1688
+ :param node: the node to delete.
1689
+ :return: None.
1690
+ """
1691
+ global _graph
1692
+
1693
+ if _graph is None:
1694
+ print('\ndelete_node(): Error: graph has not been initialized or opened.\n\n')
1695
+ return
1696
+
1697
+ if node is None:
1698
+ print('delete_node(): Error: node is None - cannot be found.')
1699
+ return
1700
+
1701
+ if node['name'] == 'FULL_NAME':
1702
+ # We need to recreate the name cache in the person-root node.
1703
+ personroot = get_personroot_node(node=node)
1704
+ else:
1705
+ personroot = None
1706
+
1707
+ cypher_delete_node(node_element_id=node.element_id)
1708
+
1709
+ if personroot is not None:
1710
+ recreate_name_cache_in_personroot(personroot=personroot)
1711
+
1712
+ return
1713
+
1714
+
1481
1715
  def get_or_create_personroot_node(person_node: Node) -> Union[Node, None]:
1482
1716
  """Get a 'person-root' node for a given 'person' node, if that node has
1483
1717
  a 'person-root'. If not, create the 'person-root' node.
@@ -2743,69 +2977,154 @@ def get_commandline_argument(argument: str, argument_list: list) -> str:
2743
2977
  return ''
2744
2978
 
2745
2979
 
2980
+ def get_commandline_argument_organization(argument_list: list) -> str:
2981
+ """Get the value of a command line argument '--organization'.
2982
+ Prompt if no argument is given.
2983
+
2984
+ :param argument_list: the argument list.
2985
+ :return: the organization, or '' if no answer is given.
2986
+ """
2987
+ answer = get_commandline_argument(argument='--organization',
2988
+ argument_list=argument_list)
2989
+ if answer == '':
2990
+ print('\nYou need to specify an organization abbreviation.')
2991
+ print('This script will be run for that organization.')
2992
+ print('The organization abbreviation you enter will determine')
2993
+ print('which parameters will be read from the Ricgraph ini file')
2994
+ print('"' + get_ricgraph_ini_file() + '".')
2995
+ print('If you make a typo, you can run this script again.')
2996
+ print('If you enter an empty value, this script will exit.')
2997
+ answer = input('For what organization do you want to run this script? ')
2998
+ if answer == '':
2999
+ return ''
3000
+
3001
+ answer = answer.upper()
3002
+ return answer
3003
+
3004
+
3005
+ def get_commandline_argument_empty_ricgraph(argument_list: list) -> str:
3006
+ """Get the value of a command line argument '--empty_ricgraph'.
3007
+ Prompt if no argument is given.
3008
+
3009
+ :param argument_list: the argument list.
3010
+ :return: 'yes' or 'no', the answer whether to empty Ricgraph,
3011
+ or '' if no answer is given.
3012
+ """
3013
+ answer = get_commandline_argument(argument='--empty_ricgraph',
3014
+ argument_list=argument_list)
3015
+ if answer == '':
3016
+ print('\nDo you want to empty Ricgraph? You have the following options:')
3017
+ print('- "yes": Ricgraph will be emptied.')
3018
+ print('- "no": Ricgraph will not be emptied.')
3019
+ print('- any other answer: Ricgraph will not be emptied,')
3020
+ print(' execution of this script will abort.')
3021
+ answer = input('Please make a choice: ')
3022
+ if answer == '':
3023
+ return ''
3024
+
3025
+ answer = answer.lower()
3026
+ if answer != 'yes' and answer != 'no':
3027
+ return ''
3028
+ return answer
3029
+
3030
+
3031
+ def get_commandline_argument_harvest_projects(argument_list: list) -> str:
3032
+ """Get the value of a command line argument '--harvest_projects'.
3033
+ Prompt if no argument is given.
3034
+
3035
+ :param argument_list: the argument list.
3036
+ :return: 'yes' or 'no', the answer whether to harvest projects,
3037
+ or '' if no answer is given.
3038
+ """
3039
+ answer = get_commandline_argument(argument='--harvest_projects',
3040
+ argument_list=argument_list)
3041
+ if answer == '':
3042
+ print('\nYou can specify whether you want to harvest projects.')
3043
+ print('Only if enter "yes", this script will harvest projects.')
3044
+ answer = input('Do you want to harvest projects? ')
3045
+ if answer == '':
3046
+ return ''
3047
+
3048
+ answer = answer.lower()
3049
+ if answer != 'yes' and answer != 'no':
3050
+ return ''
3051
+ return answer
3052
+
3053
+
3054
+ def get_configfile_key(section: str, key: str) -> str:
3055
+ """Get the value of a key in the Ricgraph config file.
3056
+
3057
+ :param section: the section where the key is to be read from.
3058
+ :param key: the name of the key.
3059
+ :return: the value of the key (can be ''), or '' if absent.
3060
+ """
3061
+ config = configparser.ConfigParser()
3062
+ config.read(get_ricgraph_ini_file())
3063
+ try:
3064
+ value = config[section][key]
3065
+ except KeyError:
3066
+ return ''
3067
+
3068
+ return value
3069
+
3070
+
2746
3071
  # ############################################
2747
3072
  # ################### main ###################
2748
3073
  # ############################################
2749
3074
  # This will be executed on module initialization
2750
- config = configparser.ConfigParser()
2751
- config.read(get_ricgraph_ini_file())
2752
- try:
2753
- RICGRAPH_PROPERTIES_STANDARD = tuple(config['Ricgraph']['ricgraph_properties_standard'].split(','))
2754
- RICGRAPH_PROPERTIES_HIDDEN = tuple(config['Ricgraph']['ricgraph_properties_hidden'].split(','))
2755
- RICGRAPH_PROPERTIES_ADDITIONAL = tuple(config['Ricgraph']['ricgraph_properties_additional'].split(','))
2756
- if len(RICGRAPH_PROPERTIES_STANDARD) == 0 \
2757
- or len(RICGRAPH_PROPERTIES_HIDDEN) == 0 \
2758
- or len(RICGRAPH_PROPERTIES_ADDITIONAL) == 0:
2759
- print('Ricgraph initialization: error, ricgraph_properties_standard and/or')
2760
- print(' ricgraph_properties_hidden and/or ricgraph_properties_additional')
2761
- print(' are empty in Ricgraph ini file, exiting.')
2762
- exit(1)
2763
-
2764
- if RICGRAPH_PROPERTIES_STANDARD[0] == '' \
2765
- or RICGRAPH_PROPERTIES_HIDDEN[0] == '' \
2766
- or RICGRAPH_PROPERTIES_ADDITIONAL[0] == '':
2767
- print('Ricgraph initialization: error, ricgraph_properties_standard and/or')
2768
- print(' ricgraph_properties_hidden and/or ricgraph_properties_additional')
2769
- print(' are empty in Ricgraph ini file, exiting.')
2770
- exit(1)
3075
+ RICGRAPH_PROPERTIES_STANDARD = tuple(get_configfile_key(section='Ricgraph',
3076
+ key='ricgraph_properties_standard').split(','))
3077
+ RICGRAPH_PROPERTIES_HIDDEN = tuple(get_configfile_key(section='Ricgraph',
3078
+ key='ricgraph_properties_hidden').split(','))
3079
+ RICGRAPH_PROPERTIES_ADDITIONAL = tuple(get_configfile_key(section='Ricgraph',
3080
+ key='ricgraph_properties_additional').split(','))
3081
+ if len(RICGRAPH_PROPERTIES_STANDARD) == 0 \
3082
+ or len(RICGRAPH_PROPERTIES_HIDDEN) == 0 \
3083
+ or len(RICGRAPH_PROPERTIES_ADDITIONAL) == 0 \
3084
+ or RICGRAPH_PROPERTIES_STANDARD[0] == '' \
3085
+ or RICGRAPH_PROPERTIES_HIDDEN[0] == '' \
3086
+ or RICGRAPH_PROPERTIES_ADDITIONAL[0] == '':
3087
+ print('Ricgraph initialization: error, "ricgraph_properties_standard" and/or')
3088
+ print(' "ricgraph_properties_hidden" and/or "ricgraph_properties_additional"')
3089
+ print(' are not existing or empty in Ricgraph ini')
3090
+ print(' file "' + get_ricgraph_ini_file() + '", exiting.')
3091
+ exit(1)
2771
3092
 
2772
- # For more explanation, see file docs/ricgraph_install_configure.md,
2773
- # section RICGRAPH_NODEADD_MODE.
2774
- RICGRAPH_NODEADD_MODE = config['Ricgraph']['ricgraph_nodeadd_mode']
2775
- if RICGRAPH_NODEADD_MODE != 'strict' and RICGRAPH_NODEADD_MODE != 'lenient':
2776
- print('Ricgraph initialization: error, unknown value "' + RICGRAPH_NODEADD_MODE
2777
- + '" for ricgraph_nodeadd_mode in Ricgraph ini file, exiting.')
2778
- exit(1)
2779
- else:
2780
- print('Ricgraph is using "' + RICGRAPH_NODEADD_MODE + '" for ricgraph_nodeadd_mode.')
2781
- except KeyError:
2782
- print('Ricgraph initialization: error, ricgraph_properties_standard and/or')
2783
- print(' ricgraph_properties_hidden and/or ricgraph_properties_additional and/or ricgraph_nodeadd_mode')
2784
- print(' not found in Ricgraph ini file, exiting.')
3093
+ # For more explanation, see file docs/ricgraph_install_configure.md,
3094
+ # section RICGRAPH_NODEADD_MODE.
3095
+ RICGRAPH_NODEADD_MODE = get_configfile_key(section='Ricgraph', key='ricgraph_nodeadd_mode')
3096
+ if RICGRAPH_NODEADD_MODE != 'strict' and RICGRAPH_NODEADD_MODE != 'lenient':
3097
+ print('Ricgraph initialization: error, not existing or unknown value "' + RICGRAPH_NODEADD_MODE + '"')
3098
+ print(' for "ricgraph_nodeadd_mode" in Ricgraph ini')
3099
+ print(' file "' + get_ricgraph_ini_file() + '", exiting.')
2785
3100
  exit(1)
2786
3101
 
2787
- try:
2788
- GRAPHDB = config['GraphDB']['graphdb']
2789
- GRAPHDB_HOSTNAME = config['GraphDB']['graphdb_hostname']
2790
- GRAPHDB_DATABASENAME = config['GraphDB']['graphdb_databasename']
2791
- GRAPHDB_USER = config['GraphDB']['graphdb_user']
2792
- GRAPHDB_PASSWORD = config['GraphDB']['graphdb_password']
2793
- GRAPHDB_SCHEME = config['GraphDB']['graphdb_scheme']
2794
- GRAPHDB_PORT = config['GraphDB']['graphdb_port']
2795
- if GRAPHDB == '' or GRAPHDB_HOSTNAME == '' or GRAPHDB_DATABASENAME == '' \
2796
- or GRAPHDB_USER == '' \
2797
- or GRAPHDB_PASSWORD == '' or GRAPHDB_SCHEME == '' or GRAPHDB_PORT == '':
2798
- print('Ricgraph initialization: error, one or more of the GraphDB parameters '
2799
- + 'empty in Ricgraph ini file, exiting.')
2800
- exit(1)
2801
- GRAPHDB_URL = '{scheme}://{hostname}:{port}'.format(scheme=GRAPHDB_SCHEME,
2802
- hostname=GRAPHDB_HOSTNAME,
2803
- port=GRAPHDB_PORT)
2804
- except KeyError:
2805
- print('Ricgraph initialization: error, one or more of GraphDB parameters '
2806
- + 'not found in Ricgraph ini file, exiting.')
3102
+ print('Ricgraph is using "' + RICGRAPH_NODEADD_MODE + '" for "ricgraph_nodeadd_mode".')
3103
+
3104
+ GRAPHDB = get_configfile_key(section='GraphDB', key='graphdb')
3105
+ GRAPHDB_HOSTNAME = get_configfile_key(section='GraphDB', key='graphdb_hostname')
3106
+ GRAPHDB_DATABASENAME = get_configfile_key(section='GraphDB', key='graphdb_databasename')
3107
+ GRAPHDB_USER = get_configfile_key(section='GraphDB', key='graphdb_user')
3108
+ GRAPHDB_PASSWORD = get_configfile_key(section='GraphDB', key='graphdb_password')
3109
+ GRAPHDB_SCHEME = get_configfile_key(section='GraphDB', key='graphdb_scheme')
3110
+ GRAPHDB_PORT = get_configfile_key(section='GraphDB', key='graphdb_port')
3111
+ if GRAPHDB == '' or GRAPHDB_HOSTNAME == '' or GRAPHDB_DATABASENAME == '' \
3112
+ or GRAPHDB_USER == '' or GRAPHDB_PASSWORD == '' \
3113
+ or GRAPHDB_SCHEME == '' or GRAPHDB_PORT == '':
3114
+ print('Ricgraph initialization: error, one or more of the GraphDB parameters')
3115
+ print(' not existing or empty in Ricgraph ini')
3116
+ print(' file "' + get_ricgraph_ini_file() + '", exiting.')
2807
3117
  exit(1)
2808
3118
 
3119
+ GRAPHDB_URL = '{scheme}://{hostname}:{port}'.format(scheme=GRAPHDB_SCHEME,
3120
+ hostname=GRAPHDB_HOSTNAME,
3121
+ port=GRAPHDB_PORT)
3122
+
2809
3123
  # Make sure DataFrames are printed with all columns on full width
2810
3124
  pandas.set_option('display.max_columns', None)
2811
3125
  pandas.set_option('display.width', 500)
3126
+ # To prevent warning
3127
+ # "FutureWarning: Downcasting behavior in `replace` is deprecated and will be removed
3128
+ # in a future version. To retain the old behavior, explicitly call `result.infer_objects(copy=False)`.
3129
+ # To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`"
3130
+ pandas.set_option('future.no_silent_downcasting', True)
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: ricgraph
3
- Version: 2.7
3
+ Version: 2.9
4
4
  Summary: Ricgraph - Research in context graph
5
5
  Author: Rik D.T. Janssen
6
6
  Project-URL: Website, https://www.ricgraph.eu
@@ -25,19 +25,25 @@ Requires-Dist: requests
25
25
  [![DOI software](https://img.shields.io/badge/DOI%20%20software-10.5281/zenodo.7524314-blue)](https://doi.org/10.5281/zenodo.7524314)
26
26
  [![DOI reference publication](https://img.shields.io/badge/DOI%20reference%20publication-10.1016%2Fj.softx.2024.101736-blue)](https://doi.org/10.1016/j.softx.2024.101736)
27
27
  [![website](https://img.shields.io/badge/website-www.ricgraph.eu-blue)](https://www.ricgraph.eu)
28
- ![GitHub release date](https://img.shields.io/github/release-date/UtrechtUniversity/ricgraph?color=green)
29
- [![GitHub latest release](https://img.shields.io/github/release/UtrechtUniversity/ricgraph?color=green)](https://github.com/UtrechtUniversity/ricgraph/releases)
30
- ![GitHub commits since latest release](https://img.shields.io/github/commits-since/UtrechtUniversity/ricgraph/latest?color=green)
31
- ![GitHub last commit](https://img.shields.io/github/last-commit/UtrechtUniversity/ricgraph?color=green)
32
- [![PyPI version](https://img.shields.io/pypi/v/ricgraph?label=PyPI%20version&color=green)](https://pypi.org/project/ricgraph)
33
- [![PyPI downloads](https://img.shields.io/pypi/dm/ricgraph?label=PyPI%20downloads&color=green)](https://pypistats.org/packages/ricgraph)
34
- [![GitHub license](https://img.shields.io/github/license/UtrechtUniversity/ricgraph?color=green)](LICENSE)
28
+ ![GitHub release date](https://img.shields.io/github/release-date/UtrechtUniversity/ricgraph?color=%234c1)
29
+ [![GitHub latest release](https://img.shields.io/github/release/UtrechtUniversity/ricgraph?color=%234c1)](https://github.com/UtrechtUniversity/ricgraph/releases)
30
+ ![GitHub commits since latest release](https://img.shields.io/github/commits-since/UtrechtUniversity/ricgraph/latest?color=%234c1)
31
+ ![GitHub last commit](https://img.shields.io/github/last-commit/UtrechtUniversity/ricgraph?color=%234c1)
32
+ [![PyPI version](https://img.shields.io/pypi/v/ricgraph?label=PyPI%20version&color=%234c1)](https://pypi.org/project/ricgraph)
33
+ [![PyPI downloads](https://img.shields.io/pypi/dm/ricgraph?label=PyPI%20downloads&color=%234c1)](https://pypistats.org/packages/ricgraph)
34
+ [![Ricgraph container doc](https://img.shields.io/badge/Ricgraph_container_doc-click_here-%234c1)](https://github.com/UtrechtUniversity/ricgraph/blob/main/docs/ricgraph_containerized.md)
35
+ [![Podman container version](https://ghcr-badge.egpl.dev/utrechtuniversity/ricgraph/latest_tag?color=%234c1&label=container+version)](https://github.com/utrechtuniversity/ricgraph/pkgs/container/ricgraph)
36
+ [![GitHub license](https://img.shields.io/github/license/UtrechtUniversity/ricgraph?color=%234c1)](LICENSE)
35
37
  [![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)
36
38
  [![Technology Readiness Level 7/9 - Release Candidate - Technology ready enough and in initial use by end-users in intended scholarly environments](https://w3id.org/research-technology-readiness-levels/Level7ReleaseCandidate.svg)](https://github.com/CLARIAH/clariah-plus/blob/main/requirements/software-metadata-requirements.md#15--you-should-express-a-technology-readiness-level)
37
39
  [![FAIR checklist badge](https://fairsoftwarechecklist.net/badge.svg)](https://fairsoftwarechecklist.net/v0.2?f=31&a=32113&i=32110&r=123)
40
+
38
41
  <!---
39
42
  Note, the lines 'Website' and
40
43
  'PyPI downloads' end in two spaces, to force a line break but not a paragraph break.
44
+ Similar for others.
45
+ We use color=#4c1 (green), that color is used by the 'repo status' badge.
46
+ Documentation about the Podman badges can be found here: https://github.com/eggplants/ghcr-badge.
41
47
  --->
42
48
 
43
49
  <img alt="Ricgraph logo" src="https://raw.githubusercontent.com/UtrechtUniversity/ricgraph/refs/heads/main/docs/images/ricgraph_logo.png" height="30">
File without changes
File without changes