diff --git a/BUILD b/BUILD
index 4b5d3ebfa..c9ca21801 100644
--- a/BUILD
+++ b/BUILD
@@ -1,41 +1,97 @@
+load("@rules_python//python:defs.bzl", "py_binary")
+load("@rules_python//python:defs.bzl", "py_library")
+load("@rules_python//python:defs.bzl", "py_test")
+
+load("@knora_py_deps//:requirements.bzl", "requirement")
+
py_library(
name = "knora",
srcs = glob(["knora/knora.py"]),
+ deps = [
+ requirement("rdflib"),
+ requirement("lxml"),
+ requirement("validators"),
+ requirement("requests"),
+ requirement("jsonschema"),
+ requirement("click"),
+ requirement("rfc3987"),
+ requirement("pprint"),
+ ]
)
py_binary(
name = "knora_create_ontology",
srcs = ["knora/create_ontology.py"],
- deps = ["knora"]
+ deps = [
+ "knora",
+ requirement("jsonschema"),
+ requirement("pprint"),
+ ]
)
py_binary(
- name = "knora-xml-import",
+ name = "knora_xml_import",
srcs = ["knora/xml2knora.py"],
- deps = ["knora"]
+ deps = [
+ "knora",
+ requirement("lxml"),
+ requirement("pprint"),
+ ],
)
py_binary(
- name = "knora-reset-triplestore",
+ name = "knora_reset_triplestore",
srcs = ["knora/reset_triplestore.py"],
- deps = ["knora"]
+ deps = [":knora"],
)
py_binary(
name = "knoractl",
srcs = ["knora/knoractl.py"],
- deps = ["knora"]
+ deps = [":knora"],
+)
+
+py_test(
+ name = "test_create_ontology",
+ srcs = ["test/test_create_ontology.py"],
+ deps = [":knora"],
+)
+
+py_test(
+ name = "test_create_resource",
+ srcs = ["test/test_create_resource.py"],
+ deps = [
+ ":knora",
+ requirement("pprint"),
+ ],
)
py_test(
name = "test_knora",
- srcs = ["tests/test_knora.py"],
- deps = ["knora"],
+ srcs = ["test/test_knora.py"],
+ deps = [":knora"],
)
test_suite(
name = "all_tests",
tests = [
+ "test_create_ontology",
+ "test_create_resource",
"test_knora",
],
)
+
+py_library(
+ name = "test_lib",
+ srcs = glob(["test/*.py"]),
+ deps = [
+ ":knora",
+ ],
+)
+
+py_binary(
+ name = "run_tests",
+ main = "test/run.py",
+ srcs = ["test/run.py"],
+ deps = ["test_lib"],
+)
diff --git a/Makefile b/Makefile
index 9035f41c7..fcd8b5d9e 100644
--- a/Makefile
+++ b/Makefile
@@ -16,8 +16,13 @@ serve-docs: ## serve docs for local viewing
publish-docs: ## build and publish docs to Github Pages
mkdocs gh-deploy
+.PHONY: install-requirements
+install-requirements: ## install requirements
+ pip3 install -r requirements.txt
+
+.PHONY: test
test: ## runs all tests
- python3 -m pytest
+ cd test && python3 -m unittest
clean: ## cleans the project directory
rm -rf dist/ build/ knora.egg-info/ .pytest_cache/ site/
diff --git a/README.md b/README.md
index 0c4e0edd7..803fae6b0 100644
--- a/README.md
+++ b/README.md
@@ -33,6 +33,13 @@ $ python3 setup.py install
The project contains a Makefile defining management tasks. Please use
`make help` to see what is available.
+## Testing
+
+```bash
+$ make install-requirements
+$ make test
+```
+
## Publishing to PyPi
Generate distribution package. Make sure you have the latest versions of `setuptools` and `wheel` installed:
@@ -70,15 +77,7 @@ $ python3 -m twine upload dist/*
For local development:
```bash
-$ python3 setup.py develop
-```
-
-## Testing
-
-```bash
-$ pip3 install pytest
-$ pip3 install --editable .
-$ pytest
+$ python3 setup.py --editable .
```
## Requirements
diff --git a/WORKSPACE b/WORKSPACE
index e69de29bb..6b66dc41e 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -0,0 +1,42 @@
+workspace(name = "knora_py")
+
+# use bazel federation (set of rule versions known to work well together)
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+http_archive(
+ name = "bazel_federation",
+ url = "https://github.com/bazelbuild/bazel-federation/releases/download/0.0.1/bazel_federation-0.0.1.tar.gz",
+ sha256 = "506dfbfd74ade486ac077113f48d16835fdf6e343e1d4741552b450cfc2efb53",
+)
+
+# load the initializer methods for all the rules we want to use in this workspace
+load("@bazel_federation//:repositories.bzl",
+ "rules_python",
+)
+
+# run any rule specific setups
+rules_python()
+load("@bazel_federation//setup:rules_python.bzl", "rules_python_setup")
+rules_python_setup()
+
+# load py_repositories from rules_python
+load("@rules_python//python:repositories.bzl", "py_repositories")
+py_repositories()
+
+# load pip_repositories from rules_python
+load("@rules_python//python:pip.bzl", "pip_repositories")
+pip_repositories()
+
+# allows to use requirements.txt for loading the dependencies
+load("@rules_python//python:pip.bzl", "pip_import")
+
+# This rule translates the specified requirements.txt into
+# @knora_py_deps//:requirements.bzl, which itself exposes a pip_install method.
+pip_import(
+ name = "knora_py_deps",
+ requirements = "//:requirements.txt",
+)
+
+# Load the pip_install symbol for knora_py_deps, and create the dependencies'
+# repositories.
+load("@knora_py_deps//:requirements.bzl", "pip_install")
+pip_install()
diff --git a/knora/knora.py b/knora/knora.py
index 73e96f55e..7e8d051d0 100755
--- a/knora/knora.py
+++ b/knora/knora.py
@@ -116,6 +116,7 @@ def __init__(self, server: str, prefixes: Dict[str, str] = None):
"""
self.server = server
self.prefixes = prefixes
+ self.token = None
def login(self, email: str, password: str):
"""
@@ -142,12 +143,13 @@ def get_token(self):
return self.token
def logout(self):
- req = requests.delete(
- self.server + '/v2/authentication',
- headers={'Authorization': 'Bearer ' + self.token}
- )
- self.on_api_error(req)
- self.token = None
+ if self.token is not None:
+ req = requests.delete(
+ self.server + '/v2/authentication',
+ headers={'Authorization': 'Bearer ' + self.token}
+ )
+ self.on_api_error(req)
+ self.token = None
def __del__(self):
self.logout()
@@ -245,7 +247,7 @@ def create_project(
project['logo'] = logo
jsondata = json.dumps(project)
- print(jsondata)
+ # print(jsondata)
req = requests.post(self.server + "/admin/projects",
headers={'Content-Type': 'application/json; charset=UTF-8',
diff --git a/requirements.txt b/requirements.txt
index ccb6c7442..bc7962d65 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,3 +6,11 @@ twine
pytest
mkdocs==1.0.4
mkdocs-material
+rdflib
+lxml
+validators
+requests
+jsonschema
+click
+rfc3987
+pprint
diff --git a/setup.py b/setup.py
index 90dd74434..3da16efe5 100644
--- a/setup.py
+++ b/setup.py
@@ -27,16 +27,16 @@
'jsonschema',
'click',
'rfc3987',
- 'pprint'
+ 'pprint',
],
entry_points={
'console_scripts': [
'knora-create-ontology=knora.create_ontology:main',
'knora-xml-import=knora.xml2knora:main',
'knora-reset-triplestore=knora.reset_triplestore:main',
- 'knoractl=knoractl:main'
+ 'knoractl=knoractl:main',
],
},
include_package_data=True,
- zip_safe=False
+ zip_safe=False,
)
diff --git a/tests/lists.json b/test/lists.json
similarity index 100%
rename from tests/lists.json
rename to test/lists.json
diff --git a/test/run.py b/test/run.py
new file mode 100644
index 000000000..50206bd33
--- /dev/null
+++ b/test/run.py
@@ -0,0 +1,55 @@
+"""Universal launcher for unit tests"""
+
+import argparse
+import logging
+import os
+import sys
+import unittest
+
+
+def main():
+ """Parse args, collect tests and run them"""
+ # Disable *.pyc files
+ sys.dont_write_bytecode = True
+
+ # Add ".." to module search path
+ cur_dir = os.path.dirname(os.path.realpath(__file__))
+ top_dir = os.path.abspath(os.path.join(cur_dir, os.pardir))
+ sys.path.append(top_dir)
+
+ # Parse command line arguments
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument("-v", "--verbose", action="count", default=0,
+ help="verbosity level, use: [-v | -vv | -vvv]")
+ parser.add_argument("-s", "--start-directory", default=None,
+ help="directory to start discovery")
+ parser.add_argument("-p", "--pattern", default="test*.py",
+ help="pattern to match test files ('test*.py' default)")
+ parser.add_argument("test", nargs="*",
+ help="test specs (e.g. module.TestCase.test_func)")
+ args = parser.parse_args()
+
+ if not args.start_directory:
+ args.start_directory = cur_dir
+
+ if args.verbose > 2:
+ logging.basicConfig(level=logging.DEBUG, format="DEBUG: %(message)s")
+
+ loader = unittest.TestLoader()
+ if args.test:
+ # Add particular tests
+ for test in args.test:
+ suite = unittest.TestSuite()
+ suite.addTests(loader.loadTestsFromName(test))
+ else:
+ # Find all tests
+ suite = loader.discover(args.start_directory, args.pattern)
+
+ runner = unittest.TextTestRunner(verbosity=args.verbose)
+ result = runner.run(suite)
+ return result.wasSuccessful()
+
+
+if __name__ == "__main__":
+ # NOTE: True(success) -> 0, False(fail) -> 1
+ exit(not main())
diff --git a/tests/test-onto.json b/test/test-onto.json
similarity index 100%
rename from tests/test-onto.json
rename to test/test-onto.json
diff --git a/tests/test.tif b/test/test.tif
similarity index 100%
rename from tests/test.tif
rename to test/test.tif
diff --git a/test/test_create_ontology.py b/test/test_create_ontology.py
new file mode 100644
index 000000000..0eeebe54d
--- /dev/null
+++ b/test/test_create_ontology.py
@@ -0,0 +1,12 @@
+import unittest
+
+
+class TestCreateOntology(unittest.TestCase):
+
+ @unittest.skip("not implemented")
+ def test_create_ontology(self):
+ pass
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/test/test_create_resource.py b/test/test_create_resource.py
new file mode 100644
index 000000000..52f68302a
--- /dev/null
+++ b/test/test_create_resource.py
@@ -0,0 +1,52 @@
+import unittest
+from pprint import pprint
+from knora import Knora, Sipi
+
+
+class TestCreateResource(unittest.TestCase):
+
+ @unittest.skip("not implemented")
+ def test_create_resource(self):
+ server = "http://0.0.0.0:3333"
+ sipi = "http://0.0.0.0:1024"
+ email = "root@example.com"
+ password = "test"
+ projectcode = "00FE"
+ ontoname = "KPT"
+
+ con = Knora(server)
+ con.login(email, password)
+ graph = con.get_ontology_graph('00FE', 'kpt')
+ # print(graph)
+ # exit(0)
+ schema = con.create_schema(projectcode, ontoname)
+ # pprint(schema)
+ # exit(0)
+
+ inst1_info = con.create_resource(schema, "object1", "obj1_inst1", {
+ "textprop": "Dies ist ein Text!",
+ "intprop": 7,
+ "listprop": "options:opt2",
+ "dateprop": "1966:CE:1967-05-21",
+ "decimalprop": {'value': "3.14159", 'comment': "Die Zahl PI"},
+ "geonameprop": "2661604",
+ "richtextprop": "\nthis is text
with standoff",
+ "intervalprop": "13.57:15.88"
+ })
+ pprint(inst1_info)
+
+ # first upload image to SIPI
+ sipi = Sipi(sipi, con.get_token())
+ res = sipi.upload_image('test.tif')
+ pprint(res)
+
+ fileref = res['uploadedFiles'][0]['internalFilename']
+ inst2_info = con.create_resource(schema, "object2", "obj2_inst1", {
+ "titleprop": "Stained glass",
+ "linkprop": inst1_info['iri']
+ }, fileref)
+ pprint(inst2_info)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/test/test_knora.py b/test/test_knora.py
new file mode 100644
index 000000000..afdbbb9e9
--- /dev/null
+++ b/test/test_knora.py
@@ -0,0 +1,72 @@
+import unittest
+from knora import Knora
+
+
+class TestKnora(unittest.TestCase):
+
+ def con(self, login: bool = True) -> Knora:
+ server = "http://0.0.0.0:3333"
+ email = "root@example.com"
+ password = "test"
+ # projectcode = "00FE"
+ # ontoname = "KPT"
+ con = Knora(server)
+ if login:
+ con.login(email, password)
+ return con
+
+ # resets the content of the triplestore
+ def test_reset_triplestore_content(self):
+ res = self.con(login=False).reset_triplestore_content()
+ self.assertIsNotNone(res)
+
+ # retrieves all users
+ def test_get_users(self):
+ res = self.con(login=True).get_users()
+ # print(res)
+ self.assertEqual(len(res), 19)
+
+ # retrieves user information
+ def test_get_user(self):
+ res = self.con(login=True).get_user_by_iri(user_iri='http://rdfh.ch/users/root')
+ # print(res)
+ self.assertEqual(res["username"], "root")
+
+ # creates a user
+ def test_create_user(self):
+ connection = self.con(login=True)
+ user = {
+ "username": "testtest",
+ "email": "testtest@example.com",
+ "given_name": "test_given",
+ "family_name": "test_family",
+ "password": "test",
+ "lang": "en"
+ }
+
+ user_iri = connection.create_user(
+ username=user["username"],
+ email=user["email"],
+ given_name=user["given_name"],
+ family_name=user["family_name"],
+ password=user["password"],
+ lang=user["lang"] if user.get("lang") is not None else "en")
+
+ # print(user_iri)
+
+ # check that the created user exists
+ res = connection.get_user_by_iri(user_iri)
+ self.assertEqual(res["username"], "testtest")
+ self.assertEqual(res["email"], "testtest@example.com")
+
+ # logout current user
+ connection.logout()
+ self.assertIsNone(connection.get_token())
+
+ # login as newly created user
+ connection.login(res["email"], "test")
+ self.assertIsNotNone(connection.get_token())
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/conftest.py b/tests/conftest.py
deleted file mode 100644
index fbf9341f8..000000000
--- a/tests/conftest.py
+++ /dev/null
@@ -1,12 +0,0 @@
-import os
-
-import pytest
-
-import knora.create_ontology
-
-
-@pytest.fixture
-def create_test_ontology_fixture():
- dir_path = os.path.dirname(os.path.realpath(__file__))
- os.chdir(dir_path)
- knora.create_ontology.main(['./test-onto.json'])
diff --git a/tests/test_create_ontology.py b/tests/test_create_ontology.py
deleted file mode 100644
index 28d2d3b21..000000000
--- a/tests/test_create_ontology.py
+++ /dev/null
@@ -1,7 +0,0 @@
-import pytest
-
-
-@pytest.mark.skip(reason="broken")
-def test_create_test_onto(create_test_ontology_fixture):
- pass
-
diff --git a/tests/test_create_resource.py b/tests/test_create_resource.py
deleted file mode 100644
index d6ae52990..000000000
--- a/tests/test_create_resource.py
+++ /dev/null
@@ -1,50 +0,0 @@
-import os
-from typing import List, Set, Dict, Tuple, Optional
-from pprint import pprint
-import argparse
-import json
-from jsonschema import validate
-from knora import KnoraError, Knora, Sipi
-import pytest
-
-
-@pytest.mark.skip(reason="broken")
-def test_create_resource(create_test_ontology_fixture):
- server = "http://0.0.0.0:3333"
- sipi = "http://0.0.0.0:1024",
- user = "root@example.com",
- password = "test"
- projectcode = "00FE"
- ontoname = "KPT"
-
- con = Knora(server, user, password)
- graph = con.get_ontology_graph('00FE', 'kpt')
- # print(graph)
- # exit(0)
- schema = con.create_schema(projectcode, ontoname)
- # pprint(schema)
- # exit(0)
-
- inst1_info = con.create_resource(schema, "object1", "obj1_inst1", {
- "textprop": "Dies ist ein Text!",
- "intprop": 7,
- "listprop": "options:opt2",
- "dateprop": "1966:CE:1967-05-21",
- "decimalprop": {'value': "3.14159", 'comment': "Die Zahl PI"},
- "geonameprop": "2661604",
- "richtextprop": "\nthis is text
with standoff",
- "intervalprop": "13.57:15.88"
- })
- pprint(inst1_info)
-
- # first upload image to SIPI
- sipi = Sipi(sipi, con.get_token())
- res = sipi.upload_image('test.tif')
- pprint(res)
-
- fileref = res['uploadedFiles'][0]['internalFilename']
- inst2_info = con.create_resource(schema, "object2", "obj2_inst1", {
- "titleprop": "Stained glass",
- "linkprop": inst1_info['iri']
- }, fileref)
- pprint(inst2_info)
\ No newline at end of file
diff --git a/tests/test_knora.py b/tests/test_knora.py
deleted file mode 100644
index e2ed2fde0..000000000
--- a/tests/test_knora.py
+++ /dev/null
@@ -1,74 +0,0 @@
-import pytest
-from knora import Knora
-
-
-@pytest.fixture()
-def con():
- def _con(login: bool = True) -> Knora:
- server = "http://0.0.0.0:3333"
- email = "root@example.com"
- password = "test"
- # projectcode = "00FE"
- # ontoname = "KPT"
- con = Knora(server)
- if login:
- con.login(email, password)
- return con
-
- return _con
-
-
-# resets the content of the triplestore
-def test_reset_triplestore_content(con):
- res = con(login=False).reset_triplestore_content()
- assert res
-
-
-# retrieves all users
-def test_get_users(con):
- res = con(login=True).get_users()
- print(res)
- assert (len(res) == 18)
-
-
-# retrieves user information
-def test_get_user(con):
- res = con(login=True).get_user_by_iri(user_iri='http://rdfh.ch/users/root')
- print(res)
- assert (res["username"] == "root")
-
-
-# creates a user
-def test_create_user(con):
- connection = con(login=True)
- user = {
- "username": "testtest",
- "email": "testtest@example.com",
- "given_name": "test_given",
- "family_name": "test_family",
- "password": "test",
- "lang": "en"
- }
-
- user_iri = connection.create_user(
- username=user["username"],
- email=user["email"],
- given_name=user["given_name"],
- family_name=user["family_name"],
- password=user["password"],
- lang=user["lang"] if user.get("lang") is not None else "en")
-
- print(user_iri)
-
- # check that the created user exists
- res = connection.get_user_by_iri(user_iri)
- assert (res["username"] == "testtest")
- assert (res["email"] == "testtest@example.com")
-
- # logout
- connection.logout()
- assert (connection.get_token() is None)
-
- # login
- connection.login(res["email"], "test")
- assert (connection.get_token() is not None)