summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2022-12-14 12:01:00 +0100
committerÉtienne Loks <etienne.loks@iggdrasil.net>2022-12-14 15:34:05 +0100
commit7108320a1295641a6d591d29edf01e3a4cc45e82 (patch)
tree216a472994556d08c127f2b535f77f9c41902e35
parent5e121edfd6b3bb4de4344e2f631630bf94c3de0b (diff)
downloadIshtar-7108320a1295641a6d591d29edf01e3a4cc45e82.tar.bz2
Ishtar-7108320a1295641a6d591d29edf01e3a4cc45e82.zip
Tests: use variable for fixtures paths
-rw-r--r--.gitlab-ci.yml10
-rw-r--r--archaeological_context_records/tests.py2
-rw-r--r--archaeological_finds/tests.py16
-rw-r--r--archaeological_operations/tests.py20
-rw-r--r--example_project/settings.py5
-rw-r--r--ishtar_common/tests.py101
6 files changed, 76 insertions, 78 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 5e2998c4d..8b5692118 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,9 +1,9 @@
before_script:
- apt-get update
- - apt-get install -q -y git sed python3-pip libpq-dev python3-dev libjpeg-dev zlib1g-dev libxml2-dev libxslt1-dev libgeos-dev python3-cairocffi tidy libtidy-dev binutils libproj-dev gdal-bin libpangocairo-1.0-0 pandoc graphviz python3-argon2 file gettext
- - apt-get install -q -y locales
+ - apt-get install -q -y locales locales-all
- echo "fr_FR.UTF-8 UTF-8" >> /etc/locale.gen
- - dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=$LANG
+ - dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=fr_FR.UTF-8
+ - apt-get install -q -y git sed python3-pip libpq-dev python3-dev libjpeg-dev zlib1g-dev libxml2-dev libxslt1-dev libgeos-dev python3-cairocffi tidy libtidy-dev binutils libproj-dev gdal-bin libpangocairo-1.0-0 pandoc graphviz python3-argon2 file gettext
- pip3 install -r requirements.txt
- cp Makefile.example Makefile
@@ -41,10 +41,8 @@ test-v4:
debian:
stage: "test"
script:
- - apt-get update
- apt-get install -q -y devscripts build-essential lintian wget dh-python python3-all sudo findutils
- apt-get install -q -y libpq-dev python3-dev libjpeg-dev zlib1g-dev libxml2-dev libxslt1-dev libgeos-dev libtidy-dev binutils libproj-dev python3-setuptools
- - apt install -q -y --force-yes locales-all
- wget -O /etc/apt/sources.list.d/iggdrasil.list http://deb.iggdrasil.net/apt/debian/dists/bullseye/iggdrasil.list
- wget -O - http://deb.iggdrasil.net/iggdrasil.gpg.key | apt-key add -
- apt-get update
@@ -55,7 +53,7 @@ debian:
- dpkg -i ../python3-django-ishtar_*_all.deb
- /etc/init.d/postgresql start
- INSTANCE=my_ishtar URL=localhost MAX_UPLOAD_SIZE=100 ishtar-prepare-instance
- - sudo -u postgres createdb -O ishtar-my_ishtar test_ishtar-my_ishtar
+ - sudo -u postgres createdb -E UTF8 -O ishtar-my_ishtar test_ishtar-my_ishtar
- sudo -u postgres psql -d test_ishtar-my_ishtar -c 'CREATE EXTENSION postgis;'
- cd /srv/ishtar/my_ishtar && python3 ./manage.py test -k archaeological_operations ishtar_common archaeological_context_records archaeological_files archaeological_finds archaeological_warehouse
tags:
diff --git a/archaeological_context_records/tests.py b/archaeological_context_records/tests.py
index 69ecafdb1..9842340f3 100644
--- a/archaeological_context_records/tests.py
+++ b/archaeological_context_records/tests.py
@@ -81,7 +81,7 @@ class ImportContextRecordTest(ImportTest, TestCase):
self._test_geo_import("UE-test-shp.zip", 13)
def _test_geo_import(self, data_name, new_nb):
- root = settings.ROOT_PATH + "../archaeological_context_records/tests/"
+ root = settings.LIB_BASE_PATH + "archaeological_context_records/tests/"
filename = root + "importer-GIS-UE.zip"
self.restore_serialized(filename)
imp_type = ImporterType.objects.get(name="GIS - UE")
diff --git a/archaeological_finds/tests.py b/archaeological_finds/tests.py
index 15c54fe0d..0f7645ec8 100644
--- a/archaeological_finds/tests.py
+++ b/archaeological_finds/tests.py
@@ -626,7 +626,7 @@ class TreatmentWizardCreationTest(WizardTest, FindInit, TestCase):
class ImportFindTest(ImportTest, FindInit, TestCase):
fixtures = FIND_TOWNS_FIXTURES + [
- settings.ROOT_PATH + "../archaeological_finds/tests/import_loca_test.json",
+ settings.LIB_BASE_PATH + "archaeological_finds/tests/import_loca_test.json",
]
def setUp(self):
@@ -637,7 +637,7 @@ class ImportFindTest(ImportTest, FindInit, TestCase):
self._test_geo_import("importer-GIS-find", 1)
def _test_geo_import(self, data_name, new_nb):
- root = settings.ROOT_PATH + "../archaeological_finds/tests/"
+ root = settings.LIB_BASE_PATH + "archaeological_finds/tests/"
filename = root + data_name + ".zip"
self.restore_serialized(filename)
imp_type = ImporterType.objects.get(slug="topographie-mobilier")
@@ -706,11 +706,11 @@ class ImportFindTest(ImportTest, FindInit, TestCase):
target="documents__image", formater_type_id=formater.pk, column_id=col.pk
)
mcc_file = open(
- settings.ROOT_PATH + "../archaeological_finds/tests/MCC-finds-example.csv",
+ settings.LIB_BASE_PATH + "archaeological_finds/tests/MCC-finds-example.csv",
"rb",
)
mcc_images = open(
- settings.ROOT_PATH + "../archaeological_finds/tests/images.zip", "rb"
+ settings.LIB_BASE_PATH + "archaeological_finds/tests/images.zip", "rb"
)
file_dict = {
"imported_file": SimpleUploadedFile(mcc_file.name, mcc_file.read()),
@@ -1455,7 +1455,7 @@ class FindSearchTest(FindInit, TestCase, SearchText):
# add an image to the first find
document = Document.objects.create(title="Image!")
image_path = (
- settings.ROOT_PATH + "../ishtar_common/static/media/images/ishtar-bg.jpg"
+ settings.LIB_BASE_PATH + "ishtar_common/static/media/images/ishtar-bg.jpg"
)
document.image = SimpleUploadedFile(
name="ishtar-bg.jpg",
@@ -2177,7 +2177,7 @@ class TreatmentTest(FindInit, TestCase):
def setUp(self):
base_img = (
- settings.ROOT_PATH + "../ishtar_common/static/media/images/ishtar-bg.jpg"
+ settings.LIB_BASE_PATH + "ishtar_common/static/media/images/ishtar-bg.jpg"
)
temp_dir = tempfile.gettempdir()
img = os.path.join(temp_dir, "ishtar-bg.jpg")
@@ -2542,7 +2542,7 @@ class LabelTest(FindInit, TestCase):
def setUp(self):
templates = [
- settings.ROOT_PATH + "../archaeological_finds/tests/" + t
+ settings.LIB_BASE_PATH + "archaeological_finds/tests/" + t
for t in (
"etiquettes-mobilier.odt",
"etiquettes-mobilier",
@@ -2617,7 +2617,7 @@ class TemplateTest(FindInit, TestCase):
def setUp(self):
template = (
- settings.ROOT_PATH + "../archaeological_finds/tests/notices-panier.odt"
+ settings.LIB_BASE_PATH + "archaeological_finds/tests/notices-panier.odt"
)
filename = template.split("/")[-1]
shutil.copy(
diff --git a/archaeological_operations/tests.py b/archaeological_operations/tests.py
index a37a824d4..a9fe8760e 100644
--- a/archaeological_operations/tests.py
+++ b/archaeological_operations/tests.py
@@ -174,7 +174,7 @@ class ImportTest(object):
def init_ope_import(self, filename="MCC-operations-example.csv", sep=","):
mcc_operation = ImporterType.objects.get(name="MCC - Opérations")
mcc_operation_file = open(
- settings.ROOT_PATH + "../archaeological_operations/tests/" + filename, "rb"
+ settings.LIB_BASE_PATH + "archaeological_operations/tests/" + filename, "rb"
)
file_dict = {
"imported_file": SimpleUploadedFile(
@@ -282,8 +282,8 @@ class ImportTest(object):
self.init_ope()
mcc_parcel = ImporterType.objects.get(name="MCC - Parcelles")
mcc_file = open(
- settings.ROOT_PATH
- + "../archaeological_operations/tests/MCC-parcelles-example.csv",
+ settings.LIB_BASE_PATH +
+ "archaeological_operations/tests/MCC-parcelles-example.csv",
"rb",
)
file_dict = {
@@ -312,7 +312,7 @@ class ImportTest(object):
self.init_parcel()
mcc = ImporterType.objects.get(name="MCC - UE")
mcc_file = open(
- settings.ROOT_PATH + "../archaeological_context_records/tests/"
+ settings.LIB_BASE_PATH + "archaeological_context_records/tests/"
"MCC-context-records-example.csv",
"rb",
)
@@ -767,7 +767,7 @@ class ImportDocumentTest(ImportTest, TestCase):
)
doc_import_file = open(
- settings.ROOT_PATH + "../archaeological_operations/tests/" + filename, "rb"
+ settings.LIB_BASE_PATH + "archaeological_operations/tests/" + filename, "rb"
)
file_dict = {
@@ -3374,7 +3374,7 @@ class LabelTest(TestCase, OperationInitTest):
ope.save()
tpl = open(
- settings.ROOT_PATH + "../archaeological_operations/tests/labels-8.odt", "rb"
+ settings.LIB_BASE_PATH + "archaeological_operations/tests/labels-8.odt", "rb"
)
template = SimpleUploadedFile(tpl.name, tpl.read())
model, __ = ImporterModel.objects.get_or_create(
@@ -3454,8 +3454,8 @@ class RegisterTest(TestCase, OperationInitTest):
def test_document_generation(self):
tpl = open(
- settings.ROOT_PATH
- + "../archaeological_operations/tests/document_reference.odt",
+ settings.LIB_BASE_PATH +
+ "archaeological_operations/tests/document_reference.odt",
"rb",
)
template = SimpleUploadedFile(tpl.name, tpl.read())
@@ -4532,7 +4532,7 @@ class ApiTest(OperationInitTest, APITestCase):
return src
def _mock_request(self, mock_get, json_file="external_source_types_1.json"):
- json_file = "../archaeological_operations/tests/" + json_file
+ json_file = settings.LIB_BASE_PATH + "archaeological_operations/tests/" + json_file
mock_get.return_value.status_code = 200
def __json():
@@ -4682,7 +4682,7 @@ class ApiTest(OperationInitTest, APITestCase):
self.client.post(url, params, follow=True)
base = "default-source.ods"
- filename = settings.ROOT_PATH + "../archaeological_operations/tests/" + base
+ filename = settings.LIB_BASE_PATH + "archaeological_operations/tests/" + base
with open(filename, "rb") as fle:
source.match_document.save(base, DjangoFile(fle))
diff --git a/example_project/settings.py b/example_project/settings.py
index 33372bd5d..8248b6713 100644
--- a/example_project/settings.py
+++ b/example_project/settings.py
@@ -290,9 +290,7 @@ ISHTAR_PERMIT_TYPES = {}
ISHTAR_DOC_TYPES = {"undefined": "Undefined"}
ISHTAR_SEARCH_LANGUAGE = "french"
-
ISHTAR_SECURE = True
-
ISHTAR_DPTS = []
MAX_ATTEMPTS = 1 # django background tasks
@@ -308,6 +306,9 @@ TEST_RUNNER = "ishtar_common.tests.ManagedModelTestRunner"
SELENIUM_TEST = False
CELERY_BROKER_URL = ""
SENTRY_ID = None
+DISTRIBUTION = "source"
+LIB_BASE_PATH = ROOT_PATH + "../"
+FIXTURE_AUTH_PATH = ROOT_PATH + "../"
try:
from custom_settings import *
diff --git a/ishtar_common/tests.py b/ishtar_common/tests.py
index ce3e096c8..f4e372770 100644
--- a/ishtar_common/tests.py
+++ b/ishtar_common/tests.py
@@ -97,64 +97,64 @@ from ishtar_common.utils import (
from ishtar_common.tasks import launch_export
from ishtar_common import utils_secretary
-from django.contrib.staticfiles.testing import StaticLiveServerTestCase
-
+LIB_BASE_PATH = settings.LIB_BASE_PATH
+FIXTURE_AUTH_PATH = settings.FIXTURE_AUTH_PATH
COMMON_FIXTURES = [
- settings.ROOT_PATH + "../fixtures/initial_data-auth-fr.json",
- settings.ROOT_PATH + "../ishtar_common/fixtures/initial_data-fr.json",
- settings.ROOT_PATH + "../ishtar_common/fixtures/initial_geo-fr.json",
- settings.ROOT_PATH + "../ishtar_common/fixtures/initial_importtypes-fr.json",
+ FIXTURE_AUTH_PATH + "fixtures/initial_data-auth-fr.json",
+ LIB_BASE_PATH + "ishtar_common/fixtures/initial_data-fr.json",
+ LIB_BASE_PATH + "ishtar_common/fixtures/initial_geo-fr.json",
+ LIB_BASE_PATH + "ishtar_common/fixtures/initial_importtypes-fr.json",
]
OPERATION_FIXTURES = COMMON_FIXTURES + [
- settings.ROOT_PATH + "../archaeological_operations/fixtures/initial_data-fr.json",
- settings.ROOT_PATH
- + "../archaeological_operations/fixtures/initial_data_relation_type_norel-fr.json",
- settings.ROOT_PATH
- + "../archaeological_operations/fixtures/initial_data_relation_type-fr.json",
+ LIB_BASE_PATH + "archaeological_operations/fixtures/initial_data-fr.json",
+ LIB_BASE_PATH
+ + "archaeological_operations/fixtures/initial_data_relation_type_norel-fr.json",
+ LIB_BASE_PATH
+ + "archaeological_operations/fixtures/initial_data_relation_type-fr.json",
]
OPERATION_TOWNS_FIXTURES = OPERATION_FIXTURES + [
- settings.ROOT_PATH + "../ishtar_common/fixtures/test_towns.json"
+ LIB_BASE_PATH + "ishtar_common/fixtures/test_towns.json"
]
FILE_FIXTURES = OPERATION_FIXTURES + [
- settings.ROOT_PATH + "../archaeological_files/fixtures/initial_data-fr.json"
+ LIB_BASE_PATH + "archaeological_files/fixtures/initial_data-fr.json"
]
FILE_TOWNS_FIXTURES = OPERATION_TOWNS_FIXTURES + [
- settings.ROOT_PATH + "../archaeological_files/fixtures/initial_data-fr.json"
+ LIB_BASE_PATH + "archaeological_files/fixtures/initial_data-fr.json"
]
CONTEXT_RECORD_FIXTURES = FILE_FIXTURES + [
- settings.ROOT_PATH
- + "../archaeological_context_records/fixtures/initial_data-fr.json",
- settings.ROOT_PATH
- + "../archaeological_context_records/fixtures/initial_data_relation_type_norel-fr.json",
- settings.ROOT_PATH
- + "../archaeological_context_records/fixtures/initial_data_relation_type-fr.json",
+ LIB_BASE_PATH
+ + "archaeological_context_records/fixtures/initial_data-fr.json",
+ LIB_BASE_PATH
+ + "archaeological_context_records/fixtures/initial_data_relation_type_norel-fr.json",
+ LIB_BASE_PATH
+ + "archaeological_context_records/fixtures/initial_data_relation_type-fr.json",
]
CONTEXT_RECORD_TOWNS_FIXTURES = FILE_TOWNS_FIXTURES + [
- settings.ROOT_PATH
- + "../archaeological_context_records/fixtures/initial_data-fr.json",
- settings.ROOT_PATH
- + "../archaeological_context_records/fixtures/initial_data_relation_type_norel-fr.json",
- settings.ROOT_PATH
- + "../archaeological_context_records/fixtures/initial_data_relation_type-fr.json",
+ LIB_BASE_PATH
+ + "archaeological_context_records/fixtures/initial_data-fr.json",
+ LIB_BASE_PATH
+ + "archaeological_context_records/fixtures/initial_data_relation_type_norel-fr.json",
+ LIB_BASE_PATH
+ + "archaeological_context_records/fixtures/initial_data_relation_type-fr.json",
]
FIND_FIXTURES = CONTEXT_RECORD_FIXTURES + [
- settings.ROOT_PATH + "../archaeological_finds/fixtures/initial_data-fr.json",
+ LIB_BASE_PATH + "archaeological_finds/fixtures/initial_data-fr.json",
]
FIND_TOWNS_FIXTURES = CONTEXT_RECORD_TOWNS_FIXTURES + [
- settings.ROOT_PATH + "../archaeological_finds/fixtures/initial_data-fr.json",
+ LIB_BASE_PATH + "archaeological_finds/fixtures/initial_data-fr.json",
]
WAREHOUSE_FIXTURES = FIND_FIXTURES + [
- settings.ROOT_PATH + "../archaeological_warehouse/fixtures/initial_data-fr.json",
+ LIB_BASE_PATH + "archaeological_warehouse/fixtures/initial_data-fr.json",
]
@@ -259,7 +259,7 @@ class SearchText:
class CommandsTestCase(TestCase):
- fixtures = [settings.ROOT_PATH + "../ishtar_common/fixtures/test_towns.json"]
+ fixtures = [LIB_BASE_PATH + "ishtar_common/fixtures/test_towns.json"]
def test_clean_ishtar(self):
"""
@@ -282,14 +282,14 @@ class CommandsTestCase(TestCase):
out = StringIO()
call_command(
"import_geofla_csv",
- settings.ROOT_PATH + "../ishtar_common/tests/geofla-test.csv",
+ LIB_BASE_PATH + "ishtar_common/tests/geofla-test.csv",
"--quiet",
stdout=out,
)
self.assertEqual(town_nb + 9, models.Town.objects.count())
call_command(
"import_geofla_csv",
- settings.ROOT_PATH + "../ishtar_common/tests/geofla-test.csv",
+ LIB_BASE_PATH + "ishtar_common/tests/geofla-test.csv",
"--quiet",
stdout=out,
)
@@ -333,7 +333,7 @@ class CommandsTestCase(TestCase):
out = StringIO()
call_command(
"import_insee_comm_csv",
- settings.ROOT_PATH + "../ishtar_common/tests/insee-test.csv",
+ LIB_BASE_PATH + "ishtar_common/tests/insee-test.csv",
"--quiet",
stdout=out,
)
@@ -348,7 +348,7 @@ class CommandsTestCase(TestCase):
call_command(
"import_insee_comm_csv",
"--quiet",
- settings.ROOT_PATH + "../ishtar_common/tests/insee-test.csv",
+ LIB_BASE_PATH + "ishtar_common/tests/insee-test.csv",
stdout=out,
)
# no new town
@@ -645,8 +645,8 @@ class WizardTest(object):
class CacheTest(TestCase):
fixtures = [
- settings.ROOT_PATH + "../fixtures/initial_data-auth-fr.json",
- settings.ROOT_PATH + "../ishtar_common/fixtures/initial_data-fr.json",
+ FIXTURE_AUTH_PATH + "fixtures/initial_data-auth-fr.json",
+ LIB_BASE_PATH + "ishtar_common/fixtures/initial_data-fr.json",
]
def test_add(self):
@@ -710,7 +710,7 @@ class CacheTest(TestCase):
class GenericSerializationTest:
def create_document_default(self):
image_path = os.path.join(
- settings.ROOT_PATH, "..", "ishtar_common", "tests", "test.png"
+ LIB_BASE_PATH, "ishtar_common", "tests", "test.png"
)
self.documents = []
for idx in range(12):
@@ -2426,8 +2426,8 @@ class ImportTest(TestCase):
importer_type = models.ImporterType.objects.create(associated_models=imp_model)
dest = os.path.join("media", "MCC-operations-example.csv")
shutil.copy(
- settings.ROOT_PATH
- + "../archaeological_operations/tests/MCC-operations-example.csv",
+ LIB_BASE_PATH
+ + "archaeological_operations/tests/MCC-operations-example.csv",
dest,
)
with open(dest, "rb") as f:
@@ -2523,8 +2523,7 @@ class ImportTest(TestCase):
imp_model = self.create_importer_model()
importer_type = self.create_importer_type(imp_model)
- image_path = os.path.join("..", "ishtar_common", "tests", "test.png")
-
+ image_path = os.path.join(LIB_BASE_PATH, "ishtar_common", "tests", "test.png")
data = {
"name": "Import Zip Not Valid Must Fail",
"importer_type": importer_type.pk,
@@ -2700,8 +2699,8 @@ class ImportTest(TestCase):
class IshtarSiteProfileTest(TestCase):
fixtures = [
- settings.ROOT_PATH + "../fixtures/initial_data-auth-fr.json",
- settings.ROOT_PATH + "../ishtar_common/fixtures/initial_data-fr.json",
+ FIXTURE_AUTH_PATH + "fixtures/initial_data-auth-fr.json",
+ LIB_BASE_PATH + "ishtar_common/fixtures/initial_data-fr.json",
]
def testRelevance(self):
@@ -3570,8 +3569,8 @@ class NewItems(TestCase):
class AccountWizardTest(WizardTest, TestCase):
fixtures = [
- settings.ROOT_PATH + "../fixtures/initial_data-auth-fr.json",
- settings.ROOT_PATH + "../ishtar_common/fixtures/initial_data-fr.json",
+ FIXTURE_AUTH_PATH + "fixtures/initial_data-auth-fr.json",
+ LIB_BASE_PATH + "ishtar_common/fixtures/initial_data-fr.json",
]
url_name = "account_management"
wizard_name = "account_wizard"
@@ -3625,7 +3624,7 @@ class CleanMedia(TestCase):
# another file exists
]
base_dir = os.sep.join(
- [settings.ROOT_PATH, "..", "ishtar_common", "tests", "rename"]
+ [LIB_BASE_PATH, "ishtar_common", "tests", "rename"]
)
for name, expected in test_names:
name = os.sep.join([base_dir, name])
@@ -3645,7 +3644,7 @@ class CleanMedia(TestCase):
),
]
base_dir = os.sep.join(
- [settings.ROOT_PATH, "..", "ishtar_common", "tests", "rename"]
+ [LIB_BASE_PATH, "ishtar_common", "tests", "rename"]
)
for name, expected in test_names:
name = os.sep.join([base_dir, name])
@@ -3700,7 +3699,7 @@ class StorageTest(TestCase):
def test_filesystemstorage(self) -> None:
# bug when link to non-existing files
image_path = os.path.join(
- settings.ROOT_PATH, "..", "ishtar_common", "tests", "test.png"
+ LIB_BASE_PATH, "ishtar_common", "tests", "test.png"
)
doc = models.Document.objects.create(
source_type=self.st1,
@@ -3892,7 +3891,7 @@ class DocumentTest(TestCase):
if not settings.PDFTOPPM_BINARY:
return
pdf_path = os.path.join(
- settings.ROOT_PATH, "..", "ishtar_common", "tests", "simple.pdf"
+ LIB_BASE_PATH, "ishtar_common", "tests", "simple.pdf"
)
doc = models.Document.objects.create(
title="Document",
@@ -4011,7 +4010,7 @@ class TemplateGenerationTest(TestCase):
"complete_idx",
"complete_idxy",
]
- tpl_label = settings.ROOT_PATH + "../ishtar_common/tests/test-filters-label.odt"
+ tpl_label = LIB_BASE_PATH + "ishtar_common/tests/test-filters-label.odt"
BASE_EXPECTED_KEYS = [
"container_index",
"context_record_operation_common_name",
@@ -4023,7 +4022,7 @@ class TemplateGenerationTest(TestCase):
"complete_idx",
"complete_idxy",
]
- tpl_base = settings.ROOT_PATH + "../ishtar_common/tests/test-filters-base.odt"
+ tpl_base = LIB_BASE_PATH + "ishtar_common/tests/test-filters-base.odt"
tests = (
(LABEL_EXPECTED_KEYS, tpl_label, models.DocumentTemplate.LABEL_RE),
(BASE_EXPECTED_KEYS, tpl_base, models.DocumentTemplate.BASE_RE),