diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml new file mode 100644 index 0000000..74264ce --- /dev/null +++ b/.github/workflows/integration-tests.yml @@ -0,0 +1,41 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: Integration tests + +on: + push: + branches: [ "master", "rc/**" ] + pull_request: + branches: [ "master", "rc/**" ] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.12", "3.11", "3.10", "3.9", "3.8", "3.7"] + neo4j-version: ["community", "4.4-community"] + + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Creating Neo4j Container + run: | + chmod +x ./scripts/docker-neo4j.sh + sh ./scripts/docker-neo4j.sh ${{ matrix.neo4j-version }} + sleep 30s + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -e '.[dev]' + - name: Test with pytest + run: | + export DJANGO_SETTINGS_MODULE=settings + tests/manage.py install_labels + tests/manage.py migrate + pytest \ No newline at end of file diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml new file mode 100644 index 0000000..bdaab28 --- /dev/null +++ b/.github/workflows/python-publish.yml @@ -0,0 +1,39 @@ +# This workflow will upload a Python Package using Twine when a release is created +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Upload Python Package + +on: + release: + types: [published] + +permissions: + contents: read + +jobs: + deploy: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v3 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install build + - name: Build package + run: python -m build + - name: Publish package + uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.gitignore b/.gitignore index e62e822..5d902bc 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,5 @@ development.env .ropeproject \#*\# tests/test.db -.DS_Store \ No newline at end of file +.DS_Store +.vscode \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ab3bfd6..0000000 --- a/.travis.yml +++ /dev/null @@ -1,29 +0,0 @@ -language: python -sudo: required -python: - - "3.6" - - "3.7" - - "3.8" - - "3.9" - -env: - - NEO4J_VERSION="3.5.24" - - NEO4J_VERSION="4.0.9" - - NEO4J_VERSION="4.1.4" - - NEO4J_VERSION="4.2.0" -before_install: - - sudo add-apt-repository -y ppa:openjdk-r/ppa - - sudo apt-get update && sudo apt-get install openjdk-11-jre-headless - - curl -L http://dist.neo4j.org/neo4j-community-$NEO4J_VERSION-unix.tar.gz | tar xz -install: "python setup.py install" -before_script: - - neo4j-community-$NEO4J_VERSION/bin/neo4j-admin set-initial-password foobar - - JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 neo4j-community-$NEO4J_VERSION/bin/neo4j start - - export DJANGO_SETTINGS_MODULE=settings - - sleep 10 -script: - - cd tests - - ./manage.py install_labels - - ./manage.py migrate - - export DJANGO_SETTINGS_MODULE=tests.settings - - pytest diff --git a/Changelog b/Changelog index 692973e..fdb2f18 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,20 @@ +Version 0.1.2 2024-05 +* Bump neomodel to 5.3.0 + +Version 0.1.1 2023-08 +* Bump neomodel to 5.1.0 - full support of Neo4j version 5.x (and 4.4 LTS) +* Support higher versions of Django (> 2.2) + +Version 0.1.0 2023-04 +* Upgrade neomodel dependency to version 5.0.0 +* Adds support for all Neo4j 5.x versions, and 4.4 (LTS) +* Drops support of Neo4j version 4.3 and under + +Version 0.0.8 2023-03 +* Upgrade neomodel dependency to version 4.0.10 +* Adds support for all Neo4j 4.x versions +* Adds support for Python up to 3.11 + Version 0.0.7 2021-07-06 * Added Docker Example * Django admin regsister for nodes is now available (beta) diff --git a/MANIFEST.in b/MANIFEST.in index 2d767e7..07baa71 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,4 @@ -include README.rst +include README.md include AUTHORS.txt include Changelog include LICENSE diff --git a/README.rst b/README.md similarity index 68% rename from README.rst rename to README.md index ba6538e..085133c 100644 --- a/README.rst +++ b/README.md @@ -1,37 +1,27 @@ -Django Neomodel (beta!) -======================= +# Django Neomodel (beta!) -.. image:: https://raw.githubusercontent.com/robinedwards/neomodel/master/doc/source/_static/neomodel-300.png - :alt: neomodel +![neomodel](https://raw.githubusercontent.com/neo4j-contrib/neomodel/master/doc/source/_static/neomodel-300.png) -This module allows you to use the neo4j_ graph database with Django using neomodel_ +This module allows you to use the [neo4j](https://www.neo4j.org) graph database with Django using [neomodel](http://neomodel.readthedocs.org) -.. _neo4j: https://www.neo4j.org -.. _neomodel: http://neomodel.readthedocs.org -.. image:: https://secure.travis-ci.org/neo4j-contrib/django-neomodel.png - :target: https://secure.travis-ci.org/neo4j-contrib/django-neomodel/ +## Warnings -Warnings -======================= +* Admin functionality is very experimental. [Please see todos / issues here](https://github.com/neo4j-contrib/django-neomodel/projects/1) -* Admin functionality is very experimental. `Please see todos / issues here `_ +## Live Examples (add yours here) -Live Examples (add yours here) -======================= +* [Syracuse](https://syracuse.1145.am>): a database of company linkages created from unstructured text. Repo at [syracuse-neo](https://github.com/alanbuxton/syracuse-neo.git) -* `ResoTrack `_ +# Getting started -Getting started -=============== - -Install the module:: +Install the module: $ pip install django_neomodel -Add the following settings to your `settings.py`:: +Add the following settings to your `settings.py`: - NEOMODEL_NEO4J_BOLT_URL = os.environ.get('NEO4J_BOLT_URL', 'bolt://neo4j:test@localhost:7687') + NEOMODEL_NEO4J_BOLT_URL = os.environ.get('NEO4J_BOLT_URL', 'bolt://neo4j:foobarbaz@localhost:7687') # Make sure django_neomodel comes before your own apps INSTALLED_APPS = ( @@ -40,7 +30,7 @@ Add the following settings to your `settings.py`:: 'yourapp' ) -Write your first node definition in `yourapp/models.py`:: +Write your first node definition in `yourapp/models.py`: from neomodel import StructuredNode, StringProperty, DateProperty @@ -49,18 +39,18 @@ Write your first node definition in `yourapp/models.py`:: published = DateProperty() Create any constraints or indexes for your labels. This needs to be done after you change your node definitions -much like `manage.py migrate`:: +much like `manage.py migrate`: $ python manage.py install_labels -Now in a view `yourapp/views.py`:: +Now in a view `yourapp/views.py`: from .models import Book def get_books(request): return render('yourapp/books.html', request, {'books': Book.nodes.all()}) -In your `yourapp/admin.py`:: +In your `yourapp/admin.py`: from django_neomodel import admin as neo_admin from .models import Book @@ -71,10 +61,9 @@ In your `yourapp/admin.py`:: And you're ready to go. Don't forget to check the neomodel_ documentation. -Model forms -=========== +## Model forms -Switch the base class from `StructuredNode` to `DjangoNode` and add a 'Meta' class:: +Switch the base class from `StructuredNode` to `DjangoNode` and add a 'Meta' class: from datetime import datetime from django_neomodel import DjangoNode @@ -93,7 +82,7 @@ Switch the base class from `StructuredNode` to `DjangoNode` and add a 'Meta' cla class Meta: app_label = 'library' -Create a model form class for your `DjangoNode`:: +Create a model form class for your `DjangoNode`: class BookForm(ModelForm): class Meta: @@ -102,19 +91,17 @@ Create a model form class for your `DjangoNode`:: This class may now be used just like any other Django form. -Settings -======== +## Settings The following config options are available in django settings (default values shown). -These are mapped to neomodel.config as django is started:: +These are mapped to neomodel.config as django is started: NEOMODEL_NEO4J_BOLT_URL = 'bolt://neo4j:neo4j@localhost:7687' NEOMODEL_SIGNALS = True NEOMODEL_FORCE_TIMEZONE = False NEOMODEL_MAX_CONNECTION_POOL_SIZE = 50 -Signals -======= -Signals work with `DjangoNode` sub-classes:: +## Signals +Signals work with `DjangoNode` sub-classes: from django.db.models import signals from django_neomodel import DjangoNode @@ -131,10 +118,9 @@ Signals work with `DjangoNode` sub-classes:: The following are supported: `pre_save`, `post_save`, `pre_delete`, `post_delete`. On freshly created nodes `created=True` in the `post_save` signal argument. -Testing -======= +## Testing -You can create a setup method which clears the database before executing each test:: +You can create a setup method which clears the database before executing each test: from neomodel import db, clear_neo4j_database @@ -145,14 +131,12 @@ You can create a setup method which clears the database before executing each te def test_something(self): pass -Management Commands -=================== +## Management Commands The following django management commands have been included. -install_labels --------------- -Setup constraints and indexes on labels for your node definitions. This should be executed after any schema changes:: +### install_labels +Setup constraints and indexes on labels for your node definitions. This should be executed after any schema changes: $ python manage.py install_labels Setting up labels and constraints... @@ -161,27 +145,19 @@ Setup constraints and indexes on labels for your node definitions. This should b + Creating unique constraint for title on label Book for class tests.someapp.models.Book Finished 1 class(es). -clear_neo4j ------------ +### clear_neo4j Delete all nodes in your database, warning there is no confirmation! -Requirements -============ - -- Python 3.6+ -- neo4j 3.5+ - -.. image:: https://badges.gitter.im/Join%20Chat.svg - :alt: Join the chat at https://gitter.im/robinedwards/neomodel - :target: https://gitter.im/robinedwards/neomodel?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge +## Requirements -Docker Example -=================== +- Python 3.7+ +- neo4j 5.x, 4.4 (LTS) +## Docker Example Using Docker Compose. -Commands to setup Docker Container docker-entrypoint.sh:: +Commands to setup Docker Container docker-entrypoint.sh: # Go to tests $ cd tests/ @@ -194,19 +170,16 @@ Go to http://localhost:7474/browser/ Go to http://localhost:8000/admin/ -Running Tests -=================== +## Running Tests -Setup Neo4j Desktop with a local database with password 'foobar' and version 4.1.2 (current version when this was written). +Setup Neo4j Desktop with a local database with password 'foobarbaz' and version 5.x or 4.4.x (Neo4j LTS version). -Commands to run tests:: +Commands to run tests: # create local venv and install dependencies. - $ python3 -m venv venv; source venv/bin/activate; python setup.py develop; export DJANGO_SETTINGS_MODULE=tests.settings; - # Go to tests - $ cd tests/ - $ ./manage.py install_labels - $ ./manage.py migrate + $ pip install -e '.[dev]'; export DJANGO_SETTINGS_MODULE=tests.settings; + $ tests/manage.py install_labels + $ tests/manage.py migrate $ pytest # example output: diff --git a/django_neomodel/__init__.py b/django_neomodel/__init__.py index 9e47a89..4429d15 100644 --- a/django_neomodel/__init__.py +++ b/django_neomodel/__init__.py @@ -11,9 +11,9 @@ from django.core.exceptions import ValidationError from neomodel import RequiredProperty, DeflateError, StructuredNode, UniqueIdProperty, AliasProperty, UniqueProperty -from neomodel.core import NodeMeta -from neomodel.match import NodeSet -from neomodel.cardinality import OneOrMore, One, ZeroOrOne, ZeroOrMore +from neomodel.sync_.core import NodeMeta +from neomodel.sync_.match import NodeSet +from neomodel.sync_.cardinality import OneOrMore, One, ZeroOrOne, ZeroOrMore from types import SimpleNamespace from django.apps import apps as current_apps @@ -23,14 +23,14 @@ # Need to following to get the relationships to work RECURSIVE_RELATIONSHIP_CONSTANT = 'self' -__author__ = 'Robin Edwards' -__email__ = 'robin.ge@gmail.com' -__license__ = 'MIT' -__package__ = 'django_neomodel' -__version__ = '0.0.6' +__author__ = "Robin Edwards" +__email__ = "robin.ge@gmail.com" +__license__ = "MIT" +__package__ = "django_neomodel" +__version__ = "0.1.2" -default_app_config = 'django_neomodel.apps.NeomodelConfig' +default_app_config = "django_neomodel.apps.NeomodelConfig" def classproperty(f): @@ -40,6 +40,7 @@ def __init__(self, getter): def __get__(self, obj, type=None): return self.getter(type) + return cpf(f) @@ -122,6 +123,7 @@ class DjangoPropertyField(DjangoBaseField): """ Fake Django model field object which wraps a neomodel Property """ + is_relation = False concrete = True editable = True @@ -136,14 +138,14 @@ def __init__(self, prop, name): self.remote_field = None self.attname = name self.verbose_name = name - self.help_text = getattr(prop, 'help_text', '') + self.help_text = getattr(prop, "help_text", "") if isinstance(prop, UniqueIdProperty): # this seems that can be implemented in neomodel # django-neomodel does have the needed code already but neomodel does not support prop.primary_key = True - self.primary_key = getattr(prop, 'primary_key', False) + self.primary_key = getattr(prop, "primary_key", False) self.label = prop.label if prop.label else name form_cls = getattr(prop, 'form_field_class', 'Field') # get field string @@ -168,9 +170,11 @@ def formfield(self, **kwargs): Returns a django.forms.Field instance for this database Property. """ - defaults = {'required': self.required, - 'label': self.label or self.name, - 'help_text': self.help_text} + defaults = { + "required": self.required, + "label": self.label or self.name, + "help_text": self.help_text, + } if self.has_default(): defaults['initial'] = self.prop.default_value() @@ -188,9 +192,18 @@ def formfield(self, **kwargs): # max_value) don't apply for choice fields, so be sure to only pass # the values that TypedChoiceField will understand. for k in list(kwargs): - if k not in ('coerce', 'empty_value', 'choices', 'required', - 'widget', 'label', 'initial', 'help_text', - 'error_messages', 'show_hidden_initial'): + if k not in ( + "coerce", + "empty_value", + "choices", + "required", + "widget", + "label", + "initial", + "help_text", + "error_messages", + "show_hidden_initial", + ): del kwargs[k] defaults.update(kwargs) @@ -211,7 +224,7 @@ def get_choices(self, include_blank=True): choices = [(k, v) for k, v in self.choices.items()] for choice, __ in choices: - if choice in ('', None): + if choice in ("", None): blank_defined = True break @@ -481,7 +494,7 @@ def resolve_related_class(model, related, field): class Query: select_related = False - order_by = ['pk'] + order_by = ["pk"] class NeoNodeSet(NodeSet): @@ -604,12 +617,14 @@ def full_clean(self, exclude, validate_unique=False): except RequiredProperty as e: raise ValidationError({e.property_name: 'is required'}) except UniqueProperty as e: - raise ValidationError({e.property_name: e.msg}) + raise ValidationError({e.property_name: e.msg}) def validate_unique(self, exclude): # get unique indexed properties unique_props = [] - for k, p in self.__class__.defined_properties(aliases=False, rels=False).items(): + for k, p in self.__class__.defined_properties( + aliases=False, rels=False + ).items(): if k not in exclude and p.unique_index: unique_props.append(k) cls = self.__class__ @@ -618,32 +633,34 @@ def validate_unique(self, exclude): # see if any nodes already exist with each property for key in unique_props: - if key == 'pk' and getattr(self.__class__, key).auto_created: + if key == "pk" and getattr(self.__class__, key).auto_created: continue val = getattr(self.__class__, key).deflate(props[key]) node = cls.nodes.get_or_none(**{key: val}) # if exists and not this node - if node and node.id != getattr(self, 'id', None): - raise ValidationError({key, 'already exists'}) + if node and node.element_id != getattr(self, "element_id", None): + raise ValidationError({key, "already exists"}) def pre_save(self): - if getattr(settings, 'NEOMODEL_SIGNALS', True): - self._creating_node = getattr(self, 'id', None) is None + if getattr(settings, "NEOMODEL_SIGNALS", True): + self._creating_node = getattr(self, "element_id", None) is None signals.pre_save.send(sender=self.__class__, instance=self) def post_save(self): - if getattr(settings, 'NEOMODEL_SIGNALS', True): + if getattr(settings, "NEOMODEL_SIGNALS", True): created = self._creating_node - delattr(self, '_creating_node') - signals.post_save.send(sender=self.__class__, instance=self, created=created) + delattr(self, "_creating_node") + signals.post_save.send( + sender=self.__class__, instance=self, created=created + ) def pre_delete(self): - if getattr(settings, 'NEOMODEL_SIGNALS', True): + if getattr(settings, "NEOMODEL_SIGNALS", True): signals.pre_delete.send(sender=self.__class__, instance=self) def post_delete(self): - if getattr(settings, 'NEOMODEL_SIGNALS', True): + if getattr(settings, "NEOMODEL_SIGNALS", True): signals.post_delete.send(sender=self.__class__, instance=self) def serializable_value(self, attr): diff --git a/django_neomodel/apps.py b/django_neomodel/apps.py index 0808bfc..8c90959 100644 --- a/django_neomodel/apps.py +++ b/django_neomodel/apps.py @@ -3,17 +3,20 @@ from neomodel import config -config.AUTO_INSTALL_LABELS = False - - class NeomodelConfig(AppConfig): - name = 'django_neomodel' - verbose_name = 'Django neomodel' + name = "django_neomodel" + verbose_name = "Django neomodel" def read_settings(self): - config.DATABASE_URL = getattr(settings, 'NEOMODEL_NEO4J_BOLT_URL', config.DATABASE_URL) - config.FORCE_TIMEZONE = getattr(settings, 'NEOMODEL_FORCE_TIMEZONE', False) - config.MAX_CONNECTION_POOL_SIZE = getattr(settings, 'NEOMODEL_MAX_CONNECTION_POOL_SIZE', config.MAX_CONNECTION_POOL_SIZE) + config.DATABASE_URL = getattr( + settings, "NEOMODEL_NEO4J_BOLT_URL", config.DATABASE_URL + ) + config.FORCE_TIMEZONE = getattr(settings, "NEOMODEL_FORCE_TIMEZONE", False) + config.MAX_CONNECTION_POOL_SIZE = getattr( + settings, + "NEOMODEL_MAX_CONNECTION_POOL_SIZE", + config.MAX_CONNECTION_POOL_SIZE, + ) def ready(self): self.read_settings() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..6014c01 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,47 @@ +[build-system] +requires = ["setuptools>=45", "setuptools_scm[toml]>=6.2"] +build-backend = "setuptools.build_meta" + +[tool.setuptools_scm] + +[tool.setuptools.packages.find] +where = ["./"] + +[project] +name = "django_neomodel" +authors = [{name = "Robin Edwards", email = "robin.ge@gmail.com"}] +maintainers = [{name = "Marius Conjeaud", email = "marius.conjeaud@outlook.com"}] +description = "Use Neo4j with Django!" +readme = "README.md" +requires-python = ">=3.7" +keywords = ["graph", "neo4j", "django", "plugin", "neomodel"] +license = { text = "MIT" } +classifiers = [ + "Development Status :: 4 - Beta", + 'Intended Audience :: Developers', + 'Operating System :: OS Independent', + 'License :: OSI Approved :: MIT License', + 'Programming Language :: Python', + 'Topic :: Software Development :: Libraries :: Python Modules', + "Programming Language :: Python :: 3", + "Topic :: Database", +] +dependencies = [ + "neomodel~=5.3.0", + 'django>=2.2' +] +version='0.1.2' + +[project.urls] +repository = "http://github.com/robinedwards/django-neomodel" + +[project.optional-dependencies] +dev = [ + "pytest>=7.1", + "pytest-django>=4.5.2", + "pytest-cov>=4.0", +] + +[tool.pytest.ini_options] +addopts = "--ds=tests.settings" +testpaths = "tests" diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index 52d37fa..0000000 --- a/pytest.ini +++ /dev/null @@ -1,2 +0,0 @@ -[pytest] -DJANGO_SETTINGS_MODULE = tests.settings \ No newline at end of file diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..0a3a5a6 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,3 @@ +pytest>=7.1 +pytest-django>=4.5.2 +pytest-cov>=4.0 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..a1bd8f2 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +neomodel~=5.3.0 +django>=2.2 \ No newline at end of file diff --git a/scripts/docker-neo4j.sh b/scripts/docker-neo4j.sh new file mode 100644 index 0000000..b80f1c7 --- /dev/null +++ b/scripts/docker-neo4j.sh @@ -0,0 +1,6 @@ +docker run \ + --name neo4j \ + -p7474:7474 -p7687:7687 \ + -d \ + --env NEO4J_AUTH=neo4j/foobarbaz \ + neo4j:$1 \ No newline at end of file diff --git a/setup.py b/setup.py deleted file mode 100644 index e850ac8..0000000 --- a/setup.py +++ /dev/null @@ -1,30 +0,0 @@ -from setuptools import setup, find_packages - -setup( - name='django_neomodel', - version='0.0.7', - description='Use Neo4j with Django!', - long_description=open('README.rst').read(), - author='Robin Edwards', - author_email='robin.ge@gmail.com', - zip_safe=True, - url='http://github.com/robinedwards/django-neomodel', - license='MIT', - packages=find_packages(exclude=('tests',)), - keywords='neo4j django plugin neomodel', - install_requires=['neomodel>=4.0.3', 'pytz>=2020.1', 'django>=2.2'], - tests_require=['pytest-django>=3.10.0'], - classifiers=[ - "Development Status :: 4 - Beta", - 'Intended Audience :: Developers', - 'Operating System :: OS Independent', - 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python', - 'Topic :: Software Development :: Libraries :: Python Modules', - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - # With (3.9) warnings on Shapely install on neobolt repo - "Programming Language :: Python :: 3.9", - "Topic :: Database", - ]) diff --git a/test.db b/test.db new file mode 100644 index 0000000..d30f22d Binary files /dev/null and b/test.db differ diff --git a/tests/Dockerfile b/tests/Dockerfile index 8fecc52..1c9d654 100644 --- a/tests/Dockerfile +++ b/tests/Dockerfile @@ -1,7 +1,6 @@ FROM python:3 WORKDIR /usr/src/app -COPY ./tests/requirements.txt ./ -RUN pip install --no-cache-dir -r requirements.txt COPY .. . +RUN pip install -e '.[dev]' RUN chmod +x ./tests/docker-entrypoint.sh CMD ["./tests/docker-entrypoint.sh" ] diff --git a/tests/docker-compose.yml b/tests/docker-compose.yml index 822fb2a..d9ff45b 100644 --- a/tests/docker-compose.yml +++ b/tests/docker-compose.yml @@ -5,7 +5,9 @@ services: build: context: ../ dockerfile: ./tests/Dockerfile - command: '/bin/bash -c "chmod +x /usr/src/app/tests/docker-entrypoint.sh && /usr/src/app/tests/docker-entrypoint.sh"' + command: > + sh -c "chmod +x /usr/src/app/tests/docker-entrypoint.sh && + /usr/src/app/tests/docker-entrypoint.sh" volumes: - ..:/usr/src/app ports: @@ -13,19 +15,19 @@ services: expose: - 8000 depends_on: - - neo4j_db + - neo4j links: - - neo4j_db + - neo4j environment: - - NEO4J_BOLT_URL=bolt://neo4j:foobar@neo4j_db:7687 + - NEO4J_BOLT_URL=bolt://neo4j:foobarbaz@neo4j:7687 - DJANGO_SETTINGS_MODULE=settings - DJANGO_SUPERUSER_PASSWORD - DJANGO_SUPERUSER_EMAIL - DJANGO_SUPERUSER_USERNAME - neo4j_db: - image: neo4j:4.2-enterprise + neo4j: + image: neo4j:5.4-enterprise ports: - "7474:7474" - "7687:7687" @@ -35,7 +37,7 @@ services: volumes: - db:/data/dbms environment: - - NEO4J_AUTH=neo4j/foobar + - NEO4J_AUTH=neo4j/foobarbaz - NEO4J_ACCEPT_LICENSE_AGREEMENT=yes - dbms.connector.bolt.listen_address=:7687 - dbms.connector.bolt.advertised_address=:7687 diff --git a/tests/requirements.txt b/tests/requirements.txt deleted file mode 100644 index 44f26b2..0000000 --- a/tests/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -neomodel>=4.0.2 -pytz>=2020.1 -django>=2.2 -pytest-django>=3.10.0 -django-neomodel == 0.0.6 \ No newline at end of file diff --git a/tests/settings.py b/tests/settings.py index bb20632..1fed17d 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -9,31 +9,33 @@ DEBUG = True -ROOT_URLCONF = 'tests.urls' -SECRET_KEY = 'skskqlqlaskdsd' +ROOT_URLCONF = "tests.urls" +SECRET_KEY = "skskqlqlaskdsd" AUTOCOMMIT = True DATABASES = { - 'default': { - 'NAME': 'test.db', - 'ENGINE': 'django.db.backends.sqlite3', - 'USER': '', - 'PASSWORD': '', - 'PORT': '', + "default": { + "NAME": "test.db", + "ENGINE": "django.db.backends.sqlite3", + "USER": "", + "PASSWORD": "", + "PORT": "", }, } -NEOMODEL_NEO4J_BOLT_URL = os.environ.get('NEO4J_BOLT_URL', 'bolt://neo4j:foobar@localhost:7687') +NEOMODEL_NEO4J_BOLT_URL = os.environ.get( + "NEO4J_BOLT_URL", "bolt://neo4j:foobarbaz@localhost:7687" +) NEOMODEL_SIGNALS = True NEOMODEL_FORCE_TIMEZONE = False NEOMODEL_MAX_CONNECTION_POOL_SIZE = 50 TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'APP_DIRS': True, + "BACKEND": "django.template.backends.django.DjangoTemplates", + "APP_DIRS": True, "OPTIONS": { "context_processors": [ "django.template.context_processors.debug", @@ -47,23 +49,21 @@ INSTALLED_APPS = [ # Django - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.sites', - 'django.contrib.staticfiles', - + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.sites", + "django.contrib.staticfiles", # Third party - 'django_neomodel', - + "django_neomodel", # Test - 'tests.someapp', + "tests.someapp", ] USE_TZ = True -TIME_ZONE = 'UTC' +TIME_ZONE = "UTC" MIDDLEWARE = [ "django.contrib.sessions.middleware.SessionMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", @@ -71,5 +71,6 @@ ] STATIC_ROOT = "./static/" -STATIC_URL = '/static/' +STATIC_URL = "/static/" +DEFAULT_AUTO_FIELD = "django.db.models.AutoField" diff --git a/tests/someapp/tests/test_commands.py b/tests/someapp/tests/test_commands.py index 1493f17..8d66499 100644 --- a/tests/someapp/tests/test_commands.py +++ b/tests/someapp/tests/test_commands.py @@ -11,7 +11,7 @@ class TestCommands(TestCase): def test_install_labels_command(self): out = StringIO() call_command('install_labels', stdout=out) - self.assertIn('Creating unique constraint for title on label Book for class tests.someapp.models.Book', out.getvalue()) + self.assertIn('Creating node unique constraint for title on label Book for class tests.someapp.models.Book', out.getvalue()) def test_clear_neo4j_command(self): out = StringIO() diff --git a/tests/urls.py b/tests/urls.py index d78216a..c547787 100644 --- a/tests/urls.py +++ b/tests/urls.py @@ -1,7 +1,7 @@ -from django.conf.urls import url +from django.urls import re_path from django.contrib import admin from django.conf import settings from django.conf.urls.static import static -urlpatterns = [url(r"^admin/", admin.site.urls)] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) +urlpatterns = [re_path(r"^admin/", admin.site.urls)] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)