Skip to content

Commit

Permalink
Merge pull request #160 from vemonet/better-import-keys
Browse files Browse the repository at this point in the history
Improve dependencies versioning
  • Loading branch information
raar1 authored Jan 30, 2024
2 parents 337846a + 5a51152 commit 08ab4ae
Show file tree
Hide file tree
Showing 21 changed files with 492 additions and 226 deletions.
54 changes: 27 additions & 27 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,33 @@ repos:
name: 🪚 Fix end of files
- id: trailing-whitespace
name: ✂️ Trim trailing whitespaces
- repo: https://github.com/asottile/pyupgrade
rev: v2.37.3
hooks:
- id: pyupgrade
name: ⏫ Running pyupgrade
args:
- --py3-plus
- --keep-runtime-typing
- repo: https://github.com/myint/autoflake
rev: v1.5.3
hooks:
- id: autoflake
name: ❄️ Running autoflake
args:
- --recursive
- --in-place
- --remove-all-unused-imports
- --remove-unused-variables
- --expand-star-imports
- --exclude
- __init__.py
- --remove-duplicate-keys
- repo: https://github.com/pycqa/isort
rev: 5.10.1
hooks:
- id: isort
name: 🔄 Formatting imports with isort (python)
# - repo: https://github.com/asottile/pyupgrade
# rev: v2.37.3
# hooks:
# - id: pyupgrade
# name: ⏫ Running pyupgrade
# args:
# - --py3-plus
# - --keep-runtime-typing
# - repo: https://github.com/myint/autoflake
# rev: v1.5.3
# hooks:
# - id: autoflake
# name: ❄️ Running autoflake
# args:
# - --recursive
# - --in-place
# - --remove-all-unused-imports
# - --remove-unused-variables
# - --expand-star-imports
# - --exclude
# - __init__.py
# - --remove-duplicate-keys
# - repo: https://github.com/pycqa/isort
# rev: 5.10.1
# hooks:
# - id: isort
# name: 🔄 Formatting imports with isort (python)
ci:
autofix_commit_msg: 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks
autoupdate_commit_msg: ⬆ [pre-commit.ci] pre-commit autoupdate
6 changes: 3 additions & 3 deletions docs/getting-started/test-server.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# The nanopub test server
Throughout this documentation we make use of the
[nanopub test server](http://test-server.nanopubs.lod.labs.vu.nl/)
[nanopub test server](https://np.test.knowledgepixels.com/)
by setting `use_test_server=True` when instantiating `NanopubConf` or `NanopubClient`:
```python
from nanopub import NanopubClient, NanopubConf

client = NanopubClient(use_test_server=True)
np_conf = NanopubConf(use_test_server=True)
```
This will search and fetch from, and publish to the [nanopub test server](http://test-server.nanopubs.lod.labs.vu.nl/).
This will search and fetch from, and publish to the [nanopub test server](https://np.test.knowledgepixels.com/).

When learning about nanopub using the testserver is a good idea, because:
* You are free to experiment with publishing without polluting the production server.
Expand All @@ -25,6 +25,6 @@ A manual workaround is:
1. Open [http://purl.org/np/RA71u9tYPd7ZQifE_6hXjqVim6pkweuvjoi-8ehvLvzg8](http://purl.org/np/RA71u9tYPd7ZQifE_6hXjqVim6pkweuvjoi-8ehvLvzg8)
in your browser
2. Notice that the URL changed to [http://server.nanopubs.lod.labs.vu.nl/RA71u9tYPd7ZQifE_6hXjqVim6pkweuvjoi-8ehvLvzg8](http://server.nanopubs.lod.labs.vu.nl/RA71u9tYPd7ZQifE_6hXjqVim6pkweuvjoi-8ehvLvzg8).
3. Replace 'server' with 'test-server': [http://test-server.nanopubs.lod.labs.vu.nl/RA71u9tYPd7ZQifE_6hXjqVim6pkweuvjoi-8ehvLvzg8](http://test-server.nanopubs.lod.labs.vu.nl/RA71u9tYPd7ZQifE_6hXjqVim6pkweuvjoi-8ehvLvzg8).
3. Replace 'server' with 'test-server': [https://np.test.knowledgepixels.com/RA71u9tYPd7ZQifE_6hXjqVim6pkweuvjoi-8ehvLvzg8](https://np.test.knowledgepixels.com/RA71u9tYPd7ZQifE_6hXjqVim6pkweuvjoi-8ehvLvzg8).

> **NB**: `NanopubClient.fetch()` does this for you if `use_test_server=True`.
12 changes: 7 additions & 5 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,13 @@ theme:
scheme: default
primary: light blue
toggle:
icon: material/toggle-switch-off-outline
icon: material/weather-night
name: Switch to dark mode
- media: "(prefers-color-scheme: dark)"
scheme: slate
primary: light blue
toggle:
icon: material/toggle-switch
icon: material/weather-sunny
name: Switch to light mode
features:
- content.code.annotate
Expand All @@ -86,10 +86,12 @@ plugins:
default_handler: python
handlers:
python:
rendering:
options:
show_source: true
watch:
- nanopub

watch:
- nanopub
- docs


# Styled blocks: https://squidfunk.github.io/mkdocs-material/reference/admonitions/#supported-types
Expand Down
19 changes: 12 additions & 7 deletions nanopub/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ def profile():
p = load_profile()
print(f' 👤 User profile in \033[1m{DEFAULT_PROFILE_PATH}\033[0m')
print(str(p))
except ProfileError:
except ProfileError as e:
print(e)
print(f" ⚠️ No profile could be loaded from {DEFAULT_PROFILE_PATH}")
print(" ℹ️ Use \033[1mnp setup\033[0m to setup your nanopub profile locally with the interactive CLI")

Expand Down Expand Up @@ -163,21 +164,23 @@ def setup(
prompt = ('📬️ Would you like to publish your profile to the nanopub servers? '
'This links your ORCID iD to your RSA key, thereby making all your '
'publications linkable to you')
publish_resp = typer.prompt(prompt, type=Path, default="")
publish_resp = typer.prompt(prompt, type=str, default="")
if publish_resp and publish_resp.lower().startswith("y"):
publish = True
else:
publish = False

if not keypair and not newkeys:
prompt = '🔓️ Provide the path to your public RSA key: ' \
f'Leave empty for using the one in {USER_CONFIG_DIR}'
public_key = typer.prompt(prompt, type=Path, default="")
'Leave empty for using the one in: '
public_key = typer.prompt(prompt, type=Path,
default=DEFAULT_PUBLIC_KEY_PATH)
if not public_key:
keypair = None
else:
prompt = '🔑 Provide the path to your private RSA key: '
private_key = typer.prompt(prompt, type=Path)
private_key = typer.prompt(prompt, type=Path,
default=DEFAULT_PRIVATE_KEY_PATH)
keypair = public_key, private_key

if not keypair:
Expand All @@ -194,8 +197,10 @@ def setup(
public_key_path, private_key = keypair

# Copy the keypair to the default location
shutil.copy(public_key_path, USER_CONFIG_DIR / PUBLIC_KEY_FILE)
shutil.copy(private_key, USER_CONFIG_DIR / PRIVATE_KEY_FILE)
if not os.path.exists(DEFAULT_PUBLIC_KEY_PATH):
shutil.copy(public_key_path, USER_CONFIG_DIR / PUBLIC_KEY_FILE)
if not os.path.exists(DEFAULT_PRIVATE_KEY_PATH):
shutil.copy(private_key, USER_CONFIG_DIR / PRIVATE_KEY_FILE)

print(f'🚚 Your RSA keys have been copied to {USER_CONFIG_DIR}')

Expand Down
2 changes: 1 addition & 1 deletion nanopub/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "2.0.0"
__version__ = "2.0.1"
27 changes: 14 additions & 13 deletions nanopub/client.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""This module includes a client for the nanopub server.
"""
This module includes a client for the nanopub server.
"""

import random
Expand Down Expand Up @@ -64,10 +65,10 @@ def find_nanopubs_with_text(
retracted. Default is True, returning only publications that are not retracted.
Yields:
dicts depicting matching nanopublications.
Each dict holds: 'np': the nanopublication uri,
'date': date of creation of the nanopublication,
'description': A description of the nanopublication (if found in RDF).
results (dict): dicts depicting matching nanopublications.
Each dict holds: 'np': the nanopublication uri,
'date': date of creation of the nanopublication,
'description': A description of the nanopublication (if found in RDF).
"""
if len(text) == 0:
Expand Down Expand Up @@ -103,10 +104,10 @@ def find_nanopubs_with_pattern(
retracted. Default is True, returning only publications that are not retracted.
Yields:
dicts depicting matching nanopublications.
Each dict holds: 'np': the nanopublication uri,
'date': date of creation of the nanopublication,
'description': A description of the nanopublication (if found in RDF).
results (dict): dicts depicting matching nanopublications.
Each dict holds: 'np': the nanopublication uri,
'date': date of creation of the nanopublication,
'description': A description of the nanopublication (if found in RDF).
"""
params = {}
Expand Down Expand Up @@ -145,10 +146,10 @@ def find_things(
retracted. Default is True, returning only publications that are not retracted.
Yields:
dicts depicting matching nanopublications.
Each dict holds: 'np': the nanopublication uri,
'date': date of creation of the nanopublication,
'description': A description of the nanopublication (if found in RDF).
results (dict): dicts depicting matching nanopublications.
Each dict holds: 'np': the nanopublication uri,
'date': date of creation of the nanopublication,
'description': A description of the nanopublication (if found in RDF).
"""
if searchterm == "":
Expand Down
5 changes: 3 additions & 2 deletions nanopub/definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
USER_CONFIG_DIR = Path.home() / ".nanopub"
DEFAULT_PROFILE_PATH = USER_CONFIG_DIR / "profile.yml"

NANOPUB_TEST_SERVER = 'http://test-server.nanopubs.lod.labs.vu.nl/'
NANOPUB_TEST_SERVER = 'https://np.test.knowledgepixels.com/'
# List of servers: https://monitor.petapico.org/.csv
NANOPUB_SERVER_LIST = [
'https://np.petapico.org/',
Expand All @@ -31,6 +31,7 @@
MAX_NP_PER_INDEX = 1100
MAX_TRIPLES_PER_NANOPUB = 1200

RSA_KEY_SIZE = 2048

NANOPUB_GRLC_URLS = [
"http://grlc.nanopubs.lod.labs.vu.nl/api/local/local/",
Expand All @@ -42,4 +43,4 @@
# "https://grlc.nanopubs.knows.idlab.ugent.be/api/local/local/",
# "http://grlc.np.scify.org/api/local/local/",
]
NANOPUB_TEST_GRLC_URL = "http://test-grlc.nanopubs.lod.labs.vu.nl/api/local/local/"
NANOPUB_TEST_GRLC_URL = "https://grlc.test.nps.knowledgepixels.com/api/local/local/"
75 changes: 47 additions & 28 deletions nanopub/nanopub.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ def __init__(
self._assertion += assertion
self._provenance += provenance
self._pubinfo += pubinfo
self._bnode_count = 0

# Concatenate prefixes declarations from all provided graphs in the main graph
for user_rdf in [assertion, provenance, pubinfo]:
Expand Down Expand Up @@ -157,7 +158,7 @@ def _preformat_graph(self, g: ConjunctiveGraph) -> ConjunctiveGraph:
g.bind("orcid", ORCID)
g.bind("ntemplate", NTEMPLATE)
g.bind("foaf", FOAF)
# g = self._replace_blank_nodes(g)
g = self._replace_blank_nodes(g)
return g


Expand All @@ -184,7 +185,8 @@ def sign(self) -> None:
raise MalformedNanopubError(f"The nanopub have already been signed: {self.source_uri}")

if self.is_valid:
signed_g = add_signature(self.rdf, self._conf.profile, self._metadata.namespace, URIRef(str(self._pubinfo.identifier)))
self._replace_blank_nodes(self._rdf)
signed_g = add_signature(self.rdf, self._conf.profile, self._metadata.namespace, self._pubinfo)
self.update_from_signed(signed_g)
log.info(f"Signed {self.source_uri}")
else:
Expand Down Expand Up @@ -221,7 +223,6 @@ def update(self, publish=True) -> None:
None,
))
self._metadata = extract_np_metadata(self._rdf)
print(self._metadata)
if publish:
self.publish()
else:
Expand Down Expand Up @@ -362,6 +363,8 @@ def profile(self, value):
def namespace(self):
return self._metadata.namespace



@property
def introduces_concept(self):
concepts_introduced = list()
Expand Down Expand Up @@ -554,28 +557,44 @@ def _validate_nanopub_arguments(
"introduces_concept argument"
)

# TODO: we might to use it to convert blank nodes directly as URI here
# instead of doing it through the get_trustyuri() function
# def _replace_blank_nodes(self, rdf: ConjunctiveGraph) -> ConjunctiveGraph:
# """Replace blank nodes.
# Replace any blank nodes in the supplied RDF with a corresponding uri in the
# dummy_namespace.'Blank nodes' here refers specifically to rdflib.term.BNode objects. When
# publishing, the dummy_namespace is replaced with the URI of the actual nanopublication.
# For example, if the nanopub's URI is www.purl.org/ABC123 then the blank node will be
# replaced with a concrete URIRef of the form www.purl.org/ABC123#blanknodename where
# 'blanknodename' is the name of the rdflib.term.BNode object.
# This is to solve the problem that a user may wish to use the nanopublication to introduce
# a new concept. This new concept needs its own URI (it cannot simply be given the
# nanopublication's URI), but it should still lie within the space of the nanopub.
# Furthermore, the URI the nanopub is published to is not known ahead of time.
# """
# for s, p, o in rdf:
# if isinstance(s, BNode):
# rdf.remove((s, p, o))
# s = self._metadata.namespace[f"_{str(s)}"]
# rdf.add((s, p, o))
# if isinstance(o, BNode):
# rdf.remove((s, p, o))
# o = self._metadata.namespace[f"_{str(o)}"]
# rdf.add((s, p, o))
# return rdf

def _replace_blank_nodes(self, g: ConjunctiveGraph) -> ConjunctiveGraph:
"""Replace blank nodes.
Replace any blank nodes in the supplied RDF with a corresponding uri in the
dummy_namespace.'Blank nodes' here refers specifically to rdflib.term.BNode objects. When
publishing, the dummy_namespace is replaced with the URI of the actual nanopublication.
For example, if the nanopub's URI is www.purl.org/ABC123 then the blank node will be
replaced with a concrete URIRef of the form www.purl.org/ABC123#blanknodename where
'blanknodename' is the name of the rdflib.term.BNode object.
This is to solve the problem that a user may wish to use the nanopublication to introduce
a new concept. This new concept needs its own URI (it cannot simply be given the
nanopublication's URI), but it should still lie within the space of the nanopub.
Furthermore, the URI the nanopub is published to is not known ahead of time.
"""
bnode_map: dict = {}
for s, p, o, c in g.quads():
if isinstance(s, BNode):
g.remove((s, p, o, c))
if str(s) not in bnode_map:
if re.match(r'^[Na-zA-Z0-9]{33}$', str(s)):
# Unnamed BNode looks like N2c21867a547345d9b8a203a7c1cd7e0c
self._bnode_count += 1
bnode_map[str(s)] = self._bnode_count
else:
bnode_map[str(s)] = str(s)
s = self._metadata.namespace[f"_{bnode_map[str(s)]}"]
g.add((s, p, o, c))

if isinstance(o, BNode):
g.remove((s, p, o, c))
if str(o) not in bnode_map:
# if str(o).startswith("N") and len(str(o)) == 33:
if re.match(r'^[Na-zA-Z0-9]{33}$', str(s)):
self._bnode_count += 1
bnode_map[str(o)] = self._bnode_count
else:
bnode_map[str(o)] = str(o)
o = self._metadata.namespace[f"_{bnode_map[str(o)]}"]

g.add((s, p, o, c))
return g
Loading

0 comments on commit 08ab4ae

Please sign in to comment.