├── .github
└── workflows
│ ├── build.yml
│ ├── cffconvert.yml
│ └── pypi.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .zenodo.json
├── CHANGELOG.md
├── CITATION.cff
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── docs
├── assets
│ ├── FAIR_data_principles.png
│ ├── custom.css
│ ├── fontawesome.min.js
│ ├── icon.png
│ ├── nanopub.png
│ └── solid.min.js
├── getting-started
│ ├── development.md
│ ├── setup.md
│ ├── test-server.md
│ ├── use-the-cli.md
│ └── what-are-nanopubs.md
├── index.md
├── publishing
│ ├── profile.md
│ ├── publish-nanopublications.md
│ ├── retraction.md
│ ├── setting-subgraphs.md
│ ├── templates.md
│ └── using-publication-namespace.md
├── reference
│ ├── client.md
│ ├── client.rst
│ ├── config.md
│ ├── namespaces.md
│ ├── namespaces.rst
│ ├── nanopub.md
│ ├── profile.md
│ ├── publication.rst
│ └── templates.md
└── searching
│ ├── fetching.md
│ └── searching.md
├── examples
├── controlling-subgraphs.ipynb
├── create_and_publish.ipynb
├── create_and_publish_fdo.ipynb
├── create_and_validate_fdo_exp.ipynb
├── create_validate_update_fdo_nanopub.ipynb
├── publishing_and_retracting.ipynb
├── searching.ipynb
└── using_publication_namespace.ipynb
├── mkdocs.yml
├── nanopub
├── __init__.py
├── __main__.py
├── _version.py
├── client.py
├── constants.py
├── definitions.py
├── fdo_metadata.py
├── fdo_nanopub.py
├── fdo_ops.py
├── namespaces.py
├── nanopub.py
├── nanopub_conf.py
├── profile.py
├── py.typed
├── sign_utils.py
├── templates
│ ├── __init__.py
│ ├── nanopub_claim.py
│ ├── nanopub_index.py
│ ├── nanopub_introduction.py
│ ├── nanopub_retract.py
│ └── nanopub_update.py
├── trustyuri
│ ├── CheckFile.py
│ ├── ModuleDirectory.py
│ ├── RunBatch.py
│ ├── TrustyUriModule.py
│ ├── TrustyUriResource.py
│ ├── TrustyUriUtils.py
│ ├── __init__.py
│ ├── file
│ │ ├── FileHasher.py
│ │ ├── FileModule.py
│ │ ├── ProcessFile.py
│ │ └── __init__.py
│ └── rdf
│ │ ├── HashAdder.py
│ │ ├── RdfHasher.py
│ │ ├── RdfModule.py
│ │ ├── RdfPreprocessor.py
│ │ ├── RdfTransformer.py
│ │ ├── RdfUtils.py
│ │ ├── StatementComparator.py
│ │ ├── TransformRdf.py
│ │ └── __init__.py
└── utils.py
├── pyproject.toml
├── scripts
├── all.sh
├── dev.py
├── dev.sh
├── docs.sh
├── format.sh
├── html-cov-test.sh
├── install.sh
├── lint.sh
├── nanopub-java
├── nanopub-java.bat
├── notebooks.sh
└── test.sh
└── tests
├── __init__.py
├── conftest.py
├── java_wrapper.py
├── resources
├── id_rsa
├── id_rsa.pub
├── many_bnodes_with_annotations.json
├── nanopub_sample_signed.trig
└── nanopub_sample_signed.trig.signed.trig
├── test_cli.py
├── test_client.py
├── test_fdo_nanopub.py
├── test_fdo_ops.py
├── test_nanopub.py
├── test_profile.py
├── test_sign_utils.py
├── test_testsuite.py
└── testsuite
├── invalid
├── plain
│ ├── emptya.trig
│ ├── emptyinfo.trig
│ ├── emptyprov.trig
│ ├── extragraph.trig
│ ├── noinfolink.trig
│ ├── noprovlink.trig
│ └── valid_invalid1.trig
├── signed
│ ├── simple1-invalid-dsa.trig
│ └── simple1-invalid-rsa.trig
└── trusty
│ └── trusty1.trig
├── transform
├── signed
│ └── rsa-key1
│ │ ├── key
│ │ ├── id_rsa
│ │ └── id_rsa.pub
│ │ ├── simple1.in.trig
│ │ ├── simple1.out.code
│ │ └── simple1.out.trig
└── trusty
│ ├── aida1.in.trig
│ ├── aida1.out.code
│ ├── aida1.out.trig
│ ├── simple1.in.trig
│ ├── simple1.out.code
│ └── simple1.out.trig
└── valid
├── plain
├── aida1.trig
├── proteinatlas-16-1.trig
├── simple1.nq
├── simple1.trig
└── simple1.xml
├── signed
├── Darwin-Core-schema-resource.trig
├── EduSocDL-community.trig
├── nanobench_hasRead-template-v5.trig
├── nanobench_new-individual-template-v3.trig
├── nanobench_somebodyElse-prtemplate.trig
├── physician-suicide-1.trig
├── python-step-1.trig
├── simple1-signed-dsa.trig
├── simple1-signed-rsa.trig
└── workflow-1.trig
└── trusty
├── disgenet-v2.1.0.0-1.trig
├── disgenet-v3.0.0.0-1.trig
├── fair-definition-1.trig
├── fair-maturity-1.trig
├── fip-ontology-1.trig
├── generif-aida-1.trig
├── generif-aida-index.trig
├── genuine-sempub-1.trig
├── genuine-sempub-2.trig
├── globalbioticinteractions_aps-turfgrasses-1.trig
├── globalbioticinteractions_bees-1.trig
├── globalbioticinteractions_inaturalist-1.trig
├── globalbioticinteractions_raymond-1.trig
├── liddi-1.trig
├── linkflows-article-1.trig
├── linkflows-review-1.trig
├── nextprot-1.trig
├── openbel-1.trig
├── provcorp-definition-1.trig
├── provcorp-parc-annotation-1.trig
├── trusty1.trig
├── wd-metabolite-species-1.trig
├── wikipathways-complexes-20170510-1.trig
├── wikipathways-interactions-20170510-1.trig
└── wikipathways-pathwayParticipation-20170510-1.trig
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Tests and update docs
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 |
7 | tests:
8 | runs-on: ubuntu-latest
9 | strategy:
10 | matrix:
11 | python-version: [3.7, 3.8, 3.9, '3.10']
12 | rdflib-version:
13 | - rdflib==6.0.2
14 | - rdflib>6.0.2,<7.0.0
15 |
16 | steps:
17 | - uses: actions/checkout@v3
18 |
19 | - name: Set up Python ${{ matrix.python-version }}
20 | uses: actions/setup-python@v4
21 | with:
22 | python-version: ${{ matrix.python-version }}
23 |
24 | - name: Install dependencies with ${{ matrix.rdflib-version }}
25 | env:
26 | RDFLIB_VERSION: ${{ matrix.rdflib-version }}
27 | run: |
28 | pip install ".[test,dev]" "$RDFLIB_VERSION"
29 |
30 | - name: Lint with flake8, isort and mypy
31 | run: bash scripts/lint.sh
32 |
33 | - name: Setup nanopub profile (including RSA keys)
34 | run: |
35 | np setup --orcid-id https://orcid.org/0000-0000-0000-0000 --no-publish --name test --newkeys
36 |
37 | - name: Test with pytest
38 | run: |
39 | pytest --cov
40 |
41 | - name: Publish coverage to Coveralls
42 | env:
43 | COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
44 | if: ${{ env.COVERALLS_REPO_TOKEN }}
45 | run: |
46 | coverage xml
47 | coveralls
48 |
49 |
50 | build-docs:
51 | needs: [ tests ]
52 | runs-on: ubuntu-latest
53 |
54 | steps:
55 | - uses: actions/checkout@v3
56 |
57 | - name: Set up Python
58 | uses: actions/setup-python@v4
59 | with:
60 | python-version: 3.9
61 |
62 | - name: Install dependencies
63 | run: |
64 | pip install ".[doc]"
65 |
66 | - name: Deploy mkdocs on GitHub Pages
67 | env:
68 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
69 | run: |
70 | git pull
71 | mkdocs gh-deploy
72 |
--------------------------------------------------------------------------------
/.github/workflows/cffconvert.yml:
--------------------------------------------------------------------------------
1 | name: Validate CITATION.cff
2 |
3 | on:
4 | push:
5 | paths:
6 | - CITATION.cff
7 |
8 | jobs:
9 | validate:
10 | name: "validate"
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: Check out a copy of the repository
14 | uses: actions/checkout@v3
15 |
16 | - name: Check whether the citation metadata from CITATION.cff is valid
17 | uses: citation-file-format/cffconvert-github-action@2.0.0
18 | with:
19 | args: "--validate"
20 |
--------------------------------------------------------------------------------
/.github/workflows/pypi.yml:
--------------------------------------------------------------------------------
1 | name: Publish to PyPI
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | jobs:
8 | publish:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@v3
12 |
13 | - name: Set up Python
14 | uses: actions/setup-python@v4
15 | with:
16 | python-version: "3.7"
17 |
18 | - name: Install build dependencies
19 | run: pip install build
20 |
21 | - name: Build distribution
22 | run: python -m build
23 |
24 | - name: Publish
25 | uses: pypa/gh-action-pypi-publish@release/v1
26 | with:
27 | password: ${{ secrets.PYPI_TOKEN }}
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Signed nanopubs files in tests
2 | tests/testsuite/**/signed.*.*
3 |
4 | # Byte-compiled / optimized / DLL files
5 | __pycache__/
6 | *.py[cod]
7 | *$py.class
8 |
9 | lib/
10 |
11 | # C extensions
12 | *.so
13 |
14 | # Distribution / packaging
15 | .Python
16 | build/
17 | develop-eggs/
18 | dist/
19 | downloads/
20 | eggs/
21 | .eggs/
22 | lib64/
23 | parts/
24 | sdist/
25 | var/
26 | wheels/
27 | pip-wheel-metadata/
28 | share/python-wheels/
29 | *.egg-info/
30 | .installed.cfg
31 | *.egg
32 | MANIFEST
33 |
34 | # PyInstaller
35 | # Usually these files are written by a python script from a template
36 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
37 | *.manifest
38 | *.spec
39 |
40 | # Installer logs
41 | pip-log.txt
42 | pip-delete-this-directory.txt
43 |
44 | # Unit test / coverage reports
45 | htmlcov/
46 | .tox/
47 | .nox/
48 | .coverage
49 | .coverage.*
50 | .cache
51 | nosetests.xml
52 | coverage.xml
53 | *.cover
54 | *.py,cover
55 | .hypothesis/
56 | .pytest_cache/
57 |
58 | # Translations
59 | *.mo
60 | *.pot
61 |
62 | # Django stuff:
63 | *.log
64 | local_settings.py
65 | db.sqlite3
66 | db.sqlite3-journal
67 |
68 | # Flask stuff:
69 | instance/
70 | .webassets-cache
71 |
72 | # Scrapy stuff:
73 | .scrapy
74 |
75 | # Sphinx documentation
76 | docs/_build/
77 |
78 | # PyBuilder
79 | target/
80 |
81 | # Jupyter Notebook
82 | .ipynb_checkpoints
83 |
84 | # IPython
85 | profile_default/
86 | ipython_config.py
87 |
88 | # pyenv
89 | .python-version
90 |
91 | # pipenv
92 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
93 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
94 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
95 | # install all needed dependencies.
96 | #Pipfile.lock
97 |
98 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
99 | __pypackages__/
100 |
101 | # Celery stuff
102 | celerybeat-schedule
103 | celerybeat.pid
104 |
105 | # SageMath parsed files
106 | *.sage.py
107 |
108 | # Environments
109 | .env
110 | .venv
111 | env/
112 | venv/
113 | ENV/
114 | env.bak/
115 | venv.bak/
116 |
117 | # Spyder project settings
118 | .spyderproject
119 | .spyproject
120 |
121 | # Rope project settings
122 | .ropeproject
123 |
124 | # mkdocs documentation
125 | /site
126 |
127 | # mypy
128 | .mypy_cache/
129 | .dmypy.json
130 | dmypy.json
131 |
132 | # Pyre type checker
133 | .pyre/
134 |
135 | # ide
136 | .idea
137 | .eclipse
138 | .vscode
139 |
140 | # Vim
141 | *.swp
142 |
143 | # Eclipse
144 | *.project
145 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | # See https://pre-commit.com for more information
2 | # See https://pre-commit.com/hooks.html for more hooks
3 | repos:
4 | - repo: https://github.com/pre-commit/pre-commit-hooks
5 | rev: v4.3.0
6 | hooks:
7 | - id: check-added-large-files
8 | name: 🐘 Check for added large files
9 | - id: check-toml
10 | name: ✔️ Check TOML
11 | - id: check-yaml
12 | name: ✔️ Check YAML
13 | args:
14 | - --unsafe
15 | - id: end-of-file-fixer
16 | name: 🪚 Fix end of files
17 | - id: trailing-whitespace
18 | name: ✂️ Trim trailing whitespaces
19 | # - repo: https://github.com/asottile/pyupgrade
20 | # rev: v2.37.3
21 | # hooks:
22 | # - id: pyupgrade
23 | # name: ⏫ Running pyupgrade
24 | # args:
25 | # - --py3-plus
26 | # - --keep-runtime-typing
27 | # - repo: https://github.com/myint/autoflake
28 | # rev: v1.5.3
29 | # hooks:
30 | # - id: autoflake
31 | # name: ❄️ Running autoflake
32 | # args:
33 | # - --recursive
34 | # - --in-place
35 | # - --remove-all-unused-imports
36 | # - --remove-unused-variables
37 | # - --expand-star-imports
38 | # - --exclude
39 | # - __init__.py
40 | # - --remove-duplicate-keys
41 | # - repo: https://github.com/pycqa/isort
42 | # rev: 5.10.1
43 | # hooks:
44 | # - id: isort
45 | # name: 🔄 Formatting imports with isort (python)
46 | ci:
47 | autofix_commit_msg: 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks
48 | autoupdate_commit_msg: ⬆ [pre-commit.ci] pre-commit autoupdate
49 |
--------------------------------------------------------------------------------
/.zenodo.json:
--------------------------------------------------------------------------------
1 | {
2 | "creators": [
3 | {
4 | "affiliation": "Netherlands eScience Center",
5 | "name": "van der Burg, Sven"
6 | },
7 | {
8 | "affiliation": "Netherlands eScience Center",
9 | "name": "Richardson, Robin"
10 | },
11 | {
12 | "affiliation": "Netherlands eScience Center",
13 | "name": "Smits, Djura"
14 | },
15 | {
16 | "affiliation": "Maastricht University",
17 | "name": "Emonet, Vincent"
18 | }
19 | ],
20 | "description": "The nanopub python library provides a client for searching, publishing and modifying nanopublications.",
21 | "keywords": [
22 | "semantic",
23 | "RDF",
24 | "FAIR",
25 | "nanopublications"
26 | ],
27 | "license": {
28 | "id": "Apache-2.0"
29 | },
30 | "title": "nanopub: A python library for searching, publishing and modifying nanopublications"
31 | }
32 |
--------------------------------------------------------------------------------
/CITATION.cff:
--------------------------------------------------------------------------------
1 | # YAML 1.2
2 | ---
3 | abstract: "The nanopub python library provides a client for searching, publishing and modifying nanopublications."
4 |
5 | authors:
6 | -
7 | affiliation: "Netherlands eScience Center"
8 | family-names: Burg
9 | given-names: Sven
10 | name-particle: "van der"
11 | -
12 | affiliation: "Netherlands eScience Center"
13 | family-names: Richardson
14 | given-names: Robin
15 | orcid: "https://orcid.org/0000-0002-9984-2720"
16 | -
17 | affiliation: "Netherlands eScience Center"
18 | family-names: Smits
19 | given-names: Djura
20 | -
21 | affiliation: "Maastricht University"
22 | family-names: Emonet
23 | given-names: Vincent
24 | orcid: "https://orcid.org/0000-0002-1501-1082"
25 | cff-version: "1.0.3"
26 | keywords:
27 | - "semantic"
28 | - "RDF"
29 | - "FAIR"
30 | - "nanopublications"
31 | license: "Apache-2.0"
32 | message: "If you use this software, please cite it using these metadata."
33 | title: "nanopub: A python library for searching, publishing and modifying nanopublications"
34 | version: "2.0.0"
35 | date-released: "2022-12-15"
36 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, gender identity and expression, level of experience,
9 | education, socio-economic status, nationality, personal appearance, race,
10 | religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at r.richardson@esciencecenter.nl. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing guidelines
2 |
3 | We welcome any kind of contribution to our software, from simple comment or question to a full fledged [pull request](https://help.github.com/articles/about-pull-requests/). Please read and follow our [Code of Conduct](CODE_OF_CONDUCT.md).
4 |
5 | A contribution can be one of the following cases:
6 |
7 | 1. you have a question;
8 | 1. you think you may have found a bug (including unexpected behavior);
9 | 1. you want to make some kind of change to the code base (e.g. to fix a bug, to add a new feature, to update documentation).
10 |
11 | The sections below outline the steps in each case.
12 |
13 | ## You have a question
14 |
15 | 1. use the search functionality [here](https://github.com/fair-workflows/nanopub/issues) to see if someone already filed the same issue;
16 | 1. if your issue search did not yield any relevant results, make a new issue;
17 | 1. apply the "Question" label; apply other labels when relevant.
18 |
19 | ## You think you may have found a bug
20 |
21 | 1. use the search functionality [here](https://github.com/fair-workflows/nanopub/issues) to see if someone already filed the same issue;
22 | 1. if your issue search did not yield any relevant results, make a new issue, making sure to provide enough information to the rest of the community to understand the cause and context of the problem. Depending on the issue, you may want to include:
23 | - the [SHA hashcode](https://help.github.com/articles/autolinked-references-and-urls/#commit-shas) of the commit that is causing your problem;
24 | - some identifying information (name and version number) for dependencies you're using;
25 | - information about the operating system;
26 | 1. apply relevant labels to the newly created issue.
27 |
28 | ## You want to make some kind of change to the code base
29 |
30 | 1. (**important**) announce your plan to the rest of the community _before you start working_. This announcement should be in the form of a (new) issue;
31 | 1. (**important**) wait until some kind of consensus is reached about your idea being a good idea;
32 | 1. if needed, fork the repository to your own Github profile and create your own feature branch off of the latest master commit. While working on your feature branch, make sure to stay up to date with the master branch by pulling in changes, possibly from the 'upstream' repository (follow the instructions [here](https://help.github.com/articles/configuring-a-remote-for-a-fork/) and [here](https://help.github.com/articles/syncing-a-fork/));
33 | 1. visit the **[development page](https://nanopublication.github.io/nanopub-py/getting-started/development/)** on the documentation website for more details on the development workflow.
34 |
35 | 1. make sure the existing tests still work by running ``pytest``. Note that any pull requests to the nanopub repository on github will automatically trigger running of the test suite;
36 | 1. check that the code is in accordance with the PEP8 style guide (cf. [development page](https://nanopublication.github.io/nanopub-py/getting-started/development/) to run the lint script with `flake8` and `mypy`)
37 | 1. add your own tests (if necessary);
38 | 1. update or expand the documentation;
39 | 1. [push](http://rogerdudler.github.io/git-guide/) your feature branch to (your fork of) the nanopub repository on GitHub;
40 | 1. create the pull request, e.g. following the instructions [here](https://help.github.com/articles/creating-a-pull-request/).
41 |
42 | In case you feel like you've made a valuable contribution, but you don't know how to write or run tests for it, or how to generate the documentation: don't let this discourage you from making the pull request; we can help you! Just go ahead and submit the pull request, but keep in mind that you might be asked to append additional commits to your pull request.
43 |
--------------------------------------------------------------------------------
/docs/assets/FAIR_data_principles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nanopublication/nanopub-py/9482610f7463ca0b8e27fe6ea47fb3f4c185bf41/docs/assets/FAIR_data_principles.png
--------------------------------------------------------------------------------
/docs/assets/custom.css:
--------------------------------------------------------------------------------
1 |
2 | code.highlight {
3 | font-size: 18px;
4 | }
5 |
--------------------------------------------------------------------------------
/docs/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nanopublication/nanopub-py/9482610f7463ca0b8e27fe6ea47fb3f4c185bf41/docs/assets/icon.png
--------------------------------------------------------------------------------
/docs/assets/nanopub.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nanopublication/nanopub-py/9482610f7463ca0b8e27fe6ea47fb3f4c185bf41/docs/assets/nanopub.png
--------------------------------------------------------------------------------
/docs/getting-started/setup.md:
--------------------------------------------------------------------------------
1 | # Setup instructions
2 |
3 | ## 📥️ Install the nanopub library
4 | Install using pip:
5 | ```
6 | pip install nanopub
7 | ```
8 |
9 | ## 🐍 Setup for users new to python
10 | We recommend using [anaconda](https://www.anaconda.com/products/individual) to install python and manage python dependencies
11 |
12 | ## 👤 Setup your profile
13 |
14 | To publish to the nanopub server you need to setup your profile (note that you can use fetch and search functionality without a profile). This allows the nanopub server to identify you.
15 |
16 | To check if your profile is properly set, run the following command in your terminal:
17 |
18 | ```bash
19 | np profile
20 | ```
21 |
22 | To setup your profile, run the following interactive command:
23 |
24 | ```bash
25 | np setup
26 | ```
27 |
28 | This will setup the following:
29 |
30 | ### Stored profile
31 | A local version of the profile will be stored in the nanopub user config dir (by default `HOMEDIR/.nanopub/profile.yml`)
32 |
33 | ### RSA keys
34 | It will add and store RSA keys to sign your nanopublications. By default they are stored under `HOMEDIR/.nanopub/id_rsa` and `HOMEDIR/.nanopub/id_rsa.pub`.
35 |
36 | ### ORCID iD
37 | This includes your [ORCID iD](https://orcid.org/) (i.e. https://orcid.org/0000-0000-0000-0000).
38 |
39 | If you don't have an ORCID iD yet, you need to [register](https://orcid.org/register). We use the ORCID iD to automatically add as author to the provenance of any nanopublication you will publish using this library.
40 |
41 | ### Introductory nanopublication
42 | We encourage you to make use of `np setup`'s option 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. Here is an [example introductory nanopublicaiton](http://purl.org/np/RAy1CYBfBYFd_TFI8Z_jr3taf6fB9u-grqsKyLzTmMvQI). The link to this nanopublication is also stored in your profile.
43 |
44 | ## ☑️ Check your profile
45 |
46 | You can check the profile currently used by default by running this command in your terminal:
47 |
48 | ```bash
49 | np profile
50 | ```
51 |
--------------------------------------------------------------------------------
/docs/getting-started/test-server.md:
--------------------------------------------------------------------------------
1 | # The nanopub test server
2 | Throughout this documentation we make use of the
3 | [nanopub test server](https://np.test.knowledgepixels.com/)
4 | by setting `use_test_server=True` when instantiating `NanopubConf` or `NanopubClient`:
5 | ```python
6 | from nanopub import NanopubClient, NanopubConf
7 |
8 | client = NanopubClient(use_test_server=True)
9 | np_conf = NanopubConf(use_test_server=True)
10 | ```
11 | This will search and fetch from, and publish to the [nanopub test server](https://np.test.knowledgepixels.com/).
12 |
13 | When learning about nanopub using the testserver is a good idea, because:
14 | * You are free to experiment with publishing without polluting the production server.
15 | * You can draft a publication and know exactly what it will look like on the nanopub server without polluting the production server.
16 | * When searching (and to a lesser extent fetching) you are not putting an unnecessary load on the production server.
17 |
18 | ## Test purl URIs do not point to the test server
19 | There is one caveat when using the test server that can be confusing:
20 | The purl URI (for example: [http://purl.org/np/RA71u9tYPd7ZQifE_6hXjqVim6pkweuvjoi-8ehvLvzg8](http://server.nanopubs.lod.labs.vu.nl/RA71u9tYPd7ZQifE_6hXjqVim6pkweuvjoi-8ehvLvzg8))
21 | points to the [nanopub production server](http://server.nanopubs.lod.labs.vu.nl/)
22 | resulting in a 404 page not found error.
23 |
24 | A manual workaround is:
25 | 1. Open [http://purl.org/np/RA71u9tYPd7ZQifE_6hXjqVim6pkweuvjoi-8ehvLvzg8](http://purl.org/np/RA71u9tYPd7ZQifE_6hXjqVim6pkweuvjoi-8ehvLvzg8)
26 | in your browser
27 | 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).
28 | 3. Replace 'server' with 'test-server': [https://np.test.knowledgepixels.com/RA71u9tYPd7ZQifE_6hXjqVim6pkweuvjoi-8ehvLvzg8](https://np.test.knowledgepixels.com/RA71u9tYPd7ZQifE_6hXjqVim6pkweuvjoi-8ehvLvzg8).
29 |
30 | > **NB**: `NanopubClient.fetch()` does this for you if `use_test_server=True`.
31 |
--------------------------------------------------------------------------------
/docs/getting-started/use-the-cli.md:
--------------------------------------------------------------------------------
1 | # Use the command line interface
2 |
3 | Once installed, you can use the `nanopub` library through the `np` command line interface to sign and publish Nanopublication.
4 |
5 | ## 👤 Check the current user profile
6 |
7 | ```bash
8 | np profile
9 | ```
10 |
11 | ## ✍️ Set your user profile
12 |
13 | See the [setup instructions](/nanopub/getting-started/setup) page for more details about setting up your profile.
14 |
15 | ```bash
16 | np setup
17 | ```
18 |
19 | ## ✒️ Sign nanopubs
20 |
21 | Sign a nanopublication from a file, this will generate the signed nanopub in a new file `signed.nanopub.trig` alongside the original:
22 |
23 | ```bash
24 | np sign nanopub.trig
25 | ```
26 |
27 | ## 📬️ Publish nanopubs
28 |
29 | Publish a nanopublication from a signed file:
30 |
31 | ```bash
32 | np publish signed.nanopub.trig
33 | ```
34 |
35 | Or directly publish a nanopublication from an unsigned file:
36 |
37 | ```bash
38 | np publish nanopub.trig
39 | ```
40 |
41 | You can also publish to the test server:
42 |
43 | ```bash
44 | np publish nanopub.trig --test
45 | ```
46 |
47 | ## ☑️ Check signed nanopubs
48 |
49 | Check if a signed nanopublication is valid:
50 |
51 | ```bash
52 | np check signed.nanopub.trig
53 | ```
54 |
55 | ## ℹ️ Get help
56 |
57 | Display the help for the different commands with the `--help` flag.
58 |
59 | ```bash
60 | np --help
61 | np sign --help
62 | ```
63 |
--------------------------------------------------------------------------------
/docs/getting-started/what-are-nanopubs.md:
--------------------------------------------------------------------------------
1 | # What are nanopublications?
2 | Nanopublications are a formalized and machine-readable way of communicating the smallest possible units of publishable information. This could be, for example, the outcome of a scientific study or a claim
3 | made by a particular scientist.
4 |
5 | Nanopublications are searchable, citable, and contain authorship and attribution information. The aim is to encourage individual scientific results to be released in a traceable and interoperable format. As such, nanopublications are an effective [FAIR](https://www.go-fair.org/fair-principles/) means of communicating scientific claims and results.
6 |
7 | Read more about nanopublications at **[nanopub.org](https://nanopub.org)**.
8 |
9 | ## Different elements of a nanopublication
10 | _From [nanopub.org](http://nanopub.org/wordpress/?page_id=65) documentation (2020/12/02)_
11 |
12 | 
13 |
14 | As can be seen in this image, a nanopublication has three basic elements:
15 |
16 | 1. Assertion: The assertion is the main content of a nanopublication in the form of an small atomic unit of information
17 | 2. Provenance: This part describes how the assertion above came to be. This can include the scientific methods that were used to generate the assertion, for example a reference to the kind of study that was performed and its parameters.
18 | 3. Publication Info: This part contains metadata about the nanopublication as a whole, such as when and by whom it was created and the license terms for its reuse.
19 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 |
2 | # Welcome to nanopub's documentation!
3 |
4 | The `nanopub` library provides a high-level, user-friendly python interface for searching, publishing and retracting nanopublications.
5 |
6 | Nanopublications are a formalized and machine-readable way of communicating the smallest possible units of publishable information. See the [What are Nanopublications?](getting-started/what-are-nanopubs) page for more information.
7 |
8 | ## 📦️ Setup
9 |
10 | Install using pip:
11 |
12 | ```bash
13 | pip install nanopub
14 | ```
15 |
16 | To publish to the nanopub server you need to setup your profile, this allows the nanopub server to identify you. To check if your profile is properly set, run `np profile` in your terminal. If it is not set yet, run the following interactive command to setup your profile:
17 |
18 | ```bash
19 | np setup
20 | ```
21 |
22 | This will add and store RSA keys to sign your nanopublications, publish a nanopublication with your name and ORCID iD to declare that you are using using these RSA keys, and store your ORCID iD to automatically add as author to the provenance of any nanopublication you will publish using this library.
23 |
24 | ## ⚡️ Quick Start
25 |
26 | ### Publishing nanopublications
27 |
28 | Use `load_profile()` to load the user profile from `$HOME/.nanopub`, and `use_test_server` to point to the test server (remove it to publish to the nanopublication network)
29 |
30 | ```python
31 | import rdflib
32 | from nanopub import Nanopub, NanopubConf, load_profile
33 |
34 | # 1. Create the config
35 | np_conf = NanopubConf(
36 | profile=load_profile(),
37 | use_test_server=True,
38 | add_prov_generated_time=True,
39 | attribute_publication_to_profile=True,
40 | )
41 |
42 | # 2. Construct a desired assertion (a graph of RDF triples) using rdflib
43 | my_assertion = rdflib.Graph()
44 | my_assertion.add((
45 | rdflib.URIRef('www.example.org/timbernerslee'),
46 | rdflib.RDF.type,
47 | rdflib.FOAF.Person
48 | ))
49 |
50 | # 3. Make a Nanopub object with this assertion
51 | np = Nanopub(
52 | conf=np_conf,
53 | assertion=my_assertion
54 | )
55 |
56 | # 4. Publish the Nanopub object
57 | np.publish()
58 | print(np)
59 | ```
60 |
61 | You can also just sign the nanopub with `np.sign()`. Upon signing, or publishing, the `np` object will be automatically updated with the signed RDF and generated trusty URI.
62 |
63 | ### Searching for nanopublications
64 |
65 | ```python
66 | from nanopub import NanopubClient
67 |
68 | # Create the client
69 | client = NanopubClient()
70 |
71 | # Search for all nanopublications containing the text 'fair'
72 | results = client.find_nanopubs_with_text('fair')
73 | for result in results:
74 | print(result)
75 | ```
76 |
77 | ### Fetching nanopublications and inspecting them
78 |
79 | ```python
80 | from nanopub import NanopubClient
81 |
82 | # Create the client
83 | client = NanopubClient()
84 |
85 | # Fetch the nanopublication at the specified URI
86 | np = client.fetch('http://purl.org/np/RApJG4fwj0szOMBMiYGmYvd5MCtRle6VbwkMJUb1SxxDM')
87 | print(np)
88 |
89 | # Iterate through all triples in the assertion graph
90 | for s, p, o in np.assertion:
91 | print(s, p, o)
92 | ```
93 |
--------------------------------------------------------------------------------
/docs/publishing/profile.md:
--------------------------------------------------------------------------------
1 | # Set the user profile
2 |
3 | !!! info "Prerequisite for publishing"
4 |
5 | Before you can sign and publish you should [setup your profile](/nanopub/getting-started/setup), check if it is properly set by running `np profile` in your terminal.
6 |
7 | ## 👤 Use the default user profile
8 |
9 | If you have setup a profile on your machine following the [setup instructions](/nanopub/getting-started/setup), you can easily load the default profile (defined in `$HOME/.nanopub/profile.yml`):
10 |
11 | ```python
12 | from nanopub import load_profile
13 |
14 | p = load_profile()
15 | ```
16 |
17 | ## ✍️ Define the user profile
18 |
19 | Otherwise, if you wish to have flexibility when defining the user profile, there are multiple options:
20 |
21 | ### Load a profile file
22 |
23 | Provide a specific path to a `profile.yml` file when using the `load_profile()` function:
24 |
25 | ```python
26 | from nanopub import load_profile
27 |
28 | p = load_profile(Path('/path/to/profile.yml'))
29 | ```
30 |
31 | ### Provide the keys filepaths
32 |
33 | If you need to switch between multiple keys it can be convenient to be able to define the profile directly in your code, you can do so with the `Profile` class:
34 |
35 | ```python
36 | from pathlib import Path
37 | from nanopub import Profile
38 |
39 | p1 = Profile(
40 | name='Your Name',
41 | orcid_id='https://orcid.org/0000-0000-0000-0000',
42 | private_key=Path.home() / "id_rsa",
43 | public_key=Path.home() / "id_rsa.pub"
44 | )
45 | ```
46 |
47 | ### Provide the keys as strings
48 |
49 | If you need to switch between multiple keys you can also provide the private and public keys as string, without needing to store them in files:
50 |
51 | ```python
52 | from nanopub import Profile
53 |
54 | p = Profile(
55 | name='Your Name',
56 | orcid_id='https://orcid.org/0000-0000-0000-0000',
57 | private_key="YOUR_PRIVATE_KEY",
58 | public_key="YOUR_PUBLIC_KEY"
59 | )
60 | ```
61 |
62 | ### Generate new keys for your nanopub profile
63 |
64 | If you do not provide private and public keys a new key pair will be automatically generated. You can then store it where you want.
65 |
66 | ```python
67 | from nanopub import Profile
68 |
69 | p = Profile(
70 | name='Your Name',
71 | orcid_id='https://orcid.org/0000-0000-0000-0000',
72 | )
73 | # By default the profile and keys will be stored in $HOME/.nanopub
74 | p.store()
75 | ```
76 |
--------------------------------------------------------------------------------
/docs/publishing/retraction.md:
--------------------------------------------------------------------------------
1 | # Retracting a nanopublication
2 | A nanopublication is persistent, you can never edit nor delete it. You can however retract a nanopublication. This is done by publishing a new nanopublication that states that you retract the original publication. You can use `NanopubClient.retract()`:
3 | ```python
4 | from nanopub import NanopubConf, NanopubRetract
5 |
6 | np_conf = NanopubConf(profile=load_profile(), use_test_server=True)
7 |
8 | np = NanopubRetract(
9 | 'http://purl.org/np/RAfk_zBYDerxd6ipfv8fAcQHEzgZcVylMTEkiLlMzsgwQ',
10 | np_conf,
11 | )
12 | np.publish()
13 | ```
14 | View the full retraction nanopublication [here](http://purl.org/np/RAv75Xhhz5jv--Nnu9RDqIGy2xHr74REGC4vtOSxrwX4c).
15 |
16 | The assertion states that the researcher (denoted by the ORCID iD from your profile) retracts the provided nanopublication:
17 | ```turtle
18 | @prefix npx: .
19 | @prefix sub: .
20 |
21 | sub:assertion {
22 | npx:retracts .
23 | }
24 | ```
25 | By default nanopublications that have a valid retraction do not show up in search results. A valid retraction is a retraction that is signed with the same public key as the nanopublication that it retracts.
26 |
27 | ## Retracting a nanopublication that is not yours
28 | By default we do not retract nanopublications that are not yours (i.e. signed with another public key). If you try to do this it will trigger an AssertionError.
29 |
30 | We can use `force=True` to override this behavior:
31 | ```python
32 | np = NanopubRetract(
33 | 'http://purl.org/np/RAfk_zBYDerxd6ipfv8fAcQHEzgZcVylMTEkiLlMzsgwQ',
34 | np_conf,
35 | force=True
36 | )
37 | ```
38 |
39 | ## Find retractions of a given nanopublication
40 | You can find out whether a given publication is retracted and what the nanopublications are that retract it using `NanopubClient.find_retractions_of`:
41 | ```python
42 | from nanopub import NanopubClient
43 | client = NanopubClient(use_test_server=True)
44 | # This URI has 1 retraction:
45 | client.find_retractions_of('http://purl.org/np/RAirauh-vy5f7UJEMTm08C5bh5pnWD-abb-qk3fPYWCzc')
46 | ['http://purl.org/np/RADjlGIB8Vqt7NbG1kqzw-4aIV_k7nyIRirMhPKEYVSlc']
47 | # This URI has no retractions
48 | client.find_retractions_of('http://purl.org/np/RAeMfoa6I05zoUmK6sRypCIy3wIpTgS8gkum7vdfOamn8')
49 | []
50 | ```
51 |
--------------------------------------------------------------------------------
/docs/reference/client.md:
--------------------------------------------------------------------------------
1 | # NanopubClient
2 |
3 | ::: nanopub.NanopubClient
4 |
--------------------------------------------------------------------------------
/docs/reference/client.rst:
--------------------------------------------------------------------------------
1 | nanopub.client
2 | ==============
3 | .. automodule:: nanopub.client
4 | :members:
5 |
--------------------------------------------------------------------------------
/docs/reference/config.md:
--------------------------------------------------------------------------------
1 | # NanopubConf
2 |
3 | ::: nanopub.NanopubConf
4 |
--------------------------------------------------------------------------------
/docs/reference/namespaces.md:
--------------------------------------------------------------------------------
1 | # Namespaces
2 |
3 | ::: nanopub.namespaces
4 |
--------------------------------------------------------------------------------
/docs/reference/namespaces.rst:
--------------------------------------------------------------------------------
1 | nanopub.namespaces
2 | ==================
3 |
4 | .. automodule:: nanopub.namespaces
5 | :members:
6 |
--------------------------------------------------------------------------------
/docs/reference/nanopub.md:
--------------------------------------------------------------------------------
1 | # Nanopub
2 |
3 | ::: nanopub.Nanopub
4 |
--------------------------------------------------------------------------------
/docs/reference/profile.md:
--------------------------------------------------------------------------------
1 | # Profile
2 |
3 | ::: nanopub.profile
4 |
--------------------------------------------------------------------------------
/docs/reference/publication.rst:
--------------------------------------------------------------------------------
1 | nanopub.publication
2 | ===================
3 |
4 | .. automodule:: nanopub.publication
5 | :members:
6 |
--------------------------------------------------------------------------------
/docs/reference/templates.md:
--------------------------------------------------------------------------------
1 | # Nanopublications templates
2 |
3 | ::: nanopub.templates.nanopub_claim
4 |
5 | ::: nanopub.templates.nanopub_retract
6 |
7 | ::: nanopub.templates.nanopub_index
8 |
9 | ::: nanopub.templates.nanopub_introduction
10 |
--------------------------------------------------------------------------------
/docs/searching/fetching.md:
--------------------------------------------------------------------------------
1 | # Fetching nanopublications
2 | ## Fetch from the default server
3 |
4 | You can fetch nanopublications from the default nanopub server using the `Nanopub` class.
5 |
6 | ```python
7 | from nanopub import Nanopub
8 |
9 | # Fetch the nanopublication at the specified URI
10 | np = Nanopub('http://purl.org/np/RApJG4fwj0szOMBMiYGmYvd5MCtRle6VbwkMJUb1SxxDM')
11 |
12 | # Print the RDF contents of the nanopublication
13 | print(np)
14 |
15 | # Iterate through all triples in the assertion graph
16 | for s, p, o in np.assertion:
17 | print(s, p, o)
18 |
19 | # Iterate through the publication info
20 | for s, p, o in np.pubinfo:
21 | print(s, p, o)
22 |
23 | # Iterate through the provenance graph
24 | for s, p, o in np.provenance:
25 | print(s,p,o)
26 |
27 | # See the concept that is introduced by this nanopublication (if any)
28 | print(np.introduces_concept)
29 | ```
30 |
31 | ## Fetch from a specific server
32 |
33 | You can fetch Nanopubs from the test server:
34 |
35 | ```python
36 | from nanopub import Nanopub
37 |
38 | np = Nanopub(
39 | source_uri='http://purl.org/np/RANGY8fx_EYVeZzJOinH9FoY-WrQBerKKUy2J9RCDWH6U',
40 | conf=NanopubConf(use_test_server=True)
41 | )
42 | print(np)
43 | ```
44 |
45 | Or from a specific nanopub server:
46 |
47 | ```python
48 | np = Nanopub(
49 | source_uri='http://purl.org/np/RApJG4fwj0szOMBMiYGmYvd5MCtRle6VbwkMJUb1SxxDM',
50 | conf=NanopubConf(use_server='https://np.petapico.org')
51 | )
52 | print(np)
53 | ```
54 |
--------------------------------------------------------------------------------
/docs/searching/searching.md:
--------------------------------------------------------------------------------
1 | # Searching the nanopub server
2 | The `NanopubClient` provides methods for searching the nanopub server. It provides an (incomplete) mapping to [Nanopub Query endpoints](https://query.knowledgepixels.com/).
3 |
4 | ## Text search
5 | Search for all nanopublications containing some text using `NanopubClient.find_nanopubs_with_text()`
6 | ```python
7 | from nanopub import NanopubClient
8 |
9 | client = NanopubClient()
10 | results = client.find_nanopubs_with_text('fair')
11 | ```
12 |
13 | ## Triple pattern search
14 | Search for nanopublications whose assertions contain triples that match a specific pattern.
15 | ```python
16 | from nanopub import NanopubClient
17 |
18 | client = NanopubClient()
19 | # Search for nanopublications whose assertions contain triples that are ```rdf:Statement```s.
20 | results = client.find_nanopubs_with_pattern(
21 | pred='http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
22 | obj='http://www.w3.org/1999/02/22-rdf-syntax-ns#Statement'
23 | )
24 | ```
25 |
26 | ## Search on introduced concept
27 | Search for any nanopublications that introduce a concept of the given type, that contain text with the given search term.
28 | ```python
29 | from nanopub import NanopubClient
30 |
31 | client = NanopubClient()
32 | # Search for nanopublications that introduce a concept that is a ```p-plan:Step```.
33 | results = client.find_things('http://purl.org/net/p-plan#Step')
34 | ```
35 |
36 | ## Interpreting search results
37 | Each search method returns a generator of dicts depicting matching nanopublications.
38 |
39 | Each dict has the following key-value pairs:
40 | * `date`: The date and time the nanopublication was created.
41 | * `description`: A description of the nanopublication that was parsed from the nanopublication RDF.
42 | * `np`: The URI of the matching nanopublication.
43 |
44 | Example results (from `NanopubClient.find_nanopubs_with_text('fair')`):
45 | ```python
46 | print(list(results))
47 | [{'date': '2020-05-01T08:05:25.575Z',
48 | 'description': 'The primary objective of the VODAN Implementation Network is '
49 | 'to showcase the creation and deployment of FAIR data related '
50 | 'to COVID-19',
51 | 'np': 'http://purl.org/np/RAdDKjIGPt_2mE9oJtB3YQX6wGGdCC8ZWpkxEIoHsxOjE'},
52 | {'date': '2020-05-14T09:34:53.554Z',
53 | 'description': 'FAIR IN community',
54 | 'np': 'http://purl.org/np/RAPE0A-NrIZDeX3pvFJr0uHshocfXuUj8n_J3BkY0sMuU'}]
55 | ```
56 |
57 | ## Returning retracted publications in search
58 | By default nanopublications that have a valid retraction do not show up in search results. A valid retraction is a retraction that is signed with the same public key as the nanopublication that it retracts.
59 |
60 | You can toggle this behavior with the `filter_retracted` parameter, here is an example with `NanopubClient.find_nanopubs_with_text`:
61 |
62 | ```python
63 | from nanopub import NanopubClient
64 |
65 | client = NanopubClient()
66 | # Search for nanopublications containing the text fair, also returning retracted publications.
67 | results = client.find_nanopubs_with_text('fair', filter_retracted=False)
68 | ```
69 |
70 | ## Filtering search results for a particular publication key
71 | You can filter search results to publications that are signed with a specific publication key (effectively filtering on publications from a single author).
72 |
73 | You use the `pubkey` argument for that. Here is an example with `NanopubClient.find_nanopubs_with_text`:
74 |
75 | ```python
76 | from nanopub import NanopubClient, profile
77 |
78 | # Search for nanopublications containing the text 'test',
79 | # filtering on publications signed with my publication key.
80 | client = NanopubClient(use_test_server=True)
81 | my_public_key = profile.public_key
82 | results = client.find_nanopubs_with_text('test', pubkey=my_public_key)
83 | ```
84 |
--------------------------------------------------------------------------------
/nanopub/__init__.py:
--------------------------------------------------------------------------------
1 | from ._version import __version__
2 | from .nanopub_conf import NanopubConf
3 | from .fdo_nanopub import FDONanopub
4 | from .fdo_metadata import FdoMetadata
5 | from .fdo_ops import create_fdo_nanopub_from_handle, validate_fdo_nanopub, retrieve_metadata_from_id, update_metadata
6 | from .client import NanopubClient
7 | from .profile import Profile, load_profile, generate_keyfiles
8 | from .nanopub import Nanopub
9 | from .templates.nanopub_index import NanopubIndex, create_nanopub_index
10 | from .templates.nanopub_introduction import NanopubIntroduction
11 | from .templates.nanopub_claim import NanopubClaim
12 | from .templates.nanopub_retract import NanopubRetract
13 | from .templates.nanopub_update import NanopubUpdate
14 |
--------------------------------------------------------------------------------
/nanopub/_version.py:
--------------------------------------------------------------------------------
1 | __version__ = "2.0.1"
2 |
--------------------------------------------------------------------------------
/nanopub/constants.py:
--------------------------------------------------------------------------------
1 | from rdflib import Namespace
2 |
3 | HDL = Namespace("https://hdl.handle.net/")
4 |
5 | FDO_PROFILE_HANDLE = '21.T11966/FdoProfile'
6 | FDO_DATA_REF_HANDLE = '21.T11966/06a6c27e3e2ef27779ec'
--------------------------------------------------------------------------------
/nanopub/definitions.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | from rdflib import Namespace
4 |
5 | ROOT_FILEPATH = Path(__file__).parent.parent
6 | TESTS_FILEPATH = ROOT_FILEPATH / "tests"
7 | TEST_RESOURCES_FILEPATH = TESTS_FILEPATH / "resources"
8 | USER_CONFIG_DIR = Path.home() / ".nanopub"
9 | DEFAULT_PROFILE_PATH = USER_CONFIG_DIR / "profile.yml"
10 |
11 | TEST_NANOPUB_REGISTRY_URL = 'https://test.registry.knowledgepixels.com/np/'
12 | # List of servers: https://monitor.petapico.org/.csv
13 | NANOPUB_REGISTRY_URLS = [
14 | 'https://registry.petapico.org/np/',
15 | 'https://registry.knowledgepixels.com/np/',
16 | 'https://registry.np.trustyuri.net/np/',
17 | ]
18 | NANOPUB_FETCH_FORMAT = "trig"
19 |
20 | DUMMY_NANOPUB_URI = "http://purl.org/nanopub/temp/np"
21 | DUMMY_NAMESPACE = Namespace(DUMMY_NANOPUB_URI + "/")
22 | DUMMY_URI = DUMMY_NAMESPACE[""]
23 |
24 | NP_TEMP_PREFIX = "http://purl.org/nanopub/temp/"
25 | NP_PREFIX = "https://w3id.org/np/"
26 |
27 | MAX_NP_PER_INDEX = 1100
28 | MAX_TRIPLES_PER_NANOPUB = 1200
29 |
30 | RSA_KEY_SIZE = 2048
31 |
32 | NANOPUB_QUERY_URLS = [
33 | 'https://query.knowledgepixels.com/api/',
34 | 'https://query.petapico.org/api/',
35 | 'https://query.np.trustyuri.net/api/',
36 | ]
37 | TEST_NANOPUB_QUERY_URL = 'https://query.knowledgepixels.com/api/' # we don't yet have a test server for this
38 |
--------------------------------------------------------------------------------
/nanopub/fdo_metadata.py:
--------------------------------------------------------------------------------
1 | from rdflib import Graph, URIRef, Literal
2 | from typing import Optional, Union
3 | from rdflib.namespace import RDFS
4 | from nanopub.namespaces import HDL, FDOF
5 | from nanopub.constants import FDO_PROFILE_HANDLE
6 |
7 |
8 | class FdoMetadata:
9 | """
10 | EXPERIMENTAL: This class is experimental and may change or be removed in future versions.
11 | """
12 |
13 | def __init__(self, nanopub: Optional[Graph] = None):
14 | self.id: Optional[str] = None
15 | self.tuples: dict[URIRef, Union[Literal, URIRef]] = {}
16 |
17 | if nanopub:
18 | for s, p, o in nanopub:
19 | if p == FDOF.hasFdoProfile and self.id is None:
20 | self.id = self.extract_handle(s)
21 | self.tuples[p] = o
22 |
23 | if self.id is None:
24 | raise ValueError("Missing required FDO profile statement")
25 |
26 | def extract_handle(self, subject: URIRef) -> str:
27 | return str(subject).split("/")[-1]
28 |
29 | def get_statements(self) -> list[tuple[URIRef, URIRef, Union[Literal, URIRef]]]:
30 | """
31 | Returns the metadata as a list of RDF triples.
32 | """
33 | if not self.id:
34 | raise ValueError("FDO ID is not set")
35 | subject = URIRef(f"https://hdl.handle.net/{self.id}")
36 | return [(subject, p, o) for p, o in self.tuples.items()]
37 |
38 | def get_graph(self) -> Graph:
39 | """
40 | Returns the metadata as an rdflib.Graph.
41 | """
42 | g = Graph()
43 | for s, p, o in self.get_statements():
44 | g.add((s, p, o))
45 | return g
46 |
47 | def get_profile(self) -> Optional[URIRef]:
48 | val = self.tuples.get(FDOF.hasFdoProfile)
49 | return URIRef(val) if val else None
50 |
51 | def get_label(self) -> Optional[str]:
52 | val = self.tuples.get(RDFS.label)
53 | return str(val) if val else None
54 |
55 | def get_id(self) -> Optional[str]:
56 | return self.id
57 |
58 | def set_id(self, handle: str) -> None:
59 | self.id = handle
60 |
61 | def set_label(self, label: str) -> None:
62 | self.tuples[RDFS.label] = Literal(label)
63 |
64 | def set_profile(self, uri: Union[str, URIRef]) -> None:
65 | self.tuples[FDOF.hasFdoProfile] = URIRef(uri)
66 |
67 | def set_property(self, predicate: Union[str, URIRef], value: Union[str, URIRef, Literal]) -> None:
68 | pred = URIRef(predicate)
69 | obj = URIRef(value) if isinstance(value, str) and value.startswith("http") else Literal(value)
70 | self.tuples[pred] = obj
71 |
72 | def copy(self) -> "FdoMetadata":
73 | new_md = FdoMetadata()
74 | new_md.id = self.id
75 | new_md.tuples = self.tuples.copy()
76 | return new_md
77 |
--------------------------------------------------------------------------------
/nanopub/fdo_nanopub.py:
--------------------------------------------------------------------------------
1 | from .nanopub import Nanopub
2 | import rdflib
3 | from rdflib.namespace import RDF, RDFS, XSD
4 | from nanopub.namespaces import HDL, FDOF, NPX
5 | from nanopub.constants import FDO_PROFILE_HANDLE, FDO_DATA_REF_HANDLE
6 |
7 | def to_hdl_uri(value):
8 | if isinstance(value, rdflib.URIRef):
9 | return value
10 | elif isinstance(value, str) and not value.startswith('http'):
11 | return HDL[value]
12 | else:
13 | raise ValueError(f"Invalid value: {value}")
14 |
15 | class FDONanopub(Nanopub):
16 | """
17 | EXPERIMENTAL: This class is experimental and may change or be removed in future versions.
18 | """
19 |
20 | def __init__(self, fdo_id: rdflib.URIRef | str, label: str, fdo_profile: str = None, *args, **kwargs):
21 | super().__init__(*args, **kwargs)
22 | self.fdo_uri = to_hdl_uri(fdo_id)
23 | self.fdo_profile = fdo_profile
24 | self._init_core_fdo_triples(label)
25 |
26 | def _init_core_fdo_triples(self, label: str):
27 | self.assertion.add((self.fdo_uri, RDF.type, FDOF.FAIRDigitalObject))
28 | self.assertion.add((self.fdo_uri, RDFS.label, rdflib.Literal(label)))
29 | self.assertion.add((self.fdo_uri, FDOF.hasMetadata, self.metadata.np_uri))
30 | if self.fdo_profile:
31 | profile_uri = to_hdl_uri(self.fdo_profile)
32 | self.assertion.add((self.fdo_uri, FDOF.hasFdoProfile, profile_uri))
33 |
34 | self.pubinfo.add((self.metadata.np_uri, RDFS.label, rdflib.Literal(f"FAIR Digital Object: {label}")))
35 | self.pubinfo.add((self.metadata.np_uri, NPX.introduces, self.fdo_uri))
36 |
37 | def add_fdo_profile(self, profile_uri: rdflib.URIRef):
38 | profile_uri = to_hdl_uri(profile_uri)
39 | self.assertion.add((self.fdo_uri, FDOF.hasFdoProfile, rdflib.Literal(profile_uri)))
40 | self.pubinfo.add((HDL[FDO_PROFILE_HANDLE], RDFS.label, rdflib.Literal("FdoProfile")))
41 |
42 | def add_fdo_data_ref(self, data_ref: rdflib.Literal):
43 | target_uri = to_hdl_uri(data_ref)
44 | self.assertion.add((self.fdo_uri, FDOF.isMaterializedBy, target_uri))
45 | self.pubinfo.add((HDL[FDO_DATA_REF_HANDLE], RDFS.label, rdflib.Literal("DataRef")))
46 |
47 | def add_attribute(self, attr_HANDLE: rdflib.URIRef, value: rdflib.Literal):
48 | attr_HANDLE = to_hdl_uri(attr_HANDLE)
49 | self.assertion.add((self.fdo_uri, attr_HANDLE, rdflib.Literal(value)))
50 |
51 | def add_attribute_label(self, attr_HANDLE: rdflib.URIRef, label: str):
52 | attr_HANDLE = to_hdl_uri(attr_HANDLE)
53 | self.pubinfo.add((attr_HANDLE, RDFS.label, rdflib.Literal(label)))
54 |
55 |
--------------------------------------------------------------------------------
/nanopub/namespaces.py:
--------------------------------------------------------------------------------
1 | """
2 | This module holds handy namespaces that are often used in nanopublications.
3 | """
4 | from rdflib import Namespace
5 |
6 | NP = Namespace("http://www.nanopub.org/nschema#")
7 | """Nanopub namespace"""
8 |
9 | NPX = Namespace("http://purl.org/nanopub/x/")
10 | """Nanopub/x namespace"""
11 |
12 | NTEMPLATE = Namespace("https://w3id.org/np/o/ntemplate/")
13 | """Nanopub template namespace"""
14 |
15 | PROV = Namespace("http://www.w3.org/ns/prov#")
16 | """Provenance Ontogoly (PROV-O) namespace"""
17 |
18 | HYCL = Namespace("http://purl.org/petapico/o/hycl#")
19 | """HYCL namespace for claims and hypothesis"""
20 |
21 | ORCID = Namespace("https://orcid.org/")
22 | """ORCID namespace"""
23 |
24 | PAV = Namespace("http://purl.org/pav/")
25 | """Provenance And Versioning namespace"""
26 |
27 | PMID = Namespace("http://www.ncbi.nlm.nih.gov/pubmed/")
28 | """PubMed namespace"""
29 |
30 | HDL = Namespace("https://hdl.handle.net/")
31 | """Handle namespace"""
32 |
33 | FDOF = Namespace("https://w3id.org/fdof/ontology#")
34 | """FAIR Digital Object Framework namespace"""
--------------------------------------------------------------------------------
/nanopub/nanopub_conf.py:
--------------------------------------------------------------------------------
1 | from dataclasses import asdict, dataclass
2 | from typing import Optional
3 |
4 | from nanopub.definitions import NANOPUB_REGISTRY_URLS
5 | from nanopub.profile import Profile
6 |
7 |
8 | @dataclass
9 | class NanopubConf:
10 | """Represents the configuration for nanopubs.
11 |
12 | Args:
13 | profile: Profile of the user publishing the nanopub
14 | use_test_server: A boolean to automatically use the test server
15 | use_server: The URL of the server that will be used to publish the nanopub
16 | add_prov_generated_time: add generated time to provenance
17 | add_pubinfo_generated_time: add generated time to pubinfo
18 | attribute_assertion_to_profile: bool
19 | attribute_publication_to_profile: bool
20 | assertion_attributed_to: Optional str
21 | publication_attributed_to: Optional str
22 | derived_from: Optional str
23 | """
24 |
25 | profile: Optional[Profile] = None
26 |
27 | use_test_server: bool = False
28 | use_server: str = NANOPUB_REGISTRY_URLS[0]
29 |
30 | add_prov_generated_time: bool = False
31 | add_pubinfo_generated_time: bool = False
32 |
33 | attribute_assertion_to_profile: bool = False
34 | attribute_publication_to_profile: bool = False
35 |
36 | assertion_attributed_to: Optional[str] = None
37 | publication_attributed_to: Optional[str] = None
38 |
39 | derived_from: Optional[str] = None
40 |
41 |
42 | dict = asdict
43 |
--------------------------------------------------------------------------------
/nanopub/py.typed:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nanopublication/nanopub-py/9482610f7463ca0b8e27fe6ea47fb3f4c185bf41/nanopub/py.typed
--------------------------------------------------------------------------------
/nanopub/templates/__init__.py:
--------------------------------------------------------------------------------
1 | from .nanopub_claim import NanopubClaim
2 | from .nanopub_index import NanopubIndex, create_nanopub_index
3 | from .nanopub_introduction import NanopubIntroduction
4 | from .nanopub_retract import NanopubRetract
5 | from .nanopub_update import NanopubUpdate
6 |
--------------------------------------------------------------------------------
/nanopub/templates/nanopub_claim.py:
--------------------------------------------------------------------------------
1 | from copy import deepcopy
2 |
3 | from rdflib import RDF, RDFS, Literal, URIRef
4 |
5 | from nanopub.namespaces import HYCL
6 | from nanopub.nanopub import Nanopub
7 | from nanopub.nanopub_conf import NanopubConf
8 | from nanopub.profile import ProfileError
9 |
10 |
11 | class NanopubClaim(Nanopub):
12 | """Quickly claim a statement.
13 |
14 | Constructs statement triples around the provided text following the Hypotheses and Claims
15 | Ontology (http://purl.org/petapico/o/hycl).
16 |
17 | Args:
18 | conf: config for the nanopub
19 | claim (str): the text of the statement, example: 'All cats are grey'
20 | """
21 |
22 | def __init__(
23 | self,
24 | claim: str,
25 | conf: NanopubConf,
26 | ) -> None:
27 | conf = deepcopy(conf)
28 | conf.add_prov_generated_time = True
29 | conf.add_pubinfo_generated_time = True
30 | conf.attribute_publication_to_profile = True
31 | super().__init__(
32 | conf=conf,
33 | )
34 |
35 | if not self.profile:
36 | raise ProfileError("No profile provided, cannot generate a Nanopub Claim")
37 |
38 | this_statement = self._metadata.namespace.claim
39 | # this_statement = BNode("mystatement")
40 | self.assertion.add((this_statement, RDF.type, HYCL.Statement))
41 | self.assertion.add((this_statement, RDFS.label, Literal(claim)))
42 |
43 | orcid_id_uri = URIRef(self.profile.orcid_id)
44 | self.provenance.add((orcid_id_uri, HYCL.claims, this_statement))
45 |
--------------------------------------------------------------------------------
/nanopub/templates/nanopub_introduction.py:
--------------------------------------------------------------------------------
1 | from copy import deepcopy
2 | from typing import Optional
3 |
4 | from rdflib import Literal, URIRef
5 | from rdflib.namespace import FOAF
6 |
7 | from nanopub.namespaces import NPX
8 | from nanopub.nanopub import Nanopub
9 | from nanopub.nanopub_conf import NanopubConf
10 | from nanopub.profile import ProfileError
11 |
12 |
13 | class NanopubIntroduction(Nanopub):
14 | """Publish a Nanopub introduction to introduce a key pair for an ORCID
15 |
16 | Args:
17 | conf: config for the nanopub
18 | host: the service where the keypair are hosted
19 | """
20 |
21 | def __init__(
22 | self,
23 | conf: NanopubConf,
24 | host: Optional[str] = None,
25 | ) -> None:
26 | conf = deepcopy(conf)
27 | conf.add_prov_generated_time = False
28 | conf.add_pubinfo_generated_time = True
29 | conf.attribute_publication_to_profile = True
30 | conf.attribute_assertion_to_profile = True
31 | super().__init__(
32 | conf=conf,
33 | )
34 | if not self.profile:
35 | raise ProfileError("No profile provided, cannot generate a Nanopub Introduction")
36 |
37 | key_declaration = self._metadata.namespace.keyDeclaration
38 | orcid_node = URIRef(self.conf.profile.orcid_id)
39 |
40 | self.assertion.add((key_declaration, NPX.declaredBy, orcid_node))
41 | self.assertion.add((key_declaration, NPX.hasAlgorithm, Literal("RSA")))
42 | self.assertion.add((key_declaration, NPX.hasPublicKey, Literal(self.conf.profile.public_key)))
43 | self.assertion.add((orcid_node, FOAF.name, Literal(self.conf.profile.name)))
44 | if host:
45 | self.assertion.add((key_declaration, NPX.hasKeyLocation, URIRef(host)))
46 |
--------------------------------------------------------------------------------
/nanopub/templates/nanopub_retract.py:
--------------------------------------------------------------------------------
1 | from copy import deepcopy
2 |
3 | from rdflib import URIRef
4 |
5 | from nanopub.namespaces import NPX
6 | from nanopub.nanopub import Nanopub
7 | from nanopub.nanopub_conf import NanopubConf
8 | from nanopub.profile import ProfileError
9 | from nanopub.utils import MalformedNanopubError
10 |
11 |
12 | class NanopubRetract(Nanopub):
13 | """Retract a nanopublication.
14 |
15 | Publish a retraction nanpublication that declares retraction of the nanopublication that
16 | corresponds to the 'uri' argument.
17 |
18 | Args:
19 | conf: config for the nanopub
20 | uri (str): The uri pointing to the to-be-retracted nanopublication
21 | force (bool): Toggle using force to retract, this will even retract the
22 | nanopublication if it is signed with a different public key than the one
23 | in the user profile.
24 | """
25 |
26 | def __init__(
27 | self,
28 | conf: NanopubConf,
29 | uri: str,
30 | force: bool = False,
31 | ) -> None:
32 | conf = deepcopy(conf)
33 | conf.add_prov_generated_time = True
34 | conf.add_pubinfo_generated_time = True
35 | conf.attribute_publication_to_profile = True
36 | conf.attribute_assertion_to_profile = True
37 | super().__init__(
38 | conf=conf,
39 | )
40 | if not self.profile:
41 | raise ProfileError("No profile provided, cannot generate a Nanopub to retract another nanopub")
42 |
43 | if not force:
44 | self._check_public_keys_match(uri)
45 | orcid_id = self.profile.orcid_id
46 | self.assertion.add(
47 | (URIRef(orcid_id), NPX.retracts, URIRef(uri))
48 | )
49 |
50 |
51 | def _check_public_keys_match(self, uri):
52 | """Check for matching public keys of a nanopublication with the profile.
53 |
54 | Raises:
55 | AssertionError: When the nanopublication is signed with a public key that does not
56 | match the public key in the profile
57 | """
58 | np = Nanopub(
59 | uri,
60 | conf=NanopubConf(
61 | use_test_server=self._conf.use_test_server,
62 | use_server=self._conf.use_server,
63 | )
64 | )
65 | if np.metadata.public_key is None:
66 | raise MalformedNanopubError(f"Public key not found in the nanopub {np.source_uri}")
67 | if self._conf.profile.public_key is None:
68 | raise ValueError(f"Public key not found for profile {self._conf.profile.orcid_id}")
69 | if np.metadata.public_key != self._conf.profile.public_key is None:
70 | raise AssertionError(
71 | "The public key in your profile does not match the public key"
72 | "that the publication that you want to retract is signed with."
73 | )
74 |
--------------------------------------------------------------------------------
/nanopub/templates/nanopub_update.py:
--------------------------------------------------------------------------------
1 | from copy import deepcopy
2 | from pathlib import Path
3 | from typing import Union
4 |
5 | from rdflib import ConjunctiveGraph, Graph, URIRef
6 |
7 | from nanopub.namespaces import NPX
8 | from nanopub.nanopub import Nanopub
9 | from nanopub.nanopub_conf import NanopubConf
10 | from nanopub.profile import ProfileError
11 | from nanopub.utils import MalformedNanopubError
12 |
13 |
14 | # TODO: improve to better inherit from the nanopub we want to update
15 | class NanopubUpdate(Nanopub):
16 | """Update a nanopublication.
17 |
18 | Publish a retraction nanpublication that declares retraction of the nanopublication that
19 | corresponds to the 'uri' argument.
20 |
21 | Args:
22 | conf: config for the nanopub
23 | uri (str): The uri pointing to the to-be-retracted nanopublication
24 | force (bool): Toggle using force to retract, this will even retract the
25 | nanopublication if it is signed with a different public key than the one
26 | in the user profile.
27 | """
28 |
29 | def __init__(
30 | self,
31 | conf: NanopubConf,
32 | uri: str,
33 | force: bool = False,
34 | assertion: Graph = Graph(),
35 | provenance: Graph = Graph(),
36 | pubinfo: Graph = Graph(),
37 | rdf: Union[ConjunctiveGraph, Path] = None,
38 | ) -> None:
39 | conf = deepcopy(conf)
40 | conf.add_prov_generated_time = True
41 | conf.add_pubinfo_generated_time = True
42 | conf.attribute_publication_to_profile = True
43 | conf.attribute_assertion_to_profile = True
44 | super().__init__(
45 | conf=conf,
46 | assertion=assertion,
47 | provenance=provenance,
48 | pubinfo=pubinfo,
49 | rdf=rdf,
50 | )
51 | if not self.profile:
52 | raise ProfileError("No profile provided, cannot generate a Nanopub to retract another nanopub")
53 |
54 | if not force:
55 | self._check_public_keys_match(uri)
56 |
57 | self.pubinfo.add(
58 | (self._metadata.namespace[""], NPX.supersedes, URIRef(uri))
59 | )
60 |
61 |
62 | def _check_public_keys_match(self, uri):
63 | """Check for matching public keys of a nanopublication with the profile.
64 |
65 | Raises:
66 | AssertionError: When the nanopublication is signed with a public key that does not
67 | match the public key in the profile
68 | """
69 | np = Nanopub(
70 | uri,
71 | conf=NanopubConf(
72 | use_test_server=self._conf.use_test_server,
73 | use_server=self._conf.use_server,
74 | )
75 | )
76 | if np.metadata.public_key is None:
77 | raise MalformedNanopubError(f"Public key not found in the nanopub {np.source_uri}")
78 | if self._conf.profile.public_key is None:
79 | raise ValueError(f"Public key not found for profile {self._conf.profile.orcid_id}")
80 | if np.metadata.public_key != self._conf.profile.public_key is None:
81 | raise AssertionError(
82 | "The public key in your profile does not match the public key"
83 | "that the publication that you want to update is signed with."
84 | )
85 |
--------------------------------------------------------------------------------
/nanopub/trustyuri/CheckFile.py:
--------------------------------------------------------------------------------
1 | import codecs
2 | import logging
3 | import sys
4 |
5 | from nanopub.trustyuri import ModuleDirectory, TrustyUriUtils
6 | from nanopub.trustyuri.TrustyUriResource import TrustyUriResource
7 |
8 | try:
9 | from urllib2 import urlopen
10 | except Exception:
11 | from urllib.request import urlopen
12 |
13 |
14 | def check(args):
15 | filename = args[0]
16 |
17 | tail = TrustyUriUtils.get_trustyuri_tail(filename)
18 | module_id = tail[:2]
19 | module = ModuleDirectory.get_module(module_id)
20 | try:
21 | content = codecs.open(filename, 'r', 'utf-8').read()
22 | except Exception:
23 | content = urlopen(filename).read()
24 | resource = TrustyUriResource(filename, content, tail)
25 | if module.has_correct_hash(resource):
26 | print("Correct hash: " + tail)
27 | else:
28 | print("*** INCORRECT HASH ***")
29 |
30 |
31 | if __name__ == "__main__":
32 | logging.basicConfig(level=logging.ERROR)
33 | args = sys.argv
34 | args.pop(0)
35 | check(args)
36 |
--------------------------------------------------------------------------------
/nanopub/trustyuri/ModuleDirectory.py:
--------------------------------------------------------------------------------
1 | from nanopub.trustyuri.file.FileModule import FileModule
2 | from nanopub.trustyuri.rdf.RdfModule import RdfModule
3 |
4 | modules: dict = {}
5 |
6 |
7 | def add_module(module):
8 | modules[module.module_id()] = module
9 |
10 |
11 | def get_module(name):
12 | return modules[name]
13 |
14 |
15 | add_module(FileModule())
16 | add_module(RdfModule())
17 |
--------------------------------------------------------------------------------
/nanopub/trustyuri/RunBatch.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import re
3 | import sys
4 | import time
5 |
6 | from nanopub.trustyuri.file import ProcessFile
7 | from nanopub.trustyuri.rdf import TransformRdf
8 |
9 | from . import CheckFile
10 |
11 | logging.basicConfig(level=logging.ERROR)
12 |
13 | filename = sys.argv[1]
14 |
15 | with open(filename) as f:
16 | for line in f:
17 | line = line.strip()
18 | if (re.match(r'^#|^$', line)):
19 | continue
20 | print("COMMAND: " + line)
21 | cmdargs = line.split(' ')
22 | cmd = cmdargs.pop(0)
23 | starttime = time.time()
24 | try:
25 | if (cmd == "CheckFile"):
26 | CheckFile.check(cmdargs)
27 | elif (cmd == "ProcessFile"):
28 | ProcessFile.process(cmdargs)
29 | elif (cmd == "TransformRdf"):
30 | TransformRdf.transform(cmdargs)
31 | else:
32 | print("ERROR: Unrecognized command %s" % cmd)
33 | exit(1)
34 | except Exception:
35 | print(sys.exc_info()[0])
36 | t = time.time() - starttime
37 | print("Time in seconds: %g" % t)
38 | print("---")
39 |
--------------------------------------------------------------------------------
/nanopub/trustyuri/TrustyUriModule.py:
--------------------------------------------------------------------------------
1 | class TrustyUriModule:
2 | def module_id(self):
3 | return ""
4 | def has_correct_hash(self, resource):
5 | return False
6 |
--------------------------------------------------------------------------------
/nanopub/trustyuri/TrustyUriResource.py:
--------------------------------------------------------------------------------
1 | class TrustyUriResource:
2 | def __init__(self, filename, content, hashstr):
3 | self.filename = filename
4 | self.content = content
5 | self.hashstr = hashstr
6 | def get_filename(self):
7 | return self.filename
8 | def get_hashstr(self):
9 | return self.hashstr
10 | def get_content(self):
11 | return self.content
12 |
--------------------------------------------------------------------------------
/nanopub/trustyuri/TrustyUriUtils.py:
--------------------------------------------------------------------------------
1 | import base64
2 | import re
3 |
4 |
5 | def get_trustyuri_tail(s):
6 | if not re.search(r'(.*[^A-Za-z0-9\-_]|)[A-Za-z0-9\-_]{25,}(\.[A-Za-z0-9\-_]{0,20})?', s):
7 | return ""
8 | return re.sub(r'^(.*[^A-Za-z0-9\-_]|)([A-Za-z0-9\-_]{25,})(\.[A-Za-z0-9\-_]{0,20})?$', r'\2', s)
9 |
10 |
11 | def get_base64(s):
12 | return re.sub(r'=', '', base64.b64encode(s, b'-_').decode('utf-8'))
13 |
--------------------------------------------------------------------------------
/nanopub/trustyuri/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nanopublication/nanopub-py/9482610f7463ca0b8e27fe6ea47fb3f4c185bf41/nanopub/trustyuri/__init__.py
--------------------------------------------------------------------------------
/nanopub/trustyuri/file/FileHasher.py:
--------------------------------------------------------------------------------
1 | import hashlib
2 |
3 | from nanopub.trustyuri import TrustyUriUtils
4 |
5 |
6 | def make_hash(content):
7 | try:
8 | return "FA" + TrustyUriUtils.get_base64(hashlib.sha256(content).digest())
9 | except Exception:
10 | return "FA" + TrustyUriUtils.get_base64(hashlib.sha256(content.encode()).digest())
11 |
--------------------------------------------------------------------------------
/nanopub/trustyuri/file/FileModule.py:
--------------------------------------------------------------------------------
1 | from nanopub.trustyuri.file import FileHasher
2 | from nanopub.trustyuri.TrustyUriModule import TrustyUriModule
3 |
4 |
5 | class FileModule(TrustyUriModule):
6 | def module_id(self):
7 | return "FA"
8 | def has_correct_hash(self, resource):
9 | h = FileHasher.make_hash(resource.get_content())
10 | return resource.get_hashstr() == h
11 |
--------------------------------------------------------------------------------
/nanopub/trustyuri/file/ProcessFile.py:
--------------------------------------------------------------------------------
1 | import os
2 | import re
3 | import sys
4 |
5 | from nanopub.trustyuri.file import FileHasher
6 |
7 |
8 | def process(args):
9 | filename = args[0]
10 |
11 | with open(filename) as f:
12 | hashstr = FileHasher.make_hash(f.read())
13 | ext = ""
14 | base = filename
15 | if re.search(r'.\.[A-Za-z0-9\-_]{0,20}$', filename):
16 | ext = re.sub(r'^(.*)(\.[A-Za-z0-9\-_]{0,20})$', r'\2', filename)
17 | base = re.sub(r'^(.*)(\.[A-Za-z0-9\-_]{0,20})$', r'\1', filename)
18 | os.rename(filename, base + "." + hashstr + ext)
19 |
20 |
21 | if __name__ == "__main__":
22 | args = sys.argv
23 | args.pop(0)
24 | process(args)
25 |
--------------------------------------------------------------------------------
/nanopub/trustyuri/file/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nanopublication/nanopub-py/9482610f7463ca0b8e27fe6ea47fb3f4c185bf41/nanopub/trustyuri/file/__init__.py
--------------------------------------------------------------------------------
/nanopub/trustyuri/rdf/HashAdder.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | from rdflib.term import URIRef
4 |
5 |
6 | def addhash(quads, hashstr):
7 | newquads = []
8 | for q in quads:
9 | c = transform(q[0], hashstr)
10 | s = transform(q[1], hashstr)
11 | p = transform(q[2], hashstr)
12 | o = q[3]
13 | if isinstance(q[3], URIRef):
14 | o = transform(q[3], hashstr)
15 | newquads.append((c, s, p, o))
16 | return newquads
17 |
18 |
19 | def transform(uri, hashstr):
20 | if uri is None:
21 | return None
22 | return URIRef(re.sub(" ", hashstr, str(uri)))
23 |
--------------------------------------------------------------------------------
/nanopub/trustyuri/rdf/RdfHasher.py:
--------------------------------------------------------------------------------
1 | import hashlib
2 | import re
3 | from functools import cmp_to_key
4 |
5 | from rdflib.term import Literal
6 |
7 | from nanopub.trustyuri import TrustyUriUtils
8 | from nanopub.trustyuri.rdf.RdfPreprocessor import preprocess
9 | from nanopub.trustyuri.rdf.StatementComparator import StatementComparator
10 | from nanopub.utils import log
11 |
12 |
13 | def normalize_quads(quads, hashstr=None, baseuri=None):
14 | quads.sort()
15 | quads = preprocess(quads, hashstr=hashstr, baseuri=baseuri)
16 | comp = StatementComparator(hashstr)
17 | quads = sorted(quads, key=cmp_to_key(lambda q1, q2: comp.compare(q1, q2)))
18 | s = ""
19 | previous = ""
20 | for q in quads:
21 | e = ""
22 | e = e + str(value_to_string(q[0]))
23 | e = e + str(value_to_string(q[1]))
24 | e = e + str(value_to_string(q[2]))
25 | e = e + str(value_to_string(q[3]))
26 | if not e == previous:
27 | s = s + e
28 | previous = e
29 | log.debug(f"Normalized quads before signing/hashing:\n{s}")
30 | return s
31 |
32 |
33 | def make_hash(quads, hashstr=None, baseuri=None) -> str:
34 | s = normalize_quads(quads, hashstr, baseuri)
35 |
36 | # Uncomment next line to see what goes into the hash:
37 | # print("NORMALIZED QUADS IN MAKE_HASH\n" + s + "NORMALIZED QUADS IN MAKE_HASH\n")
38 | return "RA" + TrustyUriUtils.get_base64(hashlib.sha256(s.encode('utf-8')).digest())
39 |
40 |
41 | def value_to_string(value) -> str:
42 | if value is None:
43 | return "\n"
44 | elif isinstance(value, Literal):
45 | if value.language is not None:
46 | # TODO: proper canonicalization of language tags
47 | return f"@{value.language.lower()} {escape(value)}\n"
48 | if value.datatype is not None:
49 | return f"^{value.datatype} {escape(value)}\n"
50 | return f"^http://www.w3.org/2001/XMLSchema#string {escape(value)}\n"
51 | else:
52 | return f"{str(value)}\n"
53 |
54 |
55 | def escape(s) -> str:
56 | return re.sub(r'\n', r'\\n', re.sub(r'\\', r'\\\\', str(s)))
57 |
--------------------------------------------------------------------------------
/nanopub/trustyuri/rdf/RdfModule.py:
--------------------------------------------------------------------------------
1 | from rdflib.graph import ConjunctiveGraph
2 |
3 | from nanopub.trustyuri.rdf import RdfHasher, RdfUtils
4 | from nanopub.trustyuri.TrustyUriModule import TrustyUriModule
5 |
6 |
7 | class RdfModule(TrustyUriModule):
8 | def module_id(self):
9 | return "RA"
10 | def has_correct_hash(self, resource):
11 | f = RdfUtils.get_format(resource.get_filename())
12 | cg = ConjunctiveGraph()
13 | cg.parse(data=resource.get_content(), format=f)
14 | quads = RdfUtils.get_quads(cg)
15 | h = RdfHasher.make_hash(quads, resource.get_hashstr())
16 | return resource.get_hashstr() == h
17 |
--------------------------------------------------------------------------------
/nanopub/trustyuri/rdf/RdfPreprocessor.py:
--------------------------------------------------------------------------------
1 | from rdflib.term import BNode, URIRef
2 |
3 | from nanopub.trustyuri.rdf import RdfUtils
4 |
5 |
6 | def preprocess(quads, hashstr=None, baseuri=None):
7 | newquads = []
8 | bnodemap = {}
9 | for q in quads:
10 | c = transform(q[0], hashstr, baseuri, bnodemap)
11 | s = transform(q[1], hashstr, baseuri, bnodemap)
12 | p = transform(q[2], hashstr, baseuri, bnodemap)
13 | o = q[3]
14 | if isinstance(q[3], URIRef) or isinstance(q[3], BNode):
15 | o = transform(q[3], hashstr, baseuri, bnodemap)
16 | newquads.append((c, s, p, o))
17 | return newquads
18 |
19 |
20 | def transform(uri, hashstr, baseuri, bnodemap):
21 | if uri is None:
22 | return None
23 |
24 | if baseuri is None:
25 | try:
26 | return URIRef(RdfUtils.normalize(uri, hashstr).decode('utf-8'))
27 | except Exception:
28 | return URIRef(RdfUtils.normalize(uri, hashstr))
29 | return RdfUtils.get_trustyuri(uri, baseuri, hashstr, bnodemap)
30 |
--------------------------------------------------------------------------------
/nanopub/trustyuri/rdf/RdfTransformer.py:
--------------------------------------------------------------------------------
1 | import os
2 | import re
3 |
4 | from nanopub.trustyuri.rdf import HashAdder, RdfHasher, RdfPreprocessor, RdfUtils
5 |
6 |
7 | def transform_to_file(conjgraph, baseuri, outdir, filename):
8 | quads = RdfUtils.get_quads(conjgraph)
9 | quads = RdfPreprocessor.preprocess(quads, baseuri=baseuri)
10 | hashstr = RdfHasher.make_hash(quads)
11 | quads = HashAdder.addhash(quads, hashstr)
12 | conjgraph = RdfUtils.get_conjunctivegraph(quads)
13 | name = ""
14 | if (baseuri is not None) and re.match('.*/.*', str(baseuri)):
15 | name = re.sub(r'^.*[^A-Za-z0-9.\-_]([A-Za-z0-9.\-_]*)$', r'\1', str(baseuri)) + "."
16 | ext = os.path.splitext(filename)[1]
17 | rdfFormat = RdfUtils.get_format(filename)
18 | conjgraph.serialize(outdir + "/" + name + hashstr + ext, format=rdfFormat)
19 | return RdfUtils.get_trustyuri(baseuri, baseuri, hashstr, None)
20 |
21 |
22 | def transform_to_string(conjgraph, baseuri):
23 | quads = RdfUtils.get_quads(conjgraph)
24 | quads = RdfPreprocessor.preprocess(quads, baseuri=baseuri)
25 | hashstr = RdfHasher.make_hash(quads)
26 | quads = HashAdder.addhash(quads, hashstr)
27 | conjgraph = RdfUtils.get_conjunctivegraph(quads)
28 | return conjgraph.serialize(format='trix')
29 |
30 |
31 | def transform(conjgraph, baseuri):
32 | quads = RdfUtils.get_quads(conjgraph)
33 | quads = RdfPreprocessor.preprocess(quads, baseuri=baseuri)
34 | hashstr = RdfHasher.make_hash(quads)
35 | quads = HashAdder.addhash(quads, hashstr)
36 | return RdfUtils.get_conjunctivegraph(quads)
37 |
--------------------------------------------------------------------------------
/nanopub/trustyuri/rdf/RdfUtils.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | from rdflib.graph import ConjunctiveGraph, Graph
4 | from rdflib.term import BNode, URIRef
5 | from rdflib.util import guess_format
6 |
7 | from nanopub.definitions import NP_PREFIX, NP_TEMP_PREFIX
8 |
9 |
10 | def get_trustyuri(resource, baseuri, hashstr, bnodemap):
11 | """Most of the work done to normalize URIs happens here"""
12 | if resource is None:
13 | return None
14 | np_uri = get_str(baseuri).decode('utf-8')
15 | # baseuri passed is the np namespace, np_uri is the nanopub URI without trailing # or /
16 | if np_uri.endswith('#') or np_uri.endswith('/'):
17 | np_uri = np_uri[:-1]
18 | # Extract the trusty artefact if present, or remove the trailing / if trusty not present
19 | prefix = "/".join(baseuri.split('/')[:-1]) + '/'
20 | if str(baseuri).startswith(NP_TEMP_PREFIX):
21 | prefix = NP_PREFIX
22 | if isinstance(resource, URIRef):
23 | suffix = get_suffix(resource, baseuri)
24 | if get_str(resource).decode('utf-8') == np_uri:
25 | return str(f"{prefix}{hashstr}")
26 | if suffix is None and not get_str(resource).decode('utf-8') == get_str(baseuri).decode('utf-8'):
27 | return str(resource)
28 | if suffix is None or suffix == "":
29 | return str(f"{prefix}{hashstr}")
30 | return str(f"{prefix}{hashstr}/{suffix}")
31 | if isinstance(resource, BNode):
32 | # NOTE: bnodes are replaced in nanopub.py by _replace_blank_nodes() most of the time
33 | bnode_unnamed = re.match(r'^[a-zA-Z0-9]{33}$', str(resource))
34 | # Check if BNode in the form of N2b80343001e94f48bdee0901be566ebb
35 | # Which means it was automatically generated by rdflib: we use a number in this case
36 | if bnode_unnamed:
37 | n = get_bnode_number(resource, bnodemap)
38 | np_uri = str(f"{prefix}{hashstr}")
39 | return str(np_uri + "#_" + str(n))
40 | else:
41 | # If the user gave a specific name to the bnode with rdflib
42 | return str(f"{prefix}{hashstr}" + "#_" + str(resource))
43 | else:
44 | return None
45 |
46 |
47 | def get_suffix(plainuri, baseuri):
48 | p = get_str(plainuri)
49 | b = get_str(baseuri)
50 | if (p == b):
51 | return None
52 | if (p.startswith(b)):
53 | return p[len(b):].decode('utf-8')
54 | return None
55 |
56 |
57 | def normalize(uri, hashstr):
58 | if hashstr is None:
59 | return get_str(uri)
60 | try:
61 | return re.sub(hashstr, " ", str(uri))
62 | except Exception:
63 | return re.sub(hashstr.decode('utf-8'), " ", str(uri))
64 |
65 |
66 | def get_bnode_number(bnode, bnodemap):
67 | i = get_str(bnode)
68 | if i not in bnodemap.keys():
69 | n = len(bnodemap) + 1
70 | bnodemap[i] = n
71 | return bnodemap[i]
72 |
73 |
74 | def expand_baseuri(baseuri):
75 | s = get_str(baseuri).decode('utf-8')
76 | if re.match(r'.*[A-Za-z0-9\-_]', s):
77 | s = s + "."
78 | return s
79 |
80 |
81 | def get_quads(conjunctivegraph):
82 | quads = []
83 | for s, p, o, c in conjunctivegraph.quads((None, None, None)):
84 | g = c.identifier
85 | if not isinstance(g, URIRef):
86 | g = None
87 | quads.append((g, s, p, o))
88 | quads.sort()
89 | return quads
90 |
91 |
92 | def get_conjunctivegraph(quads):
93 | cg = ConjunctiveGraph()
94 | # for (c, s, p, o) in quads:
95 | # cg.default_context = Graph(store=cg.store, identifier=c)
96 | # cg.add((s, p, o))
97 | cg.addN([(s, p, o, Graph(store=cg.store, identifier=c)) for (c, s, p, o) in quads])
98 | return cg
99 |
100 |
101 | def get_format(filename):
102 | return guess_format(filename, {'xml': 'trix', 'ttl': 'turtle', 'nq': 'nquads', 'nt': 'nt', 'rdf': 'xml'})
103 |
104 |
105 | def get_str(s):
106 | return s.encode('utf-8')
107 |
--------------------------------------------------------------------------------
/nanopub/trustyuri/rdf/StatementComparator.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | from rdflib.term import Literal
4 |
5 |
6 | class StatementComparator:
7 | def __init__(self, hashstr=None):
8 | self.hashstr = hashstr
9 |
10 | def compare(self, q1, q2):
11 | c = self.compare_context(q1, q2)
12 | if not c == 0:
13 | return c
14 | c = self.compare_subject(q1, q2)
15 | if not c == 0:
16 | return c
17 | c = self.compare_predicate(q1, q2)
18 | if not c == 0:
19 | return c
20 | return self.compare_object(q1, q2)
21 |
22 | def compare_context(self, q1, q2):
23 | r1 = q1[0]
24 | r2 = q2[0]
25 | if (r1 is None) and (r2 is None):
26 | return 0
27 | if (r1 is None) and (r2 is not None):
28 | return -1
29 | if (r1 is not None) and (r2 is None):
30 | return 1
31 | return self.compare_uri(r1, r2)
32 |
33 | def compare_subject(self, q1, q2):
34 | return self.compare_uri(q1[1], q2[1])
35 |
36 | def compare_predicate(self, q1, q2):
37 | return self.compare_uri(q1[2], q2[2])
38 |
39 | def compare_object(self, q1, q2):
40 | r1 = q1[3]
41 | r2 = q2[3]
42 | if isinstance(r1, Literal) and not isinstance(r2, Literal):
43 | return 1
44 | if not isinstance(r1, Literal) and isinstance(r2, Literal):
45 | return -1
46 | if isinstance(r1, Literal):
47 | return self.compare_literal(r1, r2)
48 | else:
49 | return self.compare_uri(r1, r2)
50 |
51 | def compare_literal(self, l1, l2):
52 | x1 = l1.encode('utf-8')
53 | x2 = l2.encode('utf-8')
54 | if (x1 < x2):
55 | return -1
56 | if (x1 > x2):
57 | return 1
58 | x1 = l1.datatype
59 | if (l1.language is not None):
60 | x1 = None
61 | if (l1.language is None and x1 is None):
62 | x1 = 'http://www.w3.org/2001/XMLSchema#string'
63 | x2 = l2.datatype
64 | if (l2.language is not None):
65 | x2 = None
66 | if (l2.language is None and x2 is None):
67 | x2 = 'http://www.w3.org/2001/XMLSchema#string'
68 | if (x1 is None) and (x2 is not None):
69 | return -1
70 | if (x1 is not None) and (x2 is None):
71 | return 1
72 | if (x1 is not None) and (x1 < x2):
73 | return -1
74 | if (x1 is not None) and (x1 > x2):
75 | return 1
76 | x1 = l1.language
77 | x2 = l2.language
78 | if (x1 is None) and (x2 is not None):
79 | return -1
80 | if (x1 is not None) and (x2 is None):
81 | return 1
82 | if (x1 is not None) and (x1 < x2):
83 | return -1
84 | if (x1 is not None) and (x1 > x2):
85 | return 1
86 | return 0
87 |
88 | def compare_uri(self, r1, r2):
89 | s1 = r1.encode('utf-8')
90 | s2 = r2.encode('utf-8')
91 | p1 = s1
92 | p2 = s2
93 | if self.hashstr is not None:
94 | try:
95 | p1 = re.sub(self.hashstr, ' ', s1)
96 | except Exception:
97 | p1 = re.sub(self.hashstr, ' ', r1)
98 | try:
99 | p2 = re.sub(self.hashstr, ' ', s2)
100 | except Exception:
101 | p2 = re.sub(self.hashstr, ' ', r2)
102 | if p1 < p2:
103 | return -1
104 | if p1 == p2:
105 | return 0
106 | return 1
107 |
--------------------------------------------------------------------------------
/nanopub/trustyuri/rdf/TransformRdf.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import os
3 | import sys
4 |
5 | from rdflib.graph import ConjunctiveGraph
6 | from rdflib.term import URIRef
7 |
8 | from nanopub.trustyuri.rdf import RdfTransformer, RdfUtils
9 |
10 |
11 | def transform(args):
12 | filename = args[0]
13 | baseuristr = args[1]
14 |
15 | with open(filename) as f:
16 | rdfFormat = RdfUtils.get_format(filename)
17 | cg = ConjunctiveGraph()
18 | cg.parse(data=f.read(), format=rdfFormat)
19 | baseuri = URIRef(baseuristr)
20 | outdir = os.path.abspath(os.path.join(str(filename), os.pardir))
21 | RdfTransformer.transform_to_file(cg, baseuri, outdir, filename)
22 |
23 |
24 | if __name__ == "__main__":
25 | logging.basicConfig(level=logging.ERROR)
26 | args = sys.argv
27 | args.pop(0)
28 | transform(args)
29 |
--------------------------------------------------------------------------------
/nanopub/trustyuri/rdf/__init__.py:
--------------------------------------------------------------------------------
1 | import rdflib
2 |
3 | rdflib.NORMALIZE_LITERALS = False
4 |
--------------------------------------------------------------------------------
/nanopub/utils.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import re
3 | from dataclasses import asdict, dataclass
4 | from typing import Any, Optional
5 |
6 | from rdflib import ConjunctiveGraph, Namespace, URIRef
7 |
8 | from nanopub.definitions import DUMMY_NAMESPACE, DUMMY_URI
9 |
10 | log = logging.getLogger()
11 |
12 |
13 | class MalformedNanopubError(ValueError):
14 | """Error to be raised if a Nanopub is not formed correctly."""
15 |
16 |
17 | @dataclass
18 | class NanopubMetadata:
19 | """Represents the different URIs and namespace used for a nanopub."""
20 |
21 | namespace: Namespace = DUMMY_NAMESPACE
22 | np_uri: URIRef = DUMMY_URI
23 |
24 | head: URIRef = DUMMY_NAMESPACE["Head"]
25 | assertion: URIRef = DUMMY_NAMESPACE["assertion"]
26 | provenance: URIRef = DUMMY_NAMESPACE["provenance"]
27 | pubinfo: URIRef = DUMMY_NAMESPACE["pubinfo"]
28 |
29 | sig_uri: URIRef = DUMMY_NAMESPACE["sig"]
30 | signature: Optional[str] = None
31 | public_key: Optional[str] = None
32 | algorithm: Optional[str] = None
33 |
34 | trusty: Optional[str] = None
35 |
36 | dict = asdict
37 |
38 |
39 | def extract_np_metadata(g: ConjunctiveGraph) -> NanopubMetadata:
40 | """Extract a nanopub URI, namespace and head/assertion/prov/pubinfo contexts from a Graph"""
41 | get_np_query = """prefix np:
42 |
43 | SELECT DISTINCT ?np ?head ?assertion ?provenance ?pubinfo ?sigUri ?signature ?pubkey ?algo
44 | WHERE {
45 | GRAPH ?head {
46 | ?np a np:Nanopublication ;
47 | np:hasAssertion ?assertion ;
48 | np:hasProvenance ?provenance ;
49 | np:hasPublicationInfo ?pubinfo .
50 | }
51 | GRAPH ?pubinfo {
52 | OPTIONAL {
53 | ?sigUri npx:hasSignatureTarget ?np ;
54 | npx:hasPublicKey ?pubkey ;
55 | npx:hasAlgorithm ?algo ;
56 | npx:hasSignature ?signature .
57 | }
58 | }
59 | }
60 | """
61 | qres: Any = g.query(get_np_query)
62 | if len(qres) < 1:
63 | raise MalformedNanopubError(
64 | "\033[1mNo nanopublication\033[0m has been found in the provided RDF. "
65 | "It should contain a np:Nanopublication object in a Head graph, pointing to 3 graphs: assertion, provenance and pubinfo"
66 | )
67 | if len(qres) > 1:
68 | np_found: list = []
69 | for row in qres:
70 | np_found.append(row.np)
71 | raise MalformedNanopubError(
72 | f"\033[1mMultiple nanopublications\033[0m are defined in this graph: {', '.join(np_found)}. "
73 | "The Nanopub object can only handles 1 nanopublication at a time"
74 | )
75 | np_meta = NanopubMetadata()
76 | for row in qres:
77 | np_meta.head = row.head
78 | np_meta.assertion = row.assertion
79 | np_meta.provenance = row.provenance
80 | np_meta.pubinfo = row.pubinfo
81 | np_meta.np_uri = row.np
82 | np_meta.sig_uri = row.sigUri
83 | np_meta.signature = row.signature
84 | np_meta.public_key = row.pubkey
85 | np_meta.algorithm = row.algo
86 |
87 | # Check if the nanopub URI has a trusty artefact:
88 | separator_char = '/'
89 | # Regex to extract base URI, separator and trusty URI (if any)
90 | extract_trusty = re.search(r'^(.*?)(\/|#)?(RA.*)?$', str(np_meta.np_uri))
91 | if extract_trusty:
92 | base_uri = extract_trusty.group(1)
93 | if extract_trusty.group(2):
94 | separator_char = extract_trusty.group(2)
95 | np_meta.namespace = Namespace(base_uri + separator_char)
96 |
97 | if extract_trusty.group(3):
98 | np_meta.trusty = extract_trusty.group(3)
99 | # TODO: improve as the signed np namespace might be using / or # or .
100 | np_meta.namespace = Namespace(np_meta.np_uri + '#')
101 |
102 | return np_meta
103 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["hatchling"]
3 | build-backend = "hatchling.build"
4 |
5 | [project]
6 | name = "nanopub"
7 | description = "Python client for Nanopublications"
8 | readme = "README.md"
9 | requires-python = ">=3.7"
10 | license = { file = "LICENSE" }
11 | authors = [
12 | { name = "Robin Richardson", email = "r.richardson@esciencecenter.nl" },
13 | { name = "Djura Smits" },
14 | { name = "Sven van den Burg" },
15 | { name = "Vincent Emonet", email = "vincent.emonet@gmail.com" },
16 | ]
17 | keywords = [
18 | "Nanopublication",
19 | "RDF",
20 | "Linked Data",
21 | "Publishing"
22 | ]
23 | classifiers = [
24 | "License :: OSI Approved :: Apache Software License",
25 | "Operating System :: OS Independent",
26 | "Programming Language :: Python :: 3",
27 | "Programming Language :: Python :: 3.7",
28 | "Programming Language :: Python :: 3.8",
29 | "Programming Language :: Python :: 3.9",
30 | "Programming Language :: Python :: 3.10",
31 | ]
32 | dynamic = ["version"]
33 |
34 | dependencies = [
35 | "rdflib >=6.0.2",
36 | "requests",
37 | "typer",
38 | "yatiml",
39 | "pycryptodome >=3.15.0",
40 | ]
41 |
42 | [project.optional-dependencies]
43 | test = [
44 | "pytest >=7.1.3",
45 | "pytest-cov >=3.0.0",
46 | "coveralls",
47 | "mypy >=0.991",
48 | "isort >=5.11.0",
49 | "flake8 >=5.0.0",
50 | "Flake8-pyproject >=1.2.2",
51 | "flaky",
52 | ]
53 | doc = [
54 | "mkdocs >=1.4.2",
55 | "mkdocs-material >=8.2.7",
56 | "mkdocstrings[python] >=0.19.1",
57 | "mdx-include >=1.4.1",
58 | "mkdocs-markdownextradata-plugin >=0.2.5",
59 | ]
60 | dev = [
61 | "pre-commit >=2.17.0,<3.0.0",
62 | "autoflake >=1.4.0,<2.0.0",
63 | "jupyter",
64 | "notebook",
65 | "types-requests",
66 | ]
67 |
68 |
69 | [project.scripts]
70 | np = "nanopub.__main__:cli"
71 |
72 |
73 | [project.urls]
74 | Homepage = "https://fair-workflows.github.io/nanopub"
75 | Documentation = "https://fair-workflows.github.io/nanopub"
76 | History = "https://github.com/fair-workflows/nanopub/releases"
77 | Tracker = "https://github.com/fair-workflows/nanopub/issues"
78 | Source = "https://github.com/fair-workflows/nanopub"
79 |
80 |
81 |
82 | # ENVIRONMENTS AND SCRIPTS
83 | [tool.hatch.envs.default]
84 | features = [
85 | "test",
86 | "doc",
87 | "dev",
88 | ]
89 | post-install-commands = [
90 | "pre-commit install",
91 | ]
92 |
93 | [tool.hatch.envs.default.scripts]
94 | dev = "./scripts/dev.sh"
95 | test = "./scripts/test.sh {args}"
96 | docs = "./scripts/docs.sh {args}"
97 | format = "./scripts/format.sh"
98 | lint = "./scripts/lint.sh"
99 |
100 |
101 | # TOOLS
102 | [tool.hatch.version]
103 | path = "nanopub/_version.py"
104 |
105 |
106 | [tool.isort]
107 | line_length = 120
108 | skip = ["nanopub/__init__.py"]
109 | profile = "black"
110 |
111 |
112 | [tool.coverage.run]
113 | source = ["nanopub"]
114 | branch = true
115 |
116 | [tool.coverage.report]
117 | omit = ["nanopub/trustyuri/*", "tests/*"]
118 |
119 |
120 | [tool.flake8]
121 | max-complexity = 17
122 | max-line-length = 120
123 | per-file-ignores = [
124 | "__init__.py:F401",
125 | ]
126 | ignore = [
127 | "E501", # line too long
128 | "E303", # too many blank lines
129 | "E301", # expected 1 blank lines found 0
130 | "W503", # line break before binary operator
131 | ]
132 |
133 |
134 | [tool.mypy]
135 | strict = false
136 | implicit_reexport = true
137 | follow_imports = "normal"
138 | ignore_missing_imports = true
139 | pretty = true
140 | show_column_numbers = true
141 | warn_no_return = true
142 | warn_unused_ignores = false
143 | warn_redundant_casts = true
144 | disallow_untyped_defs = false
145 | no_implicit_optional = false
146 |
147 |
148 | [tool.pytest.ini_options]
149 | markers = [
150 | "no_rsa_key: mark a test as a test only run when there is no nanopub RSA key setup.",
151 | ]
152 |
--------------------------------------------------------------------------------
/scripts/all.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 | set -x
5 |
6 | bash ./scripts/format.sh
7 |
8 | bash ./scripts/lint.sh
9 |
10 | bash ./scripts/test.sh
11 |
--------------------------------------------------------------------------------
/scripts/dev.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from rdflib import Graph, Literal, URIRef
4 |
5 | from nanopub import Nanopub, NanopubConf, load_profile, namespaces
6 |
7 | log = logging.getLogger()
8 | log.setLevel(logging.INFO)
9 | console_handler = logging.StreamHandler()
10 | formatter = logging.Formatter(
11 | "%(asctime)s %(levelname)s: [%(module)s:%(funcName)s] %(message)s"
12 | )
13 | console_handler.setFormatter(formatter)
14 | log.addHandler(console_handler)
15 |
16 |
17 | conf = NanopubConf(
18 | add_prov_generated_time=False,
19 | add_pubinfo_generated_time=True,
20 | attribute_assertion_to_profile=True,
21 | attribute_publication_to_profile=True,
22 | profile=load_profile(),
23 | # use_test_server=True,
24 | )
25 |
26 | assertion = Graph()
27 | assertion.add((
28 | URIRef('http://test'), namespaces.HYCL.claims, Literal('This is a test for the nanopub python library')
29 | ))
30 |
31 | np = Nanopub(conf=conf, assertion=assertion)
32 |
33 | np.sign()
34 | # np.publish()
35 | print(np)
36 |
--------------------------------------------------------------------------------
/scripts/dev.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 |
5 | clear
6 | python scripts/dev.py
7 |
--------------------------------------------------------------------------------
/scripts/docs.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 |
5 | mkdocs serve -a localhost:8001 ${@}
6 |
--------------------------------------------------------------------------------
/scripts/format.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh -e
2 | set -x
3 |
4 | autoflake --remove-all-unused-imports --recursive --remove-unused-variables --in-place nanopub tests --exclude=__init__.py
5 | isort nanopub tests
6 | pre-commit run --all-files || true
7 |
8 | # black nanopub tests
9 |
--------------------------------------------------------------------------------
/scripts/html-cov-test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 | set -x
5 |
6 | bash scripts/test.sh --cov-report=html ${@}
7 |
8 | python -m webbrowser ./htmlcov/index.html
9 |
--------------------------------------------------------------------------------
/scripts/install.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 |
5 | echo "Make sure you use a virtual environment when working in development:"
6 | echo "python -m venv .venv"
7 | echo "source .venv/bin/activate"
8 | echo
9 | read -p "Hit [Enter] to continue, or [Ctrl+C] to cancel" -n 1 -r
10 | echo
11 |
12 | pip install -e ".[dev,test,doc]"
13 |
14 | pre-commit install
15 |
--------------------------------------------------------------------------------
/scripts/lint.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 | set -x
5 |
6 | isort nanopub tests --check-only
7 | flake8 nanopub tests
8 | mypy nanopub
9 |
--------------------------------------------------------------------------------
/scripts/nanopub-java:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | function download-nanopub-jar {
6 | mkdir -p $LIBDIR
7 | # echo "Getting latest nanopub version..."
8 | # NANOPUB_LATEST_LOCATION=$(
9 | # curl --head -s https://github.com/Nanopublication/nanopub-java/releases/latest \
10 | # | egrep -i '^location:'
11 | # )
12 | # NANOPUB_VERSION=${NANOPUB_LATEST_LOCATION##*-}
13 | # NANOPUB_VERSION="${NANOPUB_VERSION%"${NANOPUB_VERSION##*[![:space:]]}"}"
14 | NANOPUB_VERSION=1.47
15 | echo "Downloading nanopub jar file version $NANOPUB_VERSION in $LIBDIR/nanopub-${NANOPUB_VERSION}-jar-with-dependencies.jar"
16 | curl -L --output "$LIBDIR/nanopub-${NANOPUB_VERSION}-jar-with-dependencies.jar" "https://github.com/Nanopublication/nanopub-java/releases/download/nanopub-${NANOPUB_VERSION}/nanopub-${NANOPUB_VERSION}-jar-with-dependencies.jar"
17 | }
18 |
19 | WORKINGDIR=`pwd`
20 | LIBDIR="$WORKINGDIR/lib"
21 |
22 | NANOPUBJAR=$(find $LIBDIR -maxdepth 1 -name "nanopub-*-jar-with-dependencies.jar" 2>/dev/null | sort -n | tail -1)
23 |
24 | if [ -z "$NANOPUBJAR" ]; then
25 | download-nanopub-jar
26 | NANOPUBJAR=$(find $LIBDIR -maxdepth 1 -name "nanopub-*-jar-with-dependencies.jar" 2>/dev/null | sort -n | tail -1)
27 | fi
28 |
29 | if [ ! -z "$NANOPUBJAR" ]; then
30 | exec java -Dsun.jnu.encoding=utf8 -Duser.language=en -Duser.country=US -Dfile.encoding=utf8 -jar $NANOPUBJAR "$@"
31 | fi
32 |
33 | echo "ERROR: Failed to find nanopub jar file."
34 | exit 1
35 |
--------------------------------------------------------------------------------
/scripts/nanopub-java.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem nanopub-java startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | echo FOR THE TESTS TO WORK DOWNLOAD THE NANOPUB JAR AT https://github.com/Nanopublication/nanopub-java/releases/latest and place it in a lib/ folder to create in the root of the repository
12 |
13 | set DIRNAME=%~dp0
14 | if "%DIRNAME%" == "" set DIRNAME=.
15 | set APP_BASE_NAME=%~n0
16 | set APP_HOME=%DIRNAME%..
17 |
18 | @rem Find java.exe
19 | if defined JAVA_HOME goto findJavaFromJavaHome
20 |
21 | set JAVA_EXE=java.exe
22 | %JAVA_EXE% -version >NUL 2>&1
23 | if "%ERRORLEVEL%" == "0" goto init
24 |
25 | echo.
26 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
27 | echo.
28 | echo Please set the JAVA_HOME variable in your environment to match the
29 | echo location of your Java installation.
30 |
31 | goto fail
32 |
33 | :findJavaFromJavaHome
34 | set JAVA_HOME=%JAVA_HOME:"=%
35 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
36 |
37 | if exist "%JAVA_EXE%" goto init
38 |
39 | echo.
40 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
41 | echo.
42 | echo Please set the JAVA_HOME variable in your environment to match the
43 | echo location of your Java installation.
44 |
45 | goto fail
46 |
47 | :init
48 | @rem Get command-line arguments, handling Windows variants
49 |
50 | if not "%OS%" == "Windows_NT" goto win9xME_args
51 |
52 | :win9xME_args
53 | @rem Slurp the command line arguments.
54 | set CMD_LINE_ARGS=
55 | set _SKIP=2
56 |
57 | :win9xME_args_slurp
58 | if "x%~1" == "x" goto execute
59 |
60 | set CMD_LINE_ARGS=%*
61 |
62 | :execute
63 | @rem Setup the command line
64 |
65 | set CLASSPATH=%APP_HOME%\lib\nanopub-1.33-jar-with-dependencies.jar
66 |
67 | @rem Execute nanopub-java
68 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% -jar "%CLASSPATH%" %CMD_LINE_ARGS%
69 |
70 | :end
71 | @rem End local scope for the variables with windows NT shell
72 | if "%ERRORLEVEL%"=="0" goto mainEnd
73 |
74 | :fail
75 | exit /b 1
76 |
77 | :mainEnd
78 | if "%OS%"=="Windows_NT" endlocal
79 |
--------------------------------------------------------------------------------
/scripts/notebooks.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 |
5 | jupyter notebook examples
6 |
--------------------------------------------------------------------------------
/scripts/test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 |
5 | pytest --cov=nanopub --cov-report=term-missing:skip-covered ${@}
6 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nanopublication/nanopub-py/9482610f7463ca0b8e27fe6ea47fb3f4c185bf41/tests/__init__.py
--------------------------------------------------------------------------------
/tests/conftest.py:
--------------------------------------------------------------------------------
1 | import os
2 | import tempfile
3 |
4 | import pytest
5 | import requests
6 |
7 | from nanopub import NanopubConf, load_profile
8 | from nanopub.client import TEST_NANOPUB_QUERY_URL
9 | from nanopub.definitions import TEST_RESOURCES_FILEPATH
10 | from tests.java_wrapper import JavaWrapper
11 |
12 |
13 | def pytest_addoption(parser):
14 | parser.addoption('--no_rsa_key', action='store_true', default=False,
15 | help="enable no_rsa_key decorated tests")
16 |
17 |
18 | def pytest_configure(config):
19 | if not config.option.no_rsa_key:
20 | setattr(config.option, 'markexpr', 'not no_rsa_key')
21 |
22 |
23 | skip_if_nanopub_server_unavailable = (
24 | pytest.mark.skipif(
25 | requests.get(TEST_NANOPUB_QUERY_URL).status_code != 200,
26 | reason='Nanopub server is unavailable'
27 | )
28 | )
29 |
30 |
31 | # Create a temporary profile.yml file for testing
32 | profile_test_path = os.path.join(tempfile.mkdtemp(), "profile.yml")
33 | profile_yaml = f"""orcid_id: https://orcid.org/0000-0000-0000-0000
34 | name: Python Tests
35 | public_key: {os.path.join(TEST_RESOURCES_FILEPATH, "id_rsa.pub")}
36 | private_key: {os.path.join(TEST_RESOURCES_FILEPATH, "id_rsa")}
37 | introduction_nanopub_uri:
38 | """
39 | with open(profile_test_path, "w") as f:
40 | f.write(profile_yaml)
41 |
42 | profile_test = load_profile(profile_test_path)
43 |
44 | default_conf = NanopubConf(
45 | profile=profile_test,
46 | use_test_server=True,
47 | add_prov_generated_time=False,
48 | add_pubinfo_generated_time=False,
49 | attribute_assertion_to_profile=True,
50 | attribute_publication_to_profile=True,
51 | assertion_attributed_to=None,
52 | publication_attributed_to=None,
53 | derived_from=None
54 | )
55 |
56 | testsuite_conf = NanopubConf(
57 | profile=profile_test,
58 | use_test_server=True,
59 | add_prov_generated_time=False,
60 | add_pubinfo_generated_time=False,
61 | attribute_assertion_to_profile=False,
62 | attribute_publication_to_profile=False,
63 | )
64 |
65 | java_wrap = JavaWrapper(private_key=profile_test.private_key)
66 |
--------------------------------------------------------------------------------
/tests/resources/id_rsa:
--------------------------------------------------------------------------------
1 | MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAPdEfIdHtZYoFh6/DWorzoHpFXMjugqW+CGpe9uk4BfUq54MToi2u7fgdGGtXLg4wsJFBYETdVeS0p1uA7EPe8LhwjHPktf5c6AZbO/lYpKM59e7/Ih4mvOy4iTIe/Dv+1OgasTSK0nXAbKUm/5iJ6LOYa82JQeE/QnT5gUw2e97AgMBAAECgYBbNQnyJINYpeSy5qoeFZaQ2Ncup2kCavmQASJMvJ5ka+/51nRJfY30n3iOZxIiad19J1SGbhUEfoXtyBzYfOubF2i2GJtdF5VyjdSoU6w/gOo2/vnbH+GCHnMclrWshohOADGQU/Y8pYhIvlQqcb6xEOts9m9C9g4uwvPXqjmhoQJBAPkmSFIZwF3i2UvJlHyeXi599L0jkGTUJy/Y4IjieUx5suwvAtG47ejhgIPKK06VtW49oGPHWjWc3cJAmnV+vTMCQQD+EPTvNtLpX9QiDEJD7b8woDwmVrvH/RUosP/cXpMQd7BUVgPlpffAlFJGDlOzwwjZjy+8kc6MYevh1kWqobSZAkEAyCs+nV99ErEHnYEFoB1oU3f0oeSpxKhCF4np03AIvi1kV6bpX+9wjNJnevp5UriqvDgc3S0zx7EQ5Vkb/1vkywJBAMMw59y4tAVT+DhITsi9aTvEfzG9RPt6trzSb2Aw0K/AJJpGkyvl/JfZ2/Oyoh/jYXM0DKrFIni76mtRIajcH1ECQQCJi6aXOaRkRPmf7FYY9cRaJdR1BtZkKZbDg6ZMD1bY97cGiM9STTMeldYcCtQBtyhVCTEObI/V6/0FAvY9Zi7w
2 |
--------------------------------------------------------------------------------
/tests/resources/id_rsa.pub:
--------------------------------------------------------------------------------
1 | MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD3RHyHR7WWKBYevw1qK86B6RVzI7oKlvghqXvbpOAX1KueDE6Itru34HRhrVy4OMLCRQWBE3VXktKdbgOxD3vC4cIxz5LX+XOgGWzv5WKSjOfXu/yIeJrzsuIkyHvw7/tToGrE0itJ1wGylJv+YieizmGvNiUHhP0J0+YFMNnvewIDAQAB
2 |
--------------------------------------------------------------------------------
/tests/test_cli.py:
--------------------------------------------------------------------------------
1 | import os
2 | from pathlib import Path
3 |
4 | import pytest
5 | from typer.testing import CliRunner
6 |
7 | from nanopub.__main__ import cli, validate_orcid_id
8 | from nanopub._version import __version__
9 | from nanopub.definitions import DEFAULT_PROFILE_PATH
10 | from tests.conftest import TEST_RESOURCES_FILEPATH
11 |
12 | runner = CliRunner()
13 |
14 | PRIVATE_KEY_PATH = os.path.join(TEST_RESOURCES_FILEPATH, "id_rsa")
15 |
16 |
17 | def test_validate_orcid_id():
18 | valid_ids = ['https://orcid.org/1234-5678-1234-5678',
19 | 'https://orcid.org/1234-5678-1234-567X']
20 | for orcid_id in valid_ids:
21 | assert validate_orcid_id(ctx=None, param=None, orcid_id=orcid_id) == orcid_id
22 |
23 | invalid_ids = ['https://orcid.org/abcd-efgh-abcd-efgh',
24 | 'https://orcid.org/1234-5678-1234-567',
25 | 'https://orcid.org/1234-5678-1234-56789',
26 | 'https://other-url.org/1234-5678-1234-5678',
27 | '0000-0000-0000-0000']
28 | for orcid_id in invalid_ids:
29 | with pytest.raises(ValueError):
30 | validate_orcid_id(ctx=None, param=None, orcid_id=orcid_id)
31 |
32 |
33 | def test_setup():
34 | # np setup --orcid-id https://orcid.org/0000-0000-0000-0000 --name "Python test" --newkeys --no-publish
35 | result = runner.invoke(cli, [
36 | "setup",
37 | "--orcid-id", "https://orcid.org/0000-0000-0000-0000",
38 | "--name", "Python test",
39 | "--newkeys", "--no-publish"
40 | ])
41 | assert result.exit_code == 1
42 | assert "Setting up nanopub profile" in result.stdout
43 | assert Path(DEFAULT_PROFILE_PATH).exists()
44 |
45 |
46 | def test_profile():
47 | result = runner.invoke(cli, [
48 | "profile",
49 | ])
50 | assert "User profile in" in result.stdout
51 |
52 |
53 | def test_publish():
54 | test_file = "./tests/testsuite/valid/plain/simple1.trig"
55 | result = runner.invoke(cli, [
56 | "publish", test_file, "--test"
57 | ])
58 | assert result.exit_code == 0
59 | assert "Nanopub published at" in result.stdout
60 |
61 |
62 | def test_sign_with_key():
63 | test_file = "./tests/testsuite/valid/plain/simple1.trig"
64 | result = runner.invoke(cli, [
65 | "sign", test_file,
66 | "-k", PRIVATE_KEY_PATH,
67 | ])
68 | assert result.exit_code == 0
69 | assert "Nanopub signed in" in result.stdout
70 |
71 |
72 | def test_version():
73 | result = runner.invoke(cli, ["version"])
74 | assert result.exit_code == 0
75 | assert __version__ == result.stdout.strip()
76 |
--------------------------------------------------------------------------------
/tests/test_fdo_nanopub.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | import rdflib
3 | from rdflib import RDF, RDFS
4 | from nanopub.namespaces import HDL, FDOF, NPX
5 | from nanopub.fdo_nanopub import FDONanopub, to_hdl_uri
6 | from nanopub.constants import FDO_DATA_REF_HANDLE_URI, FDO_PROFILE_HANDLE_URI, FDO_SERVICE_HANDLE_URI, FDO_TYPE_HANDLE_URI, FDO_STATUS_HANDLE_URI
7 |
8 | FAKE_HANDLE = "21.T11966/test"
9 | FAKE_URI = HDL[FAKE_HANDLE]
10 | FAKE_LABEL = "Test Object"
11 | FAKE_TYPE_JSON = '{"@type": "Dataset"}'
12 | FAKE_STATUS = "active"
13 | FAKE_ATTR_VALUE = rdflib.Literal("some value")
14 | FAKE_ATTR_LABEL = "Test Attribute"
15 |
16 |
17 | @pytest.mark.parametrize("fdo_id", [FAKE_HANDLE, HDL[FAKE_HANDLE]])
18 | def test_initial_fdo_triples(fdo_id):
19 | fdo = FDONanopub(fdo_id, FAKE_LABEL)
20 | fdo_uri = to_hdl_uri(fdo_id)
21 |
22 | assert (fdo_uri, RDF.type, FDOF.FAIRDigitalObject) in fdo.assertion
23 | assert (fdo_uri, RDFS.label, rdflib.Literal(FAKE_LABEL)) in fdo.assertion
24 | assert (fdo_uri, FDOF.hasMetadata, fdo.metadata.np_uri) in fdo.assertion
25 | assert (fdo.metadata.np_uri, RDFS.label, rdflib.Literal(f"FAIR Digital Object: {FAKE_LABEL}")) in fdo.pubinfo
26 | assert (fdo.metadata.np_uri, NPX.introduces, fdo_uri) in fdo.pubinfo
27 |
28 | @pytest.mark.parametrize("fdo_profile", [FAKE_HANDLE, HDL[FAKE_HANDLE]])
29 | def test_add_fdo_profile(fdo_profile):
30 | fdo = FDONanopub(FAKE_HANDLE, FAKE_LABEL)
31 | uri = to_hdl_uri(fdo_profile)
32 | fdo.add_fdo_profile(fdo_profile)
33 | assert (fdo.fdo_uri, FDO_PROFILE_HANDLE_URI, rdflib.Literal(uri)) in fdo.assertion
34 | assert (FDO_PROFILE_HANDLE_URI, RDFS.label, rdflib.Literal("FdoProfile")) in fdo.pubinfo
35 |
36 | @pytest.mark.parametrize("data_ref", [FAKE_HANDLE, HDL[FAKE_HANDLE]])
37 | def test_add_fdo_data_ref(data_ref):
38 | fdo = FDONanopub(FAKE_HANDLE, FAKE_LABEL)
39 | uri = to_hdl_uri(data_ref)
40 | fdo.add_fdo_data_ref(data_ref)
41 | assert (fdo.fdo_uri, FDO_DATA_REF_HANDLE_URI, uri) in fdo.assertion
42 | assert (FDO_DATA_REF_HANDLE_URI, RDFS.label, rdflib.Literal("DataRef")) in fdo.pubinfo
43 |
44 | @pytest.mark.parametrize("service_uri", [FAKE_HANDLE, HDL[FAKE_HANDLE]])
45 | def test_add_fdo_service(service_uri):
46 | fdo = FDONanopub(FAKE_HANDLE, FAKE_LABEL)
47 | uri = to_hdl_uri(service_uri)
48 | fdo.add_fdo_service(service_uri)
49 | assert (fdo.fdo_uri, FDO_SERVICE_HANDLE_URI, rdflib.Literal(uri)) in fdo.assertion
50 | assert (FDO_SERVICE_HANDLE_URI, RDFS.label, rdflib.Literal("FdoService")) in fdo.pubinfo
51 |
52 | @pytest.mark.parametrize("attr_HANDLE", [FAKE_HANDLE, HDL[FAKE_HANDLE]])
53 | def test_add_attribute_and_label(attr_HANDLE):
54 | fdo = FDONanopub(FAKE_HANDLE, FAKE_LABEL)
55 | uri = to_hdl_uri(attr_HANDLE)
56 | fdo.add_attribute(attr_HANDLE, FAKE_ATTR_VALUE)
57 | fdo.add_attribute_label(attr_HANDLE, FAKE_ATTR_LABEL)
58 | assert (fdo.fdo_uri, uri, FAKE_ATTR_VALUE) in fdo.assertion
59 | assert (uri, RDFS.label, rdflib.Literal(FAKE_ATTR_LABEL)) in fdo.pubinfo
60 |
61 | def test_add_fdo_type():
62 | fdo = FDONanopub(FAKE_HANDLE, FAKE_LABEL)
63 | fdo.add_fdo_type(FAKE_TYPE_JSON)
64 | # Related to https://github.com/RDFLib/rdflib/issues/1830
65 | # assert (fdo.fdo_uri, fdo.FDO_TYPE_HANDLE, rdflib.Literal(FAKE_TYPE_JSON, datatype=XSD.string)) in fdo.assertion
66 | assert (FDO_TYPE_HANDLE_URI, RDFS.label, rdflib.Literal("FdoType")) in fdo.pubinfo
67 |
68 | def test_add_fdo_status():
69 | fdo = FDONanopub(FAKE_HANDLE, FAKE_LABEL)
70 | fdo.add_fdo_status(FAKE_STATUS)
71 | assert (fdo.fdo_uri, FDO_STATUS_HANDLE_URI, rdflib.Literal(FAKE_STATUS)) in fdo.assertion
72 | assert (FDO_STATUS_HANDLE_URI, RDFS.label, rdflib.Literal("FdoStatus")) in fdo.pubinfo
73 |
--------------------------------------------------------------------------------
/tests/test_sign_utils.py:
--------------------------------------------------------------------------------
1 | from rdflib import Graph, Literal, URIRef
2 |
3 | from nanopub import Nanopub, namespaces
4 | from nanopub.client import DUMMY_NAMESPACE
5 | from nanopub.sign_utils import add_signature
6 | from tests.conftest import default_conf, java_wrap, profile_test
7 |
8 |
9 | def test_nanopub_sign():
10 | expected_np_uri = "http://purl.org/np/RAoXkQkJe_lpMhYW61Y9mqWDHa5MAj1o4pWIiYLmAzY50"
11 |
12 | assertion = Graph()
13 | assertion.add((
14 | URIRef('http://test'), namespaces.HYCL.claims, Literal('This is a test of nanopub-python')
15 | ))
16 |
17 | np = Nanopub(
18 | conf=default_conf,
19 | assertion=assertion
20 | )
21 | java_np = java_wrap.sign(np)
22 |
23 | signed_g = add_signature(
24 | np.rdf,
25 | profile_test,
26 | DUMMY_NAMESPACE,
27 | np.pubinfo
28 | )
29 | np.update_from_signed(signed_g)
30 | assert np.source_uri == expected_np_uri
31 | assert np.source_uri == java_np
32 |
--------------------------------------------------------------------------------
/tests/testsuite/invalid/plain/emptya.trig:
--------------------------------------------------------------------------------
1 | @prefix : .
2 | @prefix xsd: .
3 | @prefix dc: .
4 | @prefix pav: .
5 | @prefix prov: .
6 | @prefix np: .
7 | @prefix npx: .
8 | @prefix ex: .
9 |
10 | :Head {
11 | : np:hasAssertion :assertion ;
12 | np:hasProvenance :provenance ;
13 | np:hasPublicationInfo :pubinfo ;
14 | a np:Nanopublication .
15 | }
16 |
17 | :assertion {
18 | }
19 |
20 | :provenance {
21 | :assertion prov:hadPrimarySource .
22 | }
23 |
24 | :pubinfo {
25 | : dc:created "2014-07-24T18:05:11+01:00"^^xsd:dateTime ;
26 | pav:createdBy ;
27 | a npx:ExampleNanopub .
28 | }
29 |
--------------------------------------------------------------------------------
/tests/testsuite/invalid/plain/emptyinfo.trig:
--------------------------------------------------------------------------------
1 | @prefix : .
2 | @prefix xsd: .
3 | @prefix dc: .
4 | @prefix pav: .
5 | @prefix prov: .
6 | @prefix np: .
7 | @prefix npx: .
8 | @prefix ex: .
9 |
10 | :Head {
11 | : np:hasAssertion :assertion ;
12 | np:hasProvenance :provenance ;
13 | np:hasPublicationInfo :pubinfo ;
14 | a np:Nanopublication .
15 | }
16 |
17 | :assertion {
18 | ex:mosquito ex:transmits ex:malaria .
19 | }
20 |
21 | :provenance {
22 | :assertion prov:hadPrimarySource .
23 | }
24 |
25 | :pubinfo {
26 | }
27 |
--------------------------------------------------------------------------------
/tests/testsuite/invalid/plain/emptyprov.trig:
--------------------------------------------------------------------------------
1 | @prefix : .
2 | @prefix xsd: .
3 | @prefix dc: .
4 | @prefix pav: .
5 | @prefix prov: .
6 | @prefix np: .
7 | @prefix npx: .
8 | @prefix ex: .
9 |
10 | :Head {
11 | : np:hasAssertion :assertion ;
12 | np:hasProvenance :provenance ;
13 | np:hasPublicationInfo :pubinfo ;
14 | a np:Nanopublication .
15 | }
16 |
17 | :assertion {
18 | ex:mosquito ex:transmits ex:malaria .
19 | }
20 |
21 | :provenance {
22 | }
23 |
24 | :pubinfo {
25 | : dc:created "2014-07-24T18:05:11+01:00"^^xsd:dateTime ;
26 | pav:createdBy ;
27 | a npx:ExampleNanopub .
28 | }
29 |
--------------------------------------------------------------------------------
/tests/testsuite/invalid/plain/extragraph.trig:
--------------------------------------------------------------------------------
1 | @prefix : .
2 | @prefix xsd: .
3 | @prefix dc: .
4 | @prefix pav: .
5 | @prefix prov: .
6 | @prefix np: .
7 | @prefix npx: .
8 | @prefix ex: .
9 |
10 | :Head {
11 | : np:hasAssertion :assertion ;
12 | np:hasProvenance :provenance ;
13 | np:hasPublicationInfo :pubinfo ;
14 | a np:Nanopublication .
15 | }
16 |
17 | :assertion {
18 | ex:mosquito ex:transmits ex:malaria .
19 | }
20 |
21 | :foobar {
22 | ex:mosquito ex:transmits ex:malaria .
23 | }
24 |
25 | :provenance {
26 | :assertion prov:hadPrimarySource .
27 | }
28 |
29 | :pubinfo {
30 | : dc:created "2014-07-24T18:05:11+01:00"^^xsd:dateTime ;
31 | pav:createdBy ;
32 | a npx:ExampleNanopub .
33 | }
34 |
--------------------------------------------------------------------------------
/tests/testsuite/invalid/plain/noinfolink.trig:
--------------------------------------------------------------------------------
1 | @prefix : .
2 | @prefix xsd: .
3 | @prefix dc: .
4 | @prefix pav: .
5 | @prefix prov: .
6 | @prefix np: .
7 | @prefix npx: .
8 | @prefix ex: .
9 |
10 | :Head {
11 | : np:hasAssertion :assertion ;
12 | np:hasProvenance :provenance ;
13 | np:hasPublicationInfo :pubinfo ;
14 | a np:Nanopublication .
15 | }
16 |
17 | :assertion {
18 | ex:mosquito ex:transmits ex:malaria .
19 | ex:mosquito2 ex:transmits ex:malaria4 .
20 | }
21 |
22 | :provenance {
23 | :assertion prov:hadPrimarySource .
24 | }
25 |
26 | :pubinfo {
27 | :something dc:created "2014-07-24T18:05:11+01:00"^^xsd:dateTime ;
28 | pav:createdBy ;
29 | a npx:ExampleNanopub .
30 | }
31 |
--------------------------------------------------------------------------------
/tests/testsuite/invalid/plain/noprovlink.trig:
--------------------------------------------------------------------------------
1 | @prefix : .
2 | @prefix xsd: .
3 | @prefix dc: .
4 | @prefix pav: .
5 | @prefix prov: .
6 | @prefix np: .
7 | @prefix npx: .
8 | @prefix ex: .
9 |
10 | :Head {
11 | : np:hasAssertion :assertion ;
12 | np:hasProvenance :provenance ;
13 | np:hasPublicationInfo :pubinfo ;
14 | a np:Nanopublication .
15 | }
16 |
17 | :assertion {
18 | ex:mosquito ex:transmits ex:malaria .
19 | }
20 |
21 | :provenance {
22 | :assertionFoo prov:hadPrimarySource .
23 | }
24 |
25 | :pubinfo {
26 | : dc:created "2014-07-24T18:05:11+01:00"^^xsd:dateTime ;
27 | pav:createdBy ;
28 | a npx:ExampleNanopub .
29 | }
30 |
--------------------------------------------------------------------------------
/tests/testsuite/invalid/plain/valid_invalid1.trig:
--------------------------------------------------------------------------------
1 | @prefix : .
2 | @prefix xsd: .
3 | @prefix dc: .
4 | @prefix pav: .
5 | @prefix prov: .
6 | @prefix np: .
7 | @prefix ex: .
8 |
9 | :Head {
10 | : a np:Nanopublication ; np:hasAssertion :assertion ;
11 | np:hasProvenance :provenance ; np:hasPublicationInfo :pubinfo .
12 | }
13 | :assertion {
14 | ex:mosquito ex:transmits ex:malaria .
15 | }
16 | :provenance {
17 | :assertion prov:wasDerivedFrom .
18 | }
19 | :pubinfo {
20 | : pav:createdBy .
21 | : dc:created "2014-07-09T13:54:11+01:00"^^xsd:dateTime .
22 | }
23 |
24 |
25 | @prefix : .
26 | @prefix xsd: .
27 | @prefix dc: .
28 | @prefix pav: .
29 | @prefix prov: .
30 | @prefix np: .
31 | @prefix ex: .
32 |
33 | :Head {
34 | : a np:Nanopublication ; np:hasAssertion :assertion ;
35 | np:hasProvenance :provenance ; np:hasPublicationInfo :pubinfo .
36 | }
37 | :assertion {
38 | ex:Gene1 ex:isRealtedTo ex:malaria .
39 | }
40 | :provenance {
41 | :assertion prov:wasDerivedFrom .
42 | }
43 | :pubinfo {
44 | : pav:createdBy .
45 | : dc:created "2014-07-09T13:54:11+01:00"^^xsd:dateTime .
46 | }
47 |
48 |
49 | @prefix : .
50 | @prefix xsd: .
51 | @prefix dc: .
52 | @prefix pav: .
53 | @prefix prov: .
54 | @prefix np: .
55 | @prefix ex: .
56 |
57 | :Head {
58 | : a np:Nanopublication ;
59 | np:hasProvenance :provenance ; np:hasPublicationInfo :pubinfo .
60 | }
61 | :provenance {
62 | :assertion prov:wasDerivedFrom .
63 | }
64 | :pubinfo {
65 | : pav:createdBy .
66 | : dc:created "2014-07-09T13:54:11+01:00"^^xsd:dateTime .
67 | }
68 |
--------------------------------------------------------------------------------
/tests/testsuite/invalid/signed/simple1-invalid-dsa.trig:
--------------------------------------------------------------------------------
1 | @prefix this: .
2 | @prefix sub: .
3 | @prefix xsd: .
4 | @prefix dc: .
5 | @prefix pav: .
6 | @prefix prov: .
7 | @prefix np: .
8 | @prefix npx: .
9 | @prefix ex: .
10 |
11 | sub:Head {
12 | this: np:hasAssertion sub:assertion ;
13 | np:hasProvenance sub:provenance ;
14 | np:hasPublicationInfo sub:pubinfo ;
15 | a np:Nanopublication .
16 | }
17 |
18 | sub:assertion {
19 | ex:mosquito ex:transmits ex:malAria .
20 | }
21 |
22 | sub:provenance {
23 | sub:assertion prov:hadPrimarySource .
24 | }
25 |
26 | sub:pubinfo {
27 | sub:signature npx:hasAlgorithm "DSA" ;
28 | npx:hasPublicKey "MIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGAEHvFRpU7ryp1gAOi2yoy2VX8jraJdwPo6ZC1idtsGVcmou89Y3KOoJmlW3VU8ZPolpVWuM+EPNmLNFmifYr+svu8AOQkilZBLdkS5BrPVxIpV0dLeaBUroof1wPsVuwEPOdNzWsEmPF1Az8qLGEdPbyn7ehWqO/lNVmW8+c4O2k=" ;
29 | npx:hasSignature "MCwCFFMlGKFn+75HC3sP6JjBNubA1yPKAhReEzogcNHOueSlRzocjB7fyU4zFw==" ;
30 | npx:hasSignatureTarget this: .
31 |
32 | this: dc:created "2014-07-24T18:05:11+01:00"^^xsd:dateTime ;
33 | pav:createdBy ;
34 | a npx:ExampleNanopub .
35 | }
36 |
--------------------------------------------------------------------------------
/tests/testsuite/invalid/signed/simple1-invalid-rsa.trig:
--------------------------------------------------------------------------------
1 | @prefix this: .
2 | @prefix sub: .
3 | @prefix xsd: .
4 | @prefix dc: .
5 | @prefix pav: .
6 | @prefix prov: .
7 | @prefix np: .
8 | @prefix npx: .
9 | @prefix ex: .
10 |
11 | sub:Head {
12 | this: np:hasAssertion sub:assertion ;
13 | np:hasProvenance sub:provenance ;
14 | np:hasPublicationInfo sub:pubinfo ;
15 | a np:Nanopublication .
16 | }
17 |
18 | sub:assertion {
19 | ex:moSquito ex:transmits ex:malaria .
20 | }
21 |
22 | sub:provenance {
23 | sub:assertion prov:hadPrimarySource .
24 | }
25 |
26 | sub:pubinfo {
27 | sub:signature npx:hasAlgorithm "RSA" ;
28 | npx:hasPublicKey "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwUtewGCpT5vIfXYE1bmf/Uqu1ojqnWdYxv+ySO80ul8Gu7m8KoyPAwuvaPj0lvPtHrg000qMmkxzKhYknEjq8v7EerxZNYp5B3/3+5ZpuWOYAs78UnQVjbHSmDdmryr4D4VvvNIiUmd0yxci47dTFUj4DvfHnGd6hVe5+goqdcwIDAQAB" ;
29 | npx:hasSignature "OC0xJTavw9h/JSZIZl/NLzEZqQk1E7XWV3o1btD1cojxf9FMtgZuMMOtnPcgydRn3gK0wbUh+ATV4sEFdG51khsrOOH7+RylqnaE9XD4L65dwPZ/PpI32/LMYsQ62rsb0ajWtXr5cKDIKaoah0U1V85XlLGhoEyzrLZCU5uqJbo=" ;
30 | npx:hasSignatureTarget this: .
31 |
32 | this: dc:created "2014-07-24T18:05:11+01:00"^^xsd:dateTime ;
33 | pav:createdBy ;
34 | a npx:ExampleNanopub .
35 | }
36 |
--------------------------------------------------------------------------------
/tests/testsuite/invalid/trusty/trusty1.trig:
--------------------------------------------------------------------------------
1 | @prefix this: .
2 | @prefix sub: .
3 | @prefix xsd: .
4 | @prefix dc: .
5 | @prefix pav: .
6 | @prefix prov: .
7 | @prefix np: .
8 | @prefix npx: .
9 |
10 | sub:Head {
11 | this: np:hasAssertion sub:assertion ;
12 | np:hasProvenance sub:provenance ;
13 | np:hasPublicationInfo sub:pubinfo ;
14 | a np:Nanopublication .
15 | }
16 |
17 | sub:assertion {
18 | sub:assertion npx:asSentence ;
19 | a npx:UnderspecifiedAssertion .
20 | }
21 |
22 | sub:provenance {
23 | sub:assertion prov:hadPrimarySource .
24 | }
25 |
26 | sub:pubinfo {
27 | this: dc:created "2014-07-29T10:13:35+01:00"^^xsd:dateTime ;
28 | pav:createdBy ;
29 | a npx:ExampleNanopub .
30 | }
31 |
--------------------------------------------------------------------------------
/tests/testsuite/transform/signed/rsa-key1/key/id_rsa:
--------------------------------------------------------------------------------
1 | MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAPdEfIdHtZYoFh6/DWorzoHpFXMjugqW+CGpe9uk4BfUq54MToi2u7fgdGGtXLg4wsJFBYETdVeS0p1uA7EPe8LhwjHPktf5c6AZbO/lYpKM59e7/Ih4mvOy4iTIe/Dv+1OgasTSK0nXAbKUm/5iJ6LOYa82JQeE/QnT5gUw2e97AgMBAAECgYBbNQnyJINYpeSy5qoeFZaQ2Ncup2kCavmQASJMvJ5ka+/51nRJfY30n3iOZxIiad19J1SGbhUEfoXtyBzYfOubF2i2GJtdF5VyjdSoU6w/gOo2/vnbH+GCHnMclrWshohOADGQU/Y8pYhIvlQqcb6xEOts9m9C9g4uwvPXqjmhoQJBAPkmSFIZwF3i2UvJlHyeXi599L0jkGTUJy/Y4IjieUx5suwvAtG47ejhgIPKK06VtW49oGPHWjWc3cJAmnV+vTMCQQD+EPTvNtLpX9QiDEJD7b8woDwmVrvH/RUosP/cXpMQd7BUVgPlpffAlFJGDlOzwwjZjy+8kc6MYevh1kWqobSZAkEAyCs+nV99ErEHnYEFoB1oU3f0oeSpxKhCF4np03AIvi1kV6bpX+9wjNJnevp5UriqvDgc3S0zx7EQ5Vkb/1vkywJBAMMw59y4tAVT+DhITsi9aTvEfzG9RPt6trzSb2Aw0K/AJJpGkyvl/JfZ2/Oyoh/jYXM0DKrFIni76mtRIajcH1ECQQCJi6aXOaRkRPmf7FYY9cRaJdR1BtZkKZbDg6ZMD1bY97cGiM9STTMeldYcCtQBtyhVCTEObI/V6/0FAvY9Zi7w
2 |
--------------------------------------------------------------------------------
/tests/testsuite/transform/signed/rsa-key1/key/id_rsa.pub:
--------------------------------------------------------------------------------
1 | MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD3RHyHR7WWKBYevw1qK86B6RVzI7oKlvghqXvbpOAX1KueDE6Itru34HRhrVy4OMLCRQWBE3VXktKdbgOxD3vC4cIxz5LX+XOgGWzv5WKSjOfXu/yIeJrzsuIkyHvw7/tToGrE0itJ1wGylJv+YieizmGvNiUHhP0J0+YFMNnvewIDAQAB
2 |
--------------------------------------------------------------------------------
/tests/testsuite/transform/signed/rsa-key1/simple1.in.trig:
--------------------------------------------------------------------------------
1 | @prefix : .
2 | @prefix xsd: .
3 | @prefix dc: .
4 | @prefix pav: .
5 | @prefix prov: .
6 | @prefix np: .
7 | @prefix npx: .
8 | @prefix ex: .
9 |
10 | :Head {
11 | : np:hasAssertion :assertion ;
12 | np:hasProvenance :provenance ;
13 | np:hasPublicationInfo :pubinfo ;
14 | a np:Nanopublication .
15 | }
16 |
17 | :assertion {
18 | ex:mosquito ex:transmits ex:malaria .
19 | }
20 |
21 | :provenance {
22 | :assertion prov:hadPrimarySource .
23 | }
24 |
25 | :pubinfo {
26 | : dc:created "2014-07-24T18:05:11+01:00"^^xsd:dateTime ;
27 | pav:createdBy ;
28 | a npx:ExampleNanopub .
29 | }
30 |
--------------------------------------------------------------------------------
/tests/testsuite/transform/signed/rsa-key1/simple1.out.code:
--------------------------------------------------------------------------------
1 | RALbDbWVnLmLqpNgOsI_AaYfLbEnlOfZy3CoRRLs9XqVk
2 |
--------------------------------------------------------------------------------
/tests/testsuite/transform/signed/rsa-key1/simple1.out.trig:
--------------------------------------------------------------------------------
1 | @prefix this: .
2 | @prefix sub: .
3 | @prefix np: .
4 | @prefix ex: .
5 | @prefix pav: .
6 | @prefix npx: .
7 | @prefix xsd: .
8 | @prefix prov: .
9 | @prefix dc: .
10 |
11 | sub:Head {
12 | this: np:hasAssertion sub:assertion;
13 | np:hasProvenance sub:provenance;
14 | np:hasPublicationInfo sub:pubinfo;
15 | a np:Nanopublication .
16 | }
17 |
18 | sub:assertion {
19 | ex:mosquito ex:transmits ex:malaria .
20 | }
21 |
22 | sub:provenance {
23 | sub:assertion prov:hadPrimarySource .
24 | }
25 |
26 | sub:pubinfo {
27 | sub:sig npx:hasAlgorithm "RSA";
28 | npx:hasPublicKey "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD3RHyHR7WWKBYevw1qK86B6RVzI7oKlvghqXvbpOAX1KueDE6Itru34HRhrVy4OMLCRQWBE3VXktKdbgOxD3vC4cIxz5LX+XOgGWzv5WKSjOfXu/yIeJrzsuIkyHvw7/tToGrE0itJ1wGylJv+YieizmGvNiUHhP0J0+YFMNnvewIDAQAB";
29 | npx:hasSignature "9Z7zk22V1SgJ+jSw4WAkK3yJ7xuoEkIPJWSLEzx0b6OgHiqiioS0DMziQYCjQA8gBWu0zlJr64tj8Ip38fKynxriznwgVtcjBSKtjnLfZEZPZrtasLKxmtrobYbnyNPBi0Geq8oQpeg9Qg5MldhI7HoiEFTaOkmZJEt0TjrOUVc=";
30 | npx:hasSignatureTarget this: .
31 |
32 | this: dc:created "2014-07-24T18:05:11+01:00"^^xsd:dateTime;
33 | pav:createdBy ;
34 | a npx:ExampleNanopub .
35 | }
36 |
--------------------------------------------------------------------------------
/tests/testsuite/transform/trusty/aida1.in.trig:
--------------------------------------------------------------------------------
1 | @prefix : .
2 | @prefix xsd: .
3 | @prefix dc: .
4 | @prefix pav: .
5 | @prefix prov: .
6 | @prefix np: .
7 | @prefix npx: .
8 | @prefix ex: .
9 |
10 | :Head {
11 | : np:hasAssertion :assertion ;
12 | np:hasProvenance :provenance ;
13 | np:hasPublicationInfo :pubinfo ;
14 | a np:Nanopublication .
15 | }
16 |
17 | :assertion {
18 | :assertion npx:asSentence ;
19 | a npx:UnderspecifiedAssertion .
20 | }
21 |
22 | :provenance {
23 | :assertion prov:hadPrimarySource .
24 | }
25 |
26 | :pubinfo {
27 | : dc:created "2014-07-29T10:13:35+01:00"^^xsd:dateTime ;
28 | pav:createdBy ;
29 | a npx:ExampleNanopub .
30 | }
31 |
--------------------------------------------------------------------------------
/tests/testsuite/transform/trusty/aida1.out.code:
--------------------------------------------------------------------------------
1 | RAPpJU5UOB4pavfWyk7FE3WQiam5yBpmIlviAQWtBSC4M
2 |
--------------------------------------------------------------------------------
/tests/testsuite/transform/trusty/aida1.out.trig:
--------------------------------------------------------------------------------
1 | @prefix this: .
2 | @prefix sub: .
3 | @prefix xsd: .
4 | @prefix dc: .
5 | @prefix pav: .
6 | @prefix prov: .
7 | @prefix np: .
8 | @prefix npx: .
9 |
10 | sub:Head {
11 | this: np:hasAssertion sub:assertion;
12 | np:hasProvenance sub:provenance;
13 | np:hasPublicationInfo sub:pubinfo;
14 | a np:Nanopublication .
15 | }
16 |
17 | sub:assertion {
18 | sub:assertion npx:asSentence ;
19 | a npx:UnderspecifiedAssertion .
20 | }
21 |
22 | sub:provenance {
23 | sub:assertion prov:hadPrimarySource .
24 | }
25 |
26 | sub:pubinfo {
27 | this: dc:created "2014-07-29T10:13:35+01:00"^^xsd:dateTime;
28 | pav:createdBy ;
29 | a npx:ExampleNanopub .
30 | }
31 |
--------------------------------------------------------------------------------
/tests/testsuite/transform/trusty/simple1.in.trig:
--------------------------------------------------------------------------------
1 | @prefix : .
2 | @prefix xsd: .
3 | @prefix dc: .
4 | @prefix pav: .
5 | @prefix prov: .
6 | @prefix np: .
7 | @prefix npx: .
8 | @prefix ex: .
9 |
10 | :Head {
11 | : np:hasAssertion :assertion ;
12 | np:hasProvenance :provenance ;
13 | np:hasPublicationInfo :pubinfo ;
14 | a np:Nanopublication .
15 | }
16 |
17 | :assertion {
18 | ex:mosquito ex:transmits ex:malaria .
19 | }
20 |
21 | :provenance {
22 | :assertion prov:hadPrimarySource .
23 | }
24 |
25 | :pubinfo {
26 | : dc:created "2014-07-24T18:05:11+01:00"^^xsd:dateTime ;
27 | pav:createdBy ;
28 | a npx:ExampleNanopub .
29 | }
30 |
--------------------------------------------------------------------------------
/tests/testsuite/transform/trusty/simple1.out.code:
--------------------------------------------------------------------------------
1 | RAtAU6U_xKTH016Eoiu11SswQkBu1elB_3_BoDJWH3arA
2 |
--------------------------------------------------------------------------------
/tests/testsuite/transform/trusty/simple1.out.trig:
--------------------------------------------------------------------------------
1 | @prefix this: .
2 | @prefix sub: .
3 | @prefix xsd: .
4 | @prefix dc: .
5 | @prefix pav: .
6 | @prefix prov: .
7 | @prefix np: .
8 | @prefix npx: .
9 | @prefix ex: .
10 |
11 | sub:Head {
12 | this: np:hasAssertion sub:assertion;
13 | np:hasProvenance sub:provenance;
14 | np:hasPublicationInfo sub:pubinfo;
15 | a np:Nanopublication .
16 | }
17 |
18 | sub:assertion {
19 | ex:mosquito ex:transmits ex:malaria .
20 | }
21 |
22 | sub:provenance {
23 | sub:assertion prov:hadPrimarySource .
24 | }
25 |
26 | sub:pubinfo {
27 | this: dc:created "2014-07-24T18:05:11+01:00"^^xsd:dateTime;
28 | pav:createdBy ;
29 | a npx:ExampleNanopub .
30 | }
31 |
--------------------------------------------------------------------------------
/tests/testsuite/valid/plain/aida1.trig:
--------------------------------------------------------------------------------
1 | @prefix : .
2 | @prefix xsd: .
3 | @prefix dc: .
4 | @prefix pav: .
5 | @prefix prov: .
6 | @prefix np: .
7 | @prefix npx: .
8 | @prefix ex: .
9 |
10 | :Head {
11 | : np:hasAssertion :assertion ;
12 | np:hasProvenance :provenance ;
13 | np:hasPublicationInfo :pubinfo ;
14 | a np:Nanopublication .
15 | }
16 |
17 | :assertion {
18 | :assertion npx:asSentence ;
19 | a npx:UnderspecifiedAssertion .
20 | }
21 |
22 | :provenance {
23 | :assertion prov:hadPrimarySource .
24 | }
25 |
26 | :pubinfo {
27 | : dc:created "2014-07-29T10:13:35+01:00"^^xsd:dateTime ;
28 | pav:createdBy ;
29 | a npx:ExampleNanopub .
30 | }
31 |
--------------------------------------------------------------------------------
/tests/testsuite/valid/plain/proteinatlas-16-1.trig:
--------------------------------------------------------------------------------
1 | @prefix : .
2 | @prefix hpa: .
3 | @prefix hpas: .
4 | @prefix tissue: .
5 | @prefix xsd: .
6 | @prefix rdfs: .
7 | @prefix np: .
8 | @prefix prov: .
9 | @prefix prv: .
10 | @prefix pav: .
11 | @prefix dcterms: .
12 | @prefix sio: .
13 | @prefix owl: .
14 | @prefix eco: .
15 | @prefix msh: .
16 | @prefix lld: .
17 | @prefix bfo: .
18 | @prefix bao: .
19 | @prefix nif: .
20 | @prefix wi: .
21 | @prefix wp: .
22 | @prefix nih: .
23 |
24 | :ENSG00000000003_ih_TS_0030_head {
25 | :ENSG00000000003_ih_TS_0030 a np:Nanopublication .
26 | :ENSG00000000003_ih_TS_0030_assertion a np:Assertion ;
27 | rdfs:comment "IHC shows Not_detected protein expression of ENSG00000000003 in lung(macrophages) with a Approved evidence/reliability"^^xsd:string .
28 | :ENSG00000000003_ih_TS_0030_provenance a np:Provenance .
29 | :ENSG00000000003_ih_TS_0030_publicationInfo a np:PublicationInfo .
30 | :ENSG00000000003_ih_TS_0030 np:hasAssertion :ENSG00000000003_ih_TS_0030_assertion ;
31 | np:hasProvenance :ENSG00000000003_ih_TS_0030_provenance ;
32 | np:hasPublicationInfo :ENSG00000000003_ih_TS_0030_publicationInfo .
33 | }
34 | :ENSG00000000003_ih_TS_0030_assertion {
35 | hpa:ENSG00000000003 bfo:BFO_0000066 hpa:TS-0030 ; # Occurs in
36 | nif:nlx_qual_1010003 "Not_detected"^^xsd:string . # Expression level
37 | hpa:TS-0030 a tissue:TS-0030 .
38 | }
39 | :ENSG00000000003_ih_TS_0030_provenance {
40 | :ENSG00000000003_ih_TS_0030_assertion a :IHCEvidence .
41 | :ENSG00000000003_ih_TS_0030 prov:wasGeneratedBy :ConclusionalEvidence ;
42 | prov:wasDerivedFrom :IHCAssay ;
43 | prov:wasGeneratedBy :ManualCuration ;
44 | prv:usedData hpas:HPA004109 ;
45 | prv:usedData hpa:ENSG00000000003 ;
46 | wi:evidence "Approved"^^xsd:string .
47 | }
48 | :ENSG00000000003_ih_TS_0030_publicationInfo {
49 | :ENSG00000000003_ih_TS_0030 prv:usedData :HumanProteinAtlas ;
50 | pav:authoredBy "Human Protein Atlas project";
51 | pav:createdBy "Kalle von Feilitzen";
52 | dcterms:contributor ;
53 | dcterms:contributor ;
54 | dcterms:contributor ;
55 | dcterms:contributor ;
56 | dcterms:contributor ;
57 | dcterms:rights ;
58 | dcterms:rightsHolder .
59 | }
60 |
--------------------------------------------------------------------------------
/tests/testsuite/valid/plain/simple1.nq:
--------------------------------------------------------------------------------
1 | .
2 | .
3 | .
4 | .
5 | .
6 | .
7 | "2014-07-24T18:05:11+01:00"^^ .
8 | .
9 | .
10 |
--------------------------------------------------------------------------------
/tests/testsuite/valid/plain/simple1.trig:
--------------------------------------------------------------------------------
1 | @prefix : .
2 | @prefix xsd: .
3 | @prefix dc: .
4 | @prefix pav: .
5 | @prefix prov: .
6 | @prefix np: .
7 | @prefix npx: .
8 | @prefix ex: .
9 |
10 | :Head {
11 | : np:hasAssertion :assertion ;
12 | np:hasProvenance :provenance ;
13 | np:hasPublicationInfo :pubinfo ;
14 | a np:Nanopublication .
15 | }
16 |
17 | :assertion {
18 | ex:mosquito ex:transmits ex:malaria .
19 | }
20 |
21 | :provenance {
22 | :assertion prov:hadPrimarySource .
23 | }
24 |
25 | :pubinfo {
26 | : dc:created "2014-07-24T18:05:11+01:00"^^xsd:dateTime ;
27 | pav:createdBy ;
28 | a npx:ExampleNanopub .
29 | }
30 |
--------------------------------------------------------------------------------
/tests/testsuite/valid/plain/simple1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | http://example.org/nanopub-validator-example/Head
5 |
6 | http://example.org/nanopub-validator-example/
7 | http://www.nanopub.org/nschema#hasAssertion
8 | http://example.org/nanopub-validator-example/assertion
9 |
10 |
11 | http://example.org/nanopub-validator-example/
12 | http://www.nanopub.org/nschema#hasProvenance
13 | http://example.org/nanopub-validator-example/provenance
14 |
15 |
16 | http://example.org/nanopub-validator-example/
17 | http://www.nanopub.org/nschema#hasPublicationInfo
18 | http://example.org/nanopub-validator-example/pubinfo
19 |
20 |
21 | http://example.org/nanopub-validator-example/
22 | http://www.w3.org/1999/02/22-rdf-syntax-ns#type
23 | http://www.nanopub.org/nschema#Nanopublication
24 |
25 |
26 |
27 | http://example.org/nanopub-validator-example/assertion
28 |
29 | http://example.org/mosquito
30 | http://example.org/transmits
31 | http://example.org/malaria
32 |
33 |
34 |
35 | http://example.org/nanopub-validator-example/provenance
36 |
37 | http://example.org/nanopub-validator-example/assertion
38 | http://www.w3.org/ns/prov#hadPrimarySource
39 | http://dx.doi.org/10.3233/ISU-2010-0613
40 |
41 |
42 |
43 | http://example.org/nanopub-validator-example/pubinfo
44 |
45 | http://example.org/nanopub-validator-example/
46 | http://purl.org/dc/terms/created
47 | 2014-07-24T18:05:11+01:00
48 |
49 |
50 | http://example.org/nanopub-validator-example/
51 | http://purl.org/pav/createdBy
52 | http://orcid.org/0000-0002-1267-0234
53 |
54 |
55 | http://example.org/nanopub-validator-example/
56 | http://www.w3.org/1999/02/22-rdf-syntax-ns#type
57 | http://purl.org/nanopub/x/ExampleNanopub
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/tests/testsuite/valid/signed/Darwin-Core-schema-resource.trig:
--------------------------------------------------------------------------------
1 | @prefix this: .
2 | @prefix sub: .
3 | @prefix xsd: .
4 | @prefix rdfs: .
5 | @prefix dct: .
6 | @prefix prov: .
7 | @prefix np: .
8 | @prefix orcid: .
9 | @prefix nt: .
10 | @prefix npx: .
11 | @prefix fip: .
12 |
13 | sub:Head {
14 | this: np:hasAssertion sub:assertion;
15 | np:hasProvenance sub:provenance;
16 | np:hasPublicationInfo sub:pubinfo;
17 | a np:Nanopublication .
18 | }
19 |
20 | sub:assertion {
21 | sub:DwC a fip:Available-FAIR-Enabling-Resource, fip:Data-schema, fip:FAIR-Enabling-Resource;
22 | rdfs:comment "Darwin Core schema";
23 | rdfs:label "Darwin Core" .
24 | }
25 |
26 | sub:provenance {
27 | sub:assertion prov:wasAttributedTo orcid:0000-0001-8050-0299 .
28 | }
29 |
30 | sub:pubinfo {
31 | sub:sig npx:hasAlgorithm "RSA";
32 | npx:hasPublicKey "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCK0bP9YbOpX9gkjJ2pgsWHTSa7bNQUGoh1LmmALJZyElQjEswZH0UgweLiB0qO74y9XGnbjFUDJiQGeVML6XugTWR29ujRUk9vOU0YKe2ZXTjSm87bMD4S7w2kTIKg1EFu27TKmJwR1l4RoGJpB0YMzR/zris//sbDhpKYPUaA0QIDAQAB";
33 | npx:hasSignature "Qi7p95ignv+MnRvc/pDFxYYDUeFkrNloQEk81INsr+un26CS/mNnoUXoEquiu2R5ObZ8DTywzPkFQUqO4tLIQN/qvVmrGSvoreNBO14Uwh2X2Z9DJIPgUr/t0JvDwbj16oufAi07oUVRZJ3F/W1l5hlfu6JR7DSJn4cAT3KJgB0=";
34 | npx:hasSignatureTarget this: .
35 |
36 | this: dct:created "2020-10-05T10:49:41.102+02:00"^^xsd:dateTime;
37 | dct:creator orcid:0000-0001-8050-0299;
38 | npx:introduces sub:DwC;
39 | nt:wasCreatedFromProvenanceTemplate ;
40 | nt:wasCreatedFromPubinfoTemplate ;
41 | nt:wasCreatedFromTemplate .
42 | }
43 |
--------------------------------------------------------------------------------
/tests/testsuite/valid/signed/EduSocDL-community.trig:
--------------------------------------------------------------------------------
1 | @prefix this: .
2 | @prefix sub: .
3 | @prefix xsd: .
4 | @prefix rdfs: .
5 | @prefix dct: .
6 | @prefix prov: .
7 | @prefix np: .
8 | @prefix orcid: .
9 | @prefix nt: .
10 | @prefix npx: .
11 | @prefix fip: .
12 |
13 | sub:Head {
14 | this: np:hasAssertion sub:assertion;
15 | np:hasProvenance sub:provenance;
16 | np:hasPublicationInfo sub:pubinfo;
17 | a np:Nanopublication .
18 | }
19 |
20 | sub:assertion {
21 | sub:EduSocDL a fip:FAIR-Implementation-Community;
22 | rdfs:comment "New research project trying to bring data on COVID-19 together from different discipline";
23 | rdfs:label "Data Linking across Social and Educational Sciences on COVID-19";
24 | rdfs:seeAlso ;
25 | fip:has-research-domain , ,
26 | .
27 | }
28 |
29 | sub:provenance {
30 | sub:assertion prov:wasAttributedTo orcid:0000-0003-3517-8071 .
31 | }
32 |
33 | sub:pubinfo {
34 | sub:sig npx:hasAlgorithm "RSA";
35 | npx:hasPublicKey "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCK4NfUi+AdFS8l/WeyiKQmCyFyjrjfGnpHvUvdGUlkg2+FkOY3+31U4a4SdeLUdhf4hnxL8kQOjD8BuggdBkuwUoMA0RXPv+RblmlF5INhXDJvxTqeUMLj1EVuOtotpl//NVFZ3BE0zeuscT35szmX4L+2m14Z/PqreP2lMzbj3wIDAQAB";
36 | npx:hasSignature "bjcX/F0FWKJldeC1/8UuLDiiqw+zumSJTnQ3Pc2QZK1f6hsY9qteB4y7fGOoh2sD558pE6JFtjozp3UsuFkvzZB7KUCTu2HRu5aek3wrQtUpYPYEiW2BJNyqlkVwF7Hkm8Cw5GfSUi1cIaE817KaOWS9DiuzJ9xnPqLYNm/NZwE=";
37 | npx:hasSignatureTarget this: .
38 |
39 | this: dct:created "2020-10-05T16:20:03.409+02:00"^^xsd:dateTime;
40 | dct:creator orcid:0000-0003-3517-8071;
41 | npx:introduces sub:EduSocDL;
42 | nt:wasCreatedFromProvenanceTemplate ;
43 | nt:wasCreatedFromPubinfoTemplate ;
44 | nt:wasCreatedFromTemplate .
45 | }
46 |
--------------------------------------------------------------------------------
/tests/testsuite/valid/signed/nanobench_hasRead-template-v5.trig:
--------------------------------------------------------------------------------
1 | @prefix this: .
2 | @prefix sub: .
3 | @prefix xsd: .
4 | @prefix rdf: .
5 | @prefix rdfs: .
6 | @prefix dct: .
7 | @prefix pav: .
8 | @prefix prov: .
9 | @prefix np: .
10 | @prefix orcid: .
11 | @prefix nt: .
12 | @prefix pc: .
13 | @prefix npx: .
14 |
15 | sub:Head {
16 | this: np:hasAssertion sub:assertion;
17 | np:hasProvenance sub:provenance;
18 | np:hasPublicationInfo sub:pubinfo;
19 | a np:Nanopublication .
20 | }
21 |
22 | sub:assertion {
23 | sub:assertion a nt:AssertionTemplate;
24 | rdfs:label "Announcing a paper that I have read";
25 | nt:hasStatement sub:st1, sub:st2 .
26 |
27 | sub:comment a nt:LiteralPlaceholder;
28 | rdfs:label "comment text" .
29 |
30 | sub:paper a nt:UriPlaceholder;
31 | rdfs:label "DOI for the paper starting with '10.'";
32 | nt:hasPrefix "https://doi.org/";
33 | nt:hasPrefixLabel "the paper with DOI";
34 | nt:hasRegex "10.(\\d)+/(\\S)+" .
35 |
36 | sub:st1 rdf:object sub:paper;
37 | rdf:predicate pc:hasRead;
38 | rdf:subject nt:CREATOR;
39 | a rdf:Statement;
40 | nt:statementOrder 1 .
41 |
42 | sub:st2 rdf:object sub:comment;
43 | rdf:predicate rdfs:comment;
44 | rdf:subject sub:paper;
45 | a nt:OptionalStatement;
46 | nt:statementOrder 2 .
47 |
48 | pc:hasRead rdfs:label "have read the paper" .
49 |
50 | rdfs:comment rdfs:label "has my comment" .
51 | }
52 |
53 | sub:provenance {
54 | sub:assertion prov:wasAttributedTo orcid:0000-0002-1267-0234 .
55 | }
56 |
57 | sub:pubinfo {
58 | sub:sig npx:hasAlgorithm "RSA";
59 | npx:hasPublicKey "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwUtewGCpT5vIfXYE1bmf/Uqu1ojqnWdYxv+ySO80ul8Gu7m8KoyPAwuvaPj0lvPtHrg000qMmkxzKhYknEjq8v7EerxZNYp5B3/3+5ZpuWOYAs78UnQVjbHSmDdmryr4D4VvvNIiUmd0yxci47dTFUj4DvfHnGd6hVe5+goqdcwIDAQAB";
60 | npx:hasSignature "GJs6X2F9V9bRnL+DGujqWDUwlNVFM2KAGJQGjw2bUjaIn/irTQRGwGmaBJ8YEzIOQxlZqTbwCSxnWx5J8tqgg2QuPRvyLw+IKR20IdjWeupNkLeSrJqHOhcj6Fn7iPlxgHkduzHSt2mzBJ/BFt9qSZsZWFjrkJIBqwoRMsSrVQ8=";
61 | npx:hasSignatureTarget this: .
62 |
63 | this: dct:created "2020-04-27T14:57:06.343+02:00"^^xsd:dateTime;
64 | npx:supersedes ,
65 | ;
66 | pav:createdBy orcid:0000-0002-1267-0234 .
67 | }
68 |
--------------------------------------------------------------------------------
/tests/testsuite/valid/signed/nanobench_new-individual-template-v3.trig:
--------------------------------------------------------------------------------
1 | @prefix this: .
2 | @prefix sub: .
3 | @prefix xsd: .
4 | @prefix rdf: .
5 | @prefix rdfs: .
6 | @prefix owl: .
7 | @prefix dct: .
8 | @prefix prov: .
9 | @prefix np: .
10 | @prefix orcid: .
11 | @prefix nt: .
12 | @prefix npx: .
13 |
14 | sub:Head {
15 | this: np:hasAssertion sub:assertion;
16 | np:hasProvenance sub:provenance;
17 | np:hasPublicationInfo sub:pubinfo;
18 | a np:Nanopublication .
19 | }
20 |
21 | sub:assertion {
22 | dct:description rdfs:label "can be described as follows:" .
23 |
24 | sub:assertion a nt:AssertionTemplate;
25 | rdfs:label "Defining a new individual";
26 | nt:hasStatement sub:st0, sub:st1, sub:st2, sub:st3 .
27 |
28 | sub:class a nt:GuidedChoicePlaceholder;
29 | rdfs:label "the URI of the class this individual belongs to";
30 | nt:possibleValue owl:Thing;
31 | nt:possibleValuesFromApi "http://purl.org/nanopub/api/find_signed_things?type=http%3A%2F%2Fwww.w3.org%2F2002%2F07%2Fowl%23Class&searchterm=",
32 | "https://www.wikidata.org/w/api.php?action=wbsearchentities&language=en&format=json&limit=5&search=" .
33 |
34 | sub:description a nt:LiteralPlaceholder;
35 | rdfs:label "description of the individual" .
36 |
37 | sub:individual a nt:IntroducedResource, nt:LocalResource, nt:UriPlaceholder;
38 | rdfs:label "short name, used as URI suffix" .
39 |
40 | sub:name a nt:LiteralPlaceholder;
41 | rdfs:label "the name of the individual" .
42 |
43 | sub:seeAlsoLink a nt:UriPlaceholder;
44 | rdfs:label "a URL where more information about this individual can be found" .
45 |
46 | sub:st0 rdf:object sub:class;
47 | rdf:predicate rdf:type;
48 | rdf:subject sub:individual;
49 | a nt:Statement;
50 | nt:statementOrder 0 .
51 |
52 | sub:st1 rdf:object sub:name;
53 | rdf:predicate rdfs:label;
54 | rdf:subject sub:individual;
55 | a rdf:Statement;
56 | nt:statementOrder 1 .
57 |
58 | sub:st2 rdf:object sub:description;
59 | rdf:predicate dct:description;
60 | rdf:subject sub:individual;
61 | a rdf:Statement;
62 | nt:statementOrder 2 .
63 |
64 | sub:st3 rdf:object sub:seeAlsoLink;
65 | rdf:predicate rdfs:seeAlso;
66 | rdf:subject sub:individual;
67 | a nt:OptionalStatement;
68 | nt:statementOrder 3 .
69 |
70 | rdf:type rdfs:label "is a" .
71 |
72 | rdfs:label rdfs:label "is called" .
73 |
74 | rdfs:seeAlso rdfs:label "is further explained at" .
75 |
76 | owl:Thing rdfs:label "thing" .
77 | }
78 |
79 | sub:provenance {
80 | sub:assertion prov:wasAttributedTo orcid:0000-0002-1267-0234 .
81 | }
82 |
83 | sub:pubinfo {
84 | sub:sig npx:hasAlgorithm "RSA";
85 | npx:hasPublicKey "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwUtewGCpT5vIfXYE1bmf/Uqu1ojqnWdYxv+ySO80ul8Gu7m8KoyPAwuvaPj0lvPtHrg000qMmkxzKhYknEjq8v7EerxZNYp5B3/3+5ZpuWOYAs78UnQVjbHSmDdmryr4D4VvvNIiUmd0yxci47dTFUj4DvfHnGd6hVe5+goqdcwIDAQAB";
86 | npx:hasSignature "bTApJ68j73RNNXIaN/itDZCkVQfJ0WQ3s3Y2tfFc0L2QrArOj/6kaPx5NnQg63yTrUqSAJhxC+Vrg0d3eckNl9GUNXpGQoj3mvoCvndA7U/MHvitGw0ji/oU7uijY9mvYe1xx2Vim+tiPugyi1L6IJkr8wiQ/22trlXhtuwWIyw=";
87 | npx:hasSignatureTarget this: .
88 |
89 | this: dct:created "2020-07-08T13:00:20.583+02:00"^^xsd:dateTime;
90 | dct:creator orcid:0000-0002-1267-0234;
91 | npx:supersedes .
92 | }
93 |
--------------------------------------------------------------------------------
/tests/testsuite/valid/signed/nanobench_somebodyElse-prtemplate.trig:
--------------------------------------------------------------------------------
1 | @prefix this: .
2 | @prefix sub: .
3 | @prefix xsd: .
4 | @prefix rdf: .
5 | @prefix rdfs: .
6 | @prefix dct: .
7 | @prefix pav: .
8 | @prefix prov: .
9 | @prefix np: .
10 | @prefix orcid: .
11 | @prefix nt: .
12 | @prefix npx: .
13 |
14 | sub:Head {
15 | this: np:hasAssertion sub:assertion;
16 | np:hasProvenance sub:provenance;
17 | np:hasPublicationInfo sub:pubinfo;
18 | a np:Nanopublication .
19 | }
20 |
21 | sub:assertion {
22 | sub:assertion a nt:ProvenanceTemplate;
23 | rdfs:label "Attributed to somebody else";
24 | nt:hasStatement sub:st1 .
25 |
26 | sub:somebodyElse a nt:UriPlaceholder;
27 | rdfs:label "ORCID identifier of the person to be attributed";
28 | nt:hasPrefix "https://orcid.org/";
29 | nt:hasRegex "[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{3}[0-9X]" .
30 |
31 | sub:st1 rdf:object sub:somebodyElse;
32 | rdf:predicate prov:wasAttributedTo;
33 | rdf:subject nt:ASSERTION;
34 | a rdf:Statement .
35 |
36 | prov:wasAttributedTo rdfs:label "is attributed to" .
37 | }
38 |
39 | sub:provenance {
40 | sub:assertion prov:wasAttributedTo orcid:0000-0002-1267-0234 .
41 | }
42 |
43 | sub:pubinfo {
44 | sub:sig npx:hasAlgorithm "RSA";
45 | npx:hasPublicKey "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwUtewGCpT5vIfXYE1bmf/Uqu1ojqnWdYxv+ySO80ul8Gu7m8KoyPAwuvaPj0lvPtHrg000qMmkxzKhYknEjq8v7EerxZNYp5B3/3+5ZpuWOYAs78UnQVjbHSmDdmryr4D4VvvNIiUmd0yxci47dTFUj4DvfHnGd6hVe5+goqdcwIDAQAB";
46 | npx:hasSignature "pHlUZFzESjBcAFEQeyDN5qagrzloaWEAvmKr7a6UIP7w7iJVDqR7ERe1GQWY+1MXjvWIeIpofF0Q1wQW+XVubxHz/+DgAJtNfTVnDlrv2kTyR9JapNUYGuPuvixJ9T6lNj8kf9vXVtDtJPKYsttaQJrnMSz5Ww8FDVa3xXMXBgA=";
47 | npx:hasSignatureTarget this: .
48 |
49 | this: dct:created "2020-07-07T20:13:18.606+02:00"^^xsd:dateTime;
50 | pav:createdBy orcid:0000-0002-1267-0234 .
51 | }
52 |
--------------------------------------------------------------------------------
/tests/testsuite/valid/signed/physician-suicide-1.trig:
--------------------------------------------------------------------------------
1 | @prefix this: .
2 | @prefix sub: .
3 | @prefix xsd: .
4 | @prefix dct: .
5 | @prefix prov: .
6 | @prefix np: .
7 | @prefix orcid: .
8 | @prefix nt: .
9 | @prefix fabio: .
10 | @prefix sio: .
11 | @prefix npx: .
12 |
13 | sub:Head {
14 | this: np:hasAssertion sub:assertion;
15 | np:hasProvenance sub:provenance;
16 | np:hasPublicationInfo sub:pubinfo;
17 | a np:Nanopublication .
18 | }
19 |
20 | sub:assertion {
21 | sub:local dct:creator "McGuire, T.; Moutier, C.; Downs, N.; Zisook, S.";
22 | dct:date "2013";
23 | dct:identifier ;
24 | dct:title "In response to \"Details on suicide among US physicians: data from the National Violent Death Reporting System\"";
25 | dct:type fabio:PositionPaper;
26 | sio:SIO_000277 ,
27 | ;
28 | prov:quotedText "finally as an acknowledgement of the significant rate of 300 to 400 annual physician suicides in the United States" .
29 | }
30 |
31 | sub:provenance {
32 | sub:assertion prov:wasAttributedTo orcid:0000-0002-6007-4023 .
33 | }
34 |
35 | sub:pubinfo {
36 | sub:sig npx:hasAlgorithm "RSA";
37 | npx:hasPublicKey "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCk/t11RFdsK8IUlbD7CznUrl1IYZtmFhTuGCtzFASFh3p0KsIDEAJtmYJ0CRWUlolT9XPht31Rh0iKGsJpr1PP1H/bcnV0ogspLq5JQj7LNoldB28Mz0/TDGN/YUYVvJjomkEEXHFnKR5vPRYb8gTMifFaTWYYv6JIYVPWJJ+4YwIDAQAB";
38 | npx:hasSignature "I3xNAfKMtDofyvHmfbw/SZhGNhBoBgmlRySf34uVutbnINtvjmJr7IYNed0VERhHmPeFAsohAysf3e0wHgcKkO+6aNkMuJaXTjiagUvTdJr4l8UWB/hR2536PTI4IlxiKiBiP8jHCT6cYFS3NWTKydDQ71/960qwhvRbhGfuByA=";
39 | npx:hasSignatureTarget this: .
40 |
41 | this: dct:created "2020-04-30T00:07:02.805+02:00"^^xsd:dateTime;
42 | dct:creator orcid:0000-0002-6007-4023;
43 | nt:wasCreatedFromTemplate .
44 | }
45 |
--------------------------------------------------------------------------------
/tests/testsuite/valid/signed/python-step-1.trig:
--------------------------------------------------------------------------------
1 | @prefix this: .
2 | @prefix sub: .
3 | @prefix bpmn: .
4 | @prefix np: .
5 | @prefix npx: .
6 | @prefix ns1: .
7 | @prefix pplan: .
8 | @prefix prov: .
9 | @prefix rdfs: .
10 | @prefix xsd: .
11 |
12 | sub:Head {
13 | this: np:hasAssertion sub:assertion;
14 | np:hasProvenance sub:provenance;
15 | np:hasPublicationInfo sub:pubInfo;
16 | a np:Nanopublication .
17 | }
18 |
19 | sub:assertion {
20 | sub:a a "int", pplan:Variable .
21 |
22 | sub:add_output1 a "int", pplan:Variable .
23 |
24 | sub:b a "int", pplan:Variable .
25 |
26 | sub:step ns1:description """@mark_as_fairstep(label='add integers', is_script_task=True)
27 | def add(a: int, b: int) -> int:
28 | \"\"\"
29 | Computational step adding two ints together.
30 | \"\"\"
31 | return a + b
32 | """;
33 | pplan:hasInputVar sub:a, sub:b;
34 | pplan:hasOutputVar sub:add_output1;
35 | a bpmn:ScriptTask, pplan:Step;
36 | rdfs:label "add integers" .
37 | }
38 |
39 | sub:provenance {
40 | sub:assertion prov:generatedAtTime "2020-12-29T16:54:20.582254"^^xsd:dateTime .
41 | }
42 |
43 | sub:pubInfo {
44 | sub:sig npx:hasAlgorithm "RSA";
45 | npx:hasPublicKey "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHcBtjfkmhqvHAg/vG73ky2txQkMk+QSrN6i+DvOGEXhv0g4hf89gqfg0gYIn8pHykxnrEyk6pC+3rcYVxqjsQ6l7XN/b2Q7FKKOJxt/qpLmrIe4/XNxVBeceTIdxrRy9r4dVBI4o5BzKFiNSM6PPToWtOoHR7obxL8gfRPfcXWQIDAQAB";
46 | npx:hasSignature "mpQaGvS/Z0bBgyEaaTEzP9xbSMUF5bDgMLmahBSM9WYX7tWFmv5cmowobNQYL4gTMLn6fc3eNZeqIY95yGWFcBJpqrnZsl/HCUuEmxYI/tqruDYa5gJXv3tJQuOJsNFDe/Bss2dkSU+/htsKpqbVL5pWrlH9U+7diHi9ou17kCU=";
47 | npx:hasSignatureTarget this: .
48 |
49 | this: npx:introduces sub:step;
50 | prov:generatedAtTime "2020-12-29T16:54:20.582254"^^xsd:dateTime;
51 | prov:wasAttributedTo .
52 | }
53 |
--------------------------------------------------------------------------------
/tests/testsuite/valid/signed/simple1-signed-dsa.trig:
--------------------------------------------------------------------------------
1 | @prefix this: .
2 | @prefix sub: .
3 | @prefix xsd: .
4 | @prefix dc: .
5 | @prefix pav: .
6 | @prefix prov: .
7 | @prefix np: .
8 | @prefix npx: .
9 | @prefix ex: .
10 |
11 | sub:Head {
12 | this: np:hasAssertion sub:assertion ;
13 | np:hasProvenance sub:provenance ;
14 | np:hasPublicationInfo sub:pubinfo ;
15 | a np:Nanopublication .
16 | }
17 |
18 | sub:assertion {
19 | ex:mosquito ex:transmits ex:malaria .
20 | }
21 |
22 | sub:provenance {
23 | sub:assertion prov:hadPrimarySource .
24 | }
25 |
26 | sub:pubinfo {
27 | sub:signature npx:hasAlgorithm "DSA" ;
28 | npx:hasPublicKey "MIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGAEHvFRpU7ryp1gAOi2yoy2VX8jraJdwPo6ZC1idtsGVcmou89Y3KOoJmlW3VU8ZPolpVWuM+EPNmLNFmifYr+svu8AOQkilZBLdkS5BrPVxIpV0dLeaBUroof1wPsVuwEPOdNzWsEmPF1Az8qLGEdPbyn7ehWqO/lNVmW8+c4O2k=" ;
29 | npx:hasSignature "MCwCFFMlGKFn+75HC3sP6JjBNubA1yPKAhReEzogcNHOueSlRzocjB7fyU4zFw==" ;
30 | npx:hasSignatureTarget this: .
31 |
32 | this: dc:created "2014-07-24T18:05:11+01:00"^^xsd:dateTime ;
33 | pav:createdBy ;
34 | a npx:ExampleNanopub .
35 | }
36 |
--------------------------------------------------------------------------------
/tests/testsuite/valid/signed/simple1-signed-rsa.trig:
--------------------------------------------------------------------------------
1 | @prefix this: .
2 | @prefix sub: .
3 | @prefix xsd: .
4 | @prefix dc: .
5 | @prefix pav: .
6 | @prefix prov: .
7 | @prefix np: .
8 | @prefix npx: .
9 | @prefix ex: .
10 |
11 | sub:Head {
12 | this: np:hasAssertion sub:assertion ;
13 | np:hasProvenance sub:provenance ;
14 | np:hasPublicationInfo sub:pubinfo ;
15 | a np:Nanopublication .
16 | }
17 |
18 | sub:assertion {
19 | ex:mosquito ex:transmits ex:malaria .
20 | }
21 |
22 | sub:provenance {
23 | sub:assertion prov:hadPrimarySource .
24 | }
25 |
26 | sub:pubinfo {
27 | sub:signature npx:hasAlgorithm "RSA" ;
28 | npx:hasPublicKey "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwUtewGCpT5vIfXYE1bmf/Uqu1ojqnWdYxv+ySO80ul8Gu7m8KoyPAwuvaPj0lvPtHrg000qMmkxzKhYknEjq8v7EerxZNYp5B3/3+5ZpuWOYAs78UnQVjbHSmDdmryr4D4VvvNIiUmd0yxci47dTFUj4DvfHnGd6hVe5+goqdcwIDAQAB" ;
29 | npx:hasSignature "OC0xJTavw9h/JSZIZl/NLzEZqQk1E7XWV3o1btD1cojxf9FMtgZuMMOtnPcgydRn3gK0wbUh+ATV4sEFdG51khsrOOH7+RylqnaE9XD4L65dwPZ/PpI32/LMYsQ62rsb0ajWtXr5cKDIKaoah0U1V85XlLGhoEyzrLZCU5uqJbo=" ;
30 | npx:hasSignatureTarget this: .
31 |
32 | this: dc:created "2014-07-24T18:05:11+01:00"^^xsd:dateTime ;
33 | pav:createdBy ;
34 | a npx:ExampleNanopub .
35 | }
36 |
--------------------------------------------------------------------------------
/tests/testsuite/valid/signed/workflow-1.trig:
--------------------------------------------------------------------------------
1 | @prefix this: .
2 | @prefix sub: .
3 | @prefix dcterms: .
4 | @prefix np: .
5 | @prefix npx: .
6 | @prefix ns1: .
7 | @prefix ns2: .
8 | @prefix ns3: