├── examples ├── __init__.py ├── tests │ ├── __init__.py │ └── test_examples.py ├── simple_example.py ├── simple_example_influence.py ├── horsemeat_example.py ├── bundle_example.py ├── simple_example_with_neo4j.py ├── merge_example.py ├── simple_example_with_neo4j_graph.svg ├── merge_fail_example.py ├── file_buffer_example.py ├── complex_example_with_neo4j.py └── file_buffer_example_primer.json ├── hound.yml ├── provdbconnector ├── exceptions │ ├── __init__.py │ ├── provapi.py │ ├── utils.py │ └── database.py ├── utils │ ├── __init__.py │ ├── validator.py │ └── converter.py ├── db_adapters │ ├── __init__.py │ ├── neo4j │ │ ├── __init__.py │ │ └── cypher_commands.py │ ├── in_memory │ │ └── __init__.py │ └── baseadapter.py ├── tests │ ├── resources │ │ ├── __init__.py │ │ ├── primer.provn │ │ ├── primer.json │ │ └── primer.provx │ ├── utils │ │ ├── __init__.py │ │ ├── test_validator.py │ │ └── test_converter.py │ ├── db_adapters │ │ ├── __init__.py │ │ ├── neo4j │ │ │ ├── __init__.py │ │ │ └── test_neo4jadapter.py │ │ └── in_memory │ │ │ ├── __init__.py │ │ │ └── test_simple_in_memory.py │ ├── __init__.py │ └── examples.py └── __init__.py ├── docs ├── readme.rst ├── diagrams │ ├── Readme.md │ ├── Class-Diagram.xml │ ├── Process-Save-Document-Overview.xml │ └── Process-Save-Document.xml ├── modules.rst ├── index.rst ├── provdbconnector.db_adapters.in_memory.rst ├── provdbconnector.tests.db_adapters.neo4j.rst ├── provdbconnector.rst ├── provdbconnector.tests.db_adapters.in_memory.rst ├── provdbconnector.db_adapters.rst ├── _images │ └── test_cases │ │ ├── test_datatypes.svg │ │ ├── test_long_literals.svg │ │ ├── test_19_merge_record.svg │ │ ├── test_1_save_element.svg │ │ ├── test_27_save_bundle.svg │ │ ├── test_4_get_record.svg │ │ ├── test_21_merge_record_complex_fail.svg │ │ ├── test_22_merge_record_metadata.svg │ │ ├── test_8_get_records_by_filter.svg │ │ ├── test_15_delete_by_filter_with_properties.svg │ │ ├── test_20_merge_record_complex.svg │ │ ├── test_10_get_records_by_filter_with_metadata.svg │ │ ├── test_collections.svg │ │ ├── test_16_delete_by_filter_with_metadata.svg │ │ ├── test_23_merge_relation.svg │ │ ├── test_2_save_relation.svg │ │ ├── test_6_get_relation.svg │ │ ├── test_26_merge_relation_metadata.svg │ │ ├── test_24_merge_relation_complex.svg │ │ ├── test_25_merge_relation_complex_fail.svg │ │ ├── test_11_get_records_tail.svg │ │ ├── test_9_get_records_by_filter_with_properties.svg │ │ ├── test_13_get_bundle_records.svg │ │ ├── test_12_get_records_tail_recursive.svg │ │ ├── test_bundles1.svg │ │ └── test_bundles2.svg ├── provdbconnector.tests.db_adapters.rst ├── provdbconnector.tests.utils.rst ├── provdbconnector.db_adapters.neo4j.rst ├── provdbconnector.tests.rst ├── provdbconnector.utils.rst ├── provdbconnector.exceptions.rst ├── test_howto.rst ├── development.rst ├── changelog.rst ├── Makefile └── make.bat ├── requirements.txt ├── setup.cfg ├── .github ├── dependabot.yml └── workflows │ ├── pythonpackage-publish.yml │ └── pythonpackage-test.yml ├── .coveragerc ├── docker-compose.yml ├── .travis_docs.sh ├── Makefile ├── .travis.yml ├── setup.py ├── .gitignore ├── README.rst └── LICENSE /examples/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /hound.yml: -------------------------------------------------------------------------------- 1 | python: 2 | enabled: true -------------------------------------------------------------------------------- /provdbconnector/exceptions/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /provdbconnector/utils/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/readme.rst: -------------------------------------------------------------------------------- 1 | .. include:: ./../README.rst -------------------------------------------------------------------------------- /provdbconnector/db_adapters/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /provdbconnector/tests/resources/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /provdbconnector/tests/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /provdbconnector/db_adapters/neo4j/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /provdbconnector/tests/db_adapters/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /provdbconnector/tests/db_adapters/neo4j/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | prov==2.0.0 2 | neo4j==5.6.0 3 | -------------------------------------------------------------------------------- /provdbconnector/tests/db_adapters/in_memory/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.md 3 | -------------------------------------------------------------------------------- /provdbconnector/db_adapters/in_memory/__init__.py: -------------------------------------------------------------------------------- 1 | from provdbconnector.db_adapters.in_memory.simple_in_memory import SimpleInMemoryAdapter 2 | -------------------------------------------------------------------------------- /docs/diagrams/Readme.md: -------------------------------------------------------------------------------- 1 | #Diagrams 2 | 3 | All diagrams were created with [Draw.io](https://draw.io). 4 | If you update the diagrams please update the .svg image also a -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: pip 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "04:00" 8 | open-pull-requests-limit: 10 9 | -------------------------------------------------------------------------------- /provdbconnector/utils/validator.py: -------------------------------------------------------------------------------- 1 | import logging 2 | log = logging.getLogger(__name__) 3 | 4 | 5 | class Validator(object): 6 | """ 7 | Class to do some validation, not implemented yet 8 | """ 9 | pass 10 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | source = provdbconnector 3 | 4 | [report] 5 | exclude_lines = 6 | pragma: no cover 7 | def __repr__ 8 | raise AssertionError 9 | raise NotImplementedError 10 | if __name__ == .__main__.: 11 | -------------------------------------------------------------------------------- /docs/modules.rst: -------------------------------------------------------------------------------- 1 | provdbconnector modules 2 | ======================= 3 | 4 | .. toctree:: 5 | :maxdepth: 1 6 | 7 | provdbconnector.db_adapters 8 | provdbconnector.utils 9 | provdbconnector.exceptions 10 | provdbconnector.tests 11 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | neo4j: 4 | platform: linux/x86_64/v8 5 | image: neo4j:3.5 6 | environment: 7 | - NEO4J_AUTH=none 8 | ports: 9 | - "7474:7474" 10 | - "7373:7373" 11 | - "7687:7687" 12 | -------------------------------------------------------------------------------- /provdbconnector/tests/__init__.py: -------------------------------------------------------------------------------- 1 | from provdbconnector.tests.db_adapters.test_baseadapter import AdapterTestTemplate 2 | from provdbconnector.tests.test_prov_db import ProvDbTestTemplate 3 | import unittest 4 | 5 | 6 | def additional_tests(): 7 | from examples.tests.test_examples import ExamplesTest 8 | return unittest.defaultTestLoader.loadTestsFromTestCase(ExamplesTest) 9 | 10 | -------------------------------------------------------------------------------- /provdbconnector/tests/utils/test_validator.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | 4 | class ValidatorTests(unittest.TestCase): 5 | """ 6 | Test the validator class 7 | 8 | """ 9 | def setUp(self): 10 | """ 11 | Setup validator 12 | """ 13 | pass 14 | 15 | def tearDown(self): 16 | """ 17 | Delete validator 18 | """ 19 | pass 20 | 21 | -------------------------------------------------------------------------------- /provdbconnector/__init__.py: -------------------------------------------------------------------------------- 1 | from provdbconnector.prov_db import ProvDb 2 | 3 | from provdbconnector.exceptions.provapi import ProvDbException 4 | from provdbconnector import db_adapters 5 | from provdbconnector.db_adapters.neo4j.neo4jadapter import Neo4jAdapter 6 | from provdbconnector.db_adapters.neo4j.neo4jadapter import NEO4J_USER, NEO4J_PASS, NEO4J_HOST, NEO4J_HTTP_PORT, NEO4J_BOLT_PORT 7 | 8 | from provdbconnector.db_adapters.in_memory import SimpleInMemoryAdapter 9 | -------------------------------------------------------------------------------- /.travis_docs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | sphinx-apidoc -o docs provdbconnector 4 | sphinx-build -q -a -b html -d docs/build/doctrees docs/ docs/build/html &> travis-doc-test.txt 5 | TEST=$(grep 'failed' travis-doc-test.txt | LC_ALL=C.UTF-8 wc -m) 6 | echo "Lenght of errors = $TEST" 7 | if test $TEST -gt 0 8 | then 9 | echo "Error during build docs " 10 | grep 'failed' travis-doc-test.txt 11 | exit 2 12 | else 13 | echo "Build docs complete" 14 | fi 15 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. PROV Database Connector documentation master file, created by 2 | sphinx-quickstart on Mon Oct 24 11:47:37 2016. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Contents 7 | ======== 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | 12 | readme.rst 13 | development.rst 14 | changelog.rst 15 | test_howto.rst 16 | provdbconnector.rst 17 | modules.rst 18 | 19 | Indices and tables 20 | ================== 21 | 22 | * :ref:`genindex` 23 | * :ref:`modindex` 24 | * :ref:`search` 25 | 26 | -------------------------------------------------------------------------------- /docs/provdbconnector.db_adapters.in_memory.rst: -------------------------------------------------------------------------------- 1 | provdbconnector.db_adapters.in_memory package 2 | ============================================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | provdbconnector.db_adapters.in_memory.simple_in_memory module 8 | ------------------------------------------------------------- 9 | 10 | .. automodule:: provdbconnector.db_adapters.in_memory.simple_in_memory 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | 16 | Module contents 17 | --------------- 18 | 19 | .. automodule:: provdbconnector.db_adapters.in_memory 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | -------------------------------------------------------------------------------- /docs/provdbconnector.tests.db_adapters.neo4j.rst: -------------------------------------------------------------------------------- 1 | provdbconnector.tests.db_adapters.neo4j package 2 | =============================================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | provdbconnector.tests.db_adapters.neo4j.test_neo4jadapter module 8 | ---------------------------------------------------------------- 9 | 10 | .. automodule:: provdbconnector.tests.db_adapters.neo4j.test_neo4jadapter 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | 16 | Module contents 17 | --------------- 18 | 19 | .. automodule:: provdbconnector.tests.db_adapters.neo4j 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | -------------------------------------------------------------------------------- /docs/provdbconnector.rst: -------------------------------------------------------------------------------- 1 | provdbconnector package 2 | ======================= 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | 9 | provdbconnector.db_adapters 10 | provdbconnector.exceptions 11 | provdbconnector.tests 12 | provdbconnector.utils 13 | 14 | Submodules 15 | ---------- 16 | 17 | provdbconnector.prov_db module 18 | ------------------------------ 19 | 20 | .. automodule:: provdbconnector.prov_db 21 | :members: 22 | :undoc-members: 23 | :show-inheritance: 24 | 25 | 26 | Module contents 27 | --------------- 28 | 29 | .. automodule:: provdbconnector 30 | :members: 31 | :undoc-members: 32 | :show-inheritance: 33 | -------------------------------------------------------------------------------- /provdbconnector/exceptions/provapi.py: -------------------------------------------------------------------------------- 1 | class ProvDbException(Exception): 2 | """ 3 | Base exception class for all api exceptions. 4 | """ 5 | pass 6 | 7 | 8 | class NoDataBaseAdapterException(ProvDbException): 9 | """ 10 | Thrown, if no database adapter argument is passed to the api class. 11 | """ 12 | pass 13 | 14 | 15 | class InvalidArgumentTypeException(ProvDbException): 16 | """ 17 | Thrown, if an invalid argument is passed to any api method. 18 | """ 19 | pass 20 | 21 | 22 | class InvalidProvRecordException(ProvDbException): 23 | """" 24 | Thrown, if an invalid record is passed to any api method. 25 | """ 26 | pass 27 | -------------------------------------------------------------------------------- /docs/provdbconnector.tests.db_adapters.in_memory.rst: -------------------------------------------------------------------------------- 1 | provdbconnector.tests.db_adapters.in_memory package 2 | =================================================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | provdbconnector.tests.db_adapters.in_memory.test_simple_in_memory module 8 | ------------------------------------------------------------------------ 9 | 10 | .. automodule:: provdbconnector.tests.db_adapters.in_memory.test_simple_in_memory 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | 16 | Module contents 17 | --------------- 18 | 19 | .. automodule:: provdbconnector.tests.db_adapters.in_memory 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | -------------------------------------------------------------------------------- /docs/provdbconnector.db_adapters.rst: -------------------------------------------------------------------------------- 1 | provdbconnector.db_adapters package 2 | =================================== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | 9 | provdbconnector.db_adapters.in_memory 10 | provdbconnector.db_adapters.neo4j 11 | 12 | Submodules 13 | ---------- 14 | 15 | provdbconnector.db_adapters.baseadapter module 16 | ---------------------------------------------- 17 | 18 | .. automodule:: provdbconnector.db_adapters.baseadapter 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | 24 | Module contents 25 | --------------- 26 | 27 | .. automodule:: provdbconnector.db_adapters 28 | :members: 29 | :undoc-members: 30 | :show-inheritance: 31 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_datatypes.svg: -------------------------------------------------------------------------------- 1 | 2 | Neo4j Graph Visualization 3 | Created using Neo4j (http://www.neo4j.com/) 4 | 5 | 6 | 7 | 8 | ex:e1 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_long_literals.svg: -------------------------------------------------------------------------------- 1 | 2 | Neo4j Graph Visualization 3 | Created using Neo4j (http://www.neo4j.com/) 4 | 5 | 6 | 7 | 8 | ex:e1 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_19_merge_record.svg: -------------------------------------------------------------------------------- 1 | 2 | Neo4j Graph Visualization 3 | Created using Neo4j (http://www.neo4j.com/) 4 | 5 | 6 | 7 | 8 | ex:Yoda 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_1_save_element.svg: -------------------------------------------------------------------------------- 1 | 2 | Neo4j Graph Visualization 3 | Created using Neo4j (http://www.neo4j.com/) 4 | 5 | 6 | 7 | 8 | prov:exa… 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_27_save_bundle.svg: -------------------------------------------------------------------------------- 1 | 2 | Neo4j Graph Visualization 3 | Created using Neo4j (http://www.neo4j.com/) 4 | 5 | 6 | 7 | 8 | prov:Bu… 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_4_get_record.svg: -------------------------------------------------------------------------------- 1 | 2 | Neo4j Graph Visualization 3 | Created using Neo4j (http://www.neo4j.com/) 4 | 5 | 6 | 7 | 8 | prov:exa… 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_21_merge_record_complex_fail.svg: -------------------------------------------------------------------------------- 1 | 2 | Neo4j Graph Visualization 3 | Created using Neo4j (http://www.neo4j.com/) 4 | 5 | 6 | 7 | 8 | ex:Yoda 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_22_merge_record_metadata.svg: -------------------------------------------------------------------------------- 1 | 2 | Neo4j Graph Visualization 3 | Created using Neo4j (http://www.neo4j.com/) 4 | 5 | 6 | 7 | 8 | ex:Yoda 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_8_get_records_by_filter.svg: -------------------------------------------------------------------------------- 1 | 2 | Neo4j Graph Visualization 3 | Created using Neo4j (http://www.neo4j.com/) 4 | 5 | 6 | 7 | 8 | prov:exa… 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_15_delete_by_filter_with_properties.svg: -------------------------------------------------------------------------------- 1 | 2 | Neo4j Graph Visualization 3 | Created using Neo4j (http://www.neo4j.com/) 4 | 5 | 6 | 7 | 8 | prov:Bu… 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/provdbconnector.tests.db_adapters.rst: -------------------------------------------------------------------------------- 1 | provdbconnector.tests.db_adapters package 2 | ========================================= 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | 9 | provdbconnector.tests.db_adapters.in_memory 10 | provdbconnector.tests.db_adapters.neo4j 11 | 12 | Submodules 13 | ---------- 14 | 15 | provdbconnector.tests.db_adapters.test_baseadapter module 16 | --------------------------------------------------------- 17 | 18 | .. automodule:: provdbconnector.tests.db_adapters.test_baseadapter 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | 24 | Module contents 25 | --------------- 26 | 27 | .. automodule:: provdbconnector.tests.db_adapters 28 | :members: 29 | :undoc-members: 30 | :show-inheritance: 31 | -------------------------------------------------------------------------------- /provdbconnector/exceptions/utils.py: -------------------------------------------------------------------------------- 1 | from .provapi import ProvDbException 2 | 3 | 4 | class ConverterException(ProvDbException): 5 | """ 6 | Base exception class for document converter. 7 | """ 8 | pass 9 | 10 | 11 | class ParseException(ConverterException): 12 | """ 13 | Thrown, if a given statement could not ne parsed. 14 | """ 15 | pass 16 | 17 | 18 | class NoDocumentException(ConverterException): 19 | """ 20 | Thrown, if no document argument is passed. 21 | """ 22 | pass 23 | 24 | 25 | class SerializerException(ProvDbException): 26 | """ 27 | Base exception class for serializer. 28 | """ 29 | pass 30 | 31 | 32 | class ValidatorException(ProvDbException): 33 | """ 34 | Base exception class for validator. 35 | """ 36 | pass 37 | -------------------------------------------------------------------------------- /docs/provdbconnector.tests.utils.rst: -------------------------------------------------------------------------------- 1 | provdbconnector.tests.utils package 2 | =================================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | provdbconnector.tests.utils.test_converter module 8 | ------------------------------------------------- 9 | 10 | .. automodule:: provdbconnector.tests.utils.test_converter 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | provdbconnector.tests.utils.test_validator module 16 | ------------------------------------------------- 17 | 18 | .. automodule:: provdbconnector.tests.utils.test_validator 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | 24 | Module contents 25 | --------------- 26 | 27 | .. automodule:: provdbconnector.tests.utils 28 | :members: 29 | :undoc-members: 30 | :show-inheritance: 31 | -------------------------------------------------------------------------------- /.github/workflows/pythonpackage-publish.yml: -------------------------------------------------------------------------------- 1 | on: 2 | release: 3 | types: [published] 4 | jobs: 5 | build: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v3 9 | - name: Set up Python ${{ matrix.python-version }} 10 | uses: actions/setup-python@v4 11 | with: 12 | python-version: ${{ matrix.python-version }} 13 | - name: Install dependencies 14 | run: | 15 | python -m pip install --upgrade pip 16 | pip install '.[test]' 17 | pip install '.[docs]' 18 | - name: Build 19 | run: | 20 | python setup.py build 21 | - name: Publish a Python distribution to PyPI 22 | uses: pypa/gh-action-pypi-publish@release/v1 23 | with: 24 | password: ${{ secrets.PYPI_API_TOKEN }} 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_20_merge_record_complex.svg: -------------------------------------------------------------------------------- 1 | 3 | Neo4j Graph Visualization 4 | Created using Neo4j (http://www.neo4j.com/) 5 | 6 | 7 | 8 | 9 | ex:Yoda 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/simple_example.py: -------------------------------------------------------------------------------- 1 | from prov.model import ProvDocument 2 | from provdbconnector import ProvDb 3 | from provdbconnector.db_adapters.in_memory import SimpleInMemoryAdapter 4 | 5 | prov_api = ProvDb(adapter=SimpleInMemoryAdapter, auth_info=None) 6 | 7 | # create the prov document 8 | prov_document = ProvDocument() 9 | prov_document.add_namespace("ex", "http://example.com") 10 | 11 | prov_document.agent("ex:Bob") 12 | prov_document.activity("ex:Alice") 13 | 14 | prov_document.association("ex:Alice", "ex:Bob") 15 | 16 | document_id = prov_api.save_document(prov_document) 17 | 18 | print(prov_api.get_document_as_provn(document_id)) 19 | 20 | # Output: 21 | # 22 | # document 23 | # prefix 24 | # ex < http: // example.com > 25 | # 26 | # agent(ex:Bob) 27 | # activity(ex:Alice, -, -) 28 | # wasAssociatedWith(ex:Alice, ex:Bob, -) 29 | # endDocument 30 | -------------------------------------------------------------------------------- /examples/simple_example_influence.py: -------------------------------------------------------------------------------- 1 | from prov.model import ProvDocument 2 | from provdbconnector import ProvDb 3 | from provdbconnector.db_adapters.in_memory import SimpleInMemoryAdapter 4 | 5 | prov_api = ProvDb(adapter=SimpleInMemoryAdapter, auth_info=None) 6 | 7 | # create the prov document 8 | prov_document = ProvDocument() 9 | prov_document.add_namespace("ex", "http://example.com") 10 | 11 | prov_document.agent("ex:Bob") 12 | prov_document.activity("ex:Alice") 13 | 14 | prov_document.influence("ex:Alice", "ex:Bob") 15 | 16 | document_id = prov_api.save_document(prov_document) 17 | 18 | print(prov_api.get_document_as_provn(document_id)) 19 | 20 | # Output: 21 | # 22 | # document 23 | # prefix ex < http: // example.com > 24 | # 25 | # agent(ex: Bob) 26 | # activity(ex: Alice, -, -) 27 | # wasInfluencedBy(ex: Alice, ex: Bob) 28 | # endDocument 29 | -------------------------------------------------------------------------------- /docs/provdbconnector.db_adapters.neo4j.rst: -------------------------------------------------------------------------------- 1 | provdbconnector.db_adapters.neo4j package 2 | ========================================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | provdbconnector.db_adapters.neo4j.cypher_commands module 8 | -------------------------------------------------------- 9 | 10 | .. automodule:: provdbconnector.db_adapters.neo4j.cypher_commands 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | provdbconnector.db_adapters.neo4j.neo4jadapter module 16 | ----------------------------------------------------- 17 | 18 | .. automodule:: provdbconnector.db_adapters.neo4j.neo4jadapter 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | 24 | Module contents 25 | --------------- 26 | 27 | .. automodule:: provdbconnector.db_adapters.neo4j 28 | :members: 29 | :undoc-members: 30 | :show-inheritance: 31 | -------------------------------------------------------------------------------- /docs/provdbconnector.tests.rst: -------------------------------------------------------------------------------- 1 | provdbconnector.tests package 2 | ============================= 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | 9 | provdbconnector.tests.db_adapters 10 | provdbconnector.tests.resources 11 | provdbconnector.tests.utils 12 | 13 | Submodules 14 | ---------- 15 | 16 | provdbconnector.tests.examples module 17 | ------------------------------------- 18 | 19 | .. automodule:: provdbconnector.tests.examples 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | 24 | provdbconnector.tests.test_prov_db module 25 | ----------------------------------------- 26 | 27 | .. automodule:: provdbconnector.tests.test_prov_db 28 | :members: 29 | :undoc-members: 30 | :show-inheritance: 31 | 32 | 33 | Module contents 34 | --------------- 35 | 36 | .. automodule:: provdbconnector.tests 37 | :members: 38 | :undoc-members: 39 | :show-inheritance: 40 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_10_get_records_by_filter_with_metadata.svg: -------------------------------------------------------------------------------- 1 | 2 | Neo4j Graph Visualization 3 | Created using Neo4j (http://www.neo4j.com/) 4 | 5 | 6 | 7 | 8 | list, of, 10 | 11 | strings 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/provdbconnector.utils.rst: -------------------------------------------------------------------------------- 1 | provdbconnector.utils package 2 | ============================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | provdbconnector.utils.converter module 8 | -------------------------------------- 9 | 10 | .. automodule:: provdbconnector.utils.converter 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | provdbconnector.utils.serializer module 16 | --------------------------------------- 17 | 18 | .. automodule:: provdbconnector.utils.serializer 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | provdbconnector.utils.validator module 24 | -------------------------------------- 25 | 26 | .. automodule:: provdbconnector.utils.validator 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | 32 | Module contents 33 | --------------- 34 | 35 | .. automodule:: provdbconnector.utils 36 | :members: 37 | :undoc-members: 38 | :show-inheritance: 39 | -------------------------------------------------------------------------------- /docs/provdbconnector.exceptions.rst: -------------------------------------------------------------------------------- 1 | provdbconnector.exceptions package 2 | ================================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | provdbconnector.exceptions.database module 8 | ------------------------------------------ 9 | 10 | .. automodule:: provdbconnector.exceptions.database 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | provdbconnector.exceptions.provapi module 16 | ----------------------------------------- 17 | 18 | .. automodule:: provdbconnector.exceptions.provapi 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | provdbconnector.exceptions.utils module 24 | --------------------------------------- 25 | 26 | .. automodule:: provdbconnector.exceptions.utils 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | 32 | Module contents 33 | --------------- 34 | 35 | .. automodule:: provdbconnector.exceptions 36 | :members: 37 | :undoc-members: 38 | :show-inheritance: 39 | -------------------------------------------------------------------------------- /.github/workflows/pythonpackage-test.yml: -------------------------------------------------------------------------------- 1 | 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: 8 | - master 9 | 10 | jobs: 11 | test: 12 | 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] 17 | 18 | steps: 19 | - uses: actions/checkout@v3 20 | - name: Set up Python ${{ matrix.python-version }} 21 | uses: actions/setup-python@v4 22 | with: 23 | python-version: ${{ matrix.python-version }} 24 | - name: Install dependencies 25 | run: | 26 | python -m pip install --upgrade pip 27 | pip install '.[test]' 28 | pip install '.[docs]' 29 | - name: Build 30 | run: | 31 | python setup.py build 32 | - name: Test with pytest 33 | run: | 34 | docker-compose build 35 | docker-compose up -d 36 | sleep 20s 37 | coverage run --source=provdbconnector setup.py test 38 | 39 | -------------------------------------------------------------------------------- /examples/horsemeat_example.py: -------------------------------------------------------------------------------- 1 | from provdbconnector import ProvDb 2 | from provdbconnector import Neo4jAdapter 3 | import os 4 | import pkg_resources 5 | 6 | # Data is from: https://provenance.ecs.soton.ac.uk/store/documents/75490/ 7 | 8 | 9 | NEO4J_USER = os.environ.get('NEO4J_USERNAME', 'neo4j') 10 | NEO4J_PASS = os.environ.get('NEO4J_PASSWORD', 'neo4jneo4j') 11 | NEO4J_HOST = os.environ.get('NEO4J_HOST', 'localhost') 12 | NEO4J_BOLT_PORT = os.environ.get('NEO4J_BOLT_PORT', '7687') 13 | 14 | # Auth info 15 | auth_info = {"user_name": NEO4J_USER, 16 | "user_password": NEO4J_PASS, 17 | "host": NEO4J_HOST + ":" + NEO4J_BOLT_PORT 18 | } 19 | 20 | 21 | # create the api 22 | prov_api = ProvDb(adapter=Neo4jAdapter, auth_info=auth_info) 23 | 24 | # create the prov document from examples 25 | prov_document_buffer = pkg_resources.resource_stream("examples", "horsemeat_example.json") 26 | 27 | # Save document 28 | document_id = prov_api.save_document(prov_document_buffer) 29 | # This is similar to: 30 | # prov_api.create_document_from_json(prov_document_buffer) 31 | 32 | # get document 33 | print(prov_api.get_document_as_provn(document_id)) -------------------------------------------------------------------------------- /examples/bundle_example.py: -------------------------------------------------------------------------------- 1 | from prov.model import ProvDocument 2 | from provdbconnector import ProvDb 3 | from provdbconnector.db_adapters.in_memory import SimpleInMemoryAdapter 4 | 5 | prov_api = ProvDb(adapter=SimpleInMemoryAdapter, auth_info=None) 6 | 7 | # create the prov document 8 | prov_document = ProvDocument() 9 | prov_document.add_namespace("ex", "http://example.com") 10 | 11 | prov_document.agent("ex:Bob") 12 | prov_document.activity("ex:Alice") 13 | 14 | prov_document.association("ex:Alice", "ex:Bob") 15 | # create bundle 16 | b1 = prov_document.bundle("ex:bundle1") 17 | b1.agent("ex:Yoda") 18 | 19 | b2 = prov_document.bundle("ex:bundle2") 20 | b2.agent("ex:Jabba the Hutt") 21 | 22 | document_id = prov_api.save_document(prov_document) 23 | 24 | print(prov_api.get_document_as_provn(document_id)) 25 | 26 | # Output: 27 | # 28 | # document 29 | # prefix ex 30 | # 31 | # agent(ex:Bob) 32 | # activity(ex:Alice, -, -) 33 | # wasAssociatedWith(ex:Alice, ex:Bob, -) 34 | # bundle ex:bundle2 35 | # prefix ex 36 | # 37 | # agent(ex:Jabba the Hutt) 38 | # endBundle 39 | # bundle ex:bundle1 40 | # prefix ex 41 | # 42 | # agent(ex:Yoda) 43 | # endBundle 44 | # endDocument 45 | -------------------------------------------------------------------------------- /examples/simple_example_with_neo4j.py: -------------------------------------------------------------------------------- 1 | from prov.model import ProvDocument 2 | from provdbconnector import ProvDb 3 | from provdbconnector import Neo4jAdapter 4 | import os 5 | 6 | # create the api 7 | 8 | NEO4J_USER = os.environ.get('NEO4J_USERNAME', 'neo4j') 9 | NEO4J_PASS = os.environ.get('NEO4J_PASSWORD', 'neo4jneo4j') 10 | NEO4J_HOST = os.environ.get('NEO4J_HOST', 'localhost') 11 | NEO4J_BOLT_PORT = os.environ.get('NEO4J_BOLT_PORT', '7687') 12 | 13 | auth_info = {"user_name": NEO4J_USER, 14 | "user_password": NEO4J_PASS, 15 | "host": NEO4J_HOST + ":" + NEO4J_BOLT_PORT 16 | } 17 | 18 | prov_api = ProvDb(adapter=Neo4jAdapter, auth_info=auth_info) 19 | 20 | # create the prov document 21 | prov_document = ProvDocument() 22 | prov_document.add_namespace("ex", "http://example.com") 23 | 24 | prov_document.agent("ex:Bob") 25 | prov_document.activity("ex:Alice") 26 | 27 | prov_document.association("ex:Alice", "ex:Bob") 28 | 29 | document_id = prov_api.save_document(prov_document) 30 | 31 | print(prov_api.get_document_as_provn(document_id)) 32 | 33 | # Output: 34 | # 35 | # document 36 | # prefix 37 | # ex < http: // example.com > 38 | # 39 | # agent(ex:Bob) 40 | # activity(ex:Alice, -, -) 41 | # wasAssociatedWith(ex:Alice, ex:Bob, -) 42 | # endDocument 43 | -------------------------------------------------------------------------------- /examples/merge_example.py: -------------------------------------------------------------------------------- 1 | from prov.model import ProvDocument 2 | from provdbconnector import ProvDb 3 | from provdbconnector.db_adapters.in_memory import SimpleInMemoryAdapter 4 | 5 | prov_api = ProvDb(adapter=SimpleInMemoryAdapter, auth_info=None) 6 | 7 | # create the prov first document 8 | first_prov_document = ProvDocument() 9 | first_prov_document .add_namespace("ex", "http://example.com") 10 | 11 | first_prov_document .agent("ex:Bob") 12 | first_prov_document .activity("ex:Alice") 13 | 14 | first_prov_document .association("ex:Alice", "ex:Bob") 15 | 16 | first_document_id = prov_api.save_document(first_prov_document) 17 | 18 | #Create the second prov document and merge the ex:Bob entry 19 | second_prov_document = ProvDocument() 20 | second_prov_document.add_namespace("ex", "http://example.com") 21 | 22 | second_prov_document.agent("ex:Bob", other_attributes={"ex:age": 42}) 23 | 24 | second_document_id = prov_api.save_document(second_prov_document) 25 | 26 | 27 | #Query the first document ID but get the Bob with the age property back (so successfully merged) 28 | 29 | print(prov_api.get_document_as_provn(first_document_id)) 30 | 31 | # Output: 32 | # 33 | # document 34 | # prefix 35 | # ex < http: // example.com > 36 | # 37 | # activity(ex:Alice, -, -) 38 | # agent(ex:Bob, [ex:age = 42]) 39 | # wasAssociatedWith(ex:Alice, ex:Bob, -) 40 | # endDocument 41 | -------------------------------------------------------------------------------- /provdbconnector/exceptions/database.py: -------------------------------------------------------------------------------- 1 | from .provapi import ProvDbException 2 | 3 | 4 | class AdapterException(ProvDbException): 5 | """ 6 | Base exception class for database adapters. 7 | """ 8 | pass 9 | 10 | 11 | class InvalidOptionsException(AdapterException): 12 | """ 13 | Thrown, if passed argument for adapter is invalid. 14 | """ 15 | pass 16 | 17 | 18 | class AuthException(AdapterException): 19 | """ 20 | Thrown, if database adapter could not establish a connection with given credentials to the database. 21 | """ 22 | pass 23 | 24 | 25 | class DatabaseException(AdapterException): 26 | """ 27 | Thrown, if method could not performed on database. 28 | """ 29 | pass 30 | 31 | 32 | class CreateRecordException(DatabaseException): 33 | """ 34 | Thrown, if record could not be saved in database. 35 | """ 36 | pass 37 | 38 | 39 | class CreateRelationException(DatabaseException): 40 | """ 41 | Thrown, if relation could not be saved in database. 42 | """ 43 | pass 44 | 45 | 46 | class NotFoundException(DatabaseException): 47 | """ 48 | Thrown, if record or relation could not be found in database. 49 | """ 50 | pass 51 | 52 | 53 | class MergeException(DatabaseException): 54 | """ 55 | Thrown, if a record or relation can't get merged 56 | """ 57 | pass 58 | -------------------------------------------------------------------------------- /docs/test_howto.rst: -------------------------------------------------------------------------------- 1 | .. _test_howto: 2 | 3 | Testing Howto 4 | ------------- 5 | To run the test local follow the next steps 6 | 7 | 1. Setup your env 8 | ~~~~~~~~~~~~~~~~~ 9 | 10 | .. include:: ./development.rst 11 | :start-after: Setup 12 | :end-before: Execute tests 13 | 14 | 2. Start your neo4j setup 15 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 16 | 17 | The tests require a running neo4j 3.0+ instance 18 | The simples way do start neo4j ist to use the docker image provided by neo4j 19 | 20 | .. code:: sh 21 | 22 | docker run \ 23 | --publish=7474:7474 --publish=7687:7687 \ 24 | --volume=$HOME/neo4j/data:/data \ 25 | neo4j:3.0 26 | 27 | 28 | Then open a browser `http://localhost:7474` and set the password to **neo4jneo4j** 29 | Alternative you can set the env. variables: 30 | 31 | - NEO4J_USERNAME: Default: neo4j 32 | - NEO4J_PASSWORD: Default: neo4jneo4j 33 | - NEO4J_HOST: Default: localhost 34 | - NEO4J_BOLT_PORT: Default: 7687 35 | - NEO4J_HTTP_PORT: Default: 7474 36 | 37 | Alternative use docker-compose 38 | 39 | .. code:: sh 40 | 41 | docker-compose up 42 | 43 | 3. Run your tests 44 | ~~~~~~~~~~~~~~~~~ 45 | 46 | .. code:: sh 47 | 48 | # Change env 49 | source env/bin/activate 50 | #Start tests 51 | make test 52 | 53 | .. note:: 54 | If some tests fail because of certificate issues, delete or rename the known_hosts file in ~/.neo4j. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean-pyc clean-build docs clean 2 | 3 | help: 4 | @echo "setup - basic setup and install" 5 | @echo "dev-setup - basic setup for developers" 6 | @echo "clean-build - remove build artifacts" 7 | @echo "clean-pyc - remove Python file artifacts" 8 | @echo "test - run tests quickly with the default Python" 9 | @echo "coverage - check code coverage quickly with the default Python" 10 | @echo "docs - generate Sphinx HTML documentation, including API docs" 11 | @echo "release - package and upload a release" 12 | @echo "dist - package" 13 | 14 | setup: 15 | pip install -U pip setuptools 16 | pip install '.' 17 | 18 | dev-setup: 19 | mkdir -p docs/_static 20 | pip install -U pip setuptools 21 | pip install -e '.[dev]' 22 | 23 | clean: clean-build clean-pyc 24 | rm -fr htmlcov/ 25 | 26 | clean-build: 27 | rm -fr build/ 28 | rm -fr dist/ 29 | rm -fr *.egg-info 30 | 31 | clean-pyc: 32 | find . -name '*.pyc' -exec rm -f {} + 33 | find . -name '*.pyo' -exec rm -f {} + 34 | 35 | test: 36 | python setup.py test 37 | 38 | coverage: 39 | coverage run --source provdbconnector setup.py test 40 | coverage report -m 41 | coverage html 42 | 43 | docs: 44 | $(MAKE) -C docs clean 45 | sphinx-apidoc -o docs provdbconnector 46 | sphinx-build -a -b html -d docs/build/doctrees docs/ docs/build/html 47 | 48 | docs-travis: 49 | $(MAKE) -C docs clean 50 | ./.travis_docs.sh 51 | 52 | release: clean 53 | python setup.py sdist upload 54 | 55 | dist: clean 56 | python setup.py sdist 57 | -------------------------------------------------------------------------------- /examples/simple_example_with_neo4j_graph.svg: -------------------------------------------------------------------------------- 1 | Neo4j Graph VisualizationCreated using Neo4j (http://www.neo4j.com/)wasAssociatedWith ex:Bob ex:Alice -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | sudo: required 3 | python: 4 | - 3.6 5 | - 3.7 6 | - 3.8 7 | - 3.9 8 | services: 9 | - docker 10 | before_install: 11 | - docker-compose build 12 | - docker-compose up -d 13 | install: 14 | - pip install '.[test]' 15 | - pip install '.[docs]' 16 | script: 17 | - curl --output /dev/null --silent --head --fail http://localhost:7474 18 | - coverage run --source=provdbconnector setup.py test 19 | - make docs-travis 20 | - ". ./.travis_docs.sh" 21 | after_success: 22 | - coveralls 23 | - docker-compose down 24 | 25 | jobs: 26 | include: 27 | - stage: pypi release 28 | if: tag IS present 29 | python: "3.8" 30 | script: 31 | echo "Building project" 32 | python setup.py build 33 | deploy: 34 | provider: pypi 35 | user: __token__ 36 | password: 37 | secure: P7X9mQZR/2zOkDShQTSv09rbg4LgmR8ODoTnvE0d6oAOZM+Y6rWGL8u1dLxzw98anNlqbXd/5sjK6PsZ3h5Ola2WJ6KIGJAiP8stDt0BfGjW1Y3B2JocqdOZb+QOquqP3OlNHYgdL54hDjS0HsLqEhNJzBPUUPY0uOy1NZN8uf4DGMuVkNaDo/m5SpGbQPee7xOblGEMRqjyRISYAv1jkxzworzZQMQw6TwwqtZbBi6p3RMMz8SaUClIcTRlXS+O5QaEehHB+xxRMMG/fETAlZmcmByX5Px+YXX25FhlaTm9+GUQIa6/1XzxK03eyin3DwUPkJPUZqQ08NMWU5ZqD6+ITXKC/wF0A3OYqMvQWbwmRZvvebd8VBcSgzHiijXopsoBCpiQrb1wi+YfEzAwDyAjzR1qSavTjtHrkVkJik6QV2KN0Sa/SnIWEPK83b9kfNxnKRhSAzePuUp/bBr0tISvWj4S80sghui992FQEoXJV7aVBQ2SiRG6ynN6W/CbtRpPDL2NSnuM3K2Xt1vysG9iYW1zs9RVGjaVaclbR6JS1DXAdTR1pOTTWVFn67BR9nNMqYZf0M9mll+Iq3nfNbWdAIR/3g9U3syIpr4SiHUJ0YGodL7SX2t/lrbTR/WRPMF6SIE+5i8IDWbuBWF7+bEZbL3OFCwGmWH9y6fA3d8= 38 | on: 39 | tags: true 40 | -------------------------------------------------------------------------------- /examples/merge_fail_example.py: -------------------------------------------------------------------------------- 1 | from prov.model import ProvDocument 2 | from provdbconnector import ProvDb 3 | from provdbconnector.exceptions.database import MergeException 4 | from provdbconnector.db_adapters.in_memory import SimpleInMemoryAdapter 5 | 6 | prov_api = ProvDb(adapter=SimpleInMemoryAdapter, auth_info=None) 7 | 8 | # create the prov first document 9 | first_prov_document = ProvDocument() 10 | first_prov_document .add_namespace("ex", "http://example.com") 11 | 12 | first_prov_document .agent("ex:Bob", other_attributes={"ex:last_name": "Meier"}) 13 | first_prov_document .activity("ex:Alice") 14 | 15 | first_prov_document .association("ex:Alice", "ex:Bob") 16 | 17 | first_document_id = prov_api.save_document(first_prov_document) 18 | 19 | #Create the second prov document and merge the ex:Bob entry 20 | second_prov_document = ProvDocument() 21 | second_prov_document.add_namespace("ex", "http://example.com") 22 | 23 | second_prov_document.agent("ex:Bob", other_attributes={"ex:age": 42, "ex:last_name": "Müller"}) 24 | 25 | try: 26 | second_document_id = prov_api.save_document(second_prov_document) 27 | except MergeException as e: 28 | print ("Got the merge exception: {}".format(e)) 29 | 30 | # Query the first document ID and get only the last_name = Meier back. The merge was not successful. 31 | 32 | print(prov_api.get_document_as_provn(first_document_id)) 33 | 34 | # Output: 35 | # 36 | # document 37 | # prefix 38 | # ex < http: // example.com > 39 | # 40 | # activity(ex:Alice, -, -) 41 | # agent(ex:Bob, [ex:last_name = "Meier"]) 42 | # wasAssociatedWith(ex:Alice, ex:Bob, -) 43 | # endDocument -------------------------------------------------------------------------------- /docs/_images/test_cases/test_collections.svg: -------------------------------------------------------------------------------- 1 | 3 | Neo4j Graph Visualization 4 | Created using Neo4j (http://www.neo4j.com/) 5 | 6 | 7 | 9 | hadMe… 11 | 12 | 13 | 14 | 15 | 16 | 17 | ex:c1 19 | 20 | 21 | 22 | 23 | ex:e1 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/tests/test_examples.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | 4 | class ExamplesTest(unittest.TestCase): 5 | """ 6 | This test is only to load the example and check if the examples are still running 7 | 8 | """ 9 | 10 | def test_bundle_example(self): 11 | """ 12 | Test the bundle example 13 | 14 | """ 15 | import examples.bundle_example 16 | 17 | def test_test_complex_example_with_neo4j(self): 18 | """ 19 | Test the neo4j example 20 | 21 | """ 22 | import examples.complex_example_with_neo4j 23 | 24 | def test_file_buffer_example(self): 25 | """ 26 | Test the file buffer example 27 | 28 | """ 29 | import examples.file_buffer_example 30 | 31 | def test_simple_example(self): 32 | """ 33 | Test the basic example 34 | 35 | """ 36 | import examples.simple_example 37 | 38 | def test_simple_example_influence(self): 39 | """ 40 | Test the basic example with influence by relation 41 | 42 | """ 43 | import examples.simple_example_influence 44 | 45 | def test_simple_example_with_neo4j(self): 46 | """ 47 | Test the basic neo4j example 48 | 49 | """ 50 | import examples.simple_example_with_neo4j 51 | 52 | def test_merge_example(self): 53 | """ 54 | Test the merge example 55 | 56 | """ 57 | import examples.merge_example 58 | 59 | def test_merge_fail_example(self): 60 | """ 61 | Test the merge fail example 62 | 63 | """ 64 | import examples.merge_fail_example 65 | 66 | def test_horsemeat_example(self): 67 | """ 68 | Test the merge fail example 69 | """ 70 | import examples.horsemeat_example -------------------------------------------------------------------------------- /docs/_images/test_cases/test_16_delete_by_filter_with_metadata.svg: -------------------------------------------------------------------------------- 1 | 3 | Neo4j Graph Visualization 4 | Created using Neo4j (http://www.neo4j.com/) 5 | 6 | 7 | 8 | 9 | ex:prov:… 11 | 12 | 13 | 14 | 15 | prov:Bu… 17 | 18 | 19 | 20 | 21 | ex:TO 23 | 24 | NODE 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | try: 3 | from setuptools import setup, find_packages 4 | except ImportError: 5 | from distutils.core import setup, find_packages 6 | 7 | tests_require = [ 8 | 'coverage', 9 | 'coveralls' 10 | ] 11 | 12 | docs_require = [ 13 | 'Sphinx>=1.3.5', 14 | 'recommonmark>=0.4.0', 15 | 'sphinx-rtd-theme>=0.1.9', 16 | 'sphinxcontrib-napoleon>=0.4.4', 17 | 'sphinxcontrib-httpdomain>=1.5.0', 18 | 'mock', 19 | ] 20 | 21 | setup( 22 | name='prov-db-connector', 23 | version='0.5.1', 24 | description='PROV Database Connector', 25 | keywords=[ 26 | 'provenance', 'graph', 'model', 'PROV', 'PROV-DM', 'PROV-JSON', 'JSON', 27 | 'PROV-XML', 'PROV-N' 28 | ], 29 | author='DLR, Stefan Bieliauskas, Martin Stoffers', 30 | author_email='opensource@dlr.de, sb@conts.de, martin.stoffers@studserv.uni-leipzig.de', 31 | url='https://github.com/DLR-SC/prov-db-connector', 32 | classifiers=[ 33 | 'Development Status :: 1 - Planning', 34 | 'Topic :: Software Development :: Libraries :: Python Modules', 35 | 'License :: OSI Approved :: Apache Software License', 36 | 'Programming Language :: Python :: 3.6', 37 | 'Programming Language :: Python :: 3.7', 38 | 'Programming Language :: Python :: 3.8', 39 | 'Programming Language :: Python :: 3.9' 40 | ], 41 | license="Apache License 2.0", 42 | 43 | packages=find_packages(), 44 | package_dir={ 45 | 'provdbconnector': 'provdbconnector' 46 | }, 47 | include_package_data=True, 48 | zip_safe=False, 49 | install_requires=[ 50 | "prov==2.0.0", 51 | "neo4j==5.6.0" 52 | ], 53 | extras_require={ 54 | 'test': tests_require, 55 | 'dev': tests_require + docs_require, 56 | 'docs': docs_require, 57 | }, 58 | 59 | test_suite='provdbconnector.tests', 60 | ) 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | .eggs/ 5 | *$py.class 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | env/ 13 | bin/ 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | eggs/ 18 | build/ 19 | develop-eggs/ 20 | dist/ 21 | downloads/ 22 | eggs/ 23 | .eggs/ 24 | lib/ 25 | lib64/ 26 | parts/ 27 | sdist/ 28 | var/ 29 | *.egg-info/ 30 | .installed.cfg 31 | *.egg 32 | 33 | # PyInstaller 34 | # Usually these files are written by a python script from a template 35 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 36 | *.manifest 37 | *.spec 38 | 39 | # Installer logs 40 | pip-log.txt 41 | pip-delete-this-directory.txt 42 | travis-doc-test.txt 43 | 44 | # Unit test / coverage reports 45 | htmlcov/ 46 | .tox/ 47 | .coverage 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | 52 | # Translations 53 | *.mo 54 | 55 | # Mr Developer 56 | .mr.developer.cfg 57 | .project 58 | .pydevproject 59 | 60 | # Rope 61 | .ropeproject 62 | 63 | #IDE 64 | 65 | .idea 66 | 67 | 68 | # Django stuff: 69 | *.log 70 | *.pot 71 | 72 | # Sphinx documentation 73 | doc/_build/ 74 | .coverage.* 75 | .cache 76 | nosetests.xml 77 | coverage.xml 78 | *,cover 79 | .hypothesis/ 80 | 81 | # Translations 82 | *.mo 83 | *.pot 84 | 85 | # Django stuff: 86 | *.log 87 | local_settings.py 88 | 89 | # Flask stuff: 90 | instance/ 91 | .webassets-cache 92 | 93 | # Scrapy stuff: 94 | .scrapy 95 | 96 | # Sphinx documentation 97 | docs/_build/ 98 | 99 | # PyBuilder 100 | target/ 101 | 102 | # IPython Notebook 103 | .ipynb_checkpoints 104 | 105 | # pyenv 106 | .python-version 107 | 108 | # celery beat schedule file 109 | celerybeat-schedule 110 | 111 | # dotenv 112 | .env 113 | 114 | # virtualenv 115 | venv/ 116 | ENV/ 117 | 118 | # Spyder project settings 119 | .spyderproject 120 | 121 | .vscode 122 | *.code-workspace 123 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_23_merge_relation.svg: -------------------------------------------------------------------------------- 1 | 3 | Neo4j Graph Visualization 4 | Created using Neo4j (http://www.neo4j.com/) 5 | 6 | 7 | 9 | mentionOf 11 | 12 | 13 | 14 | 15 | 16 | 17 | ex:Yoda 19 | 20 | 21 | 22 | 23 | ex:Luke 25 | 26 | Skywal… 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_2_save_relation.svg: -------------------------------------------------------------------------------- 1 | 3 | Neo4j Graph Visualization 4 | Created using Neo4j (http://www.neo4j.com/) 5 | 6 | 7 | 9 | mentionOf 11 | 12 | 13 | 14 | 15 | 16 | 17 | ex:Yoda 19 | 20 | 21 | 22 | 23 | ex:Luke 25 | 26 | Skywal… 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_6_get_relation.svg: -------------------------------------------------------------------------------- 1 | 3 | Neo4j Graph Visualization 4 | Created using Neo4j (http://www.neo4j.com/) 5 | 6 | 7 | 9 | mentionOf 11 | 12 | 13 | 14 | 15 | 16 | 17 | ex:Yoda 19 | 20 | 21 | 22 | 23 | ex:Luke 25 | 26 | Skywal… 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_26_merge_relation_metadata.svg: -------------------------------------------------------------------------------- 1 | 3 | Neo4j Graph Visualization 4 | Created using Neo4j (http://www.neo4j.com/) 5 | 6 | 7 | 9 | mentionOf 11 | 12 | 13 | 14 | 15 | 16 | 17 | ex:Yoda 19 | 20 | 21 | 22 | 23 | ex:Luke 25 | 26 | Skywal… 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_24_merge_relation_complex.svg: -------------------------------------------------------------------------------- 1 | 3 | Neo4j Graph Visualization 4 | Created using Neo4j (http://www.neo4j.com/) 5 | 6 | 7 | 9 | mentionOf 11 | 12 | 13 | 14 | 15 | 16 | 17 | ex:Yoda 19 | 20 | 21 | 22 | 23 | ex:Luke 25 | 26 | Skywal… 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_25_merge_relation_complex_fail.svg: -------------------------------------------------------------------------------- 1 | 3 | Neo4j Graph Visualization 4 | Created using Neo4j (http://www.neo4j.com/) 5 | 6 | 7 | 9 | mentionOf 11 | 12 | 13 | 14 | 15 | 16 | 17 | ex:Yoda 19 | 20 | 21 | 22 | 23 | ex:Luke 25 | 26 | Skywal… 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /provdbconnector/tests/resources/primer.provn: -------------------------------------------------------------------------------- 1 | document 2 | prefix foaf 3 | prefix dcterms 4 | prefix ex 5 | entity(ex:article,[dcterms:title = "Crime rises in cities" %% xsd:string]) 6 | entity(ex:articleV1) 7 | entity(ex:articleV2) 8 | entity(ex:dataSet1) 9 | entity(ex:dataSet2) 10 | entity(ex:regionList) 11 | entity(ex:composition) 12 | entity(ex:chart1) 13 | entity(ex:chart2) 14 | entity(ex:blogEntry) 15 | activity(ex:compile,-,-) 16 | activity(ex:compile2,-,-) 17 | activity(ex:compose,-,-) 18 | activity(ex:correct,2012-03-31T09:21:00.000+01:00,2012-04-01T15:21:00.000+01:00) 19 | activity(ex:illustrate,-,-) 20 | used(ex:compose,ex:dataSet1,-) 21 | used(ex:compose,ex:regionList,-) 22 | wasGeneratedBy(ex:composition,ex:compose,-) 23 | used(ex:illustrate,ex:composition,-) 24 | wasGeneratedBy(ex:chart1,ex:illustrate,-) 25 | wasGeneratedBy(ex:chart1,ex:compile,2012-03-02T10:30:00.000Z) 26 | wasGeneratedBy(ex:chart2,ex:compile2,2012-04-01T15:21:00.000+01:00) 27 | agent(ex:derek,[prov:type = 'prov:Person', foaf:givenName = "Derek" %% xsd:string, foaf:mbox = "" %% xsd:string]) 28 | wasAssociatedWith(ex:compose,ex:derek,-) 29 | wasAssociatedWith(ex:illustrate,ex:derek,-) 30 | agent(ex:chartgen,[prov:type = 'prov:Organization', foaf:name = "Chart Generators Inc" %% xsd:string]) 31 | actedOnBehalfOf(ex:derek,ex:chartgen,ex:compose) 32 | wasAttributedTo(ex:chart1, ex:derek) 33 | used(ex:compose,ex:dataSet1,-,[prov:role = 'ex:dataToCompose']) 34 | used(ex:compose,ex:regionList,-,[prov:role = 'ex:regionsToAggregateBy']) 35 | wasGeneratedBy(ex:dataSet2,ex:correct,-) 36 | used(ex:correct,ex:dataSet1,-) 37 | wasDerivedFrom(ex:dataSet2, ex:dataSet1,[prov:type = 'prov:Revision']) 38 | wasDerivedFrom(ex:chart2, ex:dataSet2) 39 | wasDerivedFrom(ex:blogEntry, ex:article,[prov:type = 'prov:Quotation']) 40 | specializationOf(ex:articleV1,ex:article) 41 | wasDerivedFrom(ex:articleV1, ex:dataSet1) 42 | specializationOf(ex:articleV2,ex:article) 43 | wasDerivedFrom(ex:articleV2, ex:dataSet2) 44 | alternateOf(ex:articleV2,ex:articleV1) 45 | endDocument 46 | -------------------------------------------------------------------------------- /provdbconnector/tests/db_adapters/in_memory/test_simple_in_memory.py: -------------------------------------------------------------------------------- 1 | from provdbconnector.exceptions.database import InvalidOptionsException 2 | from provdbconnector.db_adapters.in_memory import SimpleInMemoryAdapter 3 | from provdbconnector.prov_db import ProvDb 4 | from provdbconnector.tests import AdapterTestTemplate 5 | from provdbconnector.tests import ProvDbTestTemplate 6 | 7 | 8 | class SimpleInMemoryAdapterTest(AdapterTestTemplate): 9 | """ 10 | This class implements the AdapterTestTemplate and only override some functions. 11 | 12 | """ 13 | def setUp(self): 14 | """ 15 | Connect to your database 16 | 17 | """ 18 | self.instance = SimpleInMemoryAdapter() 19 | self.instance.connect(None) 20 | 21 | def test_connect_invalid_options(self): 22 | """ 23 | Test your connect function with invalid data 24 | 25 | """ 26 | auth_info = {"invalid": "Invalid"} 27 | with self.assertRaises(InvalidOptionsException): 28 | self.instance.connect(auth_info) 29 | 30 | def clear_database(self): 31 | """ 32 | Clear the database 33 | 34 | """ 35 | self.instance.all_nodes = dict() 36 | self.instance.all_relations= dict() 37 | 38 | def tearDown(self): 39 | """ 40 | Delete your instance 41 | 42 | """ 43 | del self.instance 44 | 45 | 46 | class SimpleInMemoryAdapterProvDbTests(ProvDbTestTemplate): 47 | """ 48 | This is the high level test for the SimpleInMemoryAdapter 49 | 50 | """ 51 | def setUp(self): 52 | """ 53 | Setup a ProvDb instance 54 | """ 55 | self.provapi = ProvDb(api_id=1, adapter=SimpleInMemoryAdapter, auth_info=None) 56 | 57 | def clear_database(self): 58 | """ 59 | Clear function get called before each test starts 60 | 61 | """ 62 | self.provapi._adapter.all_nodes = dict() 63 | self.provapi._adapter.all_relations = dict() 64 | 65 | def tearDown(self): 66 | """ 67 | Delete prov api instance 68 | """ 69 | del self.provapi 70 | -------------------------------------------------------------------------------- /docs/diagrams/Class-Diagram.xml: -------------------------------------------------------------------------------- 1 | 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 -------------------------------------------------------------------------------- /docs/diagrams/Process-Save-Document-Overview.xml: -------------------------------------------------------------------------------- 1 | 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 -------------------------------------------------------------------------------- /examples/file_buffer_example.py: -------------------------------------------------------------------------------- 1 | from provdbconnector import ProvDb 2 | from provdbconnector.db_adapters.in_memory import SimpleInMemoryAdapter 3 | import pkg_resources 4 | 5 | # create the api 6 | prov_api = ProvDb(adapter=SimpleInMemoryAdapter, auth_info=None) 7 | 8 | # create the prov document from examples 9 | prov_document_buffer = pkg_resources.resource_stream("examples", "file_buffer_example_primer.json") 10 | 11 | # Save document 12 | document_id = prov_api.save_document(prov_document_buffer) 13 | # This is similar to: 14 | # prov_api.create_document_from_json(prov_document_buffer) 15 | 16 | # get document 17 | print(prov_api.get_document_as_provn(document_id)) 18 | 19 | # Output: 20 | 21 | # document 22 | # prefix 23 | # foaf < http: // xmlns.com / foaf / 0.1 / > 24 | # prefix 25 | # dcterms < http: // purl.org / dc / terms / > 26 | # prefix 27 | # ex < http: // example / > 28 | # 29 | # specializationOf(ex:articleV2, ex:article) 30 | # specializationOf(ex:articleV1, ex:article) 31 | # wasDerivedFrom(ex:blogEntry, ex:article, -, -, -, [prov:type = 'prov:Quotation']) 32 | # alternateOf(ex:articleV2, ex:articleV1) 33 | # wasDerivedFrom(ex:articleV1, ex:dataSet1, -, -, -) 34 | # wasDerivedFrom(ex:articleV2, ex:dataSet2, -, -, -) 35 | # wasDerivedFrom(ex:dataSet2, ex:dataSet1, -, -, -, [prov:type = 'prov:Revision']) 36 | # used(ex:correct, ex:dataSet1, -) 37 | # used(ex:compose, ex:dataSet1, -, [prov:role = "ex:dataToCompose"]) 38 | # wasDerivedFrom(ex:chart2, ex:dataSet2, -, -, -) 39 | # wasGeneratedBy(ex:dataSet2, ex:correct, -) 40 | # used(ex:compose, ex:regionList, -, [prov:role = "ex:regionsToAggregateBy"]) 41 | # used(ex:illustrate, ex:composition, -) 42 | # wasGeneratedBy(ex:composition, ex:compose, -) 43 | # wasAttributedTo(ex:chart1, ex:derek) 44 | # wasGeneratedBy(ex:chart1, ex:compile, 2012 - 03 - 02 45 | # T10:30:00) 46 | # wasGeneratedBy(ex:chart1, ex:illustrate, -) 47 | # wasAssociatedWith(ex:compose, ex:derek, -) 48 | # wasAssociatedWith(ex:illustrate, ex:derek, -) 49 | # actedOnBehalfOf(ex:derek, ex:chartgen, ex:compose) 50 | # entity(ex:article, [dcterms:title = "Crime rises in cities"]) 51 | # entity(ex:articleV1) 52 | # entity(ex:articleV2) 53 | # entity(ex:dataSet1) 54 | # entity(ex:dataSet2) 55 | # entity(ex:regionList) 56 | # entity(ex:composition) 57 | # entity(ex:chart1) 58 | # entity(ex:chart2) 59 | # entity(ex:blogEntry) 60 | # activity(ex:compile, -, -) 61 | # activity(ex:compile2, -, -) 62 | # activity(ex:compose, -, -) 63 | # activity(ex:correct, 2012 - 03 - 31 64 | # T09:21:00, 2012 - 04 - 01 65 | # T15:21:00) 66 | # activity(ex:illustrate, -, -) 67 | # agent(ex:derek, [foaf:mbox = "", foaf:givenName = "Derek", prov:type = 'prov:Person']) 68 | # agent(ex:chartgen, [foaf:name = "Chart Generators Inc", prov:type = 'prov:Organization']) 69 | # endDocument 70 | -------------------------------------------------------------------------------- /docs/diagrams/Process-Save-Document.xml: -------------------------------------------------------------------------------- 1 | 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 -------------------------------------------------------------------------------- /examples/complex_example_with_neo4j.py: -------------------------------------------------------------------------------- 1 | from provdbconnector import ProvDb 2 | from provdbconnector import Neo4jAdapter 3 | from prov.tests.examples import primer_example 4 | import os 5 | 6 | # create the api 7 | 8 | NEO4J_USER = os.environ.get('NEO4J_USERNAME', 'neo4j') 9 | NEO4J_PASS = os.environ.get('NEO4J_PASSWORD', 'neo4jneo4j') 10 | NEO4J_HOST = os.environ.get('NEO4J_HOST', 'localhost') 11 | NEO4J_BOLT_PORT = os.environ.get('NEO4J_BOLT_PORT', '7687') 12 | 13 | auth_info = {"user_name": NEO4J_USER, 14 | "user_password": NEO4J_PASS, 15 | "host": NEO4J_HOST + ":" + NEO4J_BOLT_PORT 16 | } 17 | 18 | prov_api = ProvDb(adapter=Neo4jAdapter, auth_info=auth_info) 19 | 20 | # create the prov document from examples 21 | prov_document = primer_example() 22 | 23 | # Save document 24 | document_id = prov_api.save_document(prov_document) 25 | 26 | # get document 27 | print(prov_api.get_document_as_provn(document_id)) 28 | 29 | # Output: 30 | 31 | # document 32 | # prefix 33 | # foaf < http: // xmlns.com / foaf / 0.1 / > 34 | # prefix 35 | # dcterms < http: // purl.org / dc / terms / > 36 | # prefix 37 | # ex < http: // example / > 38 | # 39 | # specializationOf(ex:articleV2, ex:article) 40 | # specializationOf(ex:articleV1, ex:article) 41 | # wasDerivedFrom(ex:blogEntry, ex:article, -, -, -, [prov:type = 'prov:Quotation']) 42 | # alternateOf(ex:articleV2, ex:articleV1) 43 | # wasDerivedFrom(ex:articleV1, ex:dataSet1, -, -, -) 44 | # wasDerivedFrom(ex:articleV2, ex:dataSet2, -, -, -) 45 | # wasDerivedFrom(ex:dataSet2, ex:dataSet1, -, -, -, [prov:type = 'prov:Revision']) 46 | # used(ex:correct, ex:dataSet1, -) 47 | # used(ex:compose, ex:dataSet1, -, [prov:role = "ex:dataToCompose"]) 48 | # wasDerivedFrom(ex:chart2, ex:dataSet2, -, -, -) 49 | # wasGeneratedBy(ex:dataSet2, ex:correct, -) 50 | # used(ex:compose, ex:regionList, -, [prov:role = "ex:regionsToAggregateBy"]) 51 | # used(ex:illustrate, ex:composition, -) 52 | # wasGeneratedBy(ex:composition, ex:compose, -) 53 | # wasAttributedTo(ex:chart1, ex:derek) 54 | # wasGeneratedBy(ex:chart1, ex:compile, 2012 - 03 - 02 55 | # T10:30:00) 56 | # wasGeneratedBy(ex:chart1, ex:illustrate, -) 57 | # wasAssociatedWith(ex:compose, ex:derek, -) 58 | # wasAssociatedWith(ex:illustrate, ex:derek, -) 59 | # actedOnBehalfOf(ex:derek, ex:chartgen, ex:compose) 60 | # entity(ex:article, [dcterms:title = "Crime rises in cities"]) 61 | # entity(ex:articleV1) 62 | # entity(ex:articleV2) 63 | # entity(ex:dataSet1) 64 | # entity(ex:dataSet2) 65 | # entity(ex:regionList) 66 | # entity(ex:composition) 67 | # entity(ex:chart1) 68 | # entity(ex:chart2) 69 | # entity(ex:blogEntry) 70 | # activity(ex:compile, -, -) 71 | # activity(ex:compile2, -, -) 72 | # activity(ex:compose, -, -) 73 | # activity(ex:correct, 2012 - 03 - 31 74 | # T09:21:00, 2012 - 04 - 01 75 | # T15:21:00) 76 | # activity(ex:illustrate, -, -) 77 | # agent(ex:derek, [foaf:mbox = "", foaf:givenName = "Derek", prov:type = 'prov:Person']) 78 | # agent(ex:chartgen, [foaf:name = "Chart Generators Inc", prov:type = 'prov:Organization']) 79 | # endDocument 80 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_11_get_records_tail.svg: -------------------------------------------------------------------------------- 1 | 3 | Neo4j Graph Visualization 4 | Created using Neo4j (http://www.neo4j.com/) 5 | 6 | 7 | 9 | mentionOf 11 | 12 | 13 | 14 | 15 | 16 | 17 | ex:prov:… 19 | 20 | 21 | 22 | 23 | prov:Bu… 25 | 26 | 27 | 28 | 29 | ex:FROM 31 | 32 | NODE 34 | 35 | 36 | 37 | 38 | ex:TO 40 | 41 | NODE 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_9_get_records_by_filter_with_properties.svg: -------------------------------------------------------------------------------- 1 | 3 | Neo4j Graph Visualization 4 | Created using Neo4j (http://www.neo4j.com/) 5 | 6 | 7 | 9 | mentionOf 11 | 12 | 13 | 14 | 15 | 16 | 17 | ex:prov:… 19 | 20 | 21 | 22 | 23 | prov:Bu… 25 | 26 | 27 | 28 | 29 | ex:FROM 31 | 32 | NODE 34 | 35 | 36 | 37 | 38 | ex:TO 40 | 41 | NODE 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /provdbconnector/tests/db_adapters/neo4j/test_neo4jadapter.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from provdbconnector.exceptions.database import InvalidOptionsException, AuthException 4 | from provdbconnector import Neo4jAdapter, NEO4J_USER, NEO4J_PASS, NEO4J_HOST, NEO4J_BOLT_PORT 5 | from provdbconnector.prov_db import ProvDb 6 | from provdbconnector.tests import AdapterTestTemplate 7 | from provdbconnector.tests import ProvDbTestTemplate 8 | 9 | 10 | class Neo4jAdapterTests(AdapterTestTemplate): 11 | """ 12 | This test extends from AdapterTestTemplate and provide a common set for the neo4j adapter 13 | """ 14 | def setUp(self): 15 | """ 16 | Setup the test 17 | """ 18 | self.instance = Neo4jAdapter() 19 | auth_info = {"user_name": NEO4J_USER, 20 | "user_password": NEO4J_PASS, 21 | "host": NEO4J_HOST + ":" + NEO4J_BOLT_PORT 22 | } 23 | self.instance.connect(auth_info) 24 | session = self.instance._create_session() 25 | session.run("MATCH (x) DETACH DELETE x") 26 | 27 | @unittest.skip( 28 | "Skipped because the server configuration currently is set to 'no password', so the authentication will never fail") 29 | def test_connect_fails(self): 30 | """ 31 | Try to connect with the wrong password 32 | """ 33 | auth_info = {"user_name": NEO4J_USER, 34 | "user_password": 'xxxxxx', 35 | "host": NEO4J_HOST + ":" + NEO4J_BOLT_PORT 36 | } 37 | self.instance.connect(auth_info) 38 | with self.assertRaises(AuthException): 39 | self.instance.connect(auth_info) 40 | 41 | def test_connect_invalid_options(self): 42 | """ 43 | Try to connect with some invalid arguments 44 | """ 45 | auth_info = {"u": NEO4J_USER, 46 | "p": 'xxxxxx', 47 | "h": NEO4J_HOST + ":" + NEO4J_BOLT_PORT 48 | } 49 | with self.assertRaises(InvalidOptionsException): 50 | self.instance.connect(auth_info) 51 | 52 | def tearDown(self): 53 | """ 54 | Delete all data on the database 55 | :return: 56 | """ 57 | session = self.instance._create_session() 58 | session.run("MATCH (x) DETACH DELETE x") 59 | del self.instance 60 | 61 | 62 | class Neo4jAdapterProvDbTests(ProvDbTestTemplate): 63 | """ 64 | High level api test for the neo4j adapter 65 | """ 66 | def setUp(self): 67 | self.auth_info = {"user_name": NEO4J_USER, 68 | "user_password": NEO4J_PASS, 69 | "host": NEO4J_HOST + ":" + NEO4J_BOLT_PORT 70 | } 71 | self.provapi = ProvDb(api_id=1, adapter=Neo4jAdapter, auth_info=self.auth_info) 72 | 73 | def clear_database(self): 74 | """ 75 | This function get called before each test starts 76 | 77 | """ 78 | session = self.provapi._adapter._create_session() 79 | session.run("MATCH (x) DETACH DELETE x") 80 | 81 | def tearDown(self): 82 | """ 83 | Delete all data in the database 84 | """ 85 | session = self.provapi._adapter._create_session() 86 | session.run("MATCH (x) DETACH DELETE x") 87 | del self.provapi 88 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_13_get_bundle_records.svg: -------------------------------------------------------------------------------- 1 | 3 | Neo4j Graph Visualization 4 | Created using Neo4j (http://www.neo4j.com/) 5 | 6 | 7 | 9 | wasAsso… 11 | 12 | 13 | 14 | 16 | wasAsso… 18 | 19 | 20 | 21 | 23 | wasGene… 25 | 26 | 27 | 28 | 29 | 30 | 31 | ex:Yoda 33 | 34 | 35 | 36 | 37 | ex:Luke 39 | 40 | Skywal… 42 | 43 | 44 | 45 | 46 | prov:ano… 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /docs/development.rst: -------------------------------------------------------------------------------- 1 | Development 2 | =========== 3 | 4 | Contribute 5 | ---------- 6 | 7 | Please, fork the code on Github and develop your feature in a new branch split from the develop branch. 8 | Commit your code to the main project by sending a pull request onto the develop branch 9 | 10 | * Issue Tracker: https://github.com/DLR-SC/prov-db-connector/issues 11 | * Source Code: https://github.com/DLR-SC/prov-db-connector 12 | 13 | Setup 14 | ----- 15 | 16 | .. code:: sh 17 | 18 | # Clone project 19 | git clone git@github.com:DLR-SC/prov-db-connector.git 20 | cd prov-db-connector 21 | 22 | # Setup virtual environment 23 | virtualenv -p /usr/bin/python3.4 env 24 | source env/bin/activate 25 | 26 | # Install dependencies 27 | make dev-setup 28 | 29 | Execute tests 30 | ------------- 31 | 32 | .. code:: sh 33 | 34 | make test 35 | 36 | Coverage report 37 | --------------- 38 | 39 | .. code:: sh 40 | 41 | make coverage 42 | 43 | Compile documentation 44 | --------------------- 45 | 46 | .. code:: sh 47 | 48 | make docs 49 | 50 | Create new database adapters 51 | ---------------------------- 52 | 53 | The database adapters are the binding class to the actual database. 54 | If you are consider to build your own adapter please keep in mind: 55 | 56 | * All adapters **must** enhance the :py:class:`~provdbconnector.db_adapters.baseadapter.Baseadapter` class. 57 | * You **must** implement all specified functions in BaseAdapter 58 | * You **should** test it via the :py:class:`~provdbconnector.tests.db_adapters.test_baseadapter.AdapterTestTemplate` class template. 59 | * You **should** test it also via the :py:class:`~provdbconnector.tests.test_provapi.ProvDbTestTemplate` class template. 60 | 61 | 1. - Create your database adapter 62 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 63 | 64 | First you must create a class that extend from :py:class:`~provdbconnector.db_adapters.baseadapter.Baseadapter` and implement all functions. 65 | 66 | .. literalinclude:: ../provdbconnector/db_adapters/in_memory/simple_in_memory.py 67 | :linenos: 68 | :lines: 1-30 69 | :language: python 70 | :emphasize-lines: 26-30 71 | 72 | 2. - Create test suites 73 | ~~~~~~~~~~~~~~~~~~~~~~~ 74 | 75 | To test your adapter you should create two test suits: 76 | 77 | * :py:class:`~provdbconnector.tests.db_adapters.in_memory.test_simple_in_memory.SimpleInMemoryAdapterTest` : Unit test for the low level functions in your adapter. 78 | * For further introduction on testing your database adapter have a look at the :ref:`test_howto`. 79 | * :py:class:`~provdbconnector.tests.db_adapters.in_memory.test_simple_in_memory.SimpleInMemoryAdapterProvDbTests` : Integration test for the adapter with the api. 80 | 81 | See this example tests for the :py:class:`~provdbconnector.db_adapters.in_memory.simple_in_memory.SimpleInMemoryAdapter` 82 | 83 | .. literalinclude:: ../provdbconnector/tests/db_adapters/in_memory/test_simple_in_memory.py 84 | :linenos: 85 | :language: python 86 | 87 | 88 | 3. - Implement your adapter logic 89 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 90 | 91 | The last step is to create your logic inside the :py:class:`~provdbconnector.db_adapters.in_memory.simple_in_memory.SimpleInMemoryAdapter` for example the save_record and get_record functions: 92 | 93 | Now you are ready to implement all other functions. 94 | 95 | .. note:: 96 | If you don't know where should you start 97 | Start with the first test and try to implement functions successively according to the tests 98 | and look into the documentation of the :py:class:`~provdbconnector.tests.db_adapters.test_baseadapter.AdapterTestTemplate` 99 | 100 | .. literalinclude:: ../provdbconnector/db_adapters/in_memory/simple_in_memory.py 101 | :linenos: 102 | :lines: 32-56, 105-115 103 | :language: python 104 | 105 | -------------------------------------------------------------------------------- /provdbconnector/utils/converter.py: -------------------------------------------------------------------------------- 1 | from functools import reduce 2 | from io import BufferedReader 3 | from provdbconnector.exceptions.utils import ParseException, NoDocumentException 4 | 5 | import six 6 | from prov.model import ProvDocument 7 | 8 | import logging 9 | log = logging.getLogger(__name__) 10 | 11 | 12 | def form_string(content): 13 | """ 14 | Take a string or BufferedReader as argument and transform the string into a ProvDocument 15 | 16 | :param content: Takes a sting or BufferedReader 17 | :return: ProvDocument 18 | """ 19 | if isinstance(content, ProvDocument): 20 | return content 21 | elif isinstance(content, BufferedReader): 22 | content = reduce(lambda total, a: total + a, content.readlines()) 23 | 24 | if type(content) is six.binary_type: 25 | content_str = content[0:15].decode() 26 | if content_str.find("{") > -1: 27 | return ProvDocument.deserialize(content=content, format='json') 28 | if content_str.find(' -1: 29 | return ProvDocument.deserialize(content=content, format='xml') 30 | elif content_str.find('document') > -1: 31 | return ProvDocument.deserialize(content=content, format='provn') 32 | 33 | raise ParseException("Unsupported input type {}".format(type(content))) 34 | 35 | 36 | def to_json(document=None): 37 | """ 38 | Try to convert a ProvDocument into the json representation 39 | 40 | :param document: 41 | :type document: prov.model.ProvDocument 42 | :return: Json string of the document 43 | :rtype: str 44 | """ 45 | if document is None: 46 | raise NoDocumentException() 47 | return document.serialize(format='json') 48 | 49 | 50 | def from_json(json=None): 51 | """ 52 | Try to convert a json string into a document 53 | 54 | :param json: The json str 55 | :type json: str 56 | :return: Prov Document 57 | :rtype: prov.model.ProvDocument 58 | :raise: NoDocumentException 59 | """ 60 | if json is None: 61 | raise NoDocumentException() 62 | return ProvDocument.deserialize(source=json, format='json') 63 | 64 | 65 | def to_provn(document=None): 66 | """ 67 | Try to convert a document into a provn representation 68 | 69 | :param document: Prov document to convert 70 | :type document: prov.model.ProvDocument 71 | :return: The prov-n str 72 | :rtype: str 73 | :raise: NoDocumentException 74 | """ 75 | if document is None: 76 | raise NoDocumentException() 77 | return document.serialize(format='provn') 78 | 79 | 80 | def from_provn(provn_str=None): 81 | """ 82 | Try to convert a provn string into a ProvDocument 83 | 84 | :param provn_str: The string to convert 85 | :type provn_str: str 86 | :return: The Prov document 87 | :rtype: ProvDocument 88 | :raises: NoDocumentException 89 | """ 90 | if provn_str is None: 91 | raise NoDocumentException() 92 | return ProvDocument.deserialize(source=provn_str, format='provn') 93 | 94 | 95 | def to_xml(document=None): 96 | """ 97 | Try to convert a document into an xml string 98 | 99 | :param document: The ProvDocument to convert 100 | :param document: ProvDocument 101 | :return: The xml string 102 | :rtype: str 103 | """ 104 | if document is None: 105 | raise NoDocumentException() 106 | return document.serialize(format='xml') 107 | 108 | 109 | def from_xml(xml_str=None): 110 | """ 111 | Try to convert a xml string into a ProvDocument 112 | 113 | :param xml_str: The xml string 114 | :type xml_str: str 115 | :return: The Prov document 116 | :rtype: ProvDocument 117 | """ 118 | if xml_str is None: 119 | raise NoDocumentException() 120 | return ProvDocument.deserialize(source=xml_str, format='xml') 121 | -------------------------------------------------------------------------------- /provdbconnector/tests/utils/test_converter.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from xml.etree import ElementTree 3 | import pkg_resources 4 | import json 5 | 6 | from prov.model import ProvDocument 7 | from prov.tests import examples 8 | from provdbconnector.utils.converter import to_json, from_json, to_provn, from_provn, to_xml, from_xml, form_string 9 | from provdbconnector.exceptions.utils import NoDocumentException, ParseException 10 | 11 | 12 | class ConverterTests(unittest.TestCase): 13 | """ 14 | Test the convert class 15 | """ 16 | 17 | def setUp(self): 18 | # Reading testfiles from prov package according to: 19 | # http://stackoverflow.com/questions/6028000/python-how-to-read-a-static-file-from-inside-a-package 20 | # 21 | # Assuming your template is located inside your module's package at this path: 22 | # /templates/temp_file 23 | # the correct way to read your template is to use pkg_resources package from setuptools distribution: 24 | test_resources = { 25 | 'xml': {'package': 'provdbconnector', 'file': '/tests/resources/primer.provx'}, 26 | 'json': {'package': 'provdbconnector', 'file': '/tests/resources/primer.json'}, 27 | 'provn': {'package': 'provdbconnector', 'file': '/tests/resources/primer.provn'} 28 | } 29 | self.test_files = dict( 30 | (key, pkg_resources.resource_stream(val['package'], val['file'])) for key, val in test_resources.items()) 31 | self.prov_document = examples.primer_example() 32 | 33 | def tearDown(self): 34 | """ 35 | Close all files 36 | """ 37 | [self.test_files[k].close() for k in self.test_files.keys()] 38 | 39 | def test_form_string(self): 40 | """ 41 | Test the convert from string 42 | """ 43 | result = form_string(self.test_files["json"]) 44 | self.assertIsNotNone(result) 45 | self.assertIsInstance(result, ProvDocument) 46 | 47 | result = form_string(self.test_files["xml"]) 48 | self.assertIsNotNone(result) 49 | self.assertIsInstance(result, ProvDocument) 50 | 51 | with self.assertRaises(NotImplementedError): 52 | form_string(self.test_files["provn"]) 53 | 54 | with self.assertRaises(ParseException): 55 | form_string("A funny string but no xml, json or prov string") 56 | 57 | def test_to_json(self): 58 | """ 59 | Test the convert to json 60 | """ 61 | self.assertRaises(NoDocumentException, lambda: to_json()) 62 | json_document = to_json(self.prov_document) 63 | self.assertIsInstance(json_document, str) 64 | try: 65 | json.loads(json_document) 66 | except ValueError: 67 | self.fail("Invalid JSON") 68 | 69 | def test_from_json(self): 70 | """ 71 | Test the convert from json 72 | """ 73 | self.assertRaises(NoDocumentException, lambda: from_json()) 74 | prov = from_json(self.test_files['json']) 75 | self.assertIsInstance(prov, ProvDocument) 76 | 77 | def test_to_provn(self): 78 | """ 79 | Test the convert to prov-n 80 | """ 81 | self.assertRaises(NoDocumentException, lambda: to_provn()) 82 | provn_document = to_provn(self.prov_document) 83 | self.assertIsInstance(provn_document, str) 84 | # Validate that string is in provn format 85 | 86 | def test_from_provn(self): 87 | """ 88 | Test the convert from prov-n 89 | """ 90 | self.assertRaises(NoDocumentException, lambda: from_provn()) 91 | # currently the prov lib don't support from_provn 92 | 93 | with self.assertRaises(NotImplementedError): 94 | from_provn(self.test_files['provn']) 95 | 96 | # self.assertIsInstance(prov, ProvDocument) 97 | 98 | def test_to_xml(self): 99 | """ 100 | Test the convert to xml 101 | """ 102 | self.assertRaises(NoDocumentException, lambda: to_xml()) 103 | xml_document = to_xml(self.prov_document) 104 | self.assertIsInstance(xml_document, str) 105 | ElementTree.fromstring(xml_document) 106 | 107 | def test_from_xml(self): 108 | """ 109 | Test the convert from xml 110 | """ 111 | self.assertRaises(NoDocumentException, lambda: from_xml()) 112 | prov = from_xml(self.test_files['xml']) 113 | self.assertIsInstance(prov, ProvDocument) 114 | -------------------------------------------------------------------------------- /docs/changelog.rst: -------------------------------------------------------------------------------- 1 | Changelog 2 | ========= 3 | Version 0.3.x 4 | ----------- 5 | 6 | - Upgraded prov to 1.5.3 .. #73: https://github.com/DLR-SC/prov-db-connector/pull/73 7 | - Upgraded neo4j-driver to 1.7.0 .. #70: https://github.com/DLR-SC/prov-db-connector/pull/70 8 | 9 | 10 | Version 0.3.1 11 | ----------- 12 | 13 | - Upgraded neo4j-driver to 1.6.2 .. #67: https://github.com/DLR-SC/prov-db-connector/pull/67 14 | - Enhanced error handling neo4j-adapater 15 | - Automatic pipi release on git tag 16 | 17 | Version 0.3 18 | ----------- 19 | 20 | - **Changed ``provdb.create_*`` to ``provdb.save_*``** because we can’t 21 | guarantee that the db-adapter actual create a new node, document, 22 | relation. Maybe the adapter merges your properties into existing 23 | data, behavior is still the same. 24 | - **Renamed files provDb.py into prov\_db.py** 25 | - Enhanced the ``prov:Mention`` support. If you create a bundle link 26 | (``prov:Mention``) the destination bundle entity will be 27 | automatically created. For example: \`\`\`python 28 | 29 | from prov.tests.examples import bundles2 30 | 31 | doc = bundles2() bundle = list(doc.get\_records()).pop() #I know, the 32 | get\_record function return a set, so it can happen that you get the 33 | wrong bundle here (alice:bundle5 is correct) 34 | prov\_api.save\_bundle(bundle) \`\`\` 35 | 36 | - Add ability to save relations between elements that doesn’t exist. 37 | For example, on a empty database: 38 | 39 | .. code:: python 40 | 41 | doc = ProvDocument() 42 | relation = doc.wasGeneratedBy("ex:Entity", "ex:Activity") 43 | 44 | #Works now fine. The ex:entity and ex:Activity elements will be created automatically 45 | provapi.save_relation(relation) 46 | 47 | - Removed node type “Unknown” for relations with unknown nodes. (The 48 | prov-db-adapter now detects which type the relation implicitly mean. 49 | 50 | .. code:: python 51 | 52 | doc = ProvDocument() 53 | relation = doc.wasGeneratedBy("ex:Entity", -) 54 | 55 | # Creates a Activity with a random identifier as destions for the relation 56 | provapi.save_relation(relation) 57 | 58 | - Introduced new methods 59 | 60 | **prov\_db.save\_relation(prov\_relation)** 61 | 62 | .. code:: python 63 | 64 | 65 | doc = ProvDocument() 66 | 67 | activity = doc.activity("ex:yourActivity") 68 | entity = doc.entity("ex:yourEntity") 69 | wasGeneratedBy = entity.wasGeneratedBy("ex:yourAgent") 70 | 71 | # Save the elements 72 | rel_id = prov_db.save_relation(wasGeneratedBy) 73 | 74 | **prov\_db.save\_element(prov\_element, [bundle\_id])** 75 | 76 | .. code:: python 77 | 78 | 79 | doc = ProvDocument() 80 | 81 | agent = doc.agent("ex:yourAgent") 82 | activity = doc.activity("ex:yourActivity") 83 | entity = doc.entity("ex:yourEntity") 84 | 85 | # Save the elements 86 | agent_id = prov_db.save_element(agent) 87 | activity_id = prov_db.save_element(activity) 88 | entity_id = prov_db.save_element(entity) 89 | 90 | **prov\_db.get\_element(identifier)** 91 | 92 | .. code:: python 93 | 94 | 95 | doc = ProvDocument() 96 | 97 | identifier = QualifiedName(doc, "ex:yourAgent") 98 | 99 | prov_element = prov_db.get_element(identifier) 100 | 101 | **prov\_db.save\_record(prov\_record, [bundle\_id])** 102 | 103 | .. code:: python 104 | 105 | 106 | doc = ProvDocument() 107 | 108 | agent = doc.agent("ex:Alice") 109 | ass_rel = doc.association("ex:Alice", "ex:Bob") 110 | 111 | # Save the elements 112 | agent_id = prov_db.save_record(agent) 113 | relation_id = prov_db.save_record(ass_rel) 114 | 115 | **prov\_api.save\_bundle(prov\_bundle)** 116 | 117 | .. code:: python 118 | 119 | 120 | doc = ProvDocument() 121 | 122 | bundle = doc.bundle("ex:bundle1") 123 | # Save the bundle 124 | prov_db.save_bundle(bundle) 125 | 126 | **prov\_db.get\_elements([ProvCLS])** 127 | 128 | .. code:: python 129 | 130 | from prov.model import ProvEntity, ProvAgent, ProvActivity 131 | 132 | document_with_all_entities = prov_db.get_elements(ProvEntity) 133 | document_with_all_agents = prov_db.get_elements(ProvAgent) 134 | document_with_all_activities = prov_db.get_elements(ProvActivity) 135 | 136 | print(document_with_all_entities) 137 | print(document_with_all_agents) 138 | print(document_with_all_activities) 139 | 140 | **prov\_db.get\_bundle(identifier)** 141 | 142 | .. code:: python 143 | 144 | doc = ProvDocument() 145 | bundle_name = doc.valid_qualified_name("ex:YourBundleName") 146 | # get the bundle 147 | prov_bundle = prov_db.get_bundle(bundle_name) 148 | doc.add_bundle(prov_bundle) 149 | -------------------------------------------------------------------------------- /provdbconnector/db_adapters/neo4j/cypher_commands.py: -------------------------------------------------------------------------------- 1 | NEO4J_TEST_CONNECTION = """MATCH (n) RETURN count(n) as count""" 2 | 3 | # create 4 | NEO4J_CREATE_DOCUMENT_NODE_RETURN_ID = """ 5 | CYPHER 3.5 6 | CREATE (node { }) RETURN ID(node) as ID""" 7 | NEO4J_CREATE_NODE_SET_PART = "SET node.`{attr_name}` = {{`{attr_name}`}}" 8 | NEO4J_CREATE_NODE_SET_PART_MERGE_ATTR = "SET node.`{attr_name}` = (CASE WHEN not exists(node.`{attr_name}`) THEN [{{`{attr_name}`}}] ELSE node.`{attr_name}` + {{`{attr_name}`}} END)" 9 | NEO4J_CREATE_NODE_MERGE_CHECK_PART = """WITH CASE WHEN check = 0 THEN (CASE WHEN EXISTS(node.`{attr_name}`) AND node.`{attr_name}` <> {{`{attr_name}`}} THEN 1 ELSE 0 END) ELSE 1 END as check , node""" 10 | NEO4J_CREATE_NODE_RETURN_ID = """ 11 | CYPHER 3.5 12 | MERGE (node:{label} {{{formal_attributes}}}) 13 | WITH 0 as check, node 14 | {merge_check_statement} 15 | {set_statement} 16 | RETURN ID(node) as ID, check """ # args: provType, values 17 | NEO4J_CREATE_RELATION_RETURN_ID = """ 18 | CYPHER 3.5 19 | MATCH 20 | (from{{`meta:identifier`:'{from_identifier}'}}), 21 | (to{{`meta:identifier`:'{to_identifier}'}}) 22 | MERGE 23 | (from)-[r:{relation_type} {{{formal_attributes}}}]->(to) 24 | WITH 0 as check, r as node 25 | {merge_check_statement} 26 | {set_statement} 27 | RETURN 28 | ID(node) as ID, check 29 | """ # args: provType, values 30 | # get 31 | NEO4J_GET_RECORDS_BY_PROPERTY_DICT = """ 32 | CYPHER 3.5 33 | MATCH (d {{{filter_dict}}} )-[r]-(x {{{filter_dict}}}) 34 | RETURN DISTINCT r as re 35 | //Get all nodes that are alone without connections to other nodes 36 | UNION 37 | MATCH (a {{{filter_dict}}}) 38 | RETURN DISTINCT a as re 39 | """ 40 | NEO4J_GET_RECORDS_TAIL_BY_FILTER = """ 41 | CYPHER 3.5 42 | MATCH (x {{{filter_dict}}})-[r *{depth}]-(y) 43 | RETURN DISTINCT y as re 44 | UNION 45 | MATCH (x {{{filter_dict}}})-[r *{depth}]-(y) 46 | WITH REDUCE(output = [], r IN r | output + r) AS flat 47 | UNWIND flat as re 48 | RETURN DISTINCT re 49 | """ 50 | 51 | NEO4J_GET_BUNDLE_RECORDS = """ 52 | CYPHER 3.5 53 | MATCH (x {`meta:identifier`: {`meta:identifier`}})-[r *1]-(y) 54 | WHERE ALL (rel in r WHERE rel.`prov:type` = 'prov:bundleAssociation') 55 | RETURN DISTINCT y as re 56 | UNION 57 | //get all relations between the nodes 58 | MATCH (origin {`meta:identifier`: {`meta:identifier`}})-[r *1]-(x)-[r_return *1]-(y)-[r_2 *1]-(origin {`meta:identifier`: {`meta:identifier`}}) 59 | WHERE ALL (rel in r WHERE rel.`prov:type` = 'prov:bundleAssociation') 60 | AND ALL (rel in r_2 WHERE rel.`prov:type` = 'prov:bundleAssociation') 61 | WITH REDUCE(output = [], r IN r_return | output + r) AS flat 62 | UNWIND flat as re 63 | RETURN DISTINCT re 64 | //get all mentionof relations 65 | UNION 66 | MATCH (bundle_1 {`meta:identifier`: {`meta:identifier`}})-[r *1]-(x)-[r_return *1]-(y)-[r_2 *1]-(bundle_2) 67 | WHERE ALL (rel in r WHERE rel.`prov:type` = 'prov:bundleAssociation') 68 | AND ALL (rel in r_2 WHERE rel.`prov:type` = 'prov:bundleAssociation') 69 | AND ALL (rel in r_return WHERE rel.`meta:prov_type` = 'prov:Mention' and startNode(rel) = x) 70 | WITH REDUCE(output = [], r IN r_return | output + r) AS flat 71 | UNWIND flat as re 72 | RETURN DISTINCT re 73 | 74 | """ 75 | 76 | NEO4J_GET_RECORD_RETURN_NODE = """ 77 | CYPHER 3.5 78 | MATCH (node) WHERE ID(node)={record_id} RETURN node""" 79 | NEO4J_GET_RELATION_RETURN_NODE = """ 80 | CYPHER 3.5 81 | MATCH ()-[relation]-() WHERE ID(relation)={relation_id} RETURN relation""" 82 | 83 | # delete 84 | NEO4J_DELETE__NODE_BY_ID = """ 85 | CYPHER 3.5 86 | MATCH (x) Where ID(x) = {node_id} DETACH DELETE x """ 87 | NEO4J_DELETE_NODE_BY_PROPERTIES = """ 88 | CYPHER 3.5 89 | MATCH (n {{{filter_dict}}}) DETACH DELETE n""" 90 | NEO4J_DELETE_BUNDLE_NODE_BY_ID = """ 91 | CYPHER 3.5 92 | MATCH (b) WHERE id(b)=toInt({bundle_id}) DELETE b """ 93 | NEO4J_DELETE_RELATION_BY_ID = """ 94 | CYPHER 3.5 95 | MATCH ()-[r]-() WHERE id(r) = {relation_id} DELETE r""" 96 | -------------------------------------------------------------------------------- /examples/file_buffer_example_primer.json: -------------------------------------------------------------------------------- 1 | { 2 | "wasAssociatedWith": { 3 | "_:wAW3963": { 4 | "prov:activity": "ex:illustrate", 5 | "prov:agent": "ex:derek" 6 | }, 7 | "_:wAW3962": { 8 | "prov:activity": "ex:compose", 9 | "prov:agent": "ex:derek" 10 | } 11 | }, 12 | "specializationOf": { 13 | "_:sO11133": { 14 | "prov:generalEntity": "ex:article", 15 | "prov:specificEntity": "ex:articleV2" 16 | }, 17 | "_:sO11132": { 18 | "prov:generalEntity": "ex:article", 19 | "prov:specificEntity": "ex:articleV1" 20 | } 21 | }, 22 | "wasAttributedTo": { 23 | "_:wAT3855": { 24 | "prov:agent": "ex:derek", 25 | "prov:entity": "ex:chart1" 26 | } 27 | }, 28 | "wasGeneratedBy": { 29 | "_:wGB7794": { 30 | "prov:activity": "ex:compile2", 31 | "prov:time": "2012-04-01T15:21:00.000+01:00", 32 | "prov:entity": "ex:chart2" 33 | }, 34 | "_:wGB7795": { 35 | "prov:activity": "ex:correct", 36 | "prov:entity": "ex:dataSet2" 37 | }, 38 | "_:wGB7792": { 39 | "prov:activity": "ex:illustrate", 40 | "prov:entity": "ex:chart1" 41 | }, 42 | "_:wGB7793": { 43 | "prov:activity": "ex:compile", 44 | "prov:time": "2012-03-02T10:30:00.000Z", 45 | "prov:entity": "ex:chart1" 46 | }, 47 | "_:wGB7791": { 48 | "prov:activity": "ex:compose", 49 | "prov:entity": "ex:composition" 50 | } 51 | }, 52 | "entity": { 53 | "ex:composition": {}, 54 | "ex:regionList": {}, 55 | "ex:blogEntry": {}, 56 | "ex:chart1": {}, 57 | "ex:dataSet2": {}, 58 | "ex:chart2": {}, 59 | "ex:dataSet1": {}, 60 | "ex:article": { 61 | "dcterms:title": { 62 | "$": "Crime rises in cities", 63 | "type": "xsd:string" 64 | } 65 | }, 66 | "ex:articleV2": {}, 67 | "ex:articleV1": {} 68 | }, 69 | "prefix": { 70 | "xsd": "http://www.w3.org/2001/XMLSchema#", 71 | "foaf": "http://xmlns.com/foaf/0.1/", 72 | "prov": "http://www.w3.org/ns/prov#", 73 | "ex": "http://example/", 74 | "dcterms": "http://purl.org/dc/terms/" 75 | }, 76 | "alternateOf": { 77 | "_:aO49": { 78 | "prov:alternate2": "ex:articleV2", 79 | "prov:alternate1": "ex:articleV1" 80 | } 81 | }, 82 | "wasDerivedFrom": { 83 | "_:wDF21119": { 84 | "prov:generatedEntity": "ex:articleV2", 85 | "prov:usedEntity": "ex:dataSet2" 86 | }, 87 | "_:wDF21116": { 88 | "prov:generatedEntity": "ex:chart2", 89 | "prov:usedEntity": "ex:dataSet2" 90 | }, 91 | "_:wDF21115": { 92 | "prov:generatedEntity": "ex:dataSet2", 93 | "prov:type": { 94 | "$": "prov:Revision", 95 | "type": "prov:QUALIFIED_NAME" 96 | }, 97 | "prov:usedEntity": "ex:dataSet1" 98 | }, 99 | "_:wDF21118": { 100 | "prov:generatedEntity": "ex:articleV1", 101 | "prov:usedEntity": "ex:dataSet1" 102 | }, 103 | "_:wDF21117": { 104 | "prov:generatedEntity": "ex:blogEntry", 105 | "prov:type": { 106 | "$": "prov:Quotation", 107 | "type": "prov:QUALIFIED_NAME" 108 | }, 109 | "prov:usedEntity": "ex:article" 110 | } 111 | }, 112 | "used": { 113 | "_:u6219": { 114 | "prov:activity": "ex:compose", 115 | "prov:role": { 116 | "$": "ex:dataToCompose", 117 | "type": "prov:QUALIFIED_NAME" 118 | }, 119 | "prov:entity": "ex:dataSet1" 120 | }, 121 | "_:u6217": { 122 | "prov:activity": "ex:compose", 123 | "prov:entity": "ex:regionList" 124 | }, 125 | "_:u6218": { 126 | "prov:activity": "ex:illustrate", 127 | "prov:entity": "ex:composition" 128 | }, 129 | "_:u6216": { 130 | "prov:activity": "ex:compose", 131 | "prov:entity": "ex:dataSet1" 132 | }, 133 | "_:u6221": { 134 | "prov:activity": "ex:correct", 135 | "prov:entity": "ex:dataSet1" 136 | }, 137 | "_:u6220": { 138 | "prov:activity": "ex:compose", 139 | "prov:role": { 140 | "$": "ex:regionsToAggregateBy", 141 | "type": "prov:QUALIFIED_NAME" 142 | }, 143 | "prov:entity": "ex:regionList" 144 | } 145 | }, 146 | "agent": { 147 | "ex:derek": { 148 | "prov:type": { 149 | "$": "prov:Person", 150 | "type": "prov:QUALIFIED_NAME" 151 | }, 152 | "foaf:givenName": { 153 | "$": "Derek", 154 | "type": "xsd:string" 155 | }, 156 | "foaf:mbox": { 157 | "$": "\u003cmailto:derek@example.org\u003e", 158 | "type": "xsd:string" 159 | } 160 | }, 161 | "ex:chartgen": { 162 | "prov:type": { 163 | "$": "prov:Organization", 164 | "type": "prov:QUALIFIED_NAME" 165 | }, 166 | "foaf:name": { 167 | "$": "Chart Generators Inc", 168 | "type": "xsd:string" 169 | } 170 | } 171 | }, 172 | "actedOnBehalfOf": { 173 | "_:aOBO259": { 174 | "prov:activity": "ex:compose", 175 | "prov:delegate": "ex:derek", 176 | "prov:responsible": "ex:chartgen" 177 | } 178 | }, 179 | "activity": { 180 | "ex:illustrate": {}, 181 | "ex:correct": { 182 | "prov:startTime": "2012-03-31T09:21:00.000+01:00", 183 | "prov:endTime": "2012-04-01T15:21:00.000+01:00" 184 | }, 185 | "ex:compile2": {}, 186 | "ex:compile": {}, 187 | "ex:compose": {} 188 | } 189 | } -------------------------------------------------------------------------------- /provdbconnector/tests/resources/primer.json: -------------------------------------------------------------------------------- 1 | { 2 | "wasAssociatedWith": { 3 | "_:wAW3963": { 4 | "prov:activity": "ex:illustrate", 5 | "prov:agent": "ex:derek" 6 | }, 7 | "_:wAW3962": { 8 | "prov:activity": "ex:compose", 9 | "prov:agent": "ex:derek" 10 | } 11 | }, 12 | "specializationOf": { 13 | "_:sO11133": { 14 | "prov:generalEntity": "ex:article", 15 | "prov:specificEntity": "ex:articleV2" 16 | }, 17 | "_:sO11132": { 18 | "prov:generalEntity": "ex:article", 19 | "prov:specificEntity": "ex:articleV1" 20 | } 21 | }, 22 | "wasAttributedTo": { 23 | "_:wAT3855": { 24 | "prov:agent": "ex:derek", 25 | "prov:entity": "ex:chart1" 26 | } 27 | }, 28 | "wasGeneratedBy": { 29 | "_:wGB7794": { 30 | "prov:activity": "ex:compile2", 31 | "prov:time": "2012-04-01T15:21:00.000+01:00", 32 | "prov:entity": "ex:chart2" 33 | }, 34 | "_:wGB7795": { 35 | "prov:activity": "ex:correct", 36 | "prov:entity": "ex:dataSet2" 37 | }, 38 | "_:wGB7792": { 39 | "prov:activity": "ex:illustrate", 40 | "prov:entity": "ex:chart1" 41 | }, 42 | "_:wGB7793": { 43 | "prov:activity": "ex:compile", 44 | "prov:time": "2012-03-02T10:30:00.000Z", 45 | "prov:entity": "ex:chart1" 46 | }, 47 | "_:wGB7791": { 48 | "prov:activity": "ex:compose", 49 | "prov:entity": "ex:composition" 50 | } 51 | }, 52 | "entity": { 53 | "ex:composition": {}, 54 | "ex:regionList": {}, 55 | "ex:blogEntry": {}, 56 | "ex:chart1": {}, 57 | "ex:dataSet2": {}, 58 | "ex:chart2": {}, 59 | "ex:dataSet1": {}, 60 | "ex:article": { 61 | "dcterms:title": { 62 | "$": "Crime rises in cities", 63 | "type": "xsd:string" 64 | } 65 | }, 66 | "ex:articleV2": {}, 67 | "ex:articleV1": {} 68 | }, 69 | "prefix": { 70 | "xsd": "http://www.w3.org/2001/XMLSchema#", 71 | "foaf": "http://xmlns.com/foaf/0.1/", 72 | "prov": "http://www.w3.org/ns/prov#", 73 | "ex": "http://example/", 74 | "dcterms": "http://purl.org/dc/terms/" 75 | }, 76 | "alternateOf": { 77 | "_:aO49": { 78 | "prov:alternate2": "ex:articleV2", 79 | "prov:alternate1": "ex:articleV1" 80 | } 81 | }, 82 | "wasDerivedFrom": { 83 | "_:wDF21119": { 84 | "prov:generatedEntity": "ex:articleV2", 85 | "prov:usedEntity": "ex:dataSet2" 86 | }, 87 | "_:wDF21116": { 88 | "prov:generatedEntity": "ex:chart2", 89 | "prov:usedEntity": "ex:dataSet2" 90 | }, 91 | "_:wDF21115": { 92 | "prov:generatedEntity": "ex:dataSet2", 93 | "prov:type": { 94 | "$": "prov:Revision", 95 | "type": "prov:QUALIFIED_NAME" 96 | }, 97 | "prov:usedEntity": "ex:dataSet1" 98 | }, 99 | "_:wDF21118": { 100 | "prov:generatedEntity": "ex:articleV1", 101 | "prov:usedEntity": "ex:dataSet1" 102 | }, 103 | "_:wDF21117": { 104 | "prov:generatedEntity": "ex:blogEntry", 105 | "prov:type": { 106 | "$": "prov:Quotation", 107 | "type": "prov:QUALIFIED_NAME" 108 | }, 109 | "prov:usedEntity": "ex:article" 110 | } 111 | }, 112 | "used": { 113 | "_:u6219": { 114 | "prov:activity": "ex:compose", 115 | "prov:role": { 116 | "$": "ex:dataToCompose", 117 | "type": "prov:QUALIFIED_NAME" 118 | }, 119 | "prov:entity": "ex:dataSet1" 120 | }, 121 | "_:u6217": { 122 | "prov:activity": "ex:compose", 123 | "prov:entity": "ex:regionList" 124 | }, 125 | "_:u6218": { 126 | "prov:activity": "ex:illustrate", 127 | "prov:entity": "ex:composition" 128 | }, 129 | "_:u6216": { 130 | "prov:activity": "ex:compose", 131 | "prov:entity": "ex:dataSet1" 132 | }, 133 | "_:u6221": { 134 | "prov:activity": "ex:correct", 135 | "prov:entity": "ex:dataSet1" 136 | }, 137 | "_:u6220": { 138 | "prov:activity": "ex:compose", 139 | "prov:role": { 140 | "$": "ex:regionsToAggregateBy", 141 | "type": "prov:QUALIFIED_NAME" 142 | }, 143 | "prov:entity": "ex:regionList" 144 | } 145 | }, 146 | "agent": { 147 | "ex:derek": { 148 | "prov:type": { 149 | "$": "prov:Person", 150 | "type": "prov:QUALIFIED_NAME" 151 | }, 152 | "foaf:givenName": { 153 | "$": "Derek", 154 | "type": "xsd:string" 155 | }, 156 | "foaf:mbox": { 157 | "$": "\u003cmailto:derek@example.org\u003e", 158 | "type": "xsd:string" 159 | } 160 | }, 161 | "ex:chartgen": { 162 | "prov:type": { 163 | "$": "prov:Organization", 164 | "type": "prov:QUALIFIED_NAME" 165 | }, 166 | "foaf:name": { 167 | "$": "Chart Generators Inc", 168 | "type": "xsd:string" 169 | } 170 | } 171 | }, 172 | "actedOnBehalfOf": { 173 | "_:aOBO259": { 174 | "prov:activity": "ex:compose", 175 | "prov:delegate": "ex:derek", 176 | "prov:responsible": "ex:chartgen" 177 | } 178 | }, 179 | "activity": { 180 | "ex:illustrate": {}, 181 | "ex:correct": { 182 | "prov:startTime": "2012-03-31T09:21:00.000+01:00", 183 | "prov:endTime": "2012-04-01T15:21:00.000+01:00" 184 | }, 185 | "ex:compile2": {}, 186 | "ex:compile": {}, 187 | "ex:compose": {} 188 | } 189 | } -------------------------------------------------------------------------------- /provdbconnector/tests/resources/primer.provx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Crime rises in cities 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 2012-03-31T09:21:00.000+01:00 20 | 2012-04-01T15:21:00.000+01:00 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 2012-03-02T10:30:00.000Z 47 | 48 | 49 | 50 | 51 | 2012-04-01T15:21:00.000+01:00 52 | 53 | 54 | prov:Person 55 | Derek 56 | <mailto:derek@example.org> 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | prov:Organization 68 | Chart Generators Inc 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | ex:dataToCompose 83 | 84 | 85 | 86 | 87 | ex:regionsToAggregateBy 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | prov:Revision 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | prov:Quotation 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_12_get_records_tail_recursive.svg: -------------------------------------------------------------------------------- 1 | 3 | Neo4j Graph Visualization 4 | Created using Neo4j (http://www.neo4j.com/) 5 | 6 | 7 | 9 | mentionOf 11 | 12 | 13 | 14 | 16 | mentionOf 18 | 19 | 20 | 21 | 23 | mentionOf 25 | 26 | 27 | 28 | 30 | mentionOf 32 | 33 | 34 | 35 | 36 | 37 | 38 | ex:prov:… 40 | 41 | 42 | 43 | 44 | prov:Bu… 46 | 47 | 48 | 49 | 50 | ex:FROM 52 | 53 | NODE 55 | 56 | 57 | 58 | 59 | ex:TO 61 | 62 | NODE 64 | 65 | 66 | 67 | 68 | ex:seco… 70 | 71 | 72 | 73 | 74 | ex:seco… 76 | 77 | 78 | 79 | 80 | ex:seco… 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /provdbconnector/db_adapters/baseadapter.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from collections import namedtuple 3 | 4 | log = logging.getLogger(__name__).addHandler(logging.NullHandler()) 5 | 6 | METADATA_PARENT_ID = "parent_id" 7 | METADATA_KEY_PROV_TYPE = "prov_type" 8 | METADATA_KEY_IDENTIFIER = "identifier" 9 | METADATA_KEY_IDENTIFIER_ORIGINAL = "identifier_original" 10 | METADATA_KEY_NAMESPACES = "namespaces" 11 | METADATA_KEY_TYPE_MAP = "type_map" 12 | 13 | # Return types for adapter classes 14 | DbDocument = namedtuple("DbDocument", "document, bundles") 15 | DbBundle = namedtuple("DbBundle", "records, bundle_record") 16 | 17 | DbRecord = namedtuple("DbRecord", "attributes, metadata") 18 | DbRelation = namedtuple("DbRelation", "attributes, metadata") 19 | 20 | 21 | class BaseAdapter(): 22 | """ 23 | Interface class for a prov database adapter 24 | """ 25 | 26 | def __init__(self, *args, **kwargs): 27 | pass 28 | 29 | def connect(self, authentication_info): 30 | """ 31 | Establish the database connection / login into the database 32 | 33 | :param authentication_info: a custom dict with credentials 34 | :type authentication_info: dict 35 | :return: Indicate whether the connection was successful 36 | :rtype: boolean 37 | :raise InvalidOptionsException: 38 | """ 39 | raise NotImplementedError("Abstract method") 40 | 41 | def save_element(self, attributes, metadata): 42 | """ 43 | Saves a entity, activity or entity into the database 44 | 45 | :param attributes: Attributes as dict for the record. Be careful you have to encode the dict 46 | :type attributes: dict 47 | :param metadata: Metadata as dict for the record. Be careful you have to encode the dict but you can be sure that all meta keys are always there 48 | :type metadata: dict 49 | :return: Record id 50 | :rtype: str 51 | """ 52 | raise NotImplementedError("Abstract method") 53 | 54 | def save_relation(self, from_node, to_node, attributes, metadata): 55 | """ 56 | Create a relation between 2 nodes 57 | 58 | :param from_node: The identifier 59 | :type from_node: str 60 | :param to_node: The identifier for the destination node 61 | :type: to_node: str 62 | :param attributes: Attributes as dict for the record. Be careful you have to encode the dict 63 | :type attributes: dict 64 | :param metadata: Metadata as dict for the record. Be careful you have to encode the dict but you can be sure that all meta keys are always there 65 | :type metadata: dict 66 | :return: Record id 67 | :rtype: str 68 | """ 69 | raise NotImplementedError("Abstract method") 70 | 71 | def get_records_by_filter(self, attributes_dict=None, metadata_dict=None): 72 | """ 73 | Returns all records (nodes and relations) based on a filter dict. 74 | The filter dict's are and AND combination but only the start node must fulfill the conditions. 75 | The result should contain all associated relations and nodes together 76 | 77 | :param attributes_dict: 78 | :type attributes_dict: dict 79 | :param metadata_dict: 80 | :type metadata_dict: dict 81 | :return: list of relations and nodes 82 | :rtype: list 83 | """ 84 | raise NotImplementedError("Abstract method") 85 | 86 | def get_records_tail(self, attributes_dict=None, metadata_dict=None, depth=None): 87 | """ 88 | Returns all connected nodes and relations based on a filter. 89 | The filter is an AND combination and this describes the filter only for the origin nodes. 90 | 91 | :param attributes_dict: 92 | :type attributes_dict: dict 93 | :param metadata_dict: 94 | :type metadata_dict: dict 95 | :param depth: 96 | :type depth: int 97 | :return: a list of relations and nodes 98 | :rtype: list 99 | """ 100 | raise NotImplementedError("Abstract method") 101 | 102 | def get_bundle_records(self, bundle_identifier): 103 | """ 104 | Returns the relations and nodes for a specific bundle identifier. 105 | Please use the bundle association to get all bundle nodes. 106 | Only the relations belongs to the bundle where the start AND end node belong also to the bundle. 107 | Except the prov:Mention see: W3C bundle links 108 | 109 | :param bundle_identifier: The bundle identifier 110 | :type bundle_identifier: str 111 | :return: list of nodes and bundles 112 | :rtype: list 113 | """ 114 | raise NotImplementedError("Abstract method") 115 | 116 | def get_record(self, record_id): 117 | """ 118 | Return a single record 119 | 120 | :param record_id: The id 121 | :type record_id: str 122 | :return: DbRecord 123 | :rtype: DbRecord 124 | """ 125 | raise NotImplementedError("Abstract method") 126 | 127 | def get_relation(self, relation_id): 128 | """ 129 | Returns a single relation 130 | 131 | :param relation_id: The id 132 | :type relation_id: str 133 | :return: DbRelation 134 | :rtype: DbRelation 135 | """ 136 | raise NotImplementedError("Abstract method") 137 | 138 | def delete_records_by_filter(self, attributes_dict, metadata_dict): 139 | """ 140 | Delete records by filter 141 | 142 | :param attributes_dict: 143 | :type attributes_dict: dict 144 | :param metadata_dict: 145 | :type metadata_dict: dict 146 | :return: Indicates whether the deletion was successful 147 | :rtype: boolean 148 | :raise NotFoundException: 149 | """ 150 | raise NotImplementedError("Abstract method") 151 | 152 | def delete_record(self, record_id): 153 | """ 154 | Delete a single record 155 | 156 | :param record_id: 157 | :type record_id: str 158 | :return: Indicates whether the deletion was successful 159 | :rtype: boolean 160 | :raise NotFoundException: 161 | """ 162 | raise NotImplementedError("Abstract method") 163 | 164 | def delete_relation(self, relation_id): 165 | """ 166 | Delete a single relation 167 | 168 | :param relation_id: 169 | :type relation_id: str 170 | :return: Indicates whether the deletion was successful 171 | :rtype: boolean 172 | :raise NotFoundException: 173 | """ 174 | raise NotImplementedError("Abstract method") 175 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | PROV Database Connector 2 | ======================= 3 | 4 | Introduction 5 | ------------ 6 | 7 | .. image:: https://zenodo.org/badge/68604048.svg 8 | :target: https://zenodo.org/badge/latestdoi/68604048 9 | :alt: Latest release 10 | .. image:: https://badge.fury.io/py/prov-db-connector.svg 11 | :target: https://pypi.python.org/pypi/prov-db-connector 12 | :alt: PyPI version 13 | .. image:: https://travis-ci.org/DLR-SC/prov-db-connector.svg?branch=master 14 | :target: https://travis-ci.org/DLR-SC/prov-db-connector 15 | :alt: Build Status 16 | .. image:: https://coveralls.io/repos/github/DLR-SC/prov-db-connector/badge.svg?branch=master 17 | :target: https://coveralls.io/github/DLR-SC/prov-db-connector?branch=master 18 | :alt: Coverage Status 19 | .. image:: https://pyup.io/repos/github/dlr-sc/prov-db-connector/shield.svg 20 | :target: https://pyup.io/repos/github/dlr-sc/prov-db-connector/ 21 | :alt: Updates 22 | 23 | 24 | 25 | This python module provides a general interface to save `W3C-PROV `_ documents into databases. 26 | Currently we support the `Neo4j `_ graph database. 27 | 28 | We transform a PROV document into a graph structure and the result looks like this: 29 | 30 | .. figure:: https://cdn.rawgit.com/dlr-sc/prov-db-connector/master/docs/_images/test_cases/test_prov_primer_example.svg 31 | :align: center 32 | :scale: 50 % 33 | :alt: Complex example in Neo4j 34 | 35 | Complex example in Neo4j 36 | 37 | See full documentation at: `prov-db-connector.readthedocs.io `_ 38 | 39 | Installation 40 | ------------ 41 | 42 | PyPi 43 | ~~~~ 44 | 45 | Install it by running:: 46 | 47 | pip install prov-db-connector 48 | 49 | You can view `prov-db-connector on PyPi's package index `_ 50 | 51 | Source 52 | ~~~~~~ 53 | 54 | .. code:: sh 55 | 56 | # Clone project 57 | git clone git@github.com:DLR-SC/prov-db-connector.git 58 | cd prov-db-connector 59 | 60 | # Setup virtual environment 61 | virtualenv -p /usr/bin/python3.4 env 62 | source env/bin/activate 63 | 64 | # Install dependencies and package into virtual enviroment 65 | make setup 66 | 67 | Usage 68 | ----- 69 | 70 | Save and get prov document example 71 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 72 | 73 | 74 | .. code-block:: python 75 | 76 | from prov.model import ProvDocument 77 | from provdbconnector import ProvDb 78 | from provdbconnector.db_adapters.in_memory import SimpleInMemoryAdapter 79 | 80 | prov_api = ProvDb(adapter=SimpleInMemoryAdapter, auth_info=None) 81 | 82 | # create the prov document 83 | prov_document = ProvDocument() 84 | prov_document.add_namespace("ex", "http://example.com") 85 | 86 | prov_document.agent("ex:Bob") 87 | prov_document.activity("ex:Alice") 88 | 89 | prov_document.association("ex:Alice", "ex:Bob") 90 | 91 | document_id = prov_api.save_document(prov_document) 92 | 93 | print(prov_api.get_document_as_provn(document_id)) 94 | 95 | # Output: 96 | # 97 | # document 98 | # prefix 99 | # ex < http: // example.com > 100 | # 101 | # agent(ex:Bob) 102 | # activity(ex:Alice, -, -) 103 | # wasAssociatedWith(ex:Alice, ex:Bob, -) 104 | # endDocument 105 | 106 | 107 | File Buffer example 108 | ~~~~~~~~~~~~~~~~~~~ 109 | 110 | 111 | .. code-block:: python 112 | 113 | from provdbconnector import ProvDb 114 | from provdbconnector.db_adapters.in_memory import SimpleInMemoryAdapter 115 | import pkg_resources 116 | 117 | # create the api 118 | prov_api = ProvDb(adapter=SimpleInMemoryAdapter, auth_info=None) 119 | 120 | # create the prov document from examples 121 | prov_document_buffer = pkg_resources.resource_stream("examples", "file_buffer_example_primer.json") 122 | 123 | # Save document 124 | document_id = prov_api.save_document(prov_document_buffer) 125 | # This is similar to: 126 | # prov_api.create_document_from_json(prov_document_buffer) 127 | 128 | # get document 129 | print(prov_api.get_document_as_provn(document_id)) 130 | 131 | # Output: 132 | 133 | # document 134 | # prefix 135 | # foaf < http: // xmlns.com / foaf / 0.1 / > 136 | # prefix 137 | # dcterms < http: // purl.org / dc / terms / > 138 | # prefix 139 | # ex < http: // example / > 140 | # 141 | # specializationOf(ex:articleV2, ex:article) 142 | # specializationOf(ex:articleV1, ex:article) 143 | # wasDerivedFrom(ex:blogEntry, ex:article, -, -, -, [prov:type = 'prov:Quotation']) 144 | # alternateOf(ex:articleV2, ex:articleV1) 145 | # wasDerivedFrom(ex:articleV1, ex:dataSet1, -, -, -) 146 | # wasDerivedFrom(ex:articleV2, ex:dataSet2, -, -, -) 147 | # wasDerivedFrom(ex:dataSet2, ex:dataSet1, -, -, -, [prov:type = 'prov:Revision']) 148 | # used(ex:correct, ex:dataSet1, -) 149 | # used(ex:compose, ex:dataSet1, -, [prov:role = "ex:dataToCompose"]) 150 | # wasDerivedFrom(ex:chart2, ex:dataSet2, -, -, -) 151 | # wasGeneratedBy(ex:dataSet2, ex:correct, -) 152 | # used(ex:compose, ex:regionList, -, [prov:role = "ex:regionsToAggregateBy"]) 153 | # used(ex:illustrate, ex:composition, -) 154 | # wasGeneratedBy(ex:composition, ex:compose, -) 155 | # wasAttributedTo(ex:chart1, ex:derek) 156 | # wasGeneratedBy(ex:chart1, ex:compile, 2012 - 03 - 02 157 | # T10:30:00) 158 | # wasGeneratedBy(ex:chart1, ex:illustrate, -) 159 | # wasAssociatedWith(ex:compose, ex:derek, -) 160 | # wasAssociatedWith(ex:illustrate, ex:derek, -) 161 | # actedOnBehalfOf(ex:derek, ex:chartgen, ex:compose) 162 | # entity(ex:article, [dcterms:title = "Crime rises in cities"]) 163 | # entity(ex:articleV1) 164 | # entity(ex:articleV2) 165 | # entity(ex:dataSet1) 166 | # entity(ex:dataSet2) 167 | # entity(ex:regionList) 168 | # entity(ex:composition) 169 | # entity(ex:chart1) 170 | # entity(ex:chart2) 171 | # entity(ex:blogEntry) 172 | # activity(ex:compile, -, -) 173 | # activity(ex:compile2, -, -) 174 | # activity(ex:compose, -, -) 175 | # activity(ex:correct, 2012 - 03 - 31 176 | # T09:21:00, 2012 - 04 - 01 177 | # T15:21:00) 178 | # activity(ex:illustrate, -, -) 179 | # agent(ex:derek, [foaf:mbox = "", foaf:givenName = "Derek", prov:type = 'prov:Person']) 180 | # agent(ex:chartgen, [foaf:name = "Chart Generators Inc", prov:type = 'prov:Organization']) 181 | # endDocument 182 | 183 | 184 | You find all examples in the `examples `_ folder 185 | 186 | 187 | Release 188 | ------- 189 | Create a new release on github, please use the semver standard for the version number 190 | 191 | 192 | License 193 | ------- 194 | 195 | See `LICENSE `_ file 196 | 197 | 198 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 14 | # the i18n builder cannot share the environment and doctrees with the others 15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 16 | 17 | .PHONY: help 18 | help: 19 | @echo "Please use \`make ' where is one of" 20 | @echo " html to make standalone HTML files" 21 | @echo " dirhtml to make HTML files named index.html in directories" 22 | @echo " singlehtml to make a single large HTML file" 23 | @echo " pickle to make pickle files" 24 | @echo " json to make JSON files" 25 | @echo " htmlhelp to make HTML files and a HTML help project" 26 | @echo " qthelp to make HTML files and a qthelp project" 27 | @echo " applehelp to make an Apple Help Book" 28 | @echo " devhelp to make HTML files and a Devhelp project" 29 | @echo " epub to make an epub" 30 | @echo " epub3 to make an epub3" 31 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 32 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 33 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 34 | @echo " text to make text files" 35 | @echo " man to make manual pages" 36 | @echo " texinfo to make Texinfo files" 37 | @echo " info to make Texinfo files and run them through makeinfo" 38 | @echo " gettext to make PO message catalogs" 39 | @echo " changes to make an overview of all changed/added/deprecated items" 40 | @echo " xml to make Docutils-native XML files" 41 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 42 | @echo " linkcheck to check all external links for integrity" 43 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 44 | @echo " coverage to run coverage check of the documentation (if enabled)" 45 | @echo " dummy to check syntax errors of document sources" 46 | 47 | .PHONY: clean 48 | clean: 49 | rm -rf $(BUILDDIR)/* 50 | 51 | .PHONY: html 52 | html: 53 | sphinx-apidoc -o . ../provdbconnector 54 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 55 | @echo 56 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 57 | 58 | .PHONY: dirhtml 59 | dirhtml: 60 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 61 | @echo 62 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 63 | 64 | .PHONY: singlehtml 65 | singlehtml: 66 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 67 | @echo 68 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 69 | 70 | .PHONY: pickle 71 | pickle: 72 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 73 | @echo 74 | @echo "Build finished; now you can process the pickle files." 75 | 76 | .PHONY: json 77 | json: 78 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 79 | @echo 80 | @echo "Build finished; now you can process the JSON files." 81 | 82 | .PHONY: htmlhelp 83 | htmlhelp: 84 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 85 | @echo 86 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 87 | ".hhp project file in $(BUILDDIR)/htmlhelp." 88 | 89 | .PHONY: qthelp 90 | qthelp: 91 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 92 | @echo 93 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 94 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 95 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PROVDatabaseConnector.qhcp" 96 | @echo "To view the help file:" 97 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PROVDatabaseConnector.qhc" 98 | 99 | .PHONY: applehelp 100 | applehelp: 101 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp 102 | @echo 103 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." 104 | @echo "N.B. You won't be able to view it unless you put it in" \ 105 | "~/Library/Documentation/Help or install it in your application" \ 106 | "bundle." 107 | 108 | .PHONY: devhelp 109 | devhelp: 110 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 111 | @echo 112 | @echo "Build finished." 113 | @echo "To view the help file:" 114 | @echo "# mkdir -p $$HOME/.local/share/devhelp/PROVDatabaseConnector" 115 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PROVDatabaseConnector" 116 | @echo "# devhelp" 117 | 118 | .PHONY: epub 119 | epub: 120 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 121 | @echo 122 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 123 | 124 | .PHONY: epub3 125 | epub3: 126 | $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 127 | @echo 128 | @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." 129 | 130 | .PHONY: latex 131 | latex: 132 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 133 | @echo 134 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 135 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 136 | "(use \`make latexpdf' here to do that automatically)." 137 | 138 | .PHONY: latexpdf 139 | latexpdf: 140 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 141 | @echo "Running LaTeX files through pdflatex..." 142 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 143 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 144 | 145 | .PHONY: latexpdfja 146 | latexpdfja: 147 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 148 | @echo "Running LaTeX files through platex and dvipdfmx..." 149 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 150 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 151 | 152 | .PHONY: text 153 | text: 154 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 155 | @echo 156 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 157 | 158 | .PHONY: man 159 | man: 160 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 161 | @echo 162 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 163 | 164 | .PHONY: texinfo 165 | texinfo: 166 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 167 | @echo 168 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 169 | @echo "Run \`make' in that directory to run these through makeinfo" \ 170 | "(use \`make info' here to do that automatically)." 171 | 172 | .PHONY: info 173 | info: 174 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 175 | @echo "Running Texinfo files through makeinfo..." 176 | make -C $(BUILDDIR)/texinfo info 177 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 178 | 179 | .PHONY: gettext 180 | gettext: 181 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 182 | @echo 183 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 184 | 185 | .PHONY: changes 186 | changes: 187 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 188 | @echo 189 | @echo "The overview file is in $(BUILDDIR)/changes." 190 | 191 | .PHONY: linkcheck 192 | linkcheck: 193 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 194 | @echo 195 | @echo "Link check complete; look for any errors in the above output " \ 196 | "or in $(BUILDDIR)/linkcheck/output.txt." 197 | 198 | .PHONY: doctest 199 | doctest: 200 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 201 | @echo "Testing of doctests in the sources finished, look at the " \ 202 | "results in $(BUILDDIR)/doctest/output.txt." 203 | 204 | .PHONY: coverage 205 | coverage: 206 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage 207 | @echo "Testing of coverage in the sources finished, look at the " \ 208 | "results in $(BUILDDIR)/coverage/python.txt." 209 | 210 | .PHONY: xml 211 | xml: 212 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 213 | @echo 214 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 215 | 216 | .PHONY: pseudoxml 217 | pseudoxml: 218 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 219 | @echo 220 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 221 | 222 | .PHONY: dummy 223 | dummy: 224 | $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy 225 | @echo 226 | @echo "Build finished. Dummy builder generates no files." 227 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. epub3 to make an epub3 31 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 32 | echo. text to make text files 33 | echo. man to make manual pages 34 | echo. texinfo to make Texinfo files 35 | echo. gettext to make PO message catalogs 36 | echo. changes to make an overview over all changed/added/deprecated items 37 | echo. xml to make Docutils-native XML files 38 | echo. pseudoxml to make pseudoxml-XML files for display purposes 39 | echo. linkcheck to check all external links for integrity 40 | echo. doctest to run all doctests embedded in the documentation if enabled 41 | echo. coverage to run coverage check of the documentation if enabled 42 | echo. dummy to check syntax errors of document sources 43 | goto end 44 | ) 45 | 46 | if "%1" == "clean" ( 47 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 48 | del /q /s %BUILDDIR%\* 49 | goto end 50 | ) 51 | 52 | 53 | REM Check if sphinx-build is available and fallback to Python version if any 54 | %SPHINXBUILD% 1>NUL 2>NUL 55 | if errorlevel 9009 goto sphinx_python 56 | goto sphinx_ok 57 | 58 | :sphinx_python 59 | 60 | set SPHINXBUILD=python -m sphinx.__init__ 61 | %SPHINXBUILD% 2> nul 62 | if errorlevel 9009 ( 63 | echo. 64 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 65 | echo.installed, then set the SPHINXBUILD environment variable to point 66 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 67 | echo.may add the Sphinx directory to PATH. 68 | echo. 69 | echo.If you don't have Sphinx installed, grab it from 70 | echo.http://sphinx-doc.org/ 71 | exit /b 1 72 | ) 73 | 74 | :sphinx_ok 75 | 76 | 77 | if "%1" == "html" ( 78 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 79 | if errorlevel 1 exit /b 1 80 | echo. 81 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 82 | goto end 83 | ) 84 | 85 | if "%1" == "dirhtml" ( 86 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 87 | if errorlevel 1 exit /b 1 88 | echo. 89 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 90 | goto end 91 | ) 92 | 93 | if "%1" == "singlehtml" ( 94 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 95 | if errorlevel 1 exit /b 1 96 | echo. 97 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 98 | goto end 99 | ) 100 | 101 | if "%1" == "pickle" ( 102 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 103 | if errorlevel 1 exit /b 1 104 | echo. 105 | echo.Build finished; now you can process the pickle files. 106 | goto end 107 | ) 108 | 109 | if "%1" == "json" ( 110 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 111 | if errorlevel 1 exit /b 1 112 | echo. 113 | echo.Build finished; now you can process the JSON files. 114 | goto end 115 | ) 116 | 117 | if "%1" == "htmlhelp" ( 118 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 119 | if errorlevel 1 exit /b 1 120 | echo. 121 | echo.Build finished; now you can run HTML Help Workshop with the ^ 122 | .hhp project file in %BUILDDIR%/htmlhelp. 123 | goto end 124 | ) 125 | 126 | if "%1" == "qthelp" ( 127 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 128 | if errorlevel 1 exit /b 1 129 | echo. 130 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 131 | .qhcp project file in %BUILDDIR%/qthelp, like this: 132 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\PROVDatabaseConnector.qhcp 133 | echo.To view the help file: 134 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\PROVDatabaseConnector.ghc 135 | goto end 136 | ) 137 | 138 | if "%1" == "devhelp" ( 139 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 140 | if errorlevel 1 exit /b 1 141 | echo. 142 | echo.Build finished. 143 | goto end 144 | ) 145 | 146 | if "%1" == "epub" ( 147 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 148 | if errorlevel 1 exit /b 1 149 | echo. 150 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 151 | goto end 152 | ) 153 | 154 | if "%1" == "epub3" ( 155 | %SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3 156 | if errorlevel 1 exit /b 1 157 | echo. 158 | echo.Build finished. The epub3 file is in %BUILDDIR%/epub3. 159 | goto end 160 | ) 161 | 162 | if "%1" == "latex" ( 163 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 164 | if errorlevel 1 exit /b 1 165 | echo. 166 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 167 | goto end 168 | ) 169 | 170 | if "%1" == "latexpdf" ( 171 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 172 | cd %BUILDDIR%/latex 173 | make all-pdf 174 | cd %~dp0 175 | echo. 176 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 177 | goto end 178 | ) 179 | 180 | if "%1" == "latexpdfja" ( 181 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 182 | cd %BUILDDIR%/latex 183 | make all-pdf-ja 184 | cd %~dp0 185 | echo. 186 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 187 | goto end 188 | ) 189 | 190 | if "%1" == "text" ( 191 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 192 | if errorlevel 1 exit /b 1 193 | echo. 194 | echo.Build finished. The text files are in %BUILDDIR%/text. 195 | goto end 196 | ) 197 | 198 | if "%1" == "man" ( 199 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 200 | if errorlevel 1 exit /b 1 201 | echo. 202 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 203 | goto end 204 | ) 205 | 206 | if "%1" == "texinfo" ( 207 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 208 | if errorlevel 1 exit /b 1 209 | echo. 210 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 211 | goto end 212 | ) 213 | 214 | if "%1" == "gettext" ( 215 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 216 | if errorlevel 1 exit /b 1 217 | echo. 218 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 219 | goto end 220 | ) 221 | 222 | if "%1" == "changes" ( 223 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 224 | if errorlevel 1 exit /b 1 225 | echo. 226 | echo.The overview file is in %BUILDDIR%/changes. 227 | goto end 228 | ) 229 | 230 | if "%1" == "linkcheck" ( 231 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 232 | if errorlevel 1 exit /b 1 233 | echo. 234 | echo.Link check complete; look for any errors in the above output ^ 235 | or in %BUILDDIR%/linkcheck/output.txt. 236 | goto end 237 | ) 238 | 239 | if "%1" == "doctest" ( 240 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 241 | if errorlevel 1 exit /b 1 242 | echo. 243 | echo.Testing of doctests in the sources finished, look at the ^ 244 | results in %BUILDDIR%/doctest/output.txt. 245 | goto end 246 | ) 247 | 248 | if "%1" == "coverage" ( 249 | %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage 250 | if errorlevel 1 exit /b 1 251 | echo. 252 | echo.Testing of coverage in the sources finished, look at the ^ 253 | results in %BUILDDIR%/coverage/python.txt. 254 | goto end 255 | ) 256 | 257 | if "%1" == "xml" ( 258 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 259 | if errorlevel 1 exit /b 1 260 | echo. 261 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 262 | goto end 263 | ) 264 | 265 | if "%1" == "pseudoxml" ( 266 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 267 | if errorlevel 1 exit /b 1 268 | echo. 269 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 270 | goto end 271 | ) 272 | 273 | if "%1" == "dummy" ( 274 | %SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy 275 | if errorlevel 1 exit /b 1 276 | echo. 277 | echo.Build finished. Dummy builder generates no files. 278 | goto end 279 | ) 280 | 281 | :end 282 | -------------------------------------------------------------------------------- /provdbconnector/tests/examples.py: -------------------------------------------------------------------------------- 1 | from prov.tests.examples import primer_example as primer_example, \ 2 | primer_example_alternate, \ 3 | w3c_publication_1, \ 4 | w3c_publication_2, \ 5 | bundles1, \ 6 | bundles2, \ 7 | collections, \ 8 | long_literals, \ 9 | datatypes 10 | 11 | from datetime import datetime 12 | from collections import namedtuple 13 | 14 | from prov.constants import PROV_RECORD_IDS_MAP, PROV 15 | from prov.model import ProvDocument, ProvActivity, Literal, Identifier 16 | from provdbconnector.db_adapters.baseadapter import METADATA_KEY_NAMESPACES, METADATA_KEY_PROV_TYPE, \ 17 | METADATA_KEY_TYPE_MAP, METADATA_KEY_IDENTIFIER 18 | 19 | 20 | def prov_db_unknown_prov_typ_example(): 21 | doc = ProvDocument() 22 | doc.add_namespace("ex", "https://example.com") 23 | doc.entity(identifier="ex:Entity1") 24 | doc.entity(identifier="ex:Entity2") 25 | doc.influence(influencee="ex:Entity1", influencer="ex:Entity2") 26 | return doc 27 | 28 | def prov_default_namespace_example(ns_postfix: str): 29 | doc = ProvDocument() 30 | doc.set_default_namespace("https://example.com/{0}".format(ns_postfix)) 31 | doc.entity(identifier="Entity1") 32 | return doc 33 | 34 | 35 | 36 | def attributes_dict_example(): 37 | """ 38 | Retuns a example dict with some different attributes 39 | 40 | :return: dict with attributes 41 | :rtype: dict 42 | """ 43 | attributes = dict() 44 | attributes.update({"ex:individual attribute": "Some value"}) 45 | attributes.update({"ex:int value": 99}) 46 | attributes.update({"ex:double value": 99.33}) 47 | attributes.update({"ex:date value": datetime.strptime('Jun 1 2005 1:33PM', '%b %d %Y %I:%M%p')}) 48 | attributes.update({"ex:list value": ["list", "of", "strings"]}) 49 | attributes.update({"ex:dict value": {"dict": "value"}}) 50 | 51 | return attributes 52 | 53 | 54 | def base_connector_bundle_parameter_example(): 55 | """ 56 | This example returns a dict with example arguments for a db_adapter 57 | 58 | :return: dict {attributes, metadata} 59 | :rtype: dict 60 | """ 61 | doc = ProvDocument() 62 | doc.add_namespace("ex", "http://example.com") 63 | attributes = dict() 64 | attributes.update({"prov:type": "prov:Bundle"}) 65 | 66 | namespaces = dict() 67 | namespaces.update({"ex": "http://example.com"}) 68 | 69 | type_map = dict() 70 | type_map.update({"int value": "int"}) 71 | type_map.update({"date value": "xds:datetime"}) 72 | 73 | metadata = dict() 74 | 75 | metadata.update({METADATA_KEY_PROV_TYPE: doc.valid_qualified_name("prov:Entity")}) 76 | metadata.update({METADATA_KEY_IDENTIFIER: doc.valid_qualified_name("ex:bundle name")}) 77 | metadata.update({METADATA_KEY_TYPE_MAP: type_map}) 78 | metadata.update({METADATA_KEY_NAMESPACES: namespaces}) 79 | 80 | return_data = dict() 81 | return_data.update({"attributes": attributes}) 82 | return_data.update({"metadata": metadata}) 83 | return return_data 84 | 85 | 86 | def base_connector_record_parameter_example(): 87 | """ 88 | Returns a dict with attributes and metadata for a simple node 89 | 90 | :return:dict with attributes metadata 91 | :rtype: dict 92 | """ 93 | doc = ProvDocument() 94 | 95 | namespaces = dict() 96 | namespaces.update({"ex": "http://example.com"}) 97 | namespaces.update({"custom": "http://custom.com"}) 98 | 99 | type_map = dict() 100 | type_map.update({"int value": "int"}) 101 | type_map.update({"date value": "xds:datetime"}) 102 | 103 | metadata = dict() 104 | 105 | metadata.update({METADATA_KEY_PROV_TYPE: doc.valid_qualified_name("prov:Activity")}) 106 | metadata.update({METADATA_KEY_IDENTIFIER: doc.valid_qualified_name("prov:example_node")}) 107 | metadata.update({METADATA_KEY_TYPE_MAP: type_map}) 108 | metadata.update({METADATA_KEY_NAMESPACES: namespaces}) 109 | 110 | return_data = dict() 111 | return_data.update({"attributes": attributes_dict_example()}) 112 | return_data.update({"metadata": metadata}) 113 | 114 | return return_data 115 | 116 | 117 | def base_connector_relation_parameter_example(): 118 | """ 119 | Returns a example with a start nodes (attributes, metadata) and also a relation dict with attributes metadata 120 | 121 | :return: dict 122 | :rtype: dict 123 | """ 124 | doc = ProvDocument() 125 | doc.add_namespace("ex", "http://example.com") 126 | doc.add_namespace("custom", "http://custom.com") 127 | 128 | namespaces = dict() 129 | namespaces.update({"ex": "http://example.com"}) 130 | namespaces.update({"custom": "http://custom.com"}) 131 | 132 | type_map = dict() 133 | type_map.update({"int value": "int"}) 134 | type_map.update({"date value": "xds:datetime"}) 135 | 136 | metadata = dict() 137 | 138 | metadata.update({METADATA_KEY_PROV_TYPE: PROV_RECORD_IDS_MAP["mentionOf"]}) 139 | metadata.update({METADATA_KEY_IDENTIFIER: "identifier for the relation"}) 140 | metadata.update({METADATA_KEY_TYPE_MAP: type_map}) 141 | metadata.update({METADATA_KEY_NAMESPACES: namespaces}) 142 | 143 | return_data = dict() 144 | return_data.update({"attributes": attributes_dict_example()}) 145 | return_data.update({"metadata": metadata}) 146 | return_data.update({"from_node": doc.valid_qualified_name("ex:Yoda")}) 147 | return_data.update({"to_node": doc.valid_qualified_name("ex:Luke Skywalker")}) 148 | return_data.update({"doc": doc}) 149 | 150 | return return_data 151 | 152 | 153 | def base_connector_merge_example(): 154 | """ 155 | This example returns a namedtuple with a from_node relation and to_node 156 | to test the merge behavior 157 | 158 | :return: namedtuple(from_node, relation, to_node) 159 | :rtype: namedtuple 160 | """ 161 | # noinspection PyPep8Naming 162 | ReturnData = namedtuple("base_connector_merge_example_return_data", "from_node,relation,to_node") 163 | example_relation = base_connector_relation_parameter_example() 164 | 165 | example_node_a = base_connector_record_parameter_example() 166 | example_node_b = base_connector_record_parameter_example() 167 | 168 | example_node_a["metadata"][METADATA_KEY_IDENTIFIER] = example_relation["from_node"] 169 | example_node_b["metadata"][METADATA_KEY_IDENTIFIER] = example_relation["to_node"] 170 | 171 | return ReturnData(example_node_a, example_relation, example_node_b) 172 | 173 | 174 | def prov_api_record_example(): 175 | """ 176 | This is a more complex record example 177 | 178 | :return: 179 | """ 180 | doc = ProvDocument() 181 | doc.add_namespace("ex", "http://example.com") 182 | doc.add_namespace("custom", "http://custom.com") 183 | 184 | attributes = attributes_dict_example() 185 | del attributes[ 186 | "ex:dict value"] # remove dict value because it is not allowed in a prov_record, but for low level adapter tests necessary 187 | del attributes[ 188 | "ex:list value"] # remove dict value because it is not allowed in a prov_record, but for low level adapter tests necessary 189 | attributes.update({"ex:Qualified name ": doc.valid_qualified_name("custom:qualified name")}) 190 | attributes.update({"ex:Qualified name 2": "ex:unqualified_name"}) 191 | attributes.update({"ex:Literal": Literal("test literal", langtag="en")}) 192 | attributes.update({"ex:Literal 2": Literal("test literal with datatype", langtag="en", 193 | datatype=PROV["InternationalizedString"])}) 194 | attributes.update({"ex:identifier type": Identifier("http://example.com/#test")}) 195 | 196 | expected_attributes = dict() 197 | for key, value in attributes.items(): 198 | new_key = doc.valid_qualified_name(key) 199 | expected_attributes.update({new_key: value}) 200 | 201 | # The prov lib don't require to auto convert string values into qualified names 202 | # valid_name = doc.valid_qualified_name("ex:Qualified name 2") 203 | # expected_attributes[valid_name] = doc.valid_qualified_name("ex:unqualified_name") 204 | 205 | namespaces = dict() 206 | namespaces.update({"ex": "http://example.com"}) 207 | namespaces.update({"custom": "http://custom.com"}) 208 | namespaces.update({"prov": "http://www.w3.org/ns/prov#"}) 209 | 210 | type_map = dict() 211 | type_map.update({"ex:date value": {"type": "xsd:dateTime"}}) 212 | type_map.update({"ex:double value": {"type": "xsd:double"}}) 213 | type_map.update({"ex:int value": {"type": "xsd:int"}}) 214 | 215 | type_map.update({"ex:Qualified name ": {'type': 'prov:QUALIFIED_NAME'}}) 216 | # type_map.update({"ex:Qualified name 2":{'type': 'prov:QUALIFIED_NAME'}}) #The prov lib don't require to auto convert strings into qualified names 217 | type_map.update({"ex:Literal": {'lang': 'en'}}) 218 | type_map.update({"ex:Literal 2": {'lang': 'en'}}) 219 | type_map.update({"ex:identifier type": {'type': 'xsd:anyURI'}}) 220 | 221 | metadata = dict() 222 | metadata.update({METADATA_KEY_PROV_TYPE: PROV_RECORD_IDS_MAP["activity"]}) 223 | metadata.update({METADATA_KEY_IDENTIFIER: doc.valid_qualified_name("ex:record")}) 224 | metadata.update({METADATA_KEY_NAMESPACES: namespaces}) 225 | metadata.update({METADATA_KEY_TYPE_MAP: type_map}) 226 | 227 | record = ProvActivity(doc, "ex:record", attributes) 228 | # noinspection PyPep8Naming 229 | Example = namedtuple("prov_api_metadata_record_example", "metadata, attributes, prov_record, expected_attributes") 230 | 231 | return Example(metadata, attributes, record, expected_attributes) 232 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_bundles1.svg: -------------------------------------------------------------------------------- 1 | 3 | Neo4j Graph Visualization 4 | Created using Neo4j (http://www.neo4j.com/) 5 | 6 | 7 | 9 | wasAssoci… 11 | 12 | 13 | 14 | 16 | wasAsso… 18 | 19 | 20 | 21 | 23 | wasAttrib… 25 | 26 | 27 | 28 | 30 | wasAsso… 32 | 33 | 34 | 35 | 37 | wasAsso… 39 | 40 | 41 | 42 | 44 | wasAssoci… 46 | 47 | 48 | 49 | 51 | wasAttri… 53 | 54 | 55 | 56 | 58 | wasGenera… 60 | 61 | 62 | 63 | 65 | wasGene… 67 | 68 | 69 | 70 | 72 | wasDerivedFrom 74 | 75 | 76 | 77 | 79 | w… 81 | 82 | 83 | 84 | 86 | wasGener… 88 | 89 | 90 | 91 | 92 | 93 | 94 | bob:bundle1 96 | 97 | 98 | 99 | 100 | ex:Bob 102 | 103 | 104 | 105 | 106 | alice:bundle2 108 | 109 | 110 | 111 | 112 | ex:Alice 114 | 115 | 116 | 117 | 118 | prov:Un… 120 | 121 | 122 | 123 | 124 | prov:Un… 126 | 127 | 128 | 129 | 130 | ex:report1 132 | 133 | 134 | 135 | 136 | ex:report2 138 | 139 | 140 | 141 | 142 | prov:Un… 144 | 145 | 146 | 147 | 148 | prov:Un… 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /docs/_images/test_cases/test_bundles2.svg: -------------------------------------------------------------------------------- 1 | 3 | Neo4j Graph Visualization 4 | Created using Neo4j (http://www.neo4j.com/) 5 | 6 | 8 | 10 | wasAssoci… 12 | 13 | 14 | 15 | 17 | wasAss… 19 | 20 | 21 | 22 | 24 | wasAttribut… 26 | 27 | 28 | 29 | 31 | wasAsso… 33 | 34 | 35 | 36 | 38 | wasAss… 40 | 41 | 42 | 43 | 45 | wasAssoci… 47 | 48 | 49 | 50 | 52 | wasAttri… 54 | 55 | 56 | 57 | 59 | wasGenerat… 61 | 62 | 63 | 64 | 66 | wasGener… 68 | 69 | 70 | 71 | 73 | mentionOf 75 | 76 | 77 | 79 | 81 | wasGe… 83 | 84 | 85 | 86 | 88 | wasDerivedFrom 90 | 91 | 92 | 93 | 95 | w… 97 | 98 | 99 | 100 | 101 | 102 | 103 | bob:bundle4 105 | 106 | 107 | 108 | 109 | ex:Bob 111 | 112 | 113 | 114 | 115 | alice:bundle5 117 | 118 | 119 | 120 | 121 | ex:Alice 123 | 124 | 125 | 126 | 127 | prov:Un… 129 | 130 | 131 | 132 | 133 | prov:Un… 135 | 136 | 137 | 138 | 139 | ex:report1 141 | 142 | 143 | 144 | 145 | prov:Un… 147 | 148 | 149 | 150 | 151 | ex:report1bis 153 | 154 | 155 | 156 | 157 | ex:report2 159 | 160 | 161 | 162 | 163 | prov:Un… 165 | 166 | 167 | 168 | --------------------------------------------------------------------------------