diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 139bc9f..0000000 --- a/.travis.yml +++ /dev/null @@ -1,56 +0,0 @@ -sudo: false -language: python -cache: pip -python: - - 2.7 - - 3.6 - - 3.7 - - 3.8 - -services: - - postgresql - -install: - - pip install tox-travis - - pip install coverage codecov - - pip install wheel - -script: - - tox - -after_success: - - pip install codecov coveralls - - codecov --required -n "py${TRAVIS_PYTHON_VERSION}" - - "COVERALLS_PARALLEL=true coveralls" - -notifications: - webhooks: https://coveralls.io/webhook - -stages: - - test - - name: publish - if: tag IS present - -jobs: - fast_finish: true - include: - - - stage: test - python: 3.8 - - - stage: publish - python: 3.8 - install: true - script: python setup.py sdist bdist_wheel - after_success: true - deploy: - edge: true - provider: releases - name: $TRAVIS_TAG - target_commitish: $TRAVIS_COMMIT - api_key: "$GITHUB_OAUTH_TOKEN" - skip_cleanup: true - file: dist/* - on: - branch: master - tags: true diff --git a/README.md b/README.md index 5bf6d74..e79ecb9 100644 --- a/README.md +++ b/README.md @@ -6,27 +6,36 @@ using the native Postgres extension `ltree`. Postgresql has already a optimized and very useful tree implementation for data. The extension is [ltree](https://www.postgresql.org/docs/9.6/static/ltree.html) -This fork contains a backport to Django 1.11 and Python 3.6. +This fork contains is a continuation of the work done by [`mariocesar`](https://github.com/mariocesar/) on [`django-ltree`](https://github.com/mariocesar/django-ltree). + ## Links - - Pypi https://pypi.org/project/django-ltree/ - - Source code https://github.com/mariocesar/django-ltree - - Bugs https://github.com/mariocesar/django-ltree/issues - - Contribute https://github.com/mariocesar/django-ltree/pulls - - Documentation `TODO` +- Pypi https://pypi.org/project/django-ltree/ +- Source code https://github.com/mariocesar/django-ltree +- Bugs https://github.com/mariocesar/django-ltree/issues +- Contribute https://github.com/mariocesar/django-ltree/pulls +- Documentation `TODO` ## Install -``` +```py pip install django-ltree ``` Then add `django_ltree` to `INSTALLED_APPS` in your Django project settings. +```python +INSTALLED_APPS = [ + ..., + 'django_ltree', + ... +] +``` + And make sure to run `django_ltree` migrations before you added the `PathField` ``` @@ -38,7 +47,7 @@ python manage.py migrate django_ltree You can alternatively specify the `django_ltree` dependency in the migrations of your applications that requires `PathField`, and run migrations smoothly. -``` +```python class Migration(migrations.Migration): dependencies = [ ('django_ltree', '__latest__'), @@ -47,8 +56,8 @@ class Migration(migrations.Migration): ## Requires -- Django 1.11 or superior -- Python 2 +- Django 5.0 or superior +- Python 3.10 or higher ## Testing diff --git a/django_ltree/fields.py b/django_ltree/fields.py index 2d1abcb..2fce5dd 100644 --- a/django_ltree/fields.py +++ b/django_ltree/fields.py @@ -101,4 +101,4 @@ def get_db_prep_value(self, value, connection, prepared=False): elif isinstance(value, (list, str)): return str(PathValue(value)) - raise ValueError("Unknown value type {}".format(type(value))) + raise ValueError(f"Unknown value type {type(value)}") diff --git a/django_ltree/lookups.py b/django_ltree/lookups.py index 1b6615c..5f88a38 100644 --- a/django_ltree/lookups.py +++ b/django_ltree/lookups.py @@ -9,7 +9,7 @@ class SimpleLookup(Lookup): def as_sql(self, compiler, connection): lhs, lhs_params = self.process_lhs(compiler, connection) rhs, rhs_params = self.process_rhs(compiler, connection) - return "{} {} {}".format(lhs, self.lookup_operator, rhs), [ + return f"{lhs} {self.lookup_operator} {rhs}", [ *lhs_params, *rhs_params, ] @@ -22,7 +22,7 @@ class EqualLookup(Lookup): def as_sql(self, compiler, connection): lhs, lhs_params = self.process_lhs(compiler, connection) rhs, rhs_params = self.process_rhs(compiler, connection) - return "{} = {}".format(lhs, rhs), [*lhs_params, *rhs_params] + return f"{lhs} = {rhs}", [*lhs_params, *rhs_params] @PathField.register_lookup diff --git a/django_ltree/migrations/0001_create_extension.py b/django_ltree/migrations/0001_create_extension.py index f74f43d..11faae1 100644 --- a/django_ltree/migrations/0001_create_extension.py +++ b/django_ltree/migrations/0001_create_extension.py @@ -4,12 +4,10 @@ class Migration(migrations.Migration): initial = True - dependencies = [ - ] + dependencies = [] operations = [ migrations.RunSQL( - "CREATE EXTENSION IF NOT EXISTS ltree;", - "DROP EXTENSION ltree;" + "CREATE EXTENSION IF NOT EXISTS ltree;", "DROP EXTENSION ltree;" ) ] diff --git a/django_ltree/models.py b/django_ltree/models.py index f36b657..64863cd 100644 --- a/django_ltree/models.py +++ b/django_ltree/models.py @@ -1,4 +1,5 @@ from django.db import models +from typing import Any from .fields import PathField, PathValue from .managers import TreeManager @@ -15,12 +16,8 @@ class Meta: def label(self): return self.path[-1] - def get_ancestors_paths(self): # type: () -> List[List[str]] - return [ - PathValue(self.path[:n]) - for n, p in enumerate(self.path) - if n > 0 - ] + def get_ancestors_paths(self) -> list[list[str]]: + return [PathValue(self.path[:n]) for n, p in enumerate(self.path) if n > 0] def ancestors(self): return type(self)._default_manager.filter(path__ancestors=self.path) @@ -44,7 +41,7 @@ def siblings(self): .exclude(path=self.path) ) - def add_child(self, slug, **kwargs): # type:(str) -> Any + def add_child(self, slug: str, **kwargs) -> Any: assert "path" not in kwargs kwargs["path"] = self.path[:] kwargs["path"].append(slug) diff --git a/poetry.lock b/poetry.lock index 8c4d286..c34b454 100644 --- a/poetry.lock +++ b/poetry.lock @@ -17,6 +17,28 @@ typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""} [package.extras] tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] +[[package]] +name = "cachetools" +version = "5.3.2" +description = "Extensible memoizing collections and decorators" +optional = false +python-versions = ">=3.7" +files = [ + {file = "cachetools-5.3.2-py3-none-any.whl", hash = "sha256:861f35a13a451f94e301ce2bec7cac63e881232ccce7ed67fab9b5df4d3beaa1"}, + {file = "cachetools-5.3.2.tar.gz", hash = "sha256:086ee420196f7b2ab9ca2db2520aca326318b68fe5ba8bc4d49cca91add450f2"}, +] + +[[package]] +name = "chardet" +version = "5.2.0" +description = "Universal encoding detector for Python 3" +optional = false +python-versions = ">=3.7" +files = [ + {file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"}, + {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"}, +] + [[package]] name = "colorama" version = "0.4.6" @@ -28,6 +50,17 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "distlib" +version = "0.3.8" +description = "Distribution utilities" +optional = false +python-versions = "*" +files = [ + {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, + {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, +] + [[package]] name = "django" version = "5.0.2" @@ -62,6 +95,22 @@ files = [ [package.extras] test = ["pytest (>=6)"] +[[package]] +name = "filelock" +version = "3.13.1" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.8" +files = [ + {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, + {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +typing = ["typing-extensions (>=4.8)"] + [[package]] name = "iniconfig" version = "2.0.0" @@ -84,6 +133,21 @@ files = [ {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, ] +[[package]] +name = "platformdirs" +version = "4.2.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, + {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] + [[package]] name = "pluggy" version = "1.4.0" @@ -99,6 +163,25 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "pyproject-api" +version = "1.6.1" +description = "API to interact with the python pyproject.toml based projects" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyproject_api-1.6.1-py3-none-any.whl", hash = "sha256:4c0116d60476b0786c88692cf4e325a9814965e2469c5998b830bba16b183675"}, + {file = "pyproject_api-1.6.1.tar.gz", hash = "sha256:1817dc018adc0d1ff9ca1ed8c60e1623d5aaca40814b953af14a9cf9a5cae538"}, +] + +[package.dependencies] +packaging = ">=23.1" +tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} + +[package.extras] +docs = ["furo (>=2023.8.19)", "sphinx (<7.2)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "setuptools (>=68.1.2)", "wheel (>=0.41.2)"] + [[package]] name = "pytest" version = "8.0.1" @@ -148,6 +231,33 @@ files = [ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] +[[package]] +name = "tox" +version = "4.13.0" +description = "tox is a generic virtualenv management and test command line tool" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tox-4.13.0-py3-none-any.whl", hash = "sha256:1143c7e2489c68026a55d3d4ae84c02c449f073b28e62f80e3e440a3b72a4afa"}, + {file = "tox-4.13.0.tar.gz", hash = "sha256:dd789a554c16c4b532924ba393c92fc8991323c4b3d466712bfecc8c9b9f24f7"}, +] + +[package.dependencies] +cachetools = ">=5.3.2" +chardet = ">=5.2" +colorama = ">=0.4.6" +filelock = ">=3.13.1" +packaging = ">=23.2" +platformdirs = ">=4.1" +pluggy = ">=1.3" +pyproject-api = ">=1.6.1" +tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} +virtualenv = ">=20.25" + +[package.extras] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-argparse-cli (>=1.11.1)", "sphinx-autodoc-typehints (>=1.25.2)", "sphinx-copybutton (>=0.5.2)", "sphinx-inline-tabs (>=2023.4.21)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.11)"] +testing = ["build[virtualenv] (>=1.0.3)", "covdefaults (>=2.3)", "detect-test-pollution (>=1.2)", "devpi-process (>=1)", "diff-cover (>=8.0.2)", "distlib (>=0.3.8)", "flaky (>=3.7)", "hatch-vcs (>=0.4)", "hatchling (>=1.21)", "psutil (>=5.9.7)", "pytest (>=7.4.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-xdist (>=3.5)", "re-assert (>=1.1)", "time-machine (>=2.13)", "wheel (>=0.42)"] + [[package]] name = "typing-extensions" version = "4.9.0" @@ -170,7 +280,27 @@ files = [ {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, ] +[[package]] +name = "virtualenv" +version = "20.25.1" +description = "Virtual Python Environment builder" +optional = false +python-versions = ">=3.7" +files = [ + {file = "virtualenv-20.25.1-py3-none-any.whl", hash = "sha256:961c026ac520bac5f69acb8ea063e8a4f071bcc9457b9c1f28f6b085c511583a"}, + {file = "virtualenv-20.25.1.tar.gz", hash = "sha256:e08e13ecdca7a0bd53798f356d5831434afa5b07b93f0abdf0797b7a06ffe197"}, +] + +[package.dependencies] +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<5" + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] + [metadata] lock-version = "2.0" python-versions = ">=3.10" -content-hash = "4de55f0cce52d83174d3a3ce175e4ef75a39a3a6e498244a69afc5d8d56193a3" +content-hash = "1ea1547b12868f41457204df394114cea4d5cac94cb7d70a70b6fe37735ece83" diff --git a/pyproject.toml b/pyproject.toml index a7120dc..5cbd55f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,6 +27,7 @@ django = ">=5.0.2" [tool.poetry.group.dev.dependencies] pytest = "^8.0.1" +tox = "^4.13.0" [build-system] requires = ["poetry-core"] diff --git a/python-versions.txt b/python-versions.txt deleted file mode 100644 index 77fc210..0000000 --- a/python-versions.txt +++ /dev/null @@ -1,4 +0,0 @@ -3.8.0 -3.7.5 -3.6.9 -2.7.14 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 9a0d28e..0000000 --- a/setup.cfg +++ /dev/null @@ -1,12 +0,0 @@ -[wheel] -universal = 1 - -[coverage:run] -branch = True -parallel = True - -[coverage:paths] -source = django_ltree - -[tool:pytest] -testpaths = tests