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.
- {ricgraph-2.7/ricgraph.egg-info → ricgraph-2.9}/PKG-INFO +15 -9
- {ricgraph-2.7 → ricgraph-2.9}/README-PyPI.md +13 -7
- {ricgraph-2.7 → ricgraph-2.9}/README.md +13 -7
- {ricgraph-2.7 → ricgraph-2.9}/pyproject.toml +1 -1
- {ricgraph-2.7 → ricgraph-2.9}/ricgraph/__init__.py +0 -2
- {ricgraph-2.7 → ricgraph-2.9}/ricgraph/ricgraph.py +436 -117
- {ricgraph-2.7 → ricgraph-2.9/ricgraph.egg-info}/PKG-INFO +15 -9
- {ricgraph-2.7 → ricgraph-2.9}/LICENSE +0 -0
- {ricgraph-2.7 → ricgraph-2.9}/ricgraph.egg-info/SOURCES.txt +0 -0
- {ricgraph-2.7 → ricgraph-2.9}/ricgraph.egg-info/dependency_links.txt +0 -0
- {ricgraph-2.7 → ricgraph-2.9}/ricgraph.egg-info/requires.txt +0 -0
- {ricgraph-2.7 → ricgraph-2.9}/ricgraph.egg-info/top_level.txt +0 -0
- {ricgraph-2.7 → ricgraph-2.9}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: ricgraph
|
|
3
|
-
Version: 2.
|
|
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
|
[](https://doi.org/10.5281/zenodo.7524314)
|
|
26
26
|
[](https://doi.org/10.1016/j.softx.2024.101736)
|
|
27
27
|
[](https://www.ricgraph.eu)
|
|
28
|
-

|
|
29
|
+
[](https://github.com/UtrechtUniversity/ricgraph/releases)
|
|
30
|
+

|
|
31
|
+

|
|
32
|
+
[](https://pypi.org/project/ricgraph)
|
|
33
|
+
[](https://pypistats.org/packages/ricgraph)
|
|
34
|
+
[](https://github.com/UtrechtUniversity/ricgraph/blob/main/docs/ricgraph_containerized.md)
|
|
35
|
+
[](https://github.com/utrechtuniversity/ricgraph/pkgs/container/ricgraph)
|
|
36
|
+
[](LICENSE)
|
|
35
37
|
[](https://www.repostatus.org/#active)
|
|
36
38
|
[](https://github.com/CLARIAH/clariah-plus/blob/main/requirements/software-metadata-requirements.md#15--you-should-express-a-technology-readiness-level)
|
|
37
39
|
[](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
|
[](https://doi.org/10.5281/zenodo.7524314)
|
|
2
2
|
[](https://doi.org/10.1016/j.softx.2024.101736)
|
|
3
3
|
[](https://www.ricgraph.eu)
|
|
4
|
-

|
|
5
|
+
[](https://github.com/UtrechtUniversity/ricgraph/releases)
|
|
6
|
+

|
|
7
|
+

|
|
8
|
+
[](https://pypi.org/project/ricgraph)
|
|
9
|
+
[](https://pypistats.org/packages/ricgraph)
|
|
10
|
+
[](https://github.com/UtrechtUniversity/ricgraph/blob/main/docs/ricgraph_containerized.md)
|
|
11
|
+
[](https://github.com/utrechtuniversity/ricgraph/pkgs/container/ricgraph)
|
|
12
|
+
[](LICENSE)
|
|
11
13
|
[](https://www.repostatus.org/#active)
|
|
12
14
|
[](https://github.com/CLARIAH/clariah-plus/blob/main/requirements/software-metadata-requirements.md#15--you-should-express-a-technology-readiness-level)
|
|
13
15
|
[](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
|
[](https://doi.org/10.5281/zenodo.7524314)
|
|
2
2
|
[](https://doi.org/10.1016/j.softx.2024.101736)
|
|
3
3
|
[](https://www.ricgraph.eu)
|
|
4
|
-

|
|
5
|
+
[](https://github.com/UtrechtUniversity/ricgraph/releases)
|
|
6
|
+

|
|
7
|
+

|
|
8
|
+
[](https://pypi.org/project/ricgraph)
|
|
9
|
+
[](https://pypistats.org/packages/ricgraph)
|
|
10
|
+
[](https://github.com/UtrechtUniversity/ricgraph/blob/main/docs/ricgraph_containerized.md)
|
|
11
|
+
[](https://github.com/utrechtuniversity/ricgraph/pkgs/container/ricgraph)
|
|
12
|
+
[](LICENSE)
|
|
11
13
|
[](https://www.repostatus.org/#active)
|
|
12
14
|
[](https://github.com/CLARIAH/clariah-plus/blob/main/requirements/software-metadata-requirements.md#15--you-should-express-a-technology-readiness-level)
|
|
13
15
|
[](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">
|
|
@@ -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
|
|
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,
|
|
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
|
-
|
|
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
|
-
# '
|
|
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
|
|
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():
|
|
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
|
|
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
|
|
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
|
|
354
|
-
print('
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
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
|
-
|
|
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['
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
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
|
|
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
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
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
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
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
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
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
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: ricgraph
|
|
3
|
-
Version: 2.
|
|
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
|
[](https://doi.org/10.5281/zenodo.7524314)
|
|
26
26
|
[](https://doi.org/10.1016/j.softx.2024.101736)
|
|
27
27
|
[](https://www.ricgraph.eu)
|
|
28
|
-

|
|
29
|
+
[](https://github.com/UtrechtUniversity/ricgraph/releases)
|
|
30
|
+

|
|
31
|
+

|
|
32
|
+
[](https://pypi.org/project/ricgraph)
|
|
33
|
+
[](https://pypistats.org/packages/ricgraph)
|
|
34
|
+
[](https://github.com/UtrechtUniversity/ricgraph/blob/main/docs/ricgraph_containerized.md)
|
|
35
|
+
[](https://github.com/utrechtuniversity/ricgraph/pkgs/container/ricgraph)
|
|
36
|
+
[](LICENSE)
|
|
35
37
|
[](https://www.repostatus.org/#active)
|
|
36
38
|
[](https://github.com/CLARIAH/clariah-plus/blob/main/requirements/software-metadata-requirements.md#15--you-should-express-a-technology-readiness-level)
|
|
37
39
|
[](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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|