diff --git a/.github/workflows/atramhasis_backend.yaml b/.github/workflows/atramhasis_backend.yaml new file mode 100644 index 00000000..3da72d0a --- /dev/null +++ b/.github/workflows/atramhasis_backend.yaml @@ -0,0 +1,42 @@ +name: Atramhasis backend tests + +on: + push: + paths: + - atramhasis/** + - scripts/** + - tests/** + - '!atramhasis/static/**' + - .github/workflows/atramhasis_backend.yaml + - pyproject.toml + - requirements*.txt + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [ "3.10", "3.11", "3.12" ] + + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + # You can test your matrix by printing the current Python version + - name: Display Python version + run: python -c "import sys; print(sys.version)" + + - name: Install python requirements + env: + HATCH_BUILD_NO_HOOKS: true + working-directory: ./ + run: | + pip --version + pip install pip-tools + pip-sync requirements-dev.txt + pip install -e . + + - name: Python tests + run: pytest tests --exitfirst --capture=no -vvv --full-trace diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 46f6daed..00000000 --- a/.travis.yml +++ /dev/null @@ -1,17 +0,0 @@ -sudo: false -language: python -os: linux -dist: focal -python: - - 3.9 - - 3.10 - - 3.11 -before_install: - - pip install --upgrade pip - - pip install setuptools==59.6.0 #https://github.com/pypa/setuptools/issues/3293 -install: - - pip install -e .[dev] -script: - - py.test --cov atramhasis --cov-report term-missing tests -after_success: - - coveralls diff --git a/atramhasis/data/datamanagers.py b/atramhasis/data/datamanagers.py index 270eadd3..52874be1 100644 --- a/atramhasis/data/datamanagers.py +++ b/atramhasis/data/datamanagers.py @@ -74,7 +74,7 @@ def find(self, conceptscheme_id, query): """ db_query = ( select(Thing) - .options(joinedload('labels')) + .options(joinedload(Thing.labels)) .filter(Thing.conceptscheme_id == conceptscheme_id) ) if 'type' in query and query['type'] in ['concept', 'collection']: @@ -127,7 +127,7 @@ def get_all(self, conceptscheme_id): """ all_results = self.session.execute( select(Thing) - .options(joinedload('labels')) + .options(joinedload(Thing.labels)) .filter(Thing.conceptscheme_id == conceptscheme_id) ).unique().scalars().all() return all_results diff --git a/atramhasis/openapi.yaml b/atramhasis/openapi.yaml index 38e84025..7489f79f 100644 --- a/atramhasis/openapi.yaml +++ b/atramhasis/openapi.yaml @@ -1138,9 +1138,6 @@ components: Provider: type: object - required: - - conceptscheme_uri - - uri_pattern properties: id: type: string @@ -1189,6 +1186,9 @@ components: type: object additionalProperties: true nullable: true + required: + - conceptscheme_uri + - uri_pattern Error: type: object required: diff --git a/atramhasis/views/exception_views.py b/atramhasis/views/exception_views.py index dbb8b027..59190fb6 100644 --- a/atramhasis/views/exception_views.py +++ b/atramhasis/views/exception_views.py @@ -5,12 +5,13 @@ import logging import sys -from openapi_core.unmarshalling.schemas.exceptions import InvalidSchemaValue +from openapi_core.validation.schemas.exceptions import InvalidSchemaValue from pyramid.httpexceptions import HTTPMethodNotAllowed from pyramid.view import notfound_view_config from pyramid.view import view_config from pyramid_openapi3 import RequestValidationError from pyramid_openapi3 import ResponseValidationError +from pyramid_openapi3 import extract_errors from pyramid_openapi3 import openapi_validation_error from skosprovider.exceptions import ProviderUnavailableException from sqlalchemy.exc import IntegrityError @@ -117,17 +118,13 @@ def failed_openapi_validation(exc, request): # noinspection PyTypeChecker errors.extend( [ - str(error) - for error in exc.errors - if not isinstance(error, InvalidSchemaValue) + f'{error.get("field")}: {error.get("message")}' + for error in + list(extract_errors(request, exc.errors)) ] ) request.response.status_int = 400 - if isinstance(exc, RequestValidationError): - subject = "Request" - else: - subject = "Response" - return {"message": f"{subject} was not valid for schema.", "errors": errors} + return {"message": "Request was not valid for schema.", "errors": errors} except Exception: log.exception("Issue with exception handling.") return openapi_validation_error(exc, request) diff --git a/pyproject.toml b/pyproject.toml index 4d6f11a8..c4df47ef 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ requires = ["hatchling", "hatch-fancy-pypi-readme"] build-backend = "hatchling.build" [project] -version = "0.0.1" +version = "2.0.0" name = "atramhasis" dynamic = ["readme"] authors = [ @@ -11,7 +11,7 @@ authors = [ ] #license = "GPL-3.0-or-later" description = "A web based editor for thesauri adhering to the SKOS specification." -requires-python = ">=3.9,<3.12" +requires-python = ">=3.10,<3.13" keywords = ["web", "wsgi", "pyramid", "SKOS", "thesaurus", "vocabulary"] classifiers = [ "Development Status :: 5 - Production/Stable", @@ -26,7 +26,7 @@ classifiers = [ dependencies = [ "pyramid", "pyramid_tm", - "SQLAlchemy<2.0.0,>=1.4.0", + "SQLAlchemy", "transaction", "zope.sqlalchemy", "skosprovider", @@ -48,12 +48,7 @@ dependencies = [ "python-dateutil", "rdflib", "bleach", - # Openapi stack - "pyramid_openapi3>=0.16.0,<0.17.0", - "openapi-core>=0.16.6,<0.17.0", - "openapi-schema-validator>=0.4.4,<0.5.0", - "openapi-spec-validator>=0.5.6,<0.6.0", - "jsonschema>=4.17.0,<5.0.0", # Does follow semantic versioning -- safe + "pyramid_openapi3==0.19", ] [project.urls] diff --git a/requirements-dev-base.txt b/requirements-dev-base.txt deleted file mode 100644 index 58c0f499..00000000 --- a/requirements-dev-base.txt +++ /dev/null @@ -1,26 +0,0 @@ -# Basic Atramhasis dev requirements - -# pyramid -pyramid-debugtoolbar==4.10 - -# Testing -pytest==7.4.2 -pytest-cov==4.1.0 -coveralls==3.3.1 -webtest==3.0.0 -mock==5.1.0 -testfixtures==7.2.2 - -# Documentation -Sphinx==6.2.1 -sphinxcontrib-httpdomain==1.8.1 -pygments==2.15.1 - -# waitress -waitress==2.1.2 - -# Linting -flake8==4.0.1 -mccabe==0.6.1 -pep8==1.7.1 -pyflakes==2.4.0 diff --git a/requirements-dev.txt b/requirements-dev.txt index 08975b23..80be11be 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,5 +1,327 @@ -# Runtime requirements ---requirement requirements.txt - -# Basic atramhasis dev requirements ---requirement requirements-dev-base.txt \ No newline at end of file +alabaster==0.7.16 + # via sphinx +alembic==1.13.1 + # via atramhasis (pyproject.toml) +attrs==23.2.0 + # via + # jsonschema + # referencing +babel==2.15.0 + # via + # atramhasis (pyproject.toml) + # sphinx +beautifulsoup4==4.12.3 + # via webtest +bleach==6.1.0 + # via atramhasis (pyproject.toml) +cachecontrol==0.14.0 + # via atramhasis (pyproject.toml) +cachetools==5.3.3 + # via pyld +certifi==2024.6.2 + # via requests +charset-normalizer==3.3.2 + # via requests +colander==2.0 + # via atramhasis (pyproject.toml) +coverage==6.5.0 + # via + # coveralls + # pytest-cov +coveralls==3.3.1 + # via atramhasis (pyproject.toml) +decorator==5.1.1 + # via dogpile-cache +docopt==0.6.2 + # via coveralls +docutils==0.19 + # via sphinx +dogpile-cache==1.3.3 + # via atramhasis (pyproject.toml) +exceptiongroup==1.2.1 + # via pytest +flake8==4.0.1 + # via atramhasis (pyproject.toml) +frozendict==2.4.4 + # via pyld +greenlet==3.0.3 + # via sqlalchemy +html5lib==1.1 + # via + # skosprovider + # skosprovider-rdf +hupper==1.12.1 + # via pyramid +idna==3.7 + # via requests +imagesize==1.4.1 + # via sphinx +iniconfig==2.0.0 + # via pytest +iso8601==2.1.0 + # via colander +isodate==0.6.1 + # via + # openapi-core + # rdflib +jinja2==3.1.4 + # via + # atramhasis (pyproject.toml) + # pyramid-jinja2 + # sphinx +jsonschema==4.22.0 + # via + # openapi-core + # openapi-schema-validator + # openapi-spec-validator +jsonschema-path==0.3.2 + # via + # openapi-core + # openapi-spec-validator +jsonschema-specifications==2023.12.1 + # via + # jsonschema + # openapi-schema-validator +language-tags==1.2.0 + # via + # atramhasis (pyproject.toml) + # skosprovider +lazy-object-proxy==1.10.0 + # via openapi-spec-validator +lxml==5.2.2 + # via pyld +mako==1.3.5 + # via + # alembic + # pyramid-mako +markupsafe==2.1.5 + # via + # atramhasis (pyproject.toml) + # jinja2 + # mako + # pyramid-jinja2 + # werkzeug +mccabe==0.6.1 + # via + # atramhasis (pyproject.toml) + # flake8 +mock==5.1.0 + # via atramhasis (pyproject.toml) +more-itertools==10.2.0 + # via openapi-core +msgpack==1.0.8 + # via cachecontrol +openapi-core==0.19.1 + # via pyramid-openapi3 +openapi-schema-validator==0.6.2 + # via + # openapi-core + # openapi-spec-validator +openapi-spec-validator==0.7.1 + # via openapi-core +packaging==24.1 + # via + # pytest + # sphinx + # zope-sqlalchemy +parse==1.20.1 + # via openapi-core +pastedeploy==3.1.0 + # via plaster-pastedeploy +pathable==0.4.3 + # via jsonschema-path +pbr==6.0.0 + # via stevedore +pep8==1.7.1 + # via atramhasis (pyproject.toml) +plaster==1.1.2 + # via + # plaster-pastedeploy + # pyramid +plaster-pastedeploy==1.0.1 + # via pyramid +pluggy==1.5.0 + # via pytest +pycodestyle==2.8.0 + # via flake8 +pyflakes==2.4.0 + # via + # atramhasis (pyproject.toml) + # flake8 +pygments==2.15.1 + # via + # atramhasis (pyproject.toml) + # pyramid-debugtoolbar + # sphinx +pyld==2.0.4 + # via skosprovider +pyparsing==3.1.2 + # via rdflib +pyramid==2.0.2 + # via + # atramhasis (pyproject.toml) + # pyramid-debugtoolbar + # pyramid-jinja2 + # pyramid-mako + # pyramid-openapi3 + # pyramid-rewrite + # pyramid-skosprovider + # pyramid-tm +pyramid-debugtoolbar==4.10 + # via atramhasis (pyproject.toml) +pyramid-jinja2==2.10.1 + # via atramhasis (pyproject.toml) +pyramid-mako==1.1.0 + # via pyramid-debugtoolbar +pyramid-openapi3==0.19 + # via atramhasis (pyproject.toml) +pyramid-rewrite==0.2 + # via atramhasis (pyproject.toml) +pyramid-skosprovider==1.2.1 + # via atramhasis (pyproject.toml) +pyramid-tm==2.5 + # via atramhasis (pyproject.toml) +pytest==7.4.2 + # via + # atramhasis (pyproject.toml) + # pytest-cov +pytest-cov==4.1.0 + # via atramhasis (pyproject.toml) +python-dateutil==2.9.0.post0 + # via atramhasis (pyproject.toml) +pyyaml==6.0.1 + # via jsonschema-path +rdflib==7.0.0 + # via + # atramhasis (pyproject.toml) + # skosprovider-getty + # skosprovider-rdf +referencing==0.31.1 + # via + # jsonschema + # jsonschema-path + # jsonschema-specifications +requests==2.32.3 + # via + # atramhasis (pyproject.toml) + # cachecontrol + # coveralls + # jsonschema-path + # skosprovider-getty + # sphinx +rfc3339-validator==0.1.4 + # via openapi-schema-validator +rfc3987==1.3.8 + # via skosprovider +rpds-py==0.18.1 + # via + # jsonschema + # referencing +setuptools==70.0.0 + # via + # pyramid + # zope-deprecation + # zope-interface + # zope-sqlalchemy +six==1.16.0 + # via + # bleach + # html5lib + # isodate + # python-dateutil + # rfc3339-validator + # sphinxcontrib-httpdomain +skosprovider==1.2.0 + # via + # atramhasis (pyproject.toml) + # pyramid-skosprovider + # skosprovider-getty + # skosprovider-rdf + # skosprovider-sqlalchemy +skosprovider-getty==1.2.0 + # via atramhasis (pyproject.toml) +skosprovider-rdf==1.3.0 + # via atramhasis (pyproject.toml) +skosprovider-sqlalchemy==2.1.1 + # via atramhasis (pyproject.toml) +snowballstemmer==2.2.0 + # via sphinx +soupsieve==2.5 + # via beautifulsoup4 +sphinx==6.2.1 + # via + # atramhasis (pyproject.toml) + # sphinxcontrib-httpdomain +sphinxcontrib-applehelp==1.0.8 + # via sphinx +sphinxcontrib-devhelp==1.0.6 + # via sphinx +sphinxcontrib-htmlhelp==2.0.5 + # via sphinx +sphinxcontrib-httpdomain==1.8.1 + # via atramhasis (pyproject.toml) +sphinxcontrib-jsmath==1.0.1 + # via sphinx +sphinxcontrib-qthelp==1.0.7 + # via sphinx +sphinxcontrib-serializinghtml==1.1.10 + # via sphinx +sqlalchemy==2.0.30 + # via + # atramhasis (pyproject.toml) + # alembic + # skosprovider-sqlalchemy + # zope-sqlalchemy +stevedore==5.2.0 + # via dogpile-cache +testfixtures==7.2.2 + # via atramhasis (pyproject.toml) +tomli==2.0.1 + # via + # coverage + # pytest +transaction==4.0 + # via + # atramhasis (pyproject.toml) + # pyramid-tm + # zope-sqlalchemy +translationstring==1.4 + # via + # colander + # pyramid +typing-extensions==4.12.2 + # via + # alembic + # dogpile-cache + # sqlalchemy +urllib3==2.2.1 + # via requests +venusian==3.1.0 + # via pyramid +waitress==2.1.2 + # via + # atramhasis (pyproject.toml) + # webtest +webencodings==0.5.1 + # via + # bleach + # html5lib +webob==1.8.7 + # via + # pyramid + # webtest +webtest==3.0.0 + # via atramhasis (pyproject.toml) +werkzeug==3.0.3 + # via openapi-core +zope-deprecation==5.0 + # via + # pyramid + # pyramid-jinja2 +zope-interface==6.4.post2 + # via + # pyramid + # transaction + # zope-sqlalchemy +zope-sqlalchemy==3.1 + # via atramhasis (pyproject.toml) diff --git a/requirements.txt b/requirements.txt index 6e72b6a8..930e9569 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,50 +1,225 @@ -# pyramid +alembic==1.13.1 + # via atramhasis (pyproject.toml) +attrs==23.2.0 + # via + # jsonschema + # referencing +babel==2.15.0 + # via atramhasis (pyproject.toml) +bleach==6.1.0 + # via atramhasis (pyproject.toml) +cachecontrol==0.14.0 + # via atramhasis (pyproject.toml) +cachetools==5.3.3 + # via pyld +certifi==2024.6.2 + # via requests +charset-normalizer==3.3.2 + # via requests +colander==2.0 + # via atramhasis (pyproject.toml) +decorator==5.1.1 + # via dogpile-cache +dogpile-cache==1.3.3 + # via atramhasis (pyproject.toml) +frozendict==2.4.4 + # via pyld +greenlet==3.0.3 + # via sqlalchemy +html5lib==1.1 + # via + # skosprovider + # skosprovider-rdf +hupper==1.12.1 + # via pyramid +idna==3.7 + # via requests +iso8601==2.1.0 + # via colander +isodate==0.6.1 + # via + # openapi-core + # rdflib +jinja2==3.1.4 + # via + # atramhasis (pyproject.toml) + # pyramid-jinja2 +jsonschema==4.22.0 + # via + # openapi-core + # openapi-schema-validator + # openapi-spec-validator +jsonschema-path==0.3.2 + # via + # openapi-core + # openapi-spec-validator +jsonschema-specifications==2023.12.1 + # via + # jsonschema + # openapi-schema-validator +language-tags==1.2.0 + # via + # atramhasis (pyproject.toml) + # skosprovider +lazy-object-proxy==1.10.0 + # via openapi-spec-validator +lxml==5.2.2 + # via pyld +mako==1.3.5 + # via alembic +markupsafe==2.1.5 + # via + # atramhasis (pyproject.toml) + # jinja2 + # mako + # pyramid-jinja2 + # werkzeug +more-itertools==10.2.0 + # via openapi-core +msgpack==1.0.8 + # via cachecontrol +openapi-core==0.19.1 + # via pyramid-openapi3 +openapi-schema-validator==0.6.2 + # via + # openapi-core + # openapi-spec-validator +openapi-spec-validator==0.7.1 + # via openapi-core +packaging==24.1 + # via zope-sqlalchemy +parse==1.20.1 + # via openapi-core +pastedeploy==3.1.0 + # via plaster-pastedeploy +pathable==0.4.3 + # via jsonschema-path +pbr==6.0.0 + # via stevedore +plaster==1.1.2 + # via + # plaster-pastedeploy + # pyramid +plaster-pastedeploy==1.0.1 + # via pyramid +pyld==2.0.4 + # via skosprovider +pyparsing==3.1.2 + # via rdflib pyramid==2.0.2 + # via + # atramhasis (pyproject.toml) + # pyramid-jinja2 + # pyramid-openapi3 + # pyramid-rewrite + # pyramid-skosprovider + # pyramid-tm +pyramid-jinja2==2.10.1 + # via atramhasis (pyproject.toml) +pyramid-openapi3==0.19 + # via atramhasis (pyproject.toml) +pyramid-rewrite==0.2 + # via atramhasis (pyproject.toml) +pyramid-skosprovider==1.2.1 + # via atramhasis (pyproject.toml) pyramid-tm==2.5 -pyramid_rewrite==0.2 - -# The openapi stack is very vulnerable so we limit all the libraries in the -# dependency tree. -pyramid_openapi3==0.16.0 -jsonschema==4.17.0 -openapi-core==0.16.6 -openapi-schema-validator==0.4.4 -openapi-spec-validator==0.5.6 - -# skosprovider + # via atramhasis (pyproject.toml) +python-dateutil==2.9.0.post0 + # via atramhasis (pyproject.toml) +pyyaml==6.0.1 + # via jsonschema-path +rdflib==7.0.0 + # via + # atramhasis (pyproject.toml) + # skosprovider-getty + # skosprovider-rdf +referencing==0.31.1 + # via + # jsonschema + # jsonschema-path + # jsonschema-specifications +requests==2.32.3 + # via + # atramhasis (pyproject.toml) + # cachecontrol + # jsonschema-path + # skosprovider-getty +rfc3339-validator==0.1.4 + # via openapi-schema-validator +rfc3987==1.3.8 + # via skosprovider +rpds-py==0.18.1 + # via + # jsonschema + # referencing +setuptools==70.0.0 + # via + # pyramid + # zope-deprecation + # zope-interface + # zope-sqlalchemy +six==1.16.0 + # via + # bleach + # html5lib + # isodate + # python-dateutil + # rfc3339-validator skosprovider==1.2.0 -skosprovider_sqlalchemy==2.1.1 -pyramid_skosprovider==1.2.1 -skosprovider_rdf==1.3.0 -skosprovider_getty==1.2.0 - -language-tags==1.2.0 - -# database -sqlalchemy==1.4.48 -zope.sqlalchemy==2.0 -transaction==3.1.0 - -# jinja2 -jinja2==3.1.2 -markupsafe==2.1.2 -pyramid-jinja2==2.10 -Babel==2.12.1 - -# alembic -alembic==1.9.4 - -# validation -colander==2.0 - -# caching -dogpile.cache==1.1.8 - -# other -python-dateutil==2.8.2 -rdflib==6.3.1 -bleach==5.0.1 - -# requests -requests==2.31.0 -cachecontrol==0.13.1 + # via + # atramhasis (pyproject.toml) + # pyramid-skosprovider + # skosprovider-getty + # skosprovider-rdf + # skosprovider-sqlalchemy +skosprovider-getty==1.2.0 + # via atramhasis (pyproject.toml) +skosprovider-rdf==1.3.0 + # via atramhasis (pyproject.toml) +skosprovider-sqlalchemy==2.1.1 + # via atramhasis (pyproject.toml) +sqlalchemy==2.0.30 + # via + # atramhasis (pyproject.toml) + # alembic + # skosprovider-sqlalchemy + # zope-sqlalchemy +stevedore==5.2.0 + # via dogpile-cache +transaction==4.0 + # via + # atramhasis (pyproject.toml) + # pyramid-tm + # zope-sqlalchemy +translationstring==1.4 + # via + # colander + # pyramid +typing-extensions==4.12.2 + # via + # alembic + # dogpile-cache + # sqlalchemy +urllib3==2.2.1 + # via requests +venusian==3.1.0 + # via pyramid +webencodings==0.5.1 + # via + # bleach + # html5lib +webob==1.8.7 + # via pyramid +werkzeug==3.0.3 + # via openapi-core +zope-deprecation==5.0 + # via + # pyramid + # pyramid-jinja2 +zope-interface==6.4.post2 + # via + # pyramid + # transaction + # zope-sqlalchemy +zope-sqlalchemy==3.1 + # via atramhasis (pyproject.toml) diff --git a/tests/__init__.py b/tests/__init__.py index f49416d6..34dc185a 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -13,6 +13,7 @@ from skosprovider_sqlalchemy.providers import SQLAlchemyProvider from skosprovider_sqlalchemy.utils import import_provider from sqlalchemy import engine_from_config +from sqlalchemy import text from sqlalchemy.exc import OperationalError from sqlalchemy.exc import ProgrammingError from sqlalchemy.orm import sessionmaker @@ -61,13 +62,16 @@ def setup_db(guarantee_empty=False): def _reset_db(): engine = engine_from_config(SETTINGS, prefix='sqlalchemy.') + session = sessionmaker(bind=engine)() try: - engine.execute("DELETE FROM concept_note") - engine.execute("DELETE FROM note") - engine.execute("DELETE FROM concept_label") - engine.execute("DELETE FROM label") + session.execute(text("DELETE FROM concept_note")) + session.execute(text("DELETE FROM note")) + session.execute(text("DELETE FROM concept_label")) + session.execute(text("DELETE FROM label")) except (ProgrammingError, OperationalError): """The tables may not exist if it's first time.""" + session.commit() + session.close() command.downgrade(ALEMBIC_CONFIG, 'base') engine.dispose() diff --git a/tests/test_functional.py b/tests/test_functional.py index 5761a330..5ea779c5 100644 --- a/tests/test_functional.py +++ b/tests/test_functional.py @@ -156,8 +156,9 @@ def setUp(self): def mock_event_handler(event): if event.uri == 'urn:x-vioe:geography:9': referenced_in = ['urn:someobject', 'http://test.test.org/object/2'] - raise ProtectedResourceException(f'resource {event.uri} is still in use, preventing operation', - referenced_in) + raise ProtectedResourceException( + f'resource {event.uri} is still in use, preventing operation', + referenced_in) @staticmethod def mock_event_handler_provider_unavailable(event): @@ -180,22 +181,26 @@ def test_get_csv(self): response = self.testapp.get('/conceptschemes/TREES/c.csv?type=collection&label=') self.assertEqual('200 OK', response.status) self.assertIn('text/csv', response.headers['Content-Type']) - self.assertIn('attachment;filename="atramhasis_export.csv"', response.headers['Content-Disposition']) + self.assertIn('attachment;filename="atramhasis_export.csv"', + response.headers['Content-Disposition']) def test_unicode_csv(self): - response = self.testapp.get('/conceptschemes/TREES/c.csv?label=Chestnut&_LOCALE_=fr') + response = self.testapp.get( + '/conceptschemes/TREES/c.csv?label=Chestnut&_LOCALE_=fr') data = response.body.decode('utf-8') self.assertIsInstance(data, str) self.assertEqual('200 OK', response.status) self.assertIn('text/csv', response.headers['Content-Type']) - self.assertIn('attachment;filename="atramhasis_export.csv"', response.headers['Content-Disposition']) + self.assertIn('attachment;filename="atramhasis_export.csv"', + response.headers['Content-Disposition']) self.assertIn('la châtaigne', data) def test_get_csv_all(self): response = self.testapp.get('/conceptschemes/TREES/c.csv') self.assertEqual('200 OK', response.status) self.assertIn('text/csv', response.headers['Content-Type']) - self.assertIn('attachment;filename="atramhasis_export.csv"', response.headers['Content-Disposition']) + self.assertIn('attachment;filename="atramhasis_export.csv"', + response.headers['Content-Disposition']) class RestFunctionalTests(FunctionalTests): @@ -203,7 +208,8 @@ def _get_default_headers(self): return {'Accept': 'application/json'} def test_get_concept(self): - res = self.testapp.get('/conceptschemes/TREES/c/1', headers=self._get_default_headers()) + res = self.testapp.get('/conceptschemes/TREES/c/1', + headers=self._get_default_headers()) self.assertEqual('200 OK', res.status) self.assertIn('application/json', res.headers['Content-Type']) self.assertIsNotNone(res.json['id']) @@ -212,32 +218,38 @@ def test_get_concept(self): self.assertIn('sortLabel', [label['type'] for label in res.json['labels']]) def test_get_conceptscheme(self): - res = self.testapp.get('/conceptschemes/TREES', headers=self._get_default_headers()) + res = self.testapp.get('/conceptschemes/TREES', + headers=self._get_default_headers()) self.assertEqual('200 OK', res.status) self.assertIn('application/json', res.headers['Content-Type']) self.assertIsNotNone(res.json['id']) def test_get_concept_dictprovider(self): - res = self.testapp.get('/conceptschemes/TEST/c/1', headers=self._get_default_headers()) + res = self.testapp.get('/conceptschemes/TEST/c/1', + headers=self._get_default_headers()) self.assertEqual('200 OK', res.status) self.assertIn('application/json', res.headers['Content-Type']) self.assertIsNotNone(res.json['id']) self.assertEqual(res.json['type'], 'concept') def test_get_concept_not_found(self): - res = self.testapp.get('/conceptschemes/TREES/c/89', headers=self._get_default_headers(), status=404, + res = self.testapp.get('/conceptschemes/TREES/c/89', + headers=self._get_default_headers(), status=404, expect_errors=True) self.assertEqual('404 Not Found', res.status) self.assertIn('application/json', res.headers['Content-Type']) def test_get_concept_dictprovider_not_found(self): - res = self.testapp.get('/conceptschemes/TEST/c/89', headers=self._get_default_headers(), status=404, + res = self.testapp.get('/conceptschemes/TEST/c/89', + headers=self._get_default_headers(), status=404, expect_errors=True) self.assertEqual('404 Not Found', res.status) self.assertIn('application/json', res.headers['Content-Type']) def test_add_concept(self): - res = self.testapp.post_json('/conceptschemes/TREES/c', headers=self._get_default_headers(), params=json_value) + res = self.testapp.post_json('/conceptschemes/TREES/c', + headers=self._get_default_headers(), + params=json_value) self.assertEqual('201 Created', res.status) self.assertIn('application/json', res.headers['Content-Type']) self.assertIsNotNone(res.json['id']) @@ -256,25 +268,25 @@ def test_add_update_concept_manual_id(self): self.assertDictEqual( { 'id': 'manual-3', - 'type': 'concept', + 'type': 'concept', 'uri': 'urn:x-skosprovider:manual-ids:manual-3', 'label': 'The Larch', 'concept_scheme': { 'uri': 'urn:x-vioe:manual', 'labels': [] - }, + }, 'labels': [ - {'label': 'The Larch', 'type': 'prefLabel', 'language': 'en'}, + {'label': 'The Larch', 'type': 'prefLabel', 'language': 'en'}, {'label': 'a', 'type': 'sortLabel', 'language': 'en'} - ], - 'notes': [], + ], + 'notes': [], 'sources': [ {'citation': 'short', 'markup': None} ], - 'narrower': [], + 'narrower': [], 'broader': [], - 'related': [], + 'related': [], 'member_of': [], - 'subordinate_arrays': [], + 'subordinate_arrays': [], 'matches': { 'close': [], 'exact': [], 'related': [], 'broad': [], 'narrow': [] } @@ -291,7 +303,8 @@ def test_add_update_concept_manual_id(self): self.assertEqual('updated', res.json['label']) def test_add_concept_empty_conceptscheme(self): - res = self.testapp.post_json('/conceptschemes/STYLES/c', headers=self._get_default_headers(), + res = self.testapp.post_json('/conceptschemes/STYLES/c', + headers=self._get_default_headers(), params=json_value) self.assertEqual('201 Created', res.status) self.assertIn('application/json', res.headers['Content-Type']) @@ -299,27 +312,31 @@ def test_add_concept_empty_conceptscheme(self): def test_add_concept_invalid_json(self): res = self.testapp.post_json( - '/conceptschemes/TREES/c', headers=self._get_default_headers(), params=json_value_invalid, status=400) + '/conceptschemes/TREES/c', headers=self._get_default_headers(), + params=json_value_invalid, status=400) self.assertEqual('400 Bad Request', res.status) self.assertIn('application/json', res.headers['Content-Type']) def test_add_concept_conceptscheme_not_found(self): res = self.testapp.post_json( - '/conceptschemes/GARDENNNN/c', headers=self._get_default_headers(), params=json_value, status=404, + '/conceptschemes/GARDENNNN/c', headers=self._get_default_headers(), + params=json_value, status=404, expect_errors=True) self.assertEqual('404 Not Found', res.status) self.assertIn('application/json', res.headers['Content-Type']) def test_edit_conceptscheme(self): res = self.testapp.put_json( - '/conceptschemes/TREES', headers=self._get_default_headers(), params=json_collection_value) + '/conceptschemes/TREES', headers=self._get_default_headers(), + params=json_collection_value) self.assertEqual('200 OK', res.status) self.assertIn('application/json', res.headers['Content-Type']) def test_edit_conceptscheme_invalid(self): json_collection_value.pop('labels') res = self.testapp.put_json( - '/conceptschemes/TREES', headers=self._get_default_headers(), params=json_collection_value, + '/conceptschemes/TREES', headers=self._get_default_headers(), + params=json_collection_value, expect_errors=True) self.assertEqual('400 Bad Request', res.status) self.assertIn('application/json', res.headers['Content-Type']) @@ -335,27 +352,31 @@ def test_edit_conceptscheme_invalid(self): def test_edit_concept(self): res = self.testapp.put_json( - '/conceptschemes/TREES/c/1', headers=self._get_default_headers(), params=json_value) + '/conceptschemes/TREES/c/1', headers=self._get_default_headers(), + params=json_value) self.assertEqual('200 OK', res.status) self.assertIn('application/json', res.headers['Content-Type']) def test_edit_concept_has_relations(self): res = self.testapp.put_json( - '/conceptschemes/MATERIALS/c/13', headers=self._get_default_headers(), params=json_value_relations) + '/conceptschemes/MATERIALS/c/13', headers=self._get_default_headers(), + params=json_value_relations) self.assertEqual('200 OK', res.status) self.assertIn('application/json', res.headers['Content-Type']) self.assertEqual(2, len(res.json['narrower'])) def test_edit_concept_not_found(self): res = self.testapp.put_json( - '/conceptschemes/TREES/c/89', headers=self._get_default_headers(), params=json_value, status=404, + '/conceptschemes/TREES/c/89', headers=self._get_default_headers(), + params=json_value, status=404, expect_errors=True) self.assertEqual('404 Not Found', res.status) self.assertIn('application/json', res.headers['Content-Type']) def test_delete_concept(self): new_id = '1' - res = self.testapp.delete(f'/conceptschemes/TREES/c/{new_id}', headers=self._get_default_headers()) + res = self.testapp.delete(f'/conceptschemes/TREES/c/{new_id}', + headers=self._get_default_headers()) self.assertEqual('200 OK', res.status) self.assertIsNotNone(res.json['id']) self.assertEqual(new_id, res.json['id']) @@ -364,12 +385,14 @@ def test_delete_concept(self): print() def test_delete_concept_not_found(self): - res = self.testapp.delete('/conceptschemes/TREES/c/7895', headers=self._get_default_headers(), + res = self.testapp.delete('/conceptschemes/TREES/c/7895', + headers=self._get_default_headers(), expect_errors=True) self.assertEqual('404 Not Found', res.status) def test_add_collection(self): - res = self.testapp.post_json('/conceptschemes/GEOGRAPHY/c', headers=self._get_default_headers(), + res = self.testapp.post_json('/conceptschemes/GEOGRAPHY/c', + headers=self._get_default_headers(), params=json_collection_value, expect_errors=True) self.assertEqual('201 Created', res.status) self.assertIn('application/json', res.headers['Content-Type']) @@ -379,7 +402,8 @@ def test_add_collection(self): def test_edit_collection(self): json_collection_value['members'] = [{"id": 7}, {"id": 8}] json_collection_value['infer_concept_relations'] = False - res = self.testapp.put_json('/conceptschemes/GEOGRAPHY/c/333', headers=self._get_default_headers(), + res = self.testapp.put_json('/conceptschemes/GEOGRAPHY/c/333', + headers=self._get_default_headers(), params=json_collection_value) self.assertEqual('200 OK', res.status) self.assertIn('application/json', res.headers['Content-Type']) @@ -389,12 +413,14 @@ def test_edit_collection(self): self.assertFalse(res.json['infer_concept_relations']) def test_delete_collection(self): - res = self.testapp.delete('/conceptschemes/GEOGRAPHY/c/333', headers=self._get_default_headers()) + res = self.testapp.delete('/conceptschemes/GEOGRAPHY/c/333', + headers=self._get_default_headers()) self.assertEqual('200 OK', res.status) self.assertIn('application/json', res.headers['Content-Type']) def test_uri(self): - res = self.testapp.post_json('/conceptschemes/MATERIALS/c', headers=self._get_default_headers(), + res = self.testapp.post_json('/conceptschemes/MATERIALS/c', + headers=self._get_default_headers(), params=json_value) self.assertEqual('201 Created', res.status) self.assertIn('application/json', res.headers['Content-Type']) @@ -403,6 +429,7 @@ def test_uri(self): def test_provider_unavailable_view(self): def raise_provider_unavailable_exception(): raise ProviderUnavailableException('test msg') + with patch('atramhasis.views.crud.AtramhasisCrud.delete_concept', Mock(side_effect=raise_provider_unavailable_exception)): res = self.testapp.delete('/conceptschemes/GEOGRAPHY/c/55', @@ -442,7 +469,8 @@ def test_get_language(self): self.assertEqual('German', res.json['name']) def test_get_language_not_found(self): - res = self.testapp.get('/languages/jos', headers=self._get_default_headers(), expect_errors=True) + res = self.testapp.get('/languages/jos', headers=self._get_default_headers(), + expect_errors=True) self.assertEqual('404 Not Found', res.status) self.assertIn('application/json', res.headers['Content-Type']) self.assertIsNotNone(res.json) @@ -457,13 +485,16 @@ def test_add_language(self): self.assertEqual(res.json['name'], 'Afrikaans') def test_add_language_non_valid(self): - res = self.testapp.put_json('/languages/flup', headers=self._get_default_headers(), - params={"id": "flup", "name": "flup"}, expect_errors=True) + res = self.testapp.put_json('/languages/flup', + headers=self._get_default_headers(), + params={"id": "flup", "name": "flup"}, + expect_errors=True) self.assertEqual('400 Bad Request', res.status) self.assertIn('application/json', res.headers['Content-Type']) self.assertIsNotNone(res.json) self.assertEqual(res.json, { - "errors": [{"id": "Invalid language tag: Unknown code 'flup', Missing language tag in 'flup'."}], + "errors": [{ + "id": "Invalid language tag: Unknown code 'flup', Missing language tag in 'flup'."}], "message": "Language could not be validated"}) def test_add_language_non_valid_json(self): @@ -472,7 +503,8 @@ def test_add_language_non_valid_json(self): self.assertEqual('400 Bad Request', res.status) self.assertIn('application/json', res.headers['Content-Type']) self.assertIsNotNone(res.json) - self.assertEqual(res.json, {'errors': {'name': 'Required'}, 'message': 'Language could not be validated'}) + self.assertEqual(res.json, {'errors': {'name': 'Required'}, + 'message': 'Language could not be validated'}) def test_edit_language(self): res = self.testapp.put_json('/languages/de', headers=self._get_default_headers(), @@ -483,13 +515,16 @@ def test_edit_language(self): self.assertEqual(res.json['name'], 'Duits') def test_edit_language_invalid_language_tag(self): - res = self.testapp.put_json('/languages/joss', headers=self._get_default_headers(), - params={"id": "joss", "name": "Duits"}, expect_errors=True) + res = self.testapp.put_json('/languages/joss', + headers=self._get_default_headers(), + params={"id": "joss", "name": "Duits"}, + expect_errors=True) self.assertEqual('400 Bad Request', res.status) self.assertIn('application/json', res.headers['Content-Type']) self.assertIsNotNone(res.json) self.assertEqual(res.json, { - 'errors': [{'id': "Invalid language tag: Unknown code 'joss', Missing language tag in 'joss'."}] + 'errors': [{ + 'id': "Invalid language tag: Unknown code 'joss', Missing language tag in 'joss'."}] , "message": "Language could not be validated"}) def test_edit_language_no_id(self): @@ -506,7 +541,8 @@ def test_delete_language(self): self.assertIn('application/json', res.headers['Content-Type']) def test_delete_language_not_found(self): - res = self.testapp.delete('/languages/jos', headers=self._get_default_headers(), expect_errors=True) + res = self.testapp.delete('/languages/jos', headers=self._get_default_headers(), + expect_errors=True) self.assertEqual('404 Not Found', res.status) self.assertIn('application/json', res.headers['Content-Type']) self.assertIsNotNone(res.json) @@ -514,7 +550,7 @@ def test_delete_language_not_found(self): def test_delete_protected_resource(self): def mock_event_handler(event): - if isinstance(event, ProtectedResourceEvent): + if isinstance(event, ProtectedResourceEvent): referenced_in = ['urn:someobject', 'http://test.test.org/object/2'] raise ProtectedResourceException( 'resource {} is still in use, preventing operation' @@ -537,11 +573,14 @@ def mock_event_handler(event): }) def test_method_not_allowed(self): - self.testapp.delete('/conceptschemes/TREES', headers=self._get_default_headers(), status=405) - self.testapp.post('/conceptschemes', headers=self._get_default_headers(), status=405) + self.testapp.delete('/conceptschemes/TREES', headers=self._get_default_headers(), + status=405) + self.testapp.post('/conceptschemes', headers=self._get_default_headers(), + status=405) def test_get_conceptschemes(self): - self.testapp.get('/conceptschemes', headers=self._get_default_headers(), status=200) + self.testapp.get('/conceptschemes', headers=self._get_default_headers(), + status=200) def test_create_provider_openapi_validation(self): response = self.testapp.post_json( @@ -555,12 +594,28 @@ def test_create_provider_openapi_validation(self): ) self.assertEqual( { - 'message': 'Request was not valid for schema.', + 'errors': ['None: Failed to cast value to array type: wrong'], + 'message': 'Request was not valid for schema.' + }, + response.json + ) + response = self.testapp.post_json( + url='/providers', + params={ + 'uri_pattern': 'invalid', + 'subject': ['right'] + }, + headers=self._get_default_headers(), + expect_errors=True + ) + self.assertEqual( + { 'errors': [ - ": 'conceptscheme_uri' is a required property", "uri_pattern: 'invalid' does not match '.*%s.*'", - "subject: 'wrong' is not of type 'array'" - ]}, + "uri_pattern: 'conceptscheme_uri' is a required property" + ], + 'message': 'Request was not valid for schema.' + }, response.json ) @@ -657,7 +712,8 @@ def test_create_full_provider_via_put(self): ) def test_update_provider(self): - conceptscheme = ConceptScheme(uri='https://id.erfgoed.net/thesauri/conceptschemes') + conceptscheme = ConceptScheme( + uri='https://id.erfgoed.net/thesauri/conceptschemes') provider = Provider( id='ERFGOEDTYPES', uri_pattern='https://id.erfgoed.net/thesauri/erfgoedtypes/%s', @@ -786,15 +842,18 @@ def _get_default_headers(self): return {'Accept': 'text/html'} def test_cookie(self): - response = self.testapp.get('/locale?language=nl', headers=self._get_default_headers()) + response = self.testapp.get('/locale?language=nl', + headers=self._get_default_headers()) self.assertIsNotNone(response.headers['Set-Cookie']) self.assertEqual(response.status, '302 Found') self.assertTrue((response.headers.get('Set-Cookie')).startswith('_LOCALE_=nl')) def test_unsupported_language(self): config_default_lang = settings.get('pyramid.default_locale_name') - response = self.testapp.get('/locale?language=fr', headers=self._get_default_headers()) - self.assertTrue((response.headers.get('Set-Cookie')).startswith('_LOCALE_=' + config_default_lang)) + response = self.testapp.get('/locale?language=fr', + headers=self._get_default_headers()) + self.assertTrue((response.headers.get('Set-Cookie')).startswith( + '_LOCALE_=' + config_default_lang)) class JsonTreeFunctionalTests(FunctionalTests): @@ -802,7 +861,8 @@ def _get_default_headers(self): return {'Accept': 'application/json'} def test_tree(self): - response = self.testapp.get('/conceptschemes/GEOGRAPHY/tree?_LOCALE_=nl', headers=self._get_default_headers()) + response = self.testapp.get('/conceptschemes/GEOGRAPHY/tree?_LOCALE_=nl', + headers=self._get_default_headers()) self.assertEqual('200 OK', response.status) self.assertIn('application/json', response.headers['Content-Type']) self.assertIsNotNone(response.json) @@ -810,7 +870,8 @@ def test_tree(self): self.assertEqual('World', response.json[0]['label']) def test_missing_labels(self): - response = self.testapp.get('/conceptschemes/MISSING_LABEL/tree?_LOCALE_=nl', headers=self._get_default_headers()) + response = self.testapp.get('/conceptschemes/MISSING_LABEL/tree?_LOCALE_=nl', + headers=self._get_default_headers()) self.assertEqual('200 OK', response.status) self.assertIsNotNone(response.json) self.assertEqual(2, len(response.json)) @@ -834,7 +895,8 @@ def test_tree_language(self): ) def test_no_tree(self): - response = self.testapp.get('/conceptschemes/FOO/tree?_LOCALE_=nl', headers=self._get_default_headers(), + response = self.testapp.get('/conceptschemes/FOO/tree?_LOCALE_=nl', + headers=self._get_default_headers(), status=404, expect_errors=True) self.assertEqual('404 Not Found', response.status) @@ -844,15 +906,18 @@ def _get_default_headers(self): return {'Accept': 'text/html'} def test_tree(self): - response = self.testapp.get('/conceptschemes/GEOGRAPHY/tree?_LOCALE_=nl', headers=self._get_default_headers()) + response = self.testapp.get('/conceptschemes/GEOGRAPHY/tree?_LOCALE_=nl', + headers=self._get_default_headers()) self.assertEqual('200 OK', response.status) self.assertIn('text/html', response.headers['Content-Type']) def test_no_tree(self): - response = self.testapp.get('/conceptschemes/FOO/tree?_LOCALE_=nl', headers=self._get_default_headers(), + response = self.testapp.get('/conceptschemes/FOO/tree?_LOCALE_=nl', + headers=self._get_default_headers(), status=404, expect_errors=True) self.assertEqual('404 Not Found', response.status) + class SkosFunctionalTests(FunctionalTests): def _get_default_headers(self): @@ -864,19 +929,23 @@ def _get_json_headers(self): def test_admin_no_skos_provider(self): with patch.dict(self.app.request_extensions.descriptors): del self.app.request_extensions.descriptors['skos_registry'] - res = self.testapp.get('/admin', headers=self._get_default_headers(), expect_errors=True) + res = self.testapp.get('/admin', headers=self._get_default_headers(), + expect_errors=True) self.assertEqual('500 Internal Server Error', res.status) self.assertTrue('message' in res) - self.assertTrue('No SKOS registry found, please check your application setup' in res) + self.assertTrue( + 'No SKOS registry found, please check your application setup' in res) def test_crud_no_skos_provider(self): with patch.dict(self.app.request_extensions.descriptors): del self.app.request_extensions.descriptors['skos_registry'] - res = self.testapp.post_json('/conceptschemes/GEOGRAPHY/c', headers=self._get_json_headers(), + res = self.testapp.post_json('/conceptschemes/GEOGRAPHY/c', + headers=self._get_json_headers(), params=json_collection_value, expect_errors=True) self.assertEqual('500 Internal Server Error', res.status) self.assertTrue('message' in res) - self.assertTrue('No SKOS registry found, please check your application setup' in res) + self.assertTrue( + 'No SKOS registry found, please check your application setup' in res) def test_match_filter(self): response = self.testapp.get( @@ -919,8 +988,9 @@ def test_create_cache(self): self.assertEqual('200 OK', tree_response.status) self.assertIsNotNone(tree_response.json) - cached_tree_response = self.testapp.get('/conceptschemes/MATERIALS/tree?_LOCALE_=nl', - headers=self._get_default_headers()) + cached_tree_response = self.testapp.get( + '/conceptschemes/MATERIALS/tree?_LOCALE_=nl', + headers=self._get_default_headers()) self.assertEqual('200 OK', cached_tree_response.status) self.assertIsNotNone(cached_tree_response.json) @@ -941,8 +1011,9 @@ def test_auto_invalidate_cache(self): tree_response = self.testapp.get('/conceptschemes/MATERIALS/tree?_LOCALE_=nl', headers=self._get_default_headers()) - cached_tree_response = self.testapp.get('/conceptschemes/MATERIALS/tree?_LOCALE_=nl', - headers=self._get_default_headers()) + cached_tree_response = self.testapp.get( + '/conceptschemes/MATERIALS/tree?_LOCALE_=nl', + headers=self._get_default_headers()) self.assertEqual(tree_response.json, cached_tree_response.json) delete_response = self.testapp.delete('/conceptschemes/MATERIALS/c/31', @@ -954,8 +1025,9 @@ def test_auto_invalidate_cache(self): headers=self._get_default_headers()) self.assertNotEqual(tree_response.json, tree_response2.json) - cached_tree_response2 = self.testapp.get('/conceptschemes/MATERIALS/tree?_LOCALE_=nl', - headers=self._get_default_headers()) + cached_tree_response2 = self.testapp.get( + '/conceptschemes/MATERIALS/tree?_LOCALE_=nl', + headers=self._get_default_headers()) self.assertEqual(tree_response2.json, cached_tree_response2.json) tree_region.configure('dogpile.cache.null', replace_existing_backend=True) @@ -970,7 +1042,8 @@ def test_void(self): self.assertEqual('text/turtle', rdf_response.content_type) def test_rdf_full_xml(self): - rdf_response = self.testapp.get('/conceptschemes/MATERIALS/c', headers={'Accept': 'application/rdf+xml'}) + rdf_response = self.testapp.get('/conceptschemes/MATERIALS/c', + headers={'Accept': 'application/rdf+xml'}) self.assertEqual('200 OK', rdf_response.status) self.assertEqual('application/rdf+xml', rdf_response.content_type) @@ -980,7 +1053,8 @@ def test_rdf_full_xml_ext(self): self.assertEqual('application/rdf+xml', rdf_response.content_type) def test_rdf_full_turtle(self): - ttl_response = self.testapp.get('/conceptschemes/MATERIALS/c', headers={'Accept': 'text/turtle'}) + ttl_response = self.testapp.get('/conceptschemes/MATERIALS/c', + headers={'Accept': 'text/turtle'}) self.assertEqual('200 OK', ttl_response.status) self.assertEqual('text/turtle', ttl_response.content_type) @@ -990,7 +1064,8 @@ def test_rdf_full_turtle_ext(self): self.assertEqual('text/turtle', ttl_response.content_type) def test_rdf_conceptscheme_xml(self): - rdf_response = self.testapp.get('/conceptschemes/MATERIALS', headers={'Accept': 'application/rdf+xml'}) + rdf_response = self.testapp.get('/conceptschemes/MATERIALS', + headers={'Accept': 'application/rdf+xml'}) self.assertEqual('200 OK', rdf_response.status) self.assertEqual('application/rdf+xml', rdf_response.content_type) @@ -1000,7 +1075,8 @@ def test_rdf_conceptscheme_xml_ext(self): self.assertEqual('application/rdf+xml', rdf_response.content_type) def test_rdf_conceptscheme_turtle(self): - ttl_response = self.testapp.get('/conceptschemes/MATERIALS', headers={'Accept': 'text/turtle'}) + ttl_response = self.testapp.get('/conceptschemes/MATERIALS', + headers={'Accept': 'text/turtle'}) self.assertEqual('200 OK', ttl_response.status) self.assertEqual('text/turtle', ttl_response.content_type) @@ -1010,7 +1086,8 @@ def test_rdf_conceptscheme_turtle_ext(self): self.assertEqual('text/turtle', ttl_response.content_type) def test_rdf_conceptscheme_jsonld(self): - res = self.testapp.get('/conceptschemes/MATERIALS', headers={'Accept': 'application/ld+json'}) + res = self.testapp.get('/conceptschemes/MATERIALS', + headers={'Accept': 'application/ld+json'}) self.assertEqual('200 OK', res.status) self.assertEqual('application/ld+json', res.content_type) @@ -1020,7 +1097,8 @@ def test_rdf_conceptscheme_jsonld_ext(self): self.assertEqual('application/ld+json', res.content_type) def test_rdf_individual_jsonld(self): - res = self.testapp.get('/conceptschemes/MATERIALS/c/1', headers={'Accept': 'application/ld+json'}) + res = self.testapp.get('/conceptschemes/MATERIALS/c/1', + headers={'Accept': 'application/ld+json'}) self.assertEqual('200 OK', res.status) self.assertEqual('application/ld+json', res.content_type) @@ -1030,7 +1108,8 @@ def test_rdf_individual_jsonld_ext(self): self.assertEqual('application/ld+json', res.content_type) def test_rdf_individual_xml(self): - rdf_response = self.testapp.get('/conceptschemes/MATERIALS/c/1', headers={'Accept': 'application/rdf+xml'}) + rdf_response = self.testapp.get('/conceptschemes/MATERIALS/c/1', + headers={'Accept': 'application/rdf+xml'}) self.assertEqual('200 OK', rdf_response.status) self.assertEqual('application/rdf+xml', rdf_response.content_type) @@ -1040,7 +1119,8 @@ def test_rdf_individual_xml_ext(self): self.assertEqual('application/rdf+xml', rdf_response.content_type) def test_rdf_individual_turtle(self): - ttl_response = self.testapp.get('/conceptschemes/MATERIALS/c/1', headers={'Accept': 'text/turtle'}) + ttl_response = self.testapp.get('/conceptschemes/MATERIALS/c/1', + headers={'Accept': 'text/turtle'}) self.assertEqual('200 OK', ttl_response.status) self.assertEqual('text/turtle', ttl_response.content_type) @@ -1065,12 +1145,14 @@ def test_rdf_individual_turtle_manual(self): self.assertEqual('text/turtle', ttl_response.content_type) def test_rdf_individual_turtle_manual_uri(self): - ttl_response = self.testapp.get('/conceptschemes/manual-ids/c/http://id.manual.org/manual/68.ttl') + ttl_response = self.testapp.get( + '/conceptschemes/manual-ids/c/http://id.manual.org/manual/68.ttl') self.assertEqual('200 OK', ttl_response.status) self.assertEqual('text/turtle', ttl_response.content_type) def test_rdf_individual_not_found(self): - res = self.testapp.get('/conceptschemes/TREES/c/test.ttl', headers={'Accept': 'text/turtle'}, status=404, + res = self.testapp.get('/conceptschemes/TREES/c/test.ttl', + headers={'Accept': 'text/turtle'}, status=404, expect_errors=True) self.assertEqual('404 Not Found', res.status) diff --git a/tests/test_views.py b/tests/test_views.py index d88a5b04..ee41cb70 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -4,7 +4,6 @@ import mock import pytest -from openapi_core.validation.request.datatypes import RequestValidationResult from paste.deploy.loadwsgi import appconfig from pyramid import testing from pyramid.config.settings import Settings @@ -730,7 +729,7 @@ def test_add_concept_manual_id_strategy(self): self.view.edit_concept() def test_add_provider(self): - self.request.openapi_validated = RequestValidationResult(errors=[]) + self.request.openapi_validated = Mock() self.request.skos_registry = Registry() view = 'atramhasis.views.crud' @@ -745,7 +744,7 @@ def test_add_provider(self): self.assertEqual(response, renderer.return_value) def test_update_provider(self): - self.request.openapi_validated = RequestValidationResult(errors=[]) + self.request.openapi_validated = Mock() self.request.matchdict = {"id": 1} view = 'atramhasis.views.crud' diff --git a/tox.ini b/tox.ini deleted file mode 100644 index df3789cf..00000000 --- a/tox.ini +++ /dev/null @@ -1,26 +0,0 @@ -[tox] -envlist = py39, py310, py311, cover - -[testenv] -passenv = 3.9 -commands = - pip install -r requirements-dev.txt - python setup.py develop - py.test tests -deps = - pytest - webtest - mock - testfixtures - -[testenv:cover] -basepython = - python3.9.0 -commands = - pip install -U setuptools - pip install -r requirements-dev.txt - python setup.py develop - py.test --cov-report term-missing --cov skosprovider tests -deps = - pytest - pytest-cov