Source code for kedro.extras.datasets.text.text_dataset

# Copyright 2020 QuantumBlack Visual Analytics Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
# NONINFRINGEMENT. IN NO EVENT WILL THE LICENSOR OR OTHER CONTRIBUTORS
# BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# The QuantumBlack Visual Analytics Limited ("QuantumBlack") name and logo
# (either separately or in combination, "QuantumBlack Trademarks") are
# trademarks of QuantumBlack. The License does not grant you any right or
# license to the QuantumBlack Trademarks. You may not use the QuantumBlack
# Trademarks or any confusingly similar mark as a trademark for your product,
#     or use the QuantumBlack Trademarks in any other manner that might cause
# confusion in the marketplace, including but not limited to in advertising,
# on websites, or on software.
#
# See the License for the specific language governing permissions and
# limitations under the License.

"""``TextDataSet`` loads/saves data from/to a text file using an underlying
filesystem (e.g.: local, S3, GCS).
"""
from copy import deepcopy
from pathlib import PurePosixPath
from typing import Any, Dict

import fsspec

from kedro.io.core import (
    AbstractVersionedDataSet,
    DataSetError,
    Version,
    get_filepath_str,
    get_protocol_and_path,
)


[docs]class TextDataSet(AbstractVersionedDataSet): """``TextDataSet`` loads/saves data from/to a text file using an underlying filesystem (e.g.: local, S3, GCS) Example: :: >>> from kedro.extras.datasets.text import TextDataSet >>> >>> string_to_write = "This will go in a file." >>> >>> # data_set = TextDataSet(filepath="gcs://bucket/test.md") >>> data_set = TextDataSet(filepath="test.md") >>> data_set.save(string_to_write) >>> reloaded = data_set.load() >>> assert string_to_write == reloaded """ DEFAULT_LOAD_ARGS = {"mode": "r"} # type: Dict[str, Any] DEFAULT_SAVE_ARGS = {"mode": "w"} # type: Dict[str, Any] # pylint: disable=too-many-arguments
[docs] def __init__( self, filepath: str, load_args: Dict[str, Any] = None, save_args: Dict[str, Any] = None, version: Version = None, credentials: Dict[str, Any] = None, fs_args: Dict[str, Any] = None, layer: str = None, ) -> None: """Creates a new instance of ``TextDataSet`` pointing to a concrete text file on a specific filesystem. Args: filepath: Filepath to a text file prefixed with a protocol like `s3://`. If prefix is not provided, `file` protocol (local filesystem) will be used. The prefix should be any protocol supported by ``fsspec``. Note: `http(s)` doesn't support versioning. load_args: Load arguments should be specified in accordance with the open function of the underlying filesystem. E.g. for local file https://docs.python.org/3/library/functions.html#open save_args: Save arguments should be specified in accordance with the open function of the underlying filesystem. E.g. for local file https://docs.python.org/3/library/functions.html#open version: If specified, should be an instance of ``kedro.io.core.Version``. If its ``load`` attribute is None, the latest version will be loaded. If its ``save`` attribute is None, save version will be autogenerated. credentials: Credentials required to get access to the underlying filesystem. E.g. for ``GCSFileSystem`` it should look like `{"token": None}`. fs_args: Extra arguments to pass into underlying filesystem class. E.g. for ``GCSFileSystem`` class: `{"project": "my-project", ...}`. layer: The data layer according to the data engineering convention: https://kedro.readthedocs.io/en/stable/06_resources/01_faq.html#what-is-data-engineering-convention """ _fs_args = deepcopy(fs_args) or {} _credentials = deepcopy(credentials) or {} protocol, path = get_protocol_and_path(filepath, version) self._protocol = protocol self._fs = fsspec.filesystem(self._protocol, **_credentials, **_fs_args) super().__init__( filepath=PurePosixPath(path), version=version, exists_function=self._fs.exists, glob_function=self._fs.glob, ) self._layer = layer # Handle default load and save arguments self._load_args = deepcopy(self.DEFAULT_LOAD_ARGS) if load_args is not None: self._load_args.update(load_args) self._save_args = deepcopy(self.DEFAULT_SAVE_ARGS) if save_args is not None: self._save_args.update(save_args)
def _describe(self) -> Dict[str, Any]: return dict( filepath=self._filepath, protocol=self._protocol, load_args=self._load_args, save_args=self._save_args, version=self._version, layer=self._layer, ) def _load(self) -> str: load_path = get_filepath_str(self._get_load_path(), self._protocol) with self._fs.open(load_path, **self._load_args) as fs_file: return fs_file.read() def _save(self, data: str) -> None: save_path = get_filepath_str(self._get_save_path(), self._protocol) with self._fs.open(save_path, **self._save_args) as fs_file: fs_file.write(data) self.invalidate_cache() def _exists(self) -> bool: try: load_path = get_filepath_str(self._get_load_path(), self._protocol) except DataSetError: return False return self._fs.exists(load_path) def _release(self) -> None: self.invalidate_cache()
[docs] def invalidate_cache(self) -> None: """Invalidate underlying filesystem caches.""" filepath = get_filepath_str(self._filepath, self._protocol) self._fs.invalidate_cache(filepath)