fix: refactor per pylint; add to tox
This commit is contained in:
parent
1aa70eba8b
commit
e494bdd2b9
11 changed files with 77 additions and 50 deletions
4
.pylintrc
Normal file
4
.pylintrc
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# -*- mode: conf; -*-
|
||||||
|
|
||||||
|
[MESSAGES CONTROL]
|
||||||
|
disable=fixme
|
|
@ -48,6 +48,9 @@ A "real-time sync" framework is also (eventually) planned, similar to
|
||||||
the one developed in the Rattail Project;
|
the one developed in the Rattail Project;
|
||||||
cf. :doc:`rattail-manual:data/sync/index`.
|
cf. :doc:`rattail-manual:data/sync/index`.
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/badge/linting-pylint-yellowgreen
|
||||||
|
:target: https://github.com/pylint-dev/pylint
|
||||||
|
|
||||||
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||||
:target: https://github.com/psf/black
|
:target: https://github.com/psf/black
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ dependencies = [
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
docs = ["Sphinx", "enum-tools[sphinx]", "furo", "sphinxcontrib-programoutput"]
|
docs = ["Sphinx", "enum-tools[sphinx]", "furo", "sphinxcontrib-programoutput"]
|
||||||
tests = ["pytest-cov", "tox"]
|
tests = ["pylint", "pytest", "pytest-cov", "tox"]
|
||||||
|
|
||||||
|
|
||||||
[project.entry-points."wutta.typer_imports"]
|
[project.entry-points."wutta.typer_imports"]
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
# -*- coding: utf-8; -*-
|
# -*- coding: utf-8; -*-
|
||||||
|
"""
|
||||||
|
Package Version
|
||||||
|
"""
|
||||||
|
|
||||||
from importlib.metadata import version
|
from importlib.metadata import version
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# WuttaSync -- Wutta Framework for data import/export and real-time sync
|
# WuttaSync -- Wutta Framework for data import/export and real-time sync
|
||||||
# Copyright © 2024 Lance Edgar
|
# Copyright © 2024-2025 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Wutta Framework.
|
# This file is part of Wutta Framework.
|
||||||
#
|
#
|
||||||
|
@ -83,7 +83,7 @@ class ImportCommandHandler(GenericHandler):
|
||||||
factory = self.app.load_object(import_handler)
|
factory = self.app.load_object(import_handler)
|
||||||
self.import_handler = factory(self.config)
|
self.import_handler = factory(self.config)
|
||||||
|
|
||||||
def run(self, params, progress=None):
|
def run(self, params, progress=None): # pylint: disable=unused-argument
|
||||||
"""
|
"""
|
||||||
Run the import/export job(s) based on command line params.
|
Run the import/export job(s) based on command line params.
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ class ImportCommandHandler(GenericHandler):
|
||||||
log.debug("params are: %s", kw)
|
log.debug("params are: %s", kw)
|
||||||
self.import_handler.process_data(*models, **kw)
|
self.import_handler.process_data(*models, **kw)
|
||||||
|
|
||||||
def list_models(self, params):
|
def list_models(self, params): # pylint: disable=unused-argument
|
||||||
"""
|
"""
|
||||||
Query the :attr:`import_handler`'s supported target models and
|
Query the :attr:`import_handler`'s supported target models and
|
||||||
print the info to stdout.
|
print the info to stdout.
|
||||||
|
@ -135,7 +135,7 @@ class ImportCommandHandler(GenericHandler):
|
||||||
sys.stdout.write("==============================\n")
|
sys.stdout.write("==============================\n")
|
||||||
|
|
||||||
|
|
||||||
def import_command_template(
|
def import_command_template( # pylint: disable=unused-argument,too-many-arguments,too-many-positional-arguments
|
||||||
models: Annotated[
|
models: Annotated[
|
||||||
Optional[List[str]],
|
Optional[List[str]],
|
||||||
typer.Argument(
|
typer.Argument(
|
||||||
|
@ -270,7 +270,7 @@ def import_command(fn):
|
||||||
return makefun.create_function(final_sig, fn)
|
return makefun.create_function(final_sig, fn)
|
||||||
|
|
||||||
|
|
||||||
def file_import_command_template(
|
def file_import_command_template( # pylint: disable=unused-argument
|
||||||
input_file_path: Annotated[
|
input_file_path: Annotated[
|
||||||
Path,
|
Path,
|
||||||
typer.Option(
|
typer.Option(
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# WuttaSync -- Wutta Framework for data import/export and real-time sync
|
# WuttaSync -- Wutta Framework for data import/export and real-time sync
|
||||||
# Copyright © 2024 Lance Edgar
|
# Copyright © 2024-2025 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Wutta Framework.
|
# This file is part of Wutta Framework.
|
||||||
#
|
#
|
||||||
|
@ -24,8 +24,6 @@
|
||||||
See also: :ref:`wutta-import-csv`
|
See also: :ref:`wutta-import-csv`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
import typer
|
import typer
|
||||||
|
|
||||||
from wuttjamaican.cli import wutta_typer
|
from wuttjamaican.cli import wutta_typer
|
||||||
|
@ -35,7 +33,7 @@ from .base import file_import_command, ImportCommandHandler
|
||||||
|
|
||||||
@wutta_typer.command()
|
@wutta_typer.command()
|
||||||
@file_import_command
|
@file_import_command
|
||||||
def import_csv(ctx: typer.Context, **kwargs):
|
def import_csv(ctx: typer.Context, **kwargs): # pylint: disable=unused-argument
|
||||||
"""
|
"""
|
||||||
Import data from CSV file(s) to Wutta DB
|
Import data from CSV file(s) to Wutta DB
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# WuttaSync -- Wutta Framework for data import/export and real-time sync
|
# WuttaSync -- Wutta Framework for data import/export and real-time sync
|
||||||
# Copyright © 2024 Lance Edgar
|
# Copyright © 2024-2025 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Wutta Framework.
|
# This file is part of Wutta Framework.
|
||||||
#
|
#
|
||||||
|
@ -23,6 +23,7 @@
|
||||||
"""
|
"""
|
||||||
Data Importer base class
|
Data Importer base class
|
||||||
"""
|
"""
|
||||||
|
# pylint: disable=too-many-lines
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
@ -44,7 +45,7 @@ class ImportLimitReached(Exception):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class Importer:
|
class Importer: # pylint: disable=too-many-instance-attributes,too-many-public-methods
|
||||||
"""
|
"""
|
||||||
Base class for all data importers / exporters.
|
Base class for all data importers / exporters.
|
||||||
|
|
||||||
|
@ -187,7 +188,7 @@ class Importer:
|
||||||
max_delete = None
|
max_delete = None
|
||||||
max_total = None
|
max_total = None
|
||||||
|
|
||||||
def __init__(self, config, **kwargs):
|
def __init__(self, config, handler=None, model_class=None, **kwargs):
|
||||||
self.config = config
|
self.config = config
|
||||||
self.app = self.config.get_app()
|
self.app = self.config.get_app()
|
||||||
|
|
||||||
|
@ -201,6 +202,8 @@ class Importer:
|
||||||
"delete", kwargs.pop("allow_delete", self.allow_delete)
|
"delete", kwargs.pop("allow_delete", self.allow_delete)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.handler = handler
|
||||||
|
self.model_class = model_class
|
||||||
self.__dict__.update(kwargs)
|
self.__dict__.update(kwargs)
|
||||||
|
|
||||||
self.fields = self.get_fields()
|
self.fields = self.get_fields()
|
||||||
|
@ -324,15 +327,15 @@ class Importer:
|
||||||
"""
|
"""
|
||||||
keys = None
|
keys = None
|
||||||
# nb. prefer 'keys' but use 'key' as fallback
|
# nb. prefer 'keys' but use 'key' as fallback
|
||||||
if hasattr(self, "keys"):
|
if "keys" in self.__dict__:
|
||||||
keys = self.keys
|
keys = self.__dict__["keys"]
|
||||||
elif hasattr(self, "key"):
|
elif "key" in self.__dict__:
|
||||||
keys = self.key
|
keys = self.__dict__["key"]
|
||||||
if keys:
|
if keys:
|
||||||
if isinstance(keys, str):
|
if isinstance(keys, str):
|
||||||
keys = self.config.parse_list(keys)
|
keys = self.config.parse_list(keys)
|
||||||
# nb. save for next time
|
# nb. save for next time
|
||||||
self.keys = keys
|
self.__dict__["keys"] = keys
|
||||||
return keys
|
return keys
|
||||||
|
|
||||||
return list(get_primary_keys(self.model_class))
|
return list(get_primary_keys(self.model_class))
|
||||||
|
@ -470,7 +473,7 @@ class Importer:
|
||||||
# cache the set of fields to use for diff checks
|
# cache the set of fields to use for diff checks
|
||||||
fields = set(self.get_fields()) - set(self.get_keys())
|
fields = set(self.get_fields()) - set(self.get_keys())
|
||||||
|
|
||||||
def create_update(source_data, i):
|
def create_update(source_data, i): # pylint: disable=unused-argument
|
||||||
|
|
||||||
# try to fetch target object per source key
|
# try to fetch target object per source key
|
||||||
key = self.get_record_key(source_data)
|
key = self.get_record_key(source_data)
|
||||||
|
@ -501,7 +504,7 @@ class Importer:
|
||||||
self.max_update,
|
self.max_update,
|
||||||
)
|
)
|
||||||
raise ImportLimitReached()
|
raise ImportLimitReached()
|
||||||
elif (
|
if (
|
||||||
self.max_total
|
self.max_total
|
||||||
and (len(created) + len(updated)) >= self.max_total
|
and (len(created) + len(updated)) >= self.max_total
|
||||||
):
|
):
|
||||||
|
@ -532,7 +535,7 @@ class Importer:
|
||||||
self.max_create,
|
self.max_create,
|
||||||
)
|
)
|
||||||
raise ImportLimitReached()
|
raise ImportLimitReached()
|
||||||
elif (
|
if (
|
||||||
self.max_total
|
self.max_total
|
||||||
and (len(created) + len(updated)) >= self.max_total
|
and (len(created) + len(updated)) >= self.max_total
|
||||||
):
|
):
|
||||||
|
@ -598,7 +601,7 @@ class Importer:
|
||||||
deletable = self.get_deletable_keys() - source_keys
|
deletable = self.get_deletable_keys() - source_keys
|
||||||
log.debug("found %s records to delete", len(deletable))
|
log.debug("found %s records to delete", len(deletable))
|
||||||
|
|
||||||
def delete(key, i):
|
def delete(key, i): # pylint: disable=unused-argument
|
||||||
cached = self.cached_target.pop(key)
|
cached = self.cached_target.pop(key)
|
||||||
obj = cached["object"]
|
obj = cached["object"]
|
||||||
|
|
||||||
|
@ -614,7 +617,7 @@ class Importer:
|
||||||
self.max_delete,
|
self.max_delete,
|
||||||
)
|
)
|
||||||
raise ImportLimitReached()
|
raise ImportLimitReached()
|
||||||
elif self.max_total and (changes + len(deleted)) >= self.max_total:
|
if self.max_total and (changes + len(deleted)) >= self.max_total:
|
||||||
log.warning(
|
log.warning(
|
||||||
"max of %s *total changes* has been reached; stopping now",
|
"max of %s *total changes* has been reached; stopping now",
|
||||||
self.max_total,
|
self.max_total,
|
||||||
|
@ -711,7 +714,7 @@ class Importer:
|
||||||
source_objects = self.get_source_objects()
|
source_objects = self.get_source_objects()
|
||||||
normalized = []
|
normalized = []
|
||||||
|
|
||||||
def normalize(obj, i):
|
def normalize(obj, i): # pylint: disable=unused-argument
|
||||||
data = self.normalize_source_object_all(obj)
|
data = self.normalize_source_object_all(obj)
|
||||||
if data:
|
if data:
|
||||||
normalized.extend(data)
|
normalized.extend(data)
|
||||||
|
@ -805,6 +808,7 @@ class Importer:
|
||||||
data = self.normalize_source_object(obj)
|
data = self.normalize_source_object(obj)
|
||||||
if data:
|
if data:
|
||||||
return [data]
|
return [data]
|
||||||
|
return None
|
||||||
|
|
||||||
def normalize_source_object(self, obj):
|
def normalize_source_object(self, obj):
|
||||||
"""
|
"""
|
||||||
|
@ -865,7 +869,7 @@ class Importer:
|
||||||
objects = self.get_target_objects(source_data=source_data)
|
objects = self.get_target_objects(source_data=source_data)
|
||||||
cached = {}
|
cached = {}
|
||||||
|
|
||||||
def cache(obj, i):
|
def cache(obj, i): # pylint: disable=unused-argument
|
||||||
data = self.normalize_target_object(obj)
|
data = self.normalize_target_object(obj)
|
||||||
if data:
|
if data:
|
||||||
key = self.get_record_key(data)
|
key = self.get_record_key(data)
|
||||||
|
@ -921,6 +925,7 @@ class Importer:
|
||||||
if self.caches_target and self.cached_target is not None:
|
if self.caches_target and self.cached_target is not None:
|
||||||
cached = self.cached_target.get(key)
|
cached = self.cached_target.get(key)
|
||||||
return cached["object"] if cached else None
|
return cached["object"] if cached else None
|
||||||
|
return None
|
||||||
|
|
||||||
def normalize_target_object(self, obj):
|
def normalize_target_object(self, obj):
|
||||||
"""
|
"""
|
||||||
|
@ -945,7 +950,7 @@ class Importer:
|
||||||
"""
|
"""
|
||||||
fields = self.get_fields()
|
fields = self.get_fields()
|
||||||
fields = [f for f in self.get_simple_fields() if f in fields]
|
fields = [f for f in self.get_simple_fields() if f in fields]
|
||||||
data = dict([(field, getattr(obj, field)) for field in fields])
|
data = {field: getattr(obj, field) for field in fields}
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def get_deletable_keys(self, progress=None):
|
def get_deletable_keys(self, progress=None):
|
||||||
|
@ -970,7 +975,7 @@ class Importer:
|
||||||
|
|
||||||
keys = set()
|
keys = set()
|
||||||
|
|
||||||
def check(key, i):
|
def check(key, i): # pylint: disable=unused-argument
|
||||||
data = self.cached_target[key]["data"]
|
data = self.cached_target[key]["data"]
|
||||||
obj = self.cached_target[key]["object"]
|
obj = self.cached_target[key]["object"]
|
||||||
if self.can_delete_object(obj, data):
|
if self.can_delete_object(obj, data):
|
||||||
|
@ -1000,11 +1005,12 @@ class Importer:
|
||||||
:returns: New object for the target side, or ``None``.
|
:returns: New object for the target side, or ``None``.
|
||||||
"""
|
"""
|
||||||
if source_data.get("__ignoreme__"):
|
if source_data.get("__ignoreme__"):
|
||||||
return
|
return None
|
||||||
|
|
||||||
obj = self.make_empty_object(key)
|
obj = self.make_empty_object(key)
|
||||||
if obj:
|
if obj:
|
||||||
return self.update_target_object(obj, source_data)
|
return self.update_target_object(obj, source_data)
|
||||||
|
return None
|
||||||
|
|
||||||
def make_empty_object(self, key):
|
def make_empty_object(self, key):
|
||||||
"""
|
"""
|
||||||
|
@ -1072,11 +1078,11 @@ class Importer:
|
||||||
# object key(s) should already be populated
|
# object key(s) should already be populated
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# elif field not in source_data:
|
# if field not in source_data:
|
||||||
# # no source data for field
|
# # no source data for field
|
||||||
# continue
|
# continue
|
||||||
|
|
||||||
elif field in fields:
|
if field in fields:
|
||||||
|
|
||||||
# field is eligible for update generally, so compare
|
# field is eligible for update generally, so compare
|
||||||
# values between records
|
# values between records
|
||||||
|
@ -1091,7 +1097,7 @@ class Importer:
|
||||||
|
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
def can_delete_object(self, obj, data=None):
|
def can_delete_object(self, obj, data=None): # pylint: disable=unused-argument
|
||||||
"""
|
"""
|
||||||
Should return true or false indicating whether the given
|
Should return true or false indicating whether the given
|
||||||
object "can" be deleted. Default is to return true in all
|
object "can" be deleted. Default is to return true in all
|
||||||
|
@ -1110,7 +1116,7 @@ class Importer:
|
||||||
"""
|
"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def delete_target_object(self, obj):
|
def delete_target_object(self, obj): # pylint: disable=unused-argument
|
||||||
"""
|
"""
|
||||||
Delete the given raw object from the target side, and return
|
Delete the given raw object from the target side, and return
|
||||||
true if successful.
|
true if successful.
|
||||||
|
@ -1174,6 +1180,8 @@ class FromFile(Importer):
|
||||||
:meth:`close_input_file()`.
|
:meth:`close_input_file()`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
input_file = None
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
"""
|
"""
|
||||||
Open the input file. See also :meth:`open_input_file()`.
|
Open the input file. See also :meth:`open_input_file()`.
|
||||||
|
@ -1267,6 +1275,8 @@ class ToSqlalchemy(Importer):
|
||||||
caches_target = True
|
caches_target = True
|
||||||
"" # nb. suppress sphinx docs
|
"" # nb. suppress sphinx docs
|
||||||
|
|
||||||
|
target_session = None
|
||||||
|
|
||||||
def get_target_object(self, key):
|
def get_target_object(self, key):
|
||||||
"""
|
"""
|
||||||
Tries to fetch the object from target DB using ORM query.
|
Tries to fetch the object from target DB using ORM query.
|
||||||
|
@ -1282,7 +1292,7 @@ class ToSqlalchemy(Importer):
|
||||||
try:
|
try:
|
||||||
return query.one()
|
return query.one()
|
||||||
except orm.exc.NoResultFound:
|
except orm.exc.NoResultFound:
|
||||||
pass
|
return None
|
||||||
|
|
||||||
def get_target_objects(self, source_data=None, progress=None):
|
def get_target_objects(self, source_data=None, progress=None):
|
||||||
"""
|
"""
|
||||||
|
@ -1292,7 +1302,7 @@ class ToSqlalchemy(Importer):
|
||||||
query = self.get_target_query(source_data=source_data)
|
query = self.get_target_query(source_data=source_data)
|
||||||
return query.all()
|
return query.all()
|
||||||
|
|
||||||
def get_target_query(self, source_data=None):
|
def get_target_query(self, source_data=None): # pylint: disable=unused-argument
|
||||||
"""
|
"""
|
||||||
Returns an ORM query suitable to fetch existing objects from
|
Returns an ORM query suitable to fetch existing objects from
|
||||||
the target side. This is called from
|
the target side. This is called from
|
||||||
|
@ -1300,7 +1310,7 @@ class ToSqlalchemy(Importer):
|
||||||
"""
|
"""
|
||||||
return self.target_session.query(self.model_class)
|
return self.target_session.query(self.model_class)
|
||||||
|
|
||||||
def create_target_object(self, key, source_data):
|
def create_target_object(self, key, source_data): # pylint: disable=empty-docstring
|
||||||
""" """
|
""" """
|
||||||
with self.target_session.no_autoflush:
|
with self.target_session.no_autoflush:
|
||||||
obj = super().create_target_object(key, source_data)
|
obj = super().create_target_object(key, source_data)
|
||||||
|
@ -1308,8 +1318,9 @@ class ToSqlalchemy(Importer):
|
||||||
# nb. add new object to target db session
|
# nb. add new object to target db session
|
||||||
self.target_session.add(obj)
|
self.target_session.add(obj)
|
||||||
return obj
|
return obj
|
||||||
|
return None
|
||||||
|
|
||||||
def delete_target_object(self, obj):
|
def delete_target_object(self, obj): # pylint: disable=empty-docstring
|
||||||
""" """
|
""" """
|
||||||
self.target_session.delete(obj)
|
self.target_session.delete(obj)
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# WuttaSync -- Wutta Framework for data import/export and real-time sync
|
# WuttaSync -- Wutta Framework for data import/export and real-time sync
|
||||||
# Copyright © 2024 Lance Edgar
|
# Copyright © 2024-2025 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Wutta Framework.
|
# This file is part of Wutta Framework.
|
||||||
#
|
#
|
||||||
|
@ -42,7 +42,7 @@ from .model import ToWutta
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class FromCsv(FromFile):
|
class FromCsv(FromFile): # pylint: disable=abstract-method
|
||||||
"""
|
"""
|
||||||
Base class for importer/exporter using CSV file as data source.
|
Base class for importer/exporter using CSV file as data source.
|
||||||
|
|
||||||
|
@ -61,6 +61,8 @@ class FromCsv(FromFile):
|
||||||
:class:`python:csv.DictReader` instance.
|
:class:`python:csv.DictReader` instance.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
input_reader = None
|
||||||
|
|
||||||
csv_encoding = "utf_8"
|
csv_encoding = "utf_8"
|
||||||
"""
|
"""
|
||||||
Encoding used by the CSV input file.
|
Encoding used by the CSV input file.
|
||||||
|
@ -104,7 +106,9 @@ class FromCsv(FromFile):
|
||||||
"""
|
"""
|
||||||
path = self.get_input_file_path()
|
path = self.get_input_file_path()
|
||||||
log.debug("opening input file: %s", path)
|
log.debug("opening input file: %s", path)
|
||||||
self.input_file = open(path, "rt", encoding=self.csv_encoding)
|
self.input_file = open( # pylint: disable=consider-using-with
|
||||||
|
path, "rt", encoding=self.csv_encoding
|
||||||
|
)
|
||||||
self.input_reader = csv.DictReader(self.input_file)
|
self.input_reader = csv.DictReader(self.input_file)
|
||||||
|
|
||||||
# nb. importer may have all supported fields by default, so
|
# nb. importer may have all supported fields by default, so
|
||||||
|
@ -118,7 +122,7 @@ class FromCsv(FromFile):
|
||||||
self.input_file.close()
|
self.input_file.close()
|
||||||
raise ValueError("input file has no recognized fields")
|
raise ValueError("input file has no recognized fields")
|
||||||
|
|
||||||
def close_input_file(self):
|
def close_input_file(self): # pylint: disable=empty-docstring
|
||||||
""" """
|
""" """
|
||||||
self.input_file.close()
|
self.input_file.close()
|
||||||
del self.input_reader
|
del self.input_reader
|
||||||
|
@ -136,7 +140,7 @@ class FromCsv(FromFile):
|
||||||
return list(self.input_reader)
|
return list(self.input_reader)
|
||||||
|
|
||||||
|
|
||||||
class FromCsvToSqlalchemyMixin:
|
class FromCsvToSqlalchemyMixin: # pylint: disable=too-few-public-methods
|
||||||
"""
|
"""
|
||||||
Mixin class for CSV → SQLAlchemy ORM :term:`importers <importer>`.
|
Mixin class for CSV → SQLAlchemy ORM :term:`importers <importer>`.
|
||||||
|
|
||||||
|
@ -161,7 +165,7 @@ class FromCsvToSqlalchemyMixin:
|
||||||
if isinstance(attr.prop.columns[0].type, UUID):
|
if isinstance(attr.prop.columns[0].type, UUID):
|
||||||
self.uuid_keys.append(field)
|
self.uuid_keys.append(field)
|
||||||
|
|
||||||
def normalize_source_object(self, obj):
|
def normalize_source_object(self, obj): # pylint: disable=empty-docstring
|
||||||
""" """
|
""" """
|
||||||
data = dict(obj)
|
data = dict(obj)
|
||||||
|
|
||||||
|
@ -292,6 +296,6 @@ class FromCsvToWutta(FromCsvToSqlalchemyHandlerMixin, FromFileHandler, ToWuttaHa
|
||||||
|
|
||||||
ToImporterBase = ToWutta
|
ToImporterBase = ToWutta
|
||||||
|
|
||||||
def get_target_model(self):
|
def get_target_model(self): # pylint: disable=empty-docstring
|
||||||
""" """
|
""" """
|
||||||
return self.app.model
|
return self.app.model
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# WuttaSync -- Wutta Framework for data import/export and real-time sync
|
# WuttaSync -- Wutta Framework for data import/export and real-time sync
|
||||||
# Copyright © 2024 Lance Edgar
|
# Copyright © 2024-2025 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Wutta Framework.
|
# This file is part of Wutta Framework.
|
||||||
#
|
#
|
||||||
|
@ -275,7 +275,7 @@ class ImportHandler(GenericHandler):
|
||||||
)
|
)
|
||||||
|
|
||||||
except:
|
except:
|
||||||
# TODO: what should happen here?
|
log.exception("what should happen here?") # TODO
|
||||||
raise
|
raise
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
@ -497,7 +497,7 @@ class ImportHandler(GenericHandler):
|
||||||
factory = self.importers[key]
|
factory = self.importers[key]
|
||||||
return factory(self.config, **kwargs)
|
return factory(self.config, **kwargs)
|
||||||
|
|
||||||
def get_importer_kwargs(self, key, **kwargs):
|
def get_importer_kwargs(self, key, **kwargs): # pylint: disable=unused-argument
|
||||||
"""
|
"""
|
||||||
Returns a dict of kwargs to be used when construcing an
|
Returns a dict of kwargs to be used when construcing an
|
||||||
importer/exporter with the given key. This is normally called
|
importer/exporter with the given key. This is normally called
|
||||||
|
@ -522,7 +522,7 @@ class FromFileHandler(ImportHandler):
|
||||||
logic.
|
logic.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def process_data(self, *keys, **kwargs):
|
def process_data(self, *keys, **kwargs): # pylint: disable=empty-docstring
|
||||||
""" """
|
""" """
|
||||||
|
|
||||||
# interpret file vs. folder path
|
# interpret file vs. folder path
|
||||||
|
@ -586,7 +586,7 @@ class ToSqlalchemyHandler(ImportHandler):
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def get_importer_kwargs(self, key, **kwargs):
|
def get_importer_kwargs(self, key, **kwargs): # pylint: disable=empty-docstring
|
||||||
""" """
|
""" """
|
||||||
kwargs = super().get_importer_kwargs(key, **kwargs)
|
kwargs = super().get_importer_kwargs(key, **kwargs)
|
||||||
kwargs.setdefault("target_session", self.target_session)
|
kwargs.setdefault("target_session", self.target_session)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# WuttaSync -- Wutta Framework for data import/export and real-time sync
|
# WuttaSync -- Wutta Framework for data import/export and real-time sync
|
||||||
# Copyright © 2024 Lance Edgar
|
# Copyright © 2024-2025 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Wutta Framework.
|
# This file is part of Wutta Framework.
|
||||||
#
|
#
|
||||||
|
@ -36,7 +36,7 @@ class ToWuttaHandler(ToSqlalchemyHandler):
|
||||||
target_key = "wutta"
|
target_key = "wutta"
|
||||||
"" # nb. suppress docs
|
"" # nb. suppress docs
|
||||||
|
|
||||||
def get_target_title(self):
|
def get_target_title(self): # pylint: disable=empty-docstring
|
||||||
""" """
|
""" """
|
||||||
# nb. we override parent to use app title as default
|
# nb. we override parent to use app title as default
|
||||||
if hasattr(self, "target_title"):
|
if hasattr(self, "target_title"):
|
||||||
|
|
4
tox.ini
4
tox.ini
|
@ -6,6 +6,10 @@ envlist = py38, py39, py310, py311
|
||||||
extras = tests
|
extras = tests
|
||||||
commands = pytest {posargs}
|
commands = pytest {posargs}
|
||||||
|
|
||||||
|
[testenv:pylint]
|
||||||
|
basepython = python3.11
|
||||||
|
commands = pylint wuttasync
|
||||||
|
|
||||||
[testenv:coverage]
|
[testenv:coverage]
|
||||||
basepython = python3.11
|
basepython = python3.11
|
||||||
commands = pytest --cov=wuttasync --cov-report=html --cov-fail-under=100
|
commands = pytest --cov=wuttasync --cov-report=html --cov-fail-under=100
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue