From d3e2396be6757f0d0b3ee4e06777c37f17d3834b Mon Sep 17 00:00:00 2001 From: Serg Tereshchenko Date: Tue, 12 Jul 2022 00:54:26 +0300 Subject: [PATCH] feat(dev): Migrate to pytest --- .github/workflows/test.yml | 4 +- .../tests/migrations/0001_initial.py | 988 ++++++++++++++++++ .../__init__.py | 0 modeltranslation/tests/models.py | 14 +- modeltranslation/tests/settings.py | 55 +- modeltranslation/tests/test_settings.py | 6 - modeltranslation/tests/tests.py | 274 +---- modeltranslation/tests/translation.py | 27 +- modeltranslation/tests/urls.py | 17 +- poetry.lock | 270 ++++- pyproject.toml | 7 +- pytest.ini | 9 + runtests.py | 63 -- 13 files changed, 1358 insertions(+), 376 deletions(-) create mode 100644 modeltranslation/tests/migrations/0001_initial.py rename modeltranslation/tests/{auth_migrations => migrations}/__init__.py (100%) delete mode 100644 modeltranslation/tests/test_settings.py create mode 100644 pytest.ini delete mode 100755 runtests.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 04fe3bfd..c0500e90 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -95,7 +95,7 @@ jobs: if [[ $DB == postgres ]]; then pip install -q psycopg2-binary fi - pip install coverage six $(./get-django-version.py ${{ matrix.django }}) + pip install coverage six pytest pytest-django pytest-cov $(./get-django-version.py ${{ matrix.django }}) - name: Run tests run: | - coverage run --source=modeltranslation ./runtests.py + pytest --cov-report term diff --git a/modeltranslation/tests/migrations/0001_initial.py b/modeltranslation/tests/migrations/0001_initial.py new file mode 100644 index 00000000..98171623 --- /dev/null +++ b/modeltranslation/tests/migrations/0001_initial.py @@ -0,0 +1,988 @@ +# Generated by Django 3.2.14 on 2022-07-11 16:41 + +import django.contrib.auth.models +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion +import modeltranslation.tests.models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='AbstractConflictModelB', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('title_de', models.IntegerField()), + ('title', models.CharField(max_length=255, verbose_name='title')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='AbstractModelB', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('titlea', models.CharField(max_length=255, verbose_name='title a')), + ('titlea_de', models.CharField(max_length=255, null=True, verbose_name='title a')), + ('titlea_en', models.CharField(max_length=255, null=True, verbose_name='title a')), + ('titleb', models.CharField(max_length=255, verbose_name='title b')), + ('titleb_de', models.CharField(max_length=255, null=True, verbose_name='title b')), + ('titleb_en', models.CharField(max_length=255, null=True, verbose_name='title b')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='ConflictModel', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('title', models.CharField(max_length=255, verbose_name='title')), + ('title_de', models.IntegerField()), + ], + ), + migrations.CreateModel( + name='CustomManager2TestModel', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('title', models.CharField(max_length=255, verbose_name='title')), + ('title_de', models.CharField(max_length=255, null=True, verbose_name='title')), + ('title_en', models.CharField(max_length=255, null=True, verbose_name='title')), + ], + ), + migrations.CreateModel( + name='CustomManagerChildTestModel', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('needs_translation', models.BooleanField(default=False)), + ('title', models.CharField(max_length=255, verbose_name='title')), + ('title_de', models.CharField(max_length=255, null=True, verbose_name='title')), + ('title_en', models.CharField(max_length=255, null=True, verbose_name='title')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='CustomManagerTestModel', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('title', models.CharField(max_length=255, verbose_name='title')), + ('title_de', models.CharField(max_length=255, null=True, verbose_name='title')), + ('title_en', models.CharField(max_length=255, null=True, verbose_name='title')), + ('description', models.CharField(db_column='xyz', max_length=255, null=True)), + ], + ), + migrations.CreateModel( + name='DataModel', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('data', models.TextField(blank=True, null=True)), + ], + ), + migrations.CreateModel( + name='DescriptorModel', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('normal', modeltranslation.tests.models.FancyField(default='')), + ('trans', modeltranslation.tests.models.FancyField(default='')), + ('trans_de', modeltranslation.tests.models.FancyField(default='', null=True)), + ('trans_en', modeltranslation.tests.models.FancyField(default='', null=True)), + ], + ), + migrations.CreateModel( + name='FallbackModel', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('title', models.CharField(max_length=255, verbose_name='title')), + ('title_de', models.CharField(max_length=255, null=True, verbose_name='title')), + ('title_en', models.CharField(max_length=255, null=True, verbose_name='title')), + ('text', models.TextField(blank=True, null=True)), + ('text_de', models.TextField(blank=True, null=True)), + ('text_en', models.TextField(blank=True, null=True)), + ('url', models.URLField(blank=True, null=True)), + ('url_de', models.URLField(blank=True, null=True)), + ('url_en', models.URLField(blank=True, null=True)), + ('email', models.EmailField(blank=True, max_length=254, null=True)), + ('email_de', models.EmailField(blank=True, max_length=254, null=True)), + ('email_en', models.EmailField(blank=True, max_length=254, null=True)), + ('description', models.CharField(max_length=255, null=True)), + ('description_de', models.CharField(max_length=255, null=True)), + ('description_en', models.CharField(max_length=255, null=True)), + ], + ), + migrations.CreateModel( + name='FallbackModel2', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('title', models.CharField(max_length=255, verbose_name='title')), + ('title_de', models.CharField(max_length=255, null=True, verbose_name='title')), + ('title_en', models.CharField(max_length=255, null=True, verbose_name='title')), + ('text', models.TextField(blank=True, null=True)), + ('text_de', models.TextField(blank=True, null=True)), + ('text_en', models.TextField(blank=True, null=True)), + ('url', models.URLField(blank=True, null=True)), + ('url_de', models.URLField(blank=True, null=True)), + ('url_en', models.URLField(blank=True, null=True)), + ('email', models.EmailField(blank=True, max_length=254, null=True)), + ('email_de', models.EmailField(blank=True, max_length=254, null=True)), + ('email_en', models.EmailField(blank=True, max_length=254, null=True)), + ], + ), + migrations.CreateModel( + name='FileFieldsModel', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('title', models.CharField(max_length=255, verbose_name='title')), + ('title_de', models.CharField(max_length=255, null=True, verbose_name='title')), + ('title_en', models.CharField(max_length=255, null=True, verbose_name='title')), + ( + 'file', + models.FileField(blank=True, null=True, upload_to='modeltranslation_tests'), + ), + ( + 'file_de', + models.FileField(blank=True, null=True, upload_to='modeltranslation_tests'), + ), + ( + 'file_en', + models.FileField(blank=True, null=True, upload_to='modeltranslation_tests'), + ), + ('file2', models.FileField(upload_to='modeltranslation_tests')), + ('file2_de', models.FileField(null=True, upload_to='modeltranslation_tests')), + ('file2_en', models.FileField(null=True, upload_to='modeltranslation_tests')), + ( + 'image', + models.ImageField(blank=True, null=True, upload_to='modeltranslation_tests'), + ), + ( + 'image_de', + models.ImageField(blank=True, null=True, upload_to='modeltranslation_tests'), + ), + ( + 'image_en', + models.ImageField(blank=True, null=True, upload_to='modeltranslation_tests'), + ), + ], + ), + migrations.CreateModel( + name='FilteredTestModel', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('title', models.CharField(max_length=255, verbose_name='title')), + ('title_de', models.CharField(max_length=255, null=True, verbose_name='title')), + ('title_en', models.CharField(max_length=255, null=True, verbose_name='title')), + ], + ), + migrations.CreateModel( + name='GroupFieldsetsModel', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('title', models.CharField(max_length=255)), + ('title_de', models.CharField(max_length=255, null=True)), + ('title_en', models.CharField(max_length=255, null=True)), + ('text', models.TextField(blank=True, null=True)), + ('text_de', models.TextField(blank=True, null=True)), + ('text_en', models.TextField(blank=True, null=True)), + ('email', models.EmailField(blank=True, max_length=254, null=True)), + ], + ), + migrations.CreateModel( + name='InheritedPermission', + fields=[ + ( + 'permission_ptr', + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to='auth.permission', + ), + ), + ('translated_var', models.CharField(max_length=255)), + ('translated_var_de', models.CharField(max_length=255, null=True)), + ('translated_var_en', models.CharField(max_length=255, null=True)), + ], + bases=('auth.permission',), + managers=[ + ('objects', django.contrib.auth.models.PermissionManager()), + ], + ), + migrations.CreateModel( + name='ManagerTestModel', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('title', models.CharField(max_length=255, verbose_name='title')), + ('title_de', models.CharField(max_length=255, null=True, verbose_name='title')), + ('title_en', models.CharField(max_length=255, null=True, verbose_name='title')), + ('visits', models.IntegerField(default=0, verbose_name='visits')), + ('visits_de', models.IntegerField(default=0, null=True, verbose_name='visits')), + ('visits_en', models.IntegerField(default=0, null=True, verbose_name='visits')), + ('description', models.CharField(max_length=255, null=True)), + ('description_de', models.CharField(max_length=255, null=True)), + ('description_en', models.CharField(max_length=255, null=True)), + ], + options={ + 'ordering': ('-visits',), + }, + ), + migrations.CreateModel( + name='ModelX', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('name', models.CharField(max_length=255)), + ('name_de', models.CharField(max_length=255, null=True)), + ('name_en', models.CharField(max_length=255, null=True)), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='ModelXY', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ( + 'model_x', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to='tests.modelx' + ), + ), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='MultitableConflictModelA', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('title_de', models.IntegerField()), + ], + ), + migrations.CreateModel( + name='MultitableModelA', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('titlea', models.CharField(max_length=255, verbose_name='title a')), + ('titlea_de', models.CharField(max_length=255, null=True, verbose_name='title a')), + ('titlea_en', models.CharField(max_length=255, null=True, verbose_name='title a')), + ], + ), + migrations.CreateModel( + name='NameModel', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('firstname', models.CharField(max_length=50)), + ('firstname_de', models.CharField(max_length=50, null=True)), + ('firstname_en', models.CharField(max_length=50, null=True)), + ('lastname', models.CharField(max_length=50)), + ('lastname_de', models.CharField(max_length=50, null=True)), + ('lastname_en', models.CharField(max_length=50, null=True)), + ('age', models.CharField(max_length=50)), + ('slug', models.SlugField(max_length=100)), + ('slug2', models.SlugField(max_length=100)), + ('slug2_de', models.SlugField(max_length=100, null=True)), + ('slug2_en', models.SlugField(max_length=100, null=True)), + ], + ), + migrations.CreateModel( + name='NonTranslated', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('title', models.CharField(max_length=255, verbose_name='title')), + ], + ), + migrations.CreateModel( + name='OtherFieldsModel', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ( + 'int', + models.PositiveIntegerField( + default=42, validators=[django.core.validators.MinValueValidator(0)] + ), + ), + ( + 'int_de', + models.PositiveIntegerField( + default=42, + null=True, + validators=[django.core.validators.MinValueValidator(0)], + ), + ), + ( + 'int_en', + models.PositiveIntegerField( + default=42, + null=True, + validators=[django.core.validators.MinValueValidator(0)], + ), + ), + ('boolean', models.BooleanField(default=False)), + ('boolean_de', models.BooleanField(default=False)), + ('boolean_en', models.BooleanField(default=False)), + ('float', models.FloatField(blank=True, null=True)), + ('float_de', models.FloatField(blank=True, null=True)), + ('float_en', models.FloatField(blank=True, null=True)), + ( + 'decimal', + models.DecimalField(blank=True, decimal_places=2, max_digits=5, null=True), + ), + ( + 'decimal_de', + models.DecimalField(blank=True, decimal_places=2, max_digits=5, null=True), + ), + ( + 'decimal_en', + models.DecimalField(blank=True, decimal_places=2, max_digits=5, null=True), + ), + ('date', models.DateField(blank=True, null=True)), + ('date_de', models.DateField(blank=True, null=True)), + ('date_en', models.DateField(blank=True, null=True)), + ('datetime', models.DateTimeField(blank=True, null=True)), + ('datetime_de', models.DateTimeField(blank=True, null=True)), + ('datetime_en', models.DateTimeField(blank=True, null=True)), + ('time', models.TimeField(blank=True, null=True)), + ('time_de', models.TimeField(blank=True, null=True)), + ('time_en', models.TimeField(blank=True, null=True)), + ('genericip', models.GenericIPAddressField(blank=True, null=True)), + ('genericip_de', models.GenericIPAddressField(blank=True, null=True)), + ('genericip_en', models.GenericIPAddressField(blank=True, null=True)), + ], + ), + migrations.CreateModel( + name='Page', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('slug', models.CharField(max_length=255)), + ('slug_de', models.CharField(max_length=255, null=True)), + ('slug_en', models.CharField(max_length=255, null=True)), + ('keywords', models.CharField(max_length=255)), + ('keywords_de', models.CharField(max_length=255, null=True)), + ('keywords_en', models.CharField(max_length=255, null=True)), + ('title', models.CharField(max_length=255)), + ('title_de', models.CharField(max_length=255, null=True)), + ('title_en', models.CharField(max_length=255, null=True)), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='PlainChildTestModel', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('needs_translation', models.BooleanField(default=False)), + ('title', models.CharField(max_length=255, verbose_name='title')), + ('title_de', models.CharField(max_length=255, null=True, verbose_name='title')), + ('title_en', models.CharField(max_length=255, null=True, verbose_name='title')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='RequiredModel', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('non_req', models.CharField(blank=True, max_length=10)), + ('non_req_de', models.CharField(blank=True, max_length=10, null=True)), + ('non_req_en', models.CharField(blank=True, max_length=10, null=True)), + ('req', models.CharField(max_length=10)), + ('req_de', models.CharField(max_length=10, null=True)), + ('req_en', models.CharField(max_length=10, null=True)), + ('req_reg', models.CharField(max_length=10)), + ('req_reg_de', models.CharField(max_length=10, null=True)), + ('req_reg_en', models.CharField(max_length=10, null=True)), + ('req_en_reg', models.CharField(max_length=10)), + ('req_en_reg_de', models.CharField(max_length=10, null=True)), + ('req_en_reg_en', models.CharField(max_length=10, null=True)), + ], + ), + migrations.CreateModel( + name='TestModel', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('title', models.CharField(max_length=255, verbose_name='title')), + ('title_de', models.CharField(max_length=255, null=True, verbose_name='title')), + ('title_en', models.CharField(max_length=255, null=True, verbose_name='title')), + ('text', models.TextField(blank=True, null=True)), + ('text_de', models.TextField(blank=True, null=True)), + ('text_en', models.TextField(blank=True, null=True)), + ('url', models.URLField(blank=True, null=True)), + ('url_de', models.URLField(blank=True, null=True)), + ('url_en', models.URLField(blank=True, null=True)), + ('email', models.EmailField(blank=True, max_length=254, null=True)), + ('email_de', models.EmailField(blank=True, max_length=254, null=True)), + ('email_en', models.EmailField(blank=True, max_length=254, null=True)), + ], + ), + migrations.CreateModel( + name='ThirdPartyModel', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('name', models.CharField(max_length=20)), + ], + ), + migrations.CreateModel( + name='ThirdPartyRegisteredModel', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('name', models.CharField(max_length=20)), + ('name_de', models.CharField(max_length=20, null=True)), + ('name_en', models.CharField(max_length=20, null=True)), + ], + ), + migrations.CreateModel( + name='UniqueNullableModel', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('title', models.CharField(max_length=255, null=True, unique=True)), + ('title_de', models.CharField(max_length=255, null=True, unique=True)), + ('title_en', models.CharField(max_length=255, null=True, unique=True)), + ], + ), + migrations.CreateModel( + name='MultitableConflictModelB', + fields=[ + ( + 'multitableconflictmodela_ptr', + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to='tests.multitableconflictmodela', + ), + ), + ('title', models.CharField(max_length=255, verbose_name='title')), + ], + bases=('tests.multitableconflictmodela',), + ), + migrations.CreateModel( + name='MultitableModelB', + fields=[ + ( + 'multitablemodela_ptr', + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to='tests.multitablemodela', + ), + ), + ('titleb', models.CharField(max_length=255, verbose_name='title b')), + ('titleb_de', models.CharField(max_length=255, null=True, verbose_name='title b')), + ('titleb_en', models.CharField(max_length=255, null=True, verbose_name='title b')), + ], + bases=('tests.multitablemodela',), + ), + migrations.CreateModel( + name='RichTextPage', + fields=[ + ( + 'page_ptr', + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to='tests.page', + ), + ), + ('content', models.CharField(max_length=255)), + ('content_de', models.CharField(max_length=255, null=True)), + ('content_en', models.CharField(max_length=255, null=True)), + ], + options={ + 'abstract': False, + }, + bases=('tests.page', models.Model), + ), + migrations.CreateModel( + name='OneToOneFieldModel', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('title', models.CharField(max_length=255, verbose_name='title')), + ('title_de', models.CharField(max_length=255, null=True, verbose_name='title')), + ('title_en', models.CharField(max_length=255, null=True, verbose_name='title')), + ( + 'non', + models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='test_o2o', + to='tests.nontranslated', + ), + ), + ( + 'non_de', + models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='test_o2o', + to='tests.nontranslated', + ), + ), + ( + 'non_en', + models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='test_o2o', + to='tests.nontranslated', + ), + ), + ( + 'optional', + models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to='tests.testmodel', + ), + ), + ( + 'optional_de', + models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to='tests.testmodel', + ), + ), + ( + 'optional_en', + models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to='tests.testmodel', + ), + ), + ( + 'test', + models.OneToOneField( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='test_o2o', + to='tests.testmodel', + ), + ), + ( + 'test_de', + models.OneToOneField( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='test_o2o', + to='tests.testmodel', + ), + ), + ( + 'test_en', + models.OneToOneField( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='test_o2o', + to='tests.testmodel', + ), + ), + ], + ), + migrations.CreateModel( + name='ModelY', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('title', models.CharField(max_length=255)), + ('title_de', models.CharField(max_length=255, null=True)), + ('title_en', models.CharField(max_length=255, null=True)), + ('xs', models.ManyToManyField(through='tests.ModelXY', to='tests.ModelX')), + ], + options={ + 'abstract': False, + }, + ), + migrations.AddField( + model_name='modelxy', + name='model_y', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='tests.modely'), + ), + migrations.CreateModel( + name='ForeignKeyModel', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('title', models.CharField(max_length=255, verbose_name='title')), + ('title_de', models.CharField(max_length=255, null=True, verbose_name='title')), + ('title_en', models.CharField(max_length=255, null=True, verbose_name='title')), + ( + 'hidden', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='+', + to='tests.testmodel', + ), + ), + ( + 'hidden_de', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='+', + to='tests.testmodel', + ), + ), + ( + 'hidden_en', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='+', + to='tests.testmodel', + ), + ), + ( + 'non', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='test_fks', + to='tests.nontranslated', + ), + ), + ( + 'non_de', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='test_fks', + to='tests.nontranslated', + ), + ), + ( + 'non_en', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='test_fks', + to='tests.nontranslated', + ), + ), + ( + 'optional', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to='tests.testmodel', + ), + ), + ( + 'optional_de', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to='tests.testmodel', + ), + ), + ( + 'optional_en', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to='tests.testmodel', + ), + ), + ( + 'test', + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='test_fks', + to='tests.testmodel', + ), + ), + ( + 'test_de', + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='test_fks', + to='tests.testmodel', + ), + ), + ( + 'test_en', + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='test_fks', + to='tests.testmodel', + ), + ), + ( + 'untrans', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='test_fks_un', + to='tests.testmodel', + ), + ), + ], + ), + migrations.CreateModel( + name='ForeignKeyFilteredModel', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name='ID' + ), + ), + ('title', models.CharField(max_length=255, verbose_name='title')), + ('title_de', models.CharField(max_length=255, null=True, verbose_name='title')), + ('title_en', models.CharField(max_length=255, null=True, verbose_name='title')), + ( + 'test', + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='test_fks', + to='tests.filteredtestmodel', + ), + ), + ], + ), + migrations.CreateModel( + name='ProxyTestModel', + fields=[], + options={ + 'proxy': True, + 'indexes': [], + 'constraints': [], + }, + bases=('tests.testmodel',), + ), + migrations.CreateModel( + name='MultitableModelC', + fields=[ + ( + 'multitablemodelb_ptr', + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to='tests.multitablemodelb', + ), + ), + ('titlec', models.CharField(max_length=255, verbose_name='title c')), + ('titlec_de', models.CharField(max_length=255, null=True, verbose_name='title c')), + ('titlec_en', models.CharField(max_length=255, null=True, verbose_name='title c')), + ], + bases=('tests.multitablemodelb',), + ), + migrations.CreateModel( + name='MultitableModelD', + fields=[ + ( + 'multitablemodelb_ptr', + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to='tests.multitablemodelb', + ), + ), + ('titled', models.CharField(max_length=255, verbose_name='title d')), + ], + bases=('tests.multitablemodelb',), + ), + ] diff --git a/modeltranslation/tests/auth_migrations/__init__.py b/modeltranslation/tests/migrations/__init__.py similarity index 100% rename from modeltranslation/tests/auth_migrations/__init__.py rename to modeltranslation/tests/migrations/__init__.py diff --git a/modeltranslation/tests/models.py b/modeltranslation/tests/models.py index 9647c2c7..ea82ac91 100644 --- a/modeltranslation/tests/models.py +++ b/modeltranslation/tests/models.py @@ -1,10 +1,8 @@ -# -*- coding: utf-8 -*- import six -from django.conf import settings +from django.contrib.auth.models import Permission from django.core import validators from django.db import models from django.utils.translation import gettext_lazy - from modeltranslation.manager import MultilingualManager @@ -128,9 +126,6 @@ class OtherFieldsModel(models.Model): # That's rich! PositiveIntegerField is only validated in forms, not in models. int = models.PositiveIntegerField(default=42, validators=[validators.MinValueValidator(0)]) boolean = models.BooleanField(default=False) - nullboolean = models.NullBooleanField() - csi = models.CommaSeparatedIntegerField(max_length=255) - ip = models.IPAddressField(blank=True, null=True) float = models.FloatField(blank=True, null=True) decimal = models.DecimalField(max_digits=5, decimal_places=2, blank=True, null=True) date = models.DateField(blank=True, null=True) @@ -495,8 +490,5 @@ class ModelY(AbstractModelY): # Non-abstract base models whos Manager is not allowed to be overwritten -if "django.contrib.auth" in settings.INSTALLED_APPS: - from django.contrib.auth.models import Permission - - class InheritedPermission(Permission): - translated_var = models.CharField(max_length=255) +class InheritedPermission(Permission): + translated_var = models.CharField(max_length=255) diff --git a/modeltranslation/tests/settings.py b/modeltranslation/tests/settings.py index 0abbf72a..8d075d18 100644 --- a/modeltranslation/tests/settings.py +++ b/modeltranslation/tests/settings.py @@ -1,23 +1,62 @@ -# -*- coding: utf-8 -*- -""" -Settings overrided for test time -""" -from django.conf import settings +import os +import warnings +warnings.simplefilter('always', DeprecationWarning) -INSTALLED_APPS = tuple(settings.INSTALLED_APPS) + ('modeltranslation.tests',) + +def _get_database_config(): + db = os.getenv('DB', 'sqlite') + host = os.getenv('DB_HOST', 'localhost') + conf = { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': ':memory:', + 'TEST': { + 'SERIALIZE': False, + }, + } + if db == 'mysql': + conf.update( + { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': os.getenv('MYSQL_DATABASE', 'modeltranslation'), + 'USER': os.getenv('MYSQL_USER', 'root'), + 'PASSWORD': os.getenv('MYSQL_PASSWORD', 'password'), + 'HOST': host, + } + ) + elif db == 'postgres': + conf.update( + { + 'ENGINE': 'django.db.backends.postgresql', + 'USER': os.getenv('POSTGRES_USER', 'postgres'), + 'PASSWORD': os.getenv('POSTGRES_DB', 'postgres'), + 'NAME': os.getenv('POSTGRES_DB', 'modeltranslation'), + 'HOST': host, + } + ) + return conf + + +DATABASES = {"default": _get_database_config()} + +INSTALLED_APPS = ( + 'django.contrib.contenttypes', + 'django.contrib.auth', + 'modeltranslation', + 'modeltranslation.tests', +) LANGUAGES = (('de', 'Deutsch'), ('en', 'English')) LANGUAGE_CODE = 'de' -MODELTRANSLATION_DEFAULT_LANGUAGE = 'de' USE_I18N = True USE_TZ = False MIDDLEWARE_CLASSES = () +MODELTRANSLATION_DEFAULT_LANGUAGE = 'de' MODELTRANSLATION_AUTO_POPULATE = False MODELTRANSLATION_FALLBACK_LANGUAGES = () ROOT_URLCONF = 'modeltranslation.tests.urls' -MIGRATION_MODULES = {'auth': 'modeltranslation.tests.auth_migrations'} +DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' diff --git a/modeltranslation/tests/test_settings.py b/modeltranslation/tests/test_settings.py deleted file mode 100644 index a9e43eee..00000000 --- a/modeltranslation/tests/test_settings.py +++ /dev/null @@ -1,6 +0,0 @@ -""" -Get test settings in dict format (for use with settings_override). -""" -from . import settings as _settings - -TEST_SETTINGS = dict((k, getattr(_settings, k)) for k in dir(_settings) if k == k.upper()) diff --git a/modeltranslation/tests/tests.py b/modeltranslation/tests/tests.py index a8abbe4e..6f308dd0 100644 --- a/modeltranslation/tests/tests.py +++ b/modeltranslation/tests/tests.py @@ -1,10 +1,9 @@ -# -*- coding: utf-8 -*- +# pyright: reportGeneralTypeIssues=warning, reportOptionalMemberAccess=warning, reportOptionalOperand=warning from decimal import Decimal from unittest import skipUnless import datetime -import fnmatch -import imp -import io +import importlib +import sys import os import shutil @@ -30,7 +29,6 @@ from modeltranslation.forms import TranslationModelForm from modeltranslation.manager import MultilingualManager from modeltranslation.models import autodiscover -from modeltranslation.tests.test_settings import TEST_SETTINGS from modeltranslation.utils import ( build_css_class, build_localized_fieldname, @@ -38,16 +36,14 @@ fallbacks, ) -MIGRATIONS = "django.contrib.auth" in TEST_SETTINGS['INSTALLED_APPS'] - -models = translation = None +from modeltranslation.tests import models, translation # None of the following tests really depend on the content of the request, # so we'll just pass in None. request = None # How many models are registered for tests. -TEST_MODELS = 35 + (1 if MIGRATIONS else 0) +TEST_MODELS = 36 class reload_override_settings(override_settings): @@ -55,11 +51,11 @@ class reload_override_settings(override_settings): def __enter__(self): super(reload_override_settings, self).__enter__() - imp.reload(mt_settings) + importlib.reload(mt_settings) def __exit__(self, exc_type, exc_value, traceback): super(reload_override_settings, self).__exit__(exc_type, exc_value, traceback) - imp.reload(mt_settings) + importlib.reload(mt_settings) # In this test suite fallback language is turned off. This context manager temporarily turns it on. @@ -84,124 +80,32 @@ def get_field_names(model): return names -@override_settings(**TEST_SETTINGS) class ModeltranslationTransactionTestBase(TransactionTestCase): cache = django_apps - synced = False - - @classmethod - def _get_migrations_path(cls): - return os.path.join(os.path.dirname(os.path.abspath(__file__)), "auth_migrations") - - @classmethod - def _copy_migrations(cls): - # Locate the original contrib.auth migrations files - import django.contrib.auth.migrations as auth_migrations - - source_dir_path = os.path.dirname(auth_migrations.__file__) - - # Copy them to the local auth_migrations directory - target_dir_path = cls._get_migrations_path() - for f in os.listdir(source_dir_path): - source_path = os.path.join(source_dir_path, f) - target_path = os.path.join(target_dir_path, f) - - # Only migration files get copied - if os.path.isfile(source_path) and not fnmatch.fnmatch(f, "__init__.py"): - shutil.copyfile(source_path, target_path) - - @classmethod - def _clean_migrations(cls): - target_dir_path = cls._get_migrations_path() - for f in os.listdir(target_dir_path): - target_path = os.path.join(target_dir_path, f) - if os.path.isfile(target_path) and not fnmatch.fnmatch(f, "__init__.py"): - os.remove(target_path) @classmethod def setUpClass(cls): - """ - Prepare database: - * Call syncdb to create tables for tests.models (since during - default testrunner's db creation modeltranslation.tests was not in INSTALLED_APPS - """ - super(ModeltranslationTransactionTestBase, cls).setUpClass() - if not ModeltranslationTransactionTestBase.synced: - # In order to perform only one syncdb - ModeltranslationTransactionTestBase.synced = True - # 0. Render initial migration of auth - if MIGRATIONS: - # Make copies of auth migrations in the (local) auth_migrations - # module to setup test database - cls._copy_migrations() - call_command('makemigrations', 'auth', verbosity=2, interactive=False) - - # 1. Reload translation in case USE_I18N was False - from django.utils import translation as dj_trans - - imp.reload(dj_trans) - - # 2. Reload MT because LANGUAGES likely changed. - imp.reload(mt_settings) - imp.reload(translator) - imp.reload(admin) - - # 3. Reset test models (because autodiscover have already run, those models - # have translation fields, but for languages previously defined. We want - # to be sure that 'de' and 'en' are available) - del cls.cache.all_models['tests'] - if MIGRATIONS: - del cls.cache.all_models['auth'] - import sys - - sys.modules.pop('modeltranslation.tests.models', None) - sys.modules.pop('modeltranslation.tests.translation', None) - if MIGRATIONS: - sys.modules.pop('django.contrib.auth.models', None) - cls.cache.get_app_config('tests').import_models() - if MIGRATIONS: - cls.cache.get_app_config('auth').import_models() - - # 4. Autodiscover - from modeltranslation.models import handle_translation_registrations - - handle_translation_registrations() - - # 5. makemigrations (``migrate=False`` in case of south) - if MIGRATIONS: - call_command('makemigrations', 'auth', verbosity=2, interactive=False) - # At this point there should not be any migrations to generate - out = io.StringIO() - call_command( - 'makemigrations', - 'auth', - verbosity=3, - dry_run=True, - interactive=False, - stdout=out, - ) - assert "No changes detected in app 'auth'\n" == out.getvalue(), ( - "Unexpected auth migration:\n %s" % out.getvalue() - ) + """Save registry (and restore it after tests).""" + super().setUpClass() + from copy import copy + from modeltranslation.translator import translator - # 6. Syncdb (``migrate=False`` in case of south) - call_command('migrate', verbosity=0, interactive=False, run_syncdb=True) + cls.registry_cpy = copy(translator._registry) - # 7. clean migrations - if MIGRATIONS: - cls._clean_migrations() + @classmethod + def tearDownClass(cls): + from modeltranslation.translator import translator - # A rather dirty trick to import models into module namespace, but not before - # tests app has been added into INSTALLED_APPS and loaded - # (that's why this is not imported in normal import section) - global models, translation - from modeltranslation.tests import models, translation # NOQA + translator._registry = cls.registry_cpy + super().tearDownClass() def setUp(self): + super().setUp() self._old_language = get_language() trans_real.activate('de') def tearDown(self): + super().tearDown() trans_real.activate(self._old_language) @@ -224,33 +128,15 @@ def _pre_setup(self): def _post_teardown(self): self.__override.disable() - imp.reload(mt_settings) # restore mt_settings.FALLBACK_LANGUAGES + importlib.reload(mt_settings) # restore mt_settings.FALLBACK_LANGUAGES super(TestAutodiscover, self)._post_teardown() - @classmethod - def setUpClass(cls): - """Save registry (and restore it after tests).""" - super(TestAutodiscover, cls).setUpClass() - from copy import copy - from modeltranslation.translator import translator - - cls.registry_cpy = copy(translator._registry) - - @classmethod - def tearDownClass(cls): - from modeltranslation.translator import translator - - translator._registry = cls.registry_cpy - super(TestAutodiscover, cls).tearDownClass() - def tearDown(self): - import sys - # Rollback model classes del self.cache.all_models['test_app'] from .test_app import models - imp.reload(models) + importlib.reload(models) # Delete translation modules from import cache sys.modules.pop('modeltranslation.tests.test_app.translation', None) sys.modules.pop('modeltranslation.tests.project_translation', None) @@ -622,8 +508,8 @@ def test_settings(self): # Improper language raises error config = {'default': (), 'fr': ('en',)} with override_settings(MODELTRANSLATION_FALLBACK_LANGUAGES=config): - self.assertRaises(ImproperlyConfigured, lambda: imp.reload(mt_settings)) - imp.reload(mt_settings) + self.assertRaises(ImproperlyConfigured, lambda: importlib.reload(mt_settings)) + importlib.reload(mt_settings) def test_resolution_order(self): from modeltranslation.utils import resolution_order @@ -1299,15 +1185,6 @@ def test_translated_models(self): self.assertTrue('boolean' in field_names) self.assertTrue('boolean_de' in field_names) self.assertTrue('boolean_en' in field_names) - self.assertTrue('nullboolean' in field_names) - self.assertTrue('nullboolean_de' in field_names) - self.assertTrue('nullboolean_en' in field_names) - self.assertTrue('csi' in field_names) - self.assertTrue('csi_de' in field_names) - self.assertTrue('csi_en' in field_names) - self.assertTrue('ip' in field_names) - self.assertTrue('ip_de' in field_names) - self.assertTrue('ip_en' in field_names) self.assertTrue('genericip' in field_names) self.assertTrue('genericip_de' in field_names) self.assertTrue('genericip_en' in field_names) @@ -1363,82 +1240,6 @@ def test_translated_models_boolean_instance(self): self.assertEqual(False, inst.boolean_de) self.assertEqual(True, inst.boolean_en) - def test_translated_models_nullboolean_instance(self): - inst = models.OtherFieldsModel() - inst.nullboolean = True - self.assertEqual('de', get_language()) - self.assertEqual(True, inst.nullboolean) - self.assertEqual(True, inst.nullboolean_de) - self.assertEqual(None, inst.nullboolean_en) - - inst.nullboolean = False - inst.save() - self.assertEqual(False, inst.nullboolean) - self.assertEqual(False, inst.nullboolean_de) - self.assertEqual(None, inst.nullboolean_en) - - trans_real.activate('en') - inst.nullboolean = True - self.assertEqual(True, inst.nullboolean) - self.assertEqual(False, inst.nullboolean_de) - self.assertEqual(True, inst.nullboolean_en) - - inst.nullboolean = None - self.assertEqual(None, inst.nullboolean) - self.assertEqual(False, inst.nullboolean_de) - self.assertEqual(None, inst.nullboolean_en) - - def test_translated_models_commaseparatedinteger_instance(self): - inst = models.OtherFieldsModel() - inst.csi = '4,8,15,16,23,42' - self.assertEqual('de', get_language()) - self.assertEqual('4,8,15,16,23,42', inst.csi) - self.assertEqual('4,8,15,16,23,42', inst.csi_de) - self.assertEqual(None, inst.csi_en) - - inst.csi = '23,42' - inst.save() - self.assertEqual('23,42', inst.csi) - self.assertEqual('23,42', inst.csi_de) - self.assertEqual(None, inst.csi_en) - - trans_real.activate('en') - inst.csi = '4,8,15,16,23,42' - self.assertEqual('4,8,15,16,23,42', inst.csi) - self.assertEqual('23,42', inst.csi_de) - self.assertEqual('4,8,15,16,23,42', inst.csi_en) - - # Now that we have covered csi, lost, illuminati and hitchhiker - # compliance in a single test, do something useful... - - # Check if validation is preserved - inst.csi = '1;2' - self.assertRaises(ValidationError, inst.full_clean) - - def test_translated_models_ipaddress_instance(self): - inst = models.OtherFieldsModel() - inst.ip = '192.0.1.42' - self.assertEqual('de', get_language()) - self.assertEqual('192.0.1.42', inst.ip) - self.assertEqual('192.0.1.42', inst.ip_de) - self.assertEqual(None, inst.ip_en) - - inst.ip = '192.0.23.1' - inst.save() - self.assertEqual('192.0.23.1', inst.ip) - self.assertEqual('192.0.23.1', inst.ip_de) - self.assertEqual(None, inst.ip_en) - - trans_real.activate('en') - inst.ip = '192.0.1.42' - self.assertEqual('192.0.1.42', inst.ip) - self.assertEqual('192.0.23.1', inst.ip_de) - self.assertEqual('192.0.1.42', inst.ip_en) - - # Check if validation is preserved - inst.ip = '1;2' - self.assertRaises(ValidationError, inst.full_clean) - def test_translated_models_genericipaddress_instance(self): inst = models.OtherFieldsModel() inst.genericip = '2a02:42fe::4' @@ -2105,7 +1906,7 @@ def test_update_command(self): self.assertEqual('already', obj2['title_de']) self.assertEqual('initial', obj2['title']) - call_command('update_translation_fields', verbosity=0) + call_command('update_translation_fields', 'tests', verbosity=0) obj1 = models.TestModel.objects.get(pk=pk1) obj2 = models.TestModel.objects.get(pk=pk2) @@ -2119,7 +1920,7 @@ def test_update_command_language_param(self): # Due to ``rewrite(False)`` here, original field will be affected. models.TestModel.objects.all().rewrite(False).update(title='initial') - call_command('update_translation_fields', language='en', verbosity=0) + call_command('update_translation_fields', 'tests', language='en', verbosity=0) obj1 = models.TestModel.objects.get(pk=pk1) obj2 = models.TestModel.objects.get(pk=pk2) @@ -2978,9 +2779,9 @@ def test_custom_manager_custom_method_name(self): qs = models.CustomManagerTestModel.objects.custom_qs() self.assertIsInstance(qs, MultilingualQuerySet) - @skipUnless(MIGRATIONS, 'migrations/auth not available') def test_3rd_party_custom_manager(self): from django.contrib.auth.models import Group, GroupManager + from modeltranslation.manager import MultilingualManager testmodel_fields = get_field_names(Group) @@ -2995,6 +2796,7 @@ def test_3rd_party_custom_manager(self): def test_multilingual_queryset_pickling(self): import pickle + from modeltranslation.manager import MultilingualQuerySet # typical @@ -3272,21 +3074,6 @@ def test_deferred_rule2(self): o.title = "bla" self.assertEqual(o.title, "bla") - @skipUnless(django.VERSION[0] == 1, 'Applicable only to django 1.x') - def test_select_related_django_1(self): - test = models.TestModel.objects.create(title_de='title_de', title_en='title_en') - with auto_populate('all'): - models.ForeignKeyModel.objects.create(untrans=test) - - fk_qs = models.ForeignKeyModel.objects.all() - self.assertNotIn('_untrans_cache', fk_qs[0].__dict__) - self.assertIn('_untrans_cache', fk_qs.select_related('untrans')[0].__dict__) - self.assertNotIn( - '_untrans_cache', fk_qs.select_related('untrans').select_related(None)[0].__dict__ - ) - # untrans is nullable so not included when select_related=True - self.assertNotIn('_untrans_cache', fk_qs.select_related()[0].__dict__) - @skipUnless(django.VERSION[0] >= 2, 'Applicable only to django > 2.x') def test_select_related_django_2(self): test = models.TestModel.objects.create(title_de='title_de', title_en='title_en') @@ -3303,7 +3090,7 @@ def test_select_related_django_2(self): self.assertNotIn('untrans', fk_qs.select_related()[0]._state.fields_cache) def test_translation_fields_appending(self): - from modeltranslation.manager import append_lookup_keys, append_lookup_key + from modeltranslation.manager import append_lookup_key, append_lookup_keys self.assertEqual(set(['untrans']), append_lookup_key(models.ForeignKeyModel, 'untrans')) self.assertEqual( @@ -3540,11 +3327,12 @@ def test_m2m(self): class InheritedPermissionTestCase(ModeltranslationTestBase): - @skipUnless(MIGRATIONS, 'migrations/auth not available') def test_managers_failure(self): """This fails with 0.13b.""" - from modeltranslation.manager import MultilingualManager from django.contrib.auth.models import Permission, User + + from modeltranslation.manager import MultilingualManager + from .models import InheritedPermission self.assertFalse( diff --git a/modeltranslation/tests/translation.py b/modeltranslation/tests/translation.py index 6d90001c..474562b7 100644 --- a/modeltranslation/tests/translation.py +++ b/modeltranslation/tests/translation.py @@ -1,9 +1,9 @@ -# -*- coding: utf-8 -*- from django.conf import settings +from django.contrib.auth.models import Group from django.utils.translation import gettext_lazy - -from modeltranslation.translator import translator, register, TranslationOptions from modeltranslation.tests import models +from modeltranslation.tests.models import InheritedPermission +from modeltranslation.translator import TranslationOptions, register, translator @register(models.TestModel) @@ -111,11 +111,8 @@ class OtherFieldsModelTranslationOptions(TranslationOptions): fields = ( 'int', 'boolean', - 'nullboolean', - 'csi', 'float', 'decimal', - 'ip', 'genericip', 'date', 'datetime', @@ -286,15 +283,13 @@ class ModelYOptions(TranslationOptions): # ######### 3-rd party with custom manager -if "django.contrib.auth" in settings.INSTALLED_APPS: - from django.contrib.auth.models import Group - from .models import InheritedPermission - @register(Group) - class GroupTranslationOptions(TranslationOptions): - fields = ('name',) +@register(Group) +class GroupTranslationOptions(TranslationOptions): + fields = ('name',) + - @register(InheritedPermission) - class InheritedPermissionOptions(TranslationOptions): - fields = ('translated_var',) - required_languages = [x[0] for x in settings.LANGUAGES] +@register(InheritedPermission) +class InheritedPermissionOptions(TranslationOptions): + fields = ('translated_var',) + required_languages = [x[0] for x in settings.LANGUAGES] diff --git a/modeltranslation/tests/urls.py b/modeltranslation/tests/urls.py index 73e38488..637600f5 100644 --- a/modeltranslation/tests/urls.py +++ b/modeltranslation/tests/urls.py @@ -1,16 +1 @@ -# -*- coding: utf-8 -*- -try: - from django.conf.urls import include, patterns, url - - # Workaround for pyflakes issue #13 - assert (include, patterns, url) # noqa -except ImportError: # Django 1.3 fallback - from django.conf.urls.defaults import include, patterns, url # NOQA -from django.contrib import admin - - -urlpatterns = patterns( - '', - url(r'^set_language/$', 'django.views.i18n.set_language', {}, name='set_language'), - url(r'^admin/', include(admin.site.urls)), -) +urlpatterns = [] diff --git a/poetry.lock b/poetry.lock index 25f9b61e..fe1f79ef 100644 --- a/poetry.lock +++ b/poetry.lock @@ -12,6 +12,28 @@ typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [package.extras] tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"] +[[package]] +name = "atomicwrites" +version = "1.4.1" +description = "Atomic file writes." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "attrs" +version = "21.4.0" +description = "Classes Without Boilerplate" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.extras] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"] +docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"] + [[package]] name = "black" version = "21.12b0" @@ -22,7 +44,6 @@ python-versions = ">=3.6.2" [package.dependencies] click = ">=7.1.2" -dataclasses = {version = ">=0.6", markers = "python_version < \"3.7\""} mypy-extensions = ">=0.4.3" pathspec = ">=0.9.0,<1" platformdirs = ">=2" @@ -61,12 +82,18 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] -name = "dataclasses" -version = "0.8" -description = "A backport of the dataclasses module for Python 3.6" +name = "coverage" +version = "6.4.2" +description = "Code coverage measurement for Python" category = "dev" optional = false -python-versions = ">=3.6, <3.7" +python-versions = ">=3.7" + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli"] [[package]] name = "django" @@ -85,6 +112,14 @@ sqlparse = ">=0.2.2" argon2 = ["argon2-cffi (>=19.1.0)"] bcrypt = ["bcrypt"] +[[package]] +name = "django-types" +version = "0.15.0" +description = "Type stubs for Django" +category = "dev" +optional = false +python-versions = ">=3.6.2,<4.0.0" + [[package]] name = "fancycompleter" version = "0.9.1" @@ -128,6 +163,14 @@ docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] perf = ["ipython"] testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] +[[package]] +name = "iniconfig" +version = "1.1.1" +description = "iniconfig: brain-dead simple config-ini parsing" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "mccabe" version = "0.6.1" @@ -144,6 +187,17 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "packaging" +version = "21.3" +description = "Core utilities for Python packages" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" + [[package]] name = "pathspec" version = "0.9.0" @@ -181,6 +235,29 @@ python-versions = ">=3.6" docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] +[[package]] +name = "pluggy" +version = "1.0.0" +description = "plugin and hook calling mechanisms for python" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "py" +version = "1.11.0" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + [[package]] name = "pycodestyle" version = "2.7.0" @@ -205,6 +282,17 @@ category = "dev" optional = false python-versions = ">=3.6" +[[package]] +name = "pyparsing" +version = "3.0.9" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" +category = "dev" +optional = false +python-versions = ">=3.6.8" + +[package.extras] +diagrams = ["railroad-diagrams", "jinja2"] + [[package]] name = "pyreadline" version = "2.1" @@ -221,6 +309,71 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "pytest" +version = "7.1.2" +description = "pytest: simple powerful testing with Python" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} +attrs = ">=19.2.0" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +py = ">=1.8.2" +tomli = ">=1.0.0" + +[package.extras] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] + +[[package]] +name = "pytest-cov" +version = "3.0.0" +description = "Pytest plugin for measuring coverage." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"] + +[[package]] +name = "pytest-django" +version = "4.5.2" +description = "A Django plugin for pytest." +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.dependencies] +pytest = ">=5.4.0" + +[package.extras] +docs = ["sphinx", "sphinx-rtd-theme"] +testing = ["django", "django-configurations (>=2.0)"] + +[[package]] +name = "pytest-sugar" +version = "0.9.5" +description = "pytest-sugar is a plugin for pytest that changes the default look and feel of pytest (e.g. progressbar, show tests that fail instantly)." +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +packaging = ">=14.1" +pytest = ">=2.9" +termcolor = ">=1.1.0" + [[package]] name = "pytz" version = "2022.1" @@ -245,6 +398,14 @@ category = "main" optional = false python-versions = ">=3.5" +[[package]] +name = "termcolor" +version = "1.1.0" +description = "ANSII Color formatting for output in terminal." +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "tomli" version = "1.2.3" @@ -291,14 +452,21 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytes [metadata] lock-version = "1.1" -python-versions = ">=3.6.2" -content-hash = "2c90acbb650482a80f57421396f034a082b4f2d3dddc4f22bc8bb3d41a97c16e" +python-versions = ">=3.7,<4" +content-hash = "946cfcafe1b532f0f584925bfbcc9f47b5c1f58d42068518a1c57fffe67bd14c" [metadata.files] asgiref = [ {file = "asgiref-3.4.1-py3-none-any.whl", hash = "sha256:ffc141aa908e6f175673e7b1b3b7af4fdb0ecb738fc5c8b88f69f055c2415214"}, {file = "asgiref-3.4.1.tar.gz", hash = "sha256:4ef1ab46b484e3c706329cedeff284a5d40824200638503f5768edb6de7d58e9"}, ] +atomicwrites = [ + {file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"}, +] +attrs = [ + {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, + {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, +] black = [ {file = "black-21.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"}, {file = "black-21.12b0.tar.gz", hash = "sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3"}, @@ -311,14 +479,57 @@ colorama = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] -dataclasses = [ - {file = "dataclasses-0.8-py3-none-any.whl", hash = "sha256:0201d89fa866f68c8ebd9d08ee6ff50c0b255f8ec63a71c16fda7af82bb887bf"}, - {file = "dataclasses-0.8.tar.gz", hash = "sha256:8479067f342acf957dc82ec415d355ab5edb7e7646b90dc6e2fd1d96ad084c97"}, +coverage = [ + {file = "coverage-6.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a9032f9b7d38bdf882ac9f66ebde3afb8145f0d4c24b2e600bc4c6304aafb87e"}, + {file = "coverage-6.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e0524adb49c716ca763dbc1d27bedce36b14f33e6b8af6dba56886476b42957c"}, + {file = "coverage-6.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4548be38a1c810d79e097a38107b6bf2ff42151900e47d49635be69943763d8"}, + {file = "coverage-6.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f23876b018dfa5d3e98e96f5644b109090f16a4acb22064e0f06933663005d39"}, + {file = "coverage-6.4.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fe75dcfcb889b6800f072f2af5a331342d63d0c1b3d2bf0f7b4f6c353e8c9c0"}, + {file = "coverage-6.4.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2f8553878a24b00d5ab04b7a92a2af50409247ca5c4b7a2bf4eabe94ed20d3ee"}, + {file = "coverage-6.4.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:d774d9e97007b018a651eadc1b3970ed20237395527e22cbeb743d8e73e0563d"}, + {file = "coverage-6.4.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d56f105592188ce7a797b2bd94b4a8cb2e36d5d9b0d8a1d2060ff2a71e6b9bbc"}, + {file = "coverage-6.4.2-cp310-cp310-win32.whl", hash = "sha256:d230d333b0be8042ac34808ad722eabba30036232e7a6fb3e317c49f61c93386"}, + {file = "coverage-6.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:5ef42e1db047ca42827a85e34abe973971c635f83aed49611b7f3ab49d0130f0"}, + {file = "coverage-6.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:25b7ec944f114f70803d6529394b64f8749e93cbfac0fe6c5ea1b7e6c14e8a46"}, + {file = "coverage-6.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bb00521ab4f99fdce2d5c05a91bddc0280f0afaee0e0a00425e28e209d4af07"}, + {file = "coverage-6.4.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2dff52b3e7f76ada36f82124703f4953186d9029d00d6287f17c68a75e2e6039"}, + {file = "coverage-6.4.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:147605e1702d996279bb3cc3b164f408698850011210d133a2cb96a73a2f7996"}, + {file = "coverage-6.4.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:422fa44070b42fef9fb8dabd5af03861708cdd6deb69463adc2130b7bf81332f"}, + {file = "coverage-6.4.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:8af6c26ba8df6338e57bedbf916d76bdae6308e57fc8f14397f03b5da8622b4e"}, + {file = "coverage-6.4.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:5336e0352c0b12c7e72727d50ff02557005f79a0b8dcad9219c7c4940a930083"}, + {file = "coverage-6.4.2-cp37-cp37m-win32.whl", hash = "sha256:0f211df2cba951ffcae210ee00e54921ab42e2b64e0bf2c0befc977377fb09b7"}, + {file = "coverage-6.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:a13772c19619118903d65a91f1d5fea84be494d12fd406d06c849b00d31bf120"}, + {file = "coverage-6.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f7bd0ffbcd03dc39490a1f40b2669cc414fae0c4e16b77bb26806a4d0b7d1452"}, + {file = "coverage-6.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0895ea6e6f7f9939166cc835df8fa4599e2d9b759b02d1521b574e13b859ac32"}, + {file = "coverage-6.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4e7ced84a11c10160c0697a6cc0b214a5d7ab21dfec1cd46e89fbf77cc66fae"}, + {file = "coverage-6.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80db4a47a199c4563d4a25919ff29c97c87569130375beca3483b41ad5f698e8"}, + {file = "coverage-6.4.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3def6791adf580d66f025223078dc84c64696a26f174131059ce8e91452584e1"}, + {file = "coverage-6.4.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4f89d8e03c8a3757aae65570d14033e8edf192ee9298303db15955cadcff0c63"}, + {file = "coverage-6.4.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6d0b48aff8e9720bdec315d67723f0babd936a7211dc5df453ddf76f89c59933"}, + {file = "coverage-6.4.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2b20286c2b726f94e766e86a3fddb7b7e37af5d0c635bdfa7e4399bc523563de"}, + {file = "coverage-6.4.2-cp38-cp38-win32.whl", hash = "sha256:d714af0bdba67739598849c9f18efdcc5a0412f4993914a0ec5ce0f1e864d783"}, + {file = "coverage-6.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:5f65e5d3ff2d895dab76b1faca4586b970a99b5d4b24e9aafffc0ce94a6022d6"}, + {file = "coverage-6.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a697977157adc052284a7160569b36a8bbec09db3c3220642e6323b47cec090f"}, + {file = "coverage-6.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c77943ef768276b61c96a3eb854eba55633c7a3fddf0a79f82805f232326d33f"}, + {file = "coverage-6.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54d8d0e073a7f238f0666d3c7c0d37469b2aa43311e4024c925ee14f5d5a1cbe"}, + {file = "coverage-6.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f22325010d8824594820d6ce84fa830838f581a7fd86a9235f0d2ed6deb61e29"}, + {file = "coverage-6.4.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24b04d305ea172ccb21bee5bacd559383cba2c6fcdef85b7701cf2de4188aa55"}, + {file = "coverage-6.4.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:866ebf42b4c5dbafd64455b0a1cd5aa7b4837a894809413b930026c91e18090b"}, + {file = "coverage-6.4.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e36750fbbc422c1c46c9d13b937ab437138b998fe74a635ec88989afb57a3978"}, + {file = "coverage-6.4.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:79419370d6a637cb18553ecb25228893966bd7935a9120fa454e7076f13b627c"}, + {file = "coverage-6.4.2-cp39-cp39-win32.whl", hash = "sha256:b5e28db9199dd3833cc8a07fa6cf429a01227b5d429facb56eccd765050c26cd"}, + {file = "coverage-6.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:edfdabe7aa4f97ed2b9dd5dde52d2bb29cb466993bb9d612ddd10d0085a683cf"}, + {file = "coverage-6.4.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:e2618cb2cf5a7cc8d698306e42ebcacd02fb7ef8cfc18485c59394152c70be97"}, + {file = "coverage-6.4.2.tar.gz", hash = "sha256:6c3ccfe89c36f3e5b9837b9ee507472310164f352c9fe332120b764c9d60adbe"}, ] django = [ {file = "Django-3.2.14-py3-none-any.whl", hash = "sha256:a8681e098fa60f7c33a4b628d6fcd3fe983a0939ff1301ecacac21d0b38bad56"}, {file = "Django-3.2.14.tar.gz", hash = "sha256:677182ba8b5b285a4e072f3ac17ceee6aff1b5ce77fd173cc5b6a2d3dc022fcf"}, ] +django-types = [ + {file = "django-types-0.15.0.tar.gz", hash = "sha256:eade768d396b00d48eaca3b58e13217b6f11257d2070937e339e635f50004a62"}, + {file = "django_types-0.15.0-py3-none-any.whl", hash = "sha256:105dad074bbe4b7ae49f3a516228d391b10f0b9084f7030b1b1425f4f89e17cc"}, +] fancycompleter = [ {file = "fancycompleter-0.9.1-py3-none-any.whl", hash = "sha256:dd076bca7d9d524cc7f25ec8f35ef95388ffef9ef46def4d3d25e9b044ad7080"}, {file = "fancycompleter-0.9.1.tar.gz", hash = "sha256:09e0feb8ae242abdfd7ef2ba55069a46f011814a80fe5476be48f51b00247272"}, @@ -331,6 +542,10 @@ importlib-metadata = [ {file = "importlib_metadata-4.8.3-py3-none-any.whl", hash = "sha256:65a9576a5b2d58ca44d133c42a241905cc45e34d2c06fd5ba2bafa221e5d7b5e"}, {file = "importlib_metadata-4.8.3.tar.gz", hash = "sha256:766abffff765960fcc18003801f7044eb6755ffae4521c8e8ce8e83b9c9b0668"}, ] +iniconfig = [ + {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, + {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, +] mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, @@ -339,6 +554,10 @@ mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] +packaging = [ + {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, + {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, +] pathspec = [ {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, @@ -351,6 +570,14 @@ platformdirs = [ {file = "platformdirs-2.4.0-py3-none-any.whl", hash = "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d"}, {file = "platformdirs-2.4.0.tar.gz", hash = "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2"}, ] +pluggy = [ + {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, + {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, +] +py = [ + {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, + {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, +] pycodestyle = [ {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, @@ -363,6 +590,10 @@ pygments = [ {file = "Pygments-2.12.0-py3-none-any.whl", hash = "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519"}, {file = "Pygments-2.12.0.tar.gz", hash = "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb"}, ] +pyparsing = [ + {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, + {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, +] pyreadline = [ {file = "pyreadline-2.1.win-amd64.exe", hash = "sha256:9ce5fa65b8992dfa373bddc5b6e0864ead8f291c94fbfec05fbd5c836162e67b"}, {file = "pyreadline-2.1.win32.exe", hash = "sha256:65540c21bfe14405a3a77e4c085ecfce88724743a4ead47c66b84defcf82c32e"}, @@ -371,6 +602,22 @@ pyreadline = [ pyrepl = [ {file = "pyrepl-0.9.0.tar.gz", hash = "sha256:292570f34b5502e871bbb966d639474f2b57fbfcd3373c2d6a2f3d56e681a775"}, ] +pytest = [ + {file = "pytest-7.1.2-py3-none-any.whl", hash = "sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c"}, + {file = "pytest-7.1.2.tar.gz", hash = "sha256:a06a0425453864a270bc45e71f783330a7428defb4230fb5e6a731fde06ecd45"}, +] +pytest-cov = [ + {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"}, + {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"}, +] +pytest-django = [ + {file = "pytest-django-4.5.2.tar.gz", hash = "sha256:d9076f759bb7c36939dbdd5ae6633c18edfc2902d1a69fdbefd2426b970ce6c2"}, + {file = "pytest_django-4.5.2-py3-none-any.whl", hash = "sha256:c60834861933773109334fe5a53e83d1ef4828f2203a1d6a0fa9972f4f75ab3e"}, +] +pytest-sugar = [ + {file = "pytest-sugar-0.9.5.tar.gz", hash = "sha256:eea78b6f15b635277d3d90280cd386d8feea1cab0f9be75947a626e8b02b477d"}, + {file = "pytest_sugar-0.9.5-py2.py3-none-any.whl", hash = "sha256:3da42de32ce4e1e95b448d61c92804433f5d4058c0a765096991c2e93d5a289f"}, +] pytz = [ {file = "pytz-2022.1-py2.py3-none-any.whl", hash = "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"}, {file = "pytz-2022.1.tar.gz", hash = "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7"}, @@ -383,6 +630,9 @@ sqlparse = [ {file = "sqlparse-0.4.2-py3-none-any.whl", hash = "sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d"}, {file = "sqlparse-0.4.2.tar.gz", hash = "sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae"}, ] +termcolor = [ + {file = "termcolor-1.1.0.tar.gz", hash = "sha256:1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b"}, +] tomli = [ {file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"}, {file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"}, diff --git a/pyproject.toml b/pyproject.toml index 47520955..f23d42da 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ packages = [ ] [tool.poetry.dependencies] -python = ">=3.6.2" +python = ">=3.7,<4" django = ">=2.2" six = "^1.15.0" @@ -17,6 +17,11 @@ six = "^1.15.0" pdbpp = "^0.10.2" flake8 = "^3.7.9" black = "^21.9b0" +pytest-cov = "^3.0.0" +pytest = "^7.1.2" +pytest-sugar = "^0.9.5" +pytest-django = "^4.5.2" +django-types = "^0.15.0" [tool.black] line-length = 100 diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 00000000..027229b7 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,9 @@ +[pytest] +DJANGO_SETTINGS_MODULE=modeltranslation.tests.settings +pythonpath = . +python_files = tests.py test_*.py +addopts = + --no-cov-on-fail + --cov-report="" + --cov modeltranslation + --maxfail=5 diff --git a/runtests.py b/runtests.py deleted file mode 100755 index 67b5c942..00000000 --- a/runtests.py +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python -import os -import sys -import warnings -from optparse import OptionParser - -import django -from django.conf import settings -from django.core.management import call_command - - -def runtests(test_path='modeltranslation'): - if not settings.configured: - # Choose database for settings - test_db = os.getenv('DB', 'sqlite') - test_db_host = os.getenv('DB_HOST', 'localhost') - DATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:'}} - if test_db == 'mysql': - DATABASES['default'].update( - { - 'ENGINE': 'django.db.backends.mysql', - 'NAME': os.getenv('MYSQL_DATABASE', 'modeltranslation'), - 'USER': os.getenv('MYSQL_USER', 'root'), - 'PASSWORD': os.getenv('MYSQL_PASSWORD', 'password'), - 'HOST': test_db_host, - } - ) - elif test_db == 'postgres': - DATABASES['default'].update( - { - 'ENGINE': 'django.db.backends.postgresql', - 'USER': os.getenv('POSTGRES_USER', 'postgres'), - 'PASSWORD': os.getenv('POSTGRES_DB', 'postgres'), - 'NAME': os.getenv('POSTGRES_DB', 'modeltranslation'), - 'HOST': test_db_host, - } - ) - - # Configure test environment - settings.configure( - DATABASES=DATABASES, - INSTALLED_APPS=( - 'django.contrib.contenttypes', - 'django.contrib.auth', - 'modeltranslation', - ), - ROOT_URLCONF=None, # tests override urlconf, but it still needs to be defined - LANGUAGES=(('en', 'English'),), - MIDDLEWARE_CLASSES=(), - ) - - django.setup() - warnings.simplefilter('always', DeprecationWarning) - failures = call_command('test', test_path, interactive=False, failfast=False, verbosity=2) - - sys.exit(bool(failures)) - - -if __name__ == '__main__': - parser = OptionParser() - - (options, args) = parser.parse_args() - runtests(*args)