Source code for wuttasync.exporting.base

# -*- coding: utf-8; -*-
################################################################################
#
#  WuttaSync -- Wutta Framework for data import/export and real-time sync
#  Copyright © 2024-2026 Lance Edgar
#
#  This file is part of Wutta Framework.
#
#  Wutta Framework is free software: you can redistribute it and/or modify it
#  under the terms of the GNU General Public License as published by the Free
#  Software Foundation, either version 3 of the License, or (at your option) any
#  later version.
#
#  Wutta Framework is distributed in the hope that it will be useful, but
#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
#  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
#  more details.
#
#  You should have received a copy of the GNU General Public License along with
#  Wutta Framework.  If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Data exporter base classes
"""

import os

from wuttasync.importing import Importer


[docs] class ToFile(Importer): """ Base class for importer/exporter using output file as data target. Depending on the subclass, it may be able to "guess" (at least partially) the path to the output file. If not, and/or to avoid ambiguity, the caller must specify the file path. In most cases caller may specify any of these via kwarg to the class constructor, or e.g. :meth:`~wuttasync.importing.handlers.ImportHandler.process_data()`: * :attr:`output_file_path` * :attr:`output_file_name` The subclass itself can also specify via override of these methods: * :meth:`get_output_file_path()` * :meth:`get_output_file_name()` And of course subclass must override these too: * :meth:`open_output_file()` * :meth:`close_output_file()` * (and see also :attr:`output_file`) """ output_file_path = None """ Path to output folder, or file. The ideal usage is to set this to the output *folder* path. That allows the handler to run several importers in one go. The same output folder path is given to each importer; they then each determine their own output filename within that. But you can also set this to the full output folder + file path, e.g. if you're just running one importer. This would override the importer's own logic for determining output filename. See also :meth:`get_output_file_path()` and :meth:`get_output_file_name()`. """ output_file_name = None """ Optional static output file name (sans folder path). If set, this will be used as output filename instead of the importer determining one on its own. See also :meth:`get_output_file_name()`. """ output_file = None """ Handle to the open output file, if applicable. May be set by :meth:`open_output_file()` for later reference within :meth:`close_output_file()`. """
[docs] def setup(self): """ Open the output file. See also :meth:`open_output_file()`. """ if not self.dry_run: self.open_output_file()
[docs] def teardown(self): """ Close the output file. See also :meth:`close_output_file()`. """ if not self.dry_run: self.close_output_file()
[docs] def get_output_file_path(self): """ This must return the full path to output file. Default logic inspects :attr:`output_file_path`; if that points to a folder then it is combined with :meth:`get_output_file_name()`. Otherwise it's returned as-is. :returns: Path to output file, as string """ path = self.output_file_path if not path: raise ValueError("must set output_file_path") if os.path.isdir(path): filename = self.get_output_file_name() return os.path.join(path, filename) return path
[docs] def get_output_file_name(self): """ This must return the output filename, sans folder path. Default logic will return :attr:`output_file_name` if set, otherwise raise error. :returns: Output filename, sans folder path """ if self.output_file_name: return self.output_file_name raise NotImplementedError("can't guess output filename")
[docs] def open_output_file(self): """ Open the output file for writing target data. Subclass must override to specify how this happens; default logic is not implemented. Remember to set :attr:`output_file` if applicable for reference when closing. See also :attr:`get_output_file_path()` and :meth:`close_output_file()`. """ raise NotImplementedError
[docs] def close_output_file(self): """ Close the output file for target data. Subclass must override to specify how this happens; default logic blindly calls the ``close()`` method on whatever :attr:`output_file` happens to point to. See also :attr:`open_output_file()`. """ self.output_file.close()