diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000000000000000000000000000000000..739c41ece8ab55e842726798472d7561ee3af8ac --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,89 @@ +name: Building and Testing + +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + build: + runs-on: 'ubuntu-latest' + strategy: + matrix: + python_version: + - '3.8' + - '3.9' + - '3.10' + - '3.11' + django_version: + - '4.0' + - '4.1' + - '4.2' + + services: + postgres: + # https://github.com/postgis/docker-postgis/blob/master/15-3.4/alpine/Dockerfile + image: postgis/postgis:15-3.4-alpine + env: + POSTGRES_DB: ddf + POSTGRES_USER: ddf_user + POSTGRES_PASSWORD: ddf_pass + ports: + # Random free port + - 5432/tcp + # Set health checks to wait until postgres has started + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + steps: + - name: 'Install OS dependencies (Ubuntu)' + if: runner.os == 'Linux' + run: | + # https://docs.djangoproject.com/en/4.2/ref/contrib/gis/install/geolibs/ + # GDAL_LIBRARY_PATH: /usr/lib/libgdal.so.* + # GEOS_LIBRARY_PATH: /usr/lib/libgeos_c.so.* + # ln -s /usr/lib/libgdal.so.32 /usr/lib/libgdal.so \ + # ln -s /usr/lib/libgeos_c.so.1 /usr/lib/libgeos_c.so + # ln -s /usr/lib/libproj.so.25 /usr/lib/libproj.so \ + sudo apt-get update \ + && sudo apt-get install -y binutils libproj-dev gdal-bin + + - name: 'Set up Python ${{ matrix.python_version }}' + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python_version }} + + - name: 'Checkout DDF code' + uses: actions/checkout@v3 + + - name: 'Install Python dependencies' + run: | + pip install -r requirements.txt + pip install -r requirements-dev.txt + pip install pytest-django + pip install django~=${{ matrix.django_version }} + pip install jsonfield==3.1.0 + pip install django-polymorphic==3.1.0 + + - name: 'Testing with SQLite' + run: pytest --create-db --reuse-db --no-migrations --ds=settings_sqlite --maxfail=2 + + - name: 'Coverage with SQLite' + run: pytest --create-db --reuse-db --no-migrations -v --cov=django_dynamic_fixture + + - name: 'Testing with Postgres' + env: + POSTGRES_HOST: localhost + POSTGRES_PORT: ${{ job.services.postgres.ports[5432] }} + POSTGRES_DB: ddf + POSTGRES_USER: ddf_user + POSTGRES_PASSWORD: ddf_pass + run: | + pip install psycopg2 + pytest --create-db --reuse-db --no-migrations --ds=settings_postgres --maxfail=2 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 7087e31ec60b71695a03cdd0eff637e7aabc24a0..0000000000000000000000000000000000000000 --- a/.travis.yml +++ /dev/null @@ -1,123 +0,0 @@ -dist: bionic -sudo: true - -language: python - -# Avoid Travis run the same build for `push` and `PR` -branches: - only: - - "master" - -services: - - postgresql - -# https://trac.osgeo.org/postgis/wiki/UsersWikiPostgreSQLPostGIS -addons: - postgresql: "10" - apt: - packages: - - libgdal-dev - - postgresql-10 - - postgresql-10-postgis-2.4 - -matrix: - include: - - python: 3.8 - env: - - DJANGO=4.0 - - DATABASE=sqlite - - JSONFIELD=3.1.0 - - POLYMORPHIC=3.0.0 - - python: 3.8 - env: - - DJANGO=4.1 - - DATABASE=postgres - - JSONFIELD=3.1.0 - - POLYMORPHIC=3.0.0 - - python: 3.8 - env: - - DJANGO=4.2 - - DATABASE=postgres - - JSONFIELD=3.1.0 - - POLYMORPHIC=3.0.0 - - python: 3.9 - env: - - DJANGO=4.0 - - DATABASE=sqlite - - JSONFIELD=3.1.0 - - POLYMORPHIC=3.0.0 - - python: 3.9 - env: - - DJANGO=4.1 - - DATABASE=postgres - - JSONFIELD=3.1.0 - - POLYMORPHIC=3.0.0 - - python: 3.9 - env: - - DJANGO=4.2 - - DATABASE=postgres - - JSONFIELD=3.1.0 - - POLYMORPHIC=3.0.0 - - python: 3.10 - env: - - DJANGO=4.0 - - DATABASE=sqlite - - JSONFIELD=3.1.0 - - POLYMORPHIC=3.0.0 - - python: 3.10 - env: - - DJANGO=4.1 - - DATABASE=postgres - - JSONFIELD=3.1.0 - - POLYMORPHIC=3.0.0 - - python: 3.10 - env: - - DJANGO=4.2 - - DATABASE=postgres - - JSONFIELD=3.1.0 - - POLYMORPHIC=3.0.0 - - python: 3.11 - env: - - DJANGO=4.0 - - DATABASE=sqlite - - JSONFIELD=3.1.0 - - POLYMORPHIC=3.0.0 - - python: 3.11 - env: - - DJANGO=4.1 - - DATABASE=postgres - - JSONFIELD=3.1.0 - - POLYMORPHIC=3.0.0 - - python: 3.11 - env: - - DJANGO=4.2 - - DATABASE=postgres - - JSONFIELD=3.1.0 - - POLYMORPHIC=3.0.0 - -before_script: - - export PYTHONPATH=$PYTHONPATH:$(pwd) - # check gis - - gdal-config --version - - gdal-config --cflags - - psql -U postgres -c "create extension postgis" - # set up postgresql - - psql -U postgres -c "create role cacheops login superuser" - # postgis django backend requires these to exist - - psql -U postgres -c "create database cacheops" - - psql -U postgres -c "create database cacheops_slave" - # create db and user - - psql -c "CREATE DATABASE ddf;" -U postgres - - psql -c "CREATE USER ddf_user WITH PASSWORD 'ddf_pass';" -U postgres - - psql -c "ALTER USER ddf_user CREATEDB;" -U postgres - - psql -c "ALTER USER ddf_user WITH SUPERUSER;" -U postgres - -install: - - pip install -r requirements.txt - - pip install psycopg2 pytest pytest-django - - pip install Django~=${DJANGO}.0 - - pip install jsonfield~=${JSONFIELD} - - pip install django-polymorphic~=${POLYMORPHIC} - -script: - - pytest --create-db --reuse-db --no-migrations --ds=settings_${DATABASE} diff --git a/Makefile b/Makefile index 7358ec1e14d6af1956a7f153bc363fad47bf37cf..1771820896d4209f3d2d68604cdcd7c609014eb6 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -VERSION=4.0.0 +VERSION=4.0.1 # Python env tasks @@ -139,3 +139,13 @@ tag: reset_tag: git tag -d ${VERSION} git push origin :refs/tags/${VERSION} + + +# GitHub Action + +act: + #brew install act + time act --container-architecture linux/amd64 --matrix python_version:3.11 --matrix django_version:4.2 + +actall: + time act --container-architecture linux/amd64 diff --git a/README.md b/README.md index 605c5c257755cbed2c6a76677634de69b8df5663..930928d116ec401bf62cefc922b3edb5355e6bf2 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,12 @@ Django Dynamic Fixture ====================== -[](https://travis-ci.org/paulocheque/django-dynamic-fixture) [](http://django-dynamic-fixture.readthedocs.org/en/latest/index.html) [](https://badge.fury.io/py/django-dynamic-fixture)   -**Latest version: 4.0.0 (Aug 2023)** +**Latest version: 4.0.1 (Sep 2023)** Django Dynamic Fixture (DDF) is a complete and simple library to create dynamic model instances for testing purposes. diff --git a/django_dynamic_fixture/__init__.py b/django_dynamic_fixture/__init__.py index 019937bbaadbd40a26e978803d5eae94e8c675f5..dabf9709d01f9beaf774e2625d84a4853caa30a8 100644 --- a/django_dynamic_fixture/__init__.py +++ b/django_dynamic_fixture/__init__.py @@ -18,11 +18,11 @@ from django_dynamic_fixture.global_settings import DDF_DEFAULT_DATA_FIXTURE, DDF from django_dynamic_fixture.script_ddf_checkings import ddf_check_models -__version__ = '4.0.0' +__version__ = '4.0.1' -if not django_greater_than(1, 10): - warnings.warn("DDF officially supports only Django 1.11 or higher.", DeprecationWarning) +if not django_greater_than(4, 0): + warnings.warn("DDF 4.* officially supports only Django 4 or higher.", DeprecationWarning) LOOKUP_SEP = '__' diff --git a/django_dynamic_fixture/ddf.py b/django_dynamic_fixture/ddf.py index 1e7f34583d5d465c3c3954a5e81852af145d52b7..dd2d038bf958dcf4837e6229f68a664fd5e8b56e 100644 --- a/django_dynamic_fixture/ddf.py +++ b/django_dynamic_fixture/ddf.py @@ -239,6 +239,7 @@ class DDFLibrary: import warnings if name in [None, True]: name = self.DEFAULT_KEY + model_class = self._get_concrete_model(model_class) if model_class in self.configs and name in self.configs[model_class]: if not os.getenv('DDF_SHELL_MODE'): msg = "Override a lesson is an anti-pattern and will turn your test suite very hard to understand." @@ -250,12 +251,19 @@ class DDFLibrary: def get_configuration(self, model_class, name=None): if name is None: name = self.DEFAULT_KEY + model_class = self._get_concrete_model(model_class) # copy is important because this dict will be updated every time in the algorithm. config = self.configs.get(model_class, {}) if name != self.DEFAULT_KEY and name not in config.keys(): raise InvalidConfigurationError('There is no lesson for model {} with the name "{}"'.format(get_unique_model_name(model_class), name)) return config.get(name, {}).copy() # default configuration never raises an error + def _get_concrete_model(self, model_class): + if hasattr(model_class, '_meta') and model_class._meta.proxy: + return model_class._meta.concrete_model or model_class + else: + return model_class + def clear(self): '''Remove all lessons of the library. Util for the DDF tests.''' self.configs = {} diff --git a/django_dynamic_fixture/global_settings.py b/django_dynamic_fixture/global_settings.py index 29bc83cf02f7aa63c37416089a7e511c52a1527e..846f6a9360c0136ae37a36073c859553d784182f 100644 --- a/django_dynamic_fixture/global_settings.py +++ b/django_dynamic_fixture/global_settings.py @@ -8,12 +8,7 @@ import sys import warnings from django.conf import settings -try: - # Django 2.0 - from django.urls import get_mod_func -except ImportError: - # Django <= 1.11 - from django.core.urlresolvers import get_mod_func +from django.urls import get_mod_func try: from importlib import import_module except ImportError: diff --git a/django_dynamic_fixture/models_test.py b/django_dynamic_fixture/models_test.py index 17d1dde7b90bc76ef31e9a622ca52d2b5eda92a2..b36b6186c3a188a3c846213d1ac4d9a88c5d777a 100644 --- a/django_dynamic_fixture/models_test.py +++ b/django_dynamic_fixture/models_test.py @@ -352,6 +352,13 @@ class ModelForLibrary(models.Model): app_label = 'django_dynamic_fixture' +class ProxyModelForLibrary(ModelForLibrary): + class Meta: + proxy = True + verbose_name = 'Proxy Library' + app_label = 'django_dynamic_fixture' + + class ModelWithUniqueCharField(models.Model): text_unique = models.CharField(max_length=20, unique=True) diff --git a/django_dynamic_fixture/tests/test_ddf.py b/django_dynamic_fixture/tests/test_ddf.py index 5adadac2105a8c4300cebc2a9c40760b2ceb25e4..4947d0a97b049515ee06eb51369235b9e0766bab 100644 --- a/django_dynamic_fixture/tests/test_ddf.py +++ b/django_dynamic_fixture/tests/test_ddf.py @@ -317,10 +317,6 @@ class NewDealWithCyclicDependenciesTest(DDFTestCase): class NewDealWithInheritanceTest(DDFTestCase): - @pytest.mark.skipif(django.VERSION > (3, 2), reason="Not supported on Django 3.2+") - def test_new_must_not_raise_an_error_if_model_is_abstract(self): - self.ddf.new(ModelAbstract) # it does not raise an exceptions - def test_get_must_raise_an_error_if_model_is_abstract(self): with pytest.raises(InvalidModelError): self.ddf.get(ModelAbstract) diff --git a/django_dynamic_fixture/tests/test_ddf_teaching_and_lessons.py b/django_dynamic_fixture/tests/test_ddf_teaching_and_lessons.py index d15639bdb00de04171288dc6983956b0e524fc81..95d7961de1135044bc0552613e6f63d6d04e3674 100644 --- a/django_dynamic_fixture/tests/test_ddf_teaching_and_lessons.py +++ b/django_dynamic_fixture/tests/test_ddf_teaching_and_lessons.py @@ -65,6 +65,24 @@ class TeachAndLessonsTest(DDFTestCase): assert instance.integer == 1000 assert instance.foreignkey.integer == 1001 + def test_it_uses_lessons_for_base_model_when_creating_a_proxy_model(self): + self.ddf.teach(ModelForLibrary, integer=123) + instance = self.ddf.get(ProxyModelForLibrary) + assert instance.__class__ is ProxyModelForLibrary + assert instance.integer == 123 + + def test_it_uses_lessons_for_proxy_models_when_creating_the_base_model(self): + self.ddf.teach(ProxyModelForLibrary, integer=456) + instance = self.ddf.get(ModelForLibrary) + assert instance.__class__ is ModelForLibrary + assert instance.integer == 456 + + def test_it_uses_lessons_for_proxy_models_when_creating_the_proxy_model(self): + self.ddf.teach(ProxyModelForLibrary, integer=789) + instance = self.ddf.get(ProxyModelForLibrary) + assert instance.__class__ is ProxyModelForLibrary + assert instance.integer == 789 + # Not implemented yet # def test_teaching_must_store_ddf_configs_too(self): # self.ddf.teach(ModelForLibrary, fill_nullable_fields=False) diff --git a/docs/source/_static/coverage.html b/docs/source/_static/coverage.html index 883dfc7cf574ae42416576e3f33e1a4a46987a55..1e7a1d3ac627748435f100cb52cfa68758b91170 100644 --- a/docs/source/_static/coverage.html +++ b/docs/source/_static/coverage.html @@ -45,7 +45,7 @@ </form> <p class="text"> <a class="nav" href="https://coverage.readthedocs.io/en/7.3.0">coverage.py v7.3.0</a>, - created at 2023-08-26 20:11 -0500 + created at 2023-09-15 17:34 -0500 </p> </div> </header> @@ -70,10 +70,10 @@ </tr> <tr class="file"> <td class="name left"><a href="d_194004471fb5367f_ddf_py.html">django_dynamic_fixture/ddf.py</a></td> - <td>399</td> + <td>405</td> <td>36</td> <td>9</td> - <td class="right" data-ratio="363 399">91%</td> + <td class="right" data-ratio="369 405">91%</td> </tr> <tr class="file"> <td class="name left"><a href="d_194004471fb5367f_decorators_py.html">django_dynamic_fixture/decorators.py</a></td> @@ -189,10 +189,10 @@ </tr> <tr class="file"> <td class="name left"><a href="d_194004471fb5367f_global_settings_py.html">django_dynamic_fixture/global_settings.py</a></td> - <td>52</td> - <td>5</td> + <td>49</td> + <td>3</td> <td>0</td> - <td class="right" data-ratio="47 52">90%</td> + <td class="right" data-ratio="46 49">94%</td> </tr> <tr class="file"> <td class="name left"><a href="d_194004471fb5367f_models_py.html">django_dynamic_fixture/models.py</a></td> @@ -210,10 +210,10 @@ </tr> <tr class="file"> <td class="name left"><a href="d_194004471fb5367f_models_test_py.html">django_dynamic_fixture/models_test.py</a></td> - <td>286</td> + <td>291</td> <td>13</td> <td>0</td> - <td class="right" data-ratio="273 286">95%</td> + <td class="right" data-ratio="278 291">96%</td> </tr> <tr class="file"> <td class="name left"><a href="d_194004471fb5367f_models_third_party_py.html">django_dynamic_fixture/models_third_party.py</a></td> @@ -245,10 +245,10 @@ </tr> <tr class="file"> <td class="name left"><a href="d_2810ef72909b6803_test_ddf_py.html">django_dynamic_fixture/tests/test_ddf.py</a></td> - <td>393</td> - <td>8</td> + <td>390</td> + <td>7</td> <td>0</td> - <td class="right" data-ratio="385 393">98%</td> + <td class="right" data-ratio="383 390">98%</td> </tr> <tr class="file"> <td class="name left"><a href="d_2810ef72909b6803_test_ddf_checkings_py.html">django_dynamic_fixture/tests/test_ddf_checkings.py</a></td> @@ -294,10 +294,10 @@ </tr> <tr class="file"> <td class="name left"><a href="d_2810ef72909b6803_test_ddf_teaching_and_lessons_py.html">django_dynamic_fixture/tests/test_ddf_teaching_and_lessons.py</a></td> - <td>143</td> + <td>158</td> <td>0</td> <td>0</td> - <td class="right" data-ratio="143 143">100%</td> + <td class="right" data-ratio="158 158">100%</td> </tr> <tr class="file"> <td class="name left"><a href="d_2810ef72909b6803_test_decorators_py.html">django_dynamic_fixture/tests/test_decorators.py</a></td> @@ -359,10 +359,10 @@ <tfoot> <tr class="total"> <td class="name left">Total</td> - <td>3400</td> - <td>266</td> + <td>3420</td> + <td>263</td> <td>25</td> - <td class="right" data-ratio="3134 3400">92%</td> + <td class="right" data-ratio="3157 3420">92%</td> </tr> </tfoot> </table> @@ -374,7 +374,7 @@ <div class="content"> <p> <a class="nav" href="https://coverage.readthedocs.io/en/7.3.0">coverage.py v7.3.0</a>, - created at 2023-08-26 20:11 -0500 + created at 2023-09-15 17:34 -0500 </p> </div> <aside class="hidden"> diff --git a/docs/source/change_log.rst b/docs/source/change_log.rst index ab9a617f61f9921e76767e3006ba35eafeaf0c65..730f2154d90582aa5d38cf598341eceb8140ed9c 100644 --- a/docs/source/change_log.rst +++ b/docs/source/change_log.rst @@ -8,6 +8,12 @@ Change Log Date format: yyyy/mm/dd +Version 4.0.1 - 2023/09/15 +------------------------------------------------------------------------------- + * <http://pypi.python.org/pypi/django-dynamic-fixture/4.0.1> + * Reuse lessons in Proxy models + * https://github.com/paulocheque/django-dynamic-fixture/pull/161 + Version 4.0.0 - 2023/08/26 ------------------------------------------------------------------------------- * <http://pypi.python.org/pypi/django-dynamic-fixture/4.0.0> diff --git a/docs/source/conf.py b/docs/source/conf.py index c6bb3f905b602da8b960dff197f1adadf7d4eea3..c7cb69c34b47a039b5031878d7c866a23d47b6c3 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -52,9 +52,9 @@ copyright = '2014, Paulo Cheque' # built documents. # # The short X.Y version. -version = '4.0.0' +version = '4.0.1' # The full version, including alpha/beta/rc tags. -release = '4.0.0' +release = '4.0.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -101,12 +101,9 @@ pygments_style = 'sphinx' # a list of builtin themes. html_theme = 'default' -on_rtd = os.environ.get('READTHEDOCS', None) == 'True' - -if not on_rtd: # only import and set the theme if we're building docs locally - import sphinx_rtd_theme - html_theme = 'sphinx_rtd_theme' - html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] +import sphinx_rtd_theme +html_theme = 'sphinx_rtd_theme' +html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the diff --git a/requirements-dev.txt b/requirements-dev.txt index 66c05b19b7f843ccb69f4bad8ae79e6afb62b7e7..67e099c924edeb50a82afa0ef68646e52bdff8ba 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -23,3 +23,4 @@ pre-commit # Docs sphinx sphinx_rtd_theme +sphinx-rtd-theme diff --git a/settings_postgres.py b/settings_postgres.py index 2bee2eae2a6b24d227f18c47eb6b5f674e17c124..a76671e49fa91a90725ca2c8d66245292ba6814f 100644 --- a/settings_postgres.py +++ b/settings_postgres.py @@ -1,3 +1,4 @@ +import os from settings_ddf import * DDF_TEST_GEODJANGO = True @@ -10,13 +11,13 @@ DATABASES = { # Postgis supports all Django features # createdb ddf 'ENGINE': 'django.contrib.gis.db.backends.postgis', - 'NAME': 'ddf', - 'USER': 'ddf_user', # please, change this if you want to run tests in your machine - 'PASSWORD': 'ddf_pass', - 'HOST': 'localhost', - 'PORT': 5432, + 'HOST': os.getenv('POSTGRES_HOST', 'localhost'), + 'PORT': os.getenv('POSTGRES_PORT', 5432), + 'NAME': os.getenv('POSTGRES_DB', 'ddf'), + 'USER': os.getenv('POSTGRES_USER', 'ddf_user'), # please, change this if you want to run tests in your machine + 'PASSWORD': os.getenv('POSTGRES_PASSWORD', 'ddf_pass'), } } if DDF_TEST_GEODJANGO: - INSTALLED_APPS += ('django.contrib.gis',) \ No newline at end of file + INSTALLED_APPS += ('django.contrib.gis',) diff --git a/setup.py b/setup.py index 0e85f6b8625b9783ead24045b250e52bfe98ce28..9f0d156d513be06121d6dfd67880a208ad83df5e 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from pathlib import Path from setuptools import setup, find_packages -VERSION = '4.0.0' +VERSION = '4.0.1' tests_require = []