feat: add concept of (non-)default importers for handler

i.e. when telling handler to "import all" which should be included
vs. excluded by default?
This commit is contained in:
Lance Edgar 2026-03-17 18:24:42 -05:00
parent ae282ab468
commit d7d0768a9c
7 changed files with 148 additions and 15 deletions

View file

@ -177,7 +177,7 @@ class ImportCommandHandler(GenericHandler):
# sort out which models to process
models = kw.pop("models", None)
if not models:
models = list(self.import_handler.importers)
models = self.import_handler.get_default_importer_keys()
log.debug(
"%s %s for models: %s",
self.import_handler.actioning,
@ -196,13 +196,31 @@ class ImportCommandHandler(GenericHandler):
This is what happens when command line has ``--list-models``.
"""
sys.stdout.write("\nALL MODELS:\n")
sys.stdout.write("==============================\n")
for key in self.import_handler.importers:
sys.stdout.write(key)
all_keys = list(self.import_handler.importers)
default_keys = [k for k in all_keys if self.import_handler.is_default(k)]
extra_keys = [k for k in all_keys if k not in default_keys]
sys.stdout.write("\n")
sys.stdout.write("==============================\n")
sys.stdout.write(f"for {self.import_handler.get_title()}\n\n")
sys.stdout.write(" DEFAULT MODELS:\n")
sys.stdout.write("==============================\n")
if default_keys:
for key in default_keys:
sys.stdout.write(f"{key}\n")
else:
sys.stdout.write("(none)\n")
sys.stdout.write("==============================\n")
sys.stdout.write(" EXTRA MODELS:\n")
sys.stdout.write("==============================\n")
if extra_keys:
for key in extra_keys:
sys.stdout.write(f"{key}\n")
else:
sys.stdout.write("(none)\n")
sys.stdout.write("==============================\n")
sys.stdout.write(f" for {self.import_handler.get_title()}\n\n")
def import_command_template( # pylint: disable=unused-argument,too-many-arguments,too-many-positional-arguments,too-many-locals

View file

@ -150,6 +150,14 @@ class ImportExportWarning(EmailSetting):
}
class export_to_wutta_from_wutta_warning( # pylint: disable=invalid-name
ImportExportWarning
):
"""
Diff warning for Wutta Wutta export.
"""
class import_to_versions_from_wutta_warning( # pylint: disable=invalid-name
ImportExportWarning
):

View file

@ -371,7 +371,7 @@ class ImportHandler( # pylint: disable=too-many-public-methods,too-many-instanc
changes = OrderedDict()
if not keys:
keys = list(self.importers)
keys = self.get_default_importer_keys()
success = False
try:
@ -655,6 +655,36 @@ class ImportHandler( # pylint: disable=too-many-public-methods,too-many-instanc
"""
return kwargs
def is_default(self, key):
"""
Return a boolean indicating whether the importer corresponding
to ``key`` should be considered "default" - i.e. included as
part of a typical "import all" job.
The default logic here returns ``True`` in all cases; subclass can
override as needed.
:param key: Key indicating the importer.
:rtype: bool
"""
return True
def get_default_importer_keys(self):
"""
Return the list of importer keys which should be considered
"default" - i.e. which should be included as part of a typical
"import all" job.
This inspects :attr:`importers` and calls :meth:`is_default()`
for each, to determine the result.
:returns: List of importer keys (strings).
"""
keys = list(self.importers)
keys = [k for k in keys if self.is_default(k)]
return keys
def process_changes(self, changes):
"""
Run post-processing operations on the given changes, if

View file

@ -126,6 +126,22 @@ class FromWuttaToWuttaBase(FromWuttaHandler, ToWuttaHandler):
},
)
def is_default(self, key):
""" """
special = [
"Setting",
"Role",
"Permission",
"User",
"UserRole",
"UserAPIToken",
"Upgrade",
]
if key in special:
return False
return True
class FromWuttaToWuttaImport(FromWuttaToWuttaBase):
"""

View file

@ -3,7 +3,7 @@
import inspect
import sys
from unittest import TestCase
from unittest.mock import patch, Mock
from unittest.mock import patch, Mock, call
from wuttasync.cli import base as mod
from wuttjamaican.testing import DataTestCase
@ -169,22 +169,60 @@ class TestImportCommandHandler(DataTestCase):
params={},
),
)
# self.assertRaises(FileNotFoundError, handler.run, ctx)
handler.run(ctx)
exit_.assert_not_called()
def test_list_models(self):
# CSV -> Wutta (all importers are default)
handler = self.make_handler(
import_handler="wuttasync.importing.csv:FromCsvToWutta"
)
with patch.object(mod, "sys") as sys:
handler.list_models({})
# just test a few random things we expect to see
self.assertTrue(sys.stdout.write.has_call("ALL MODELS:\n"))
self.assertTrue(sys.stdout.write.has_call("Person"))
self.assertTrue(sys.stdout.write.has_call("User"))
self.assertTrue(sys.stdout.write.has_call("Upgrade"))
sys.stdout.write.assert_has_calls(
[
call("==============================\n"),
call(" EXTRA MODELS:\n"),
call("==============================\n"),
call("(none)\n"),
call("==============================\n"),
]
)
# Wutta -> Wutta (only Person importer is default)
handler = self.make_handler(
import_handler="wuttasync.importing.wutta:FromWuttaToWuttaImport"
)
with patch.object(mod, "sys") as sys:
handler.list_models({})
sys.stdout.write.assert_has_calls(
[
call("==============================\n"),
call(" DEFAULT MODELS:\n"),
call("==============================\n"),
call("Person\n"),
call("==============================\n"),
call(" EXTRA MODELS:\n"),
call("==============================\n"),
]
)
# again, but pretend there are no default importers
with patch.object(handler.import_handler, "is_default", return_value=False):
with patch.object(mod, "sys") as sys:
handler.list_models({})
sys.stdout.write.assert_has_calls(
[
call("==============================\n"),
call(" DEFAULT MODELS:\n"),
call("==============================\n"),
call("(none)\n"),
call("==============================\n"),
call(" EXTRA MODELS:\n"),
call("==============================\n"),
]
)
class TestImporterCommand(TestCase):

View file

@ -7,6 +7,7 @@ from uuid import UUID
from wuttjamaican.testing import DataTestCase
from wuttasync.importing import handlers as mod, Importer, ToSqlalchemy
from wuttasync.importing.wutta import FromWuttaToWuttaImport
class FromFooToBar(mod.ImportHandler):
@ -253,6 +254,25 @@ class TestImportHandler(DataTestCase):
KeyError, handler.get_importer, "BunchOfNonsense", model_class=model.Setting
)
def test_is_default(self):
handler = self.make_handler()
# nb. anything is considered default, by default
self.assertTrue(handler.is_default("there_is_no_way_this_is_valid"))
def test_get_default_importer_keys(self):
# use handler which already has some non/default keys
handler = FromWuttaToWuttaImport(self.config)
# it supports many importers
self.assertIn("Person", handler.importers)
self.assertIn("User", handler.importers)
self.assertIn("Setting", handler.importers)
# but only Person is default
keys = handler.get_default_importer_keys()
self.assertEqual(keys, ["Person"])
def test_get_warnings_email_key(self):
handler = FromFooToBar(self.config)

View file

@ -85,6 +85,9 @@ class TestEmailSettings(ImportExportWarningTestCase):
return config
def test_export_to_wutta_from_wutta_warning(self):
self.do_test_preview("export_to_wutta_from_wutta_warning")
def test_import_to_versions_from_wutta_warning(self):
self.do_test_preview("import_to_versions_from_wutta_warning")