"""
Read and write data files.
"""
import re
from collections import namedtuple
from .base import Reader
from .base import Root
from .base import Writer
from .google_api import GCellType
from .google_api import GDateTimeOption
from .google_api import GDrive
from .google_api import GMail
from .google_api import GSheets
from .google_api import GValueOption
from .readers import ExcelReader
from .readers import GSheetsReader
from .tables import extension_delimiter_map
from .tables import read_table_excel
from .tables import read_table_gsheets
from .tables import read_table_text
from .utils import _readers
from .utils import checksum
from .utils import copy
from .utils import git_head
from .utils import is_admin
from .utils import is_dir_accessible
from .utils import is_file_readable
from .utils import logger
from .utils import register
from .utils import remove_write_permissions
from .utils import run_as_admin
from .utils import search
from .utils import send_email
from .writers import HDF5Writer
from .writers import JSONWriter
__author__ = 'Measurement Standards Laboratory of New Zealand'
__copyright__ = '\xa9 2018 - 2023, ' + __author__
__version__ = '0.2.0.dev0'
_v = re.search(r'(\d+)\.(\d+)\.(\d+)[.-]?(.*)', __version__).groups()
version_info = namedtuple('version_info', 'major minor micro releaselevel')(int(_v[0]), int(_v[1]), int(_v[2]), _v[3])
""":obj:`~collections.namedtuple`: Contains the version information as a (major, minor, micro, releaselevel) tuple."""
[docs]def read(file, **kwargs):
"""Read a file that has a :ref:`Reader <io-readers>` implemented.
Parameters
----------
file : :term:`path-like <path-like object>` or :term:`file-like <file object>`
The file to read. For example, it could be a :class:`str` representing
a file system path or a stream.
**kwargs
All keyword arguments are passed to the
:meth:`Reader.can_read() <msl.io.base.Reader.can_read>`
and :meth:`Reader.read() <msl.io.base.Reader.read>` methods.
Returns
-------
:class:`~msl.io.base.Reader`
The data from the file.
Raises
------
OSError
If no :class:`~msl.io.base.Reader` exists to be able to read
the specified file.
"""
if hasattr(file, 'as_posix'): # a pathlib.Path object
file = str(file)
if hasattr(file, 'read') or is_file_readable(file, strict=True):
logger.debug('finding Reader for %r', file)
for r in _readers:
logger.debug('checking %s', r.__name__)
try:
can_read = r.can_read(file, **kwargs)
except Exception as e:
logger.debug('%s: %s [%s]', e.__class__.__name__, e, r.__name__)
continue
if can_read:
logger.debug('reading file with %s', r.__name__)
root = r(file)
root.read(**kwargs)
root.read_only = True
return root
raise OSError('No Reader exists to read {!r}'.format(file))
[docs]def read_table(file, **kwargs):
"""Read data in a table format from a file.
A *table* has the following properties:
1. The first row is a header.
2. All rows have the same number of columns.
3. All data values in a column have the same data type.
Parameters
----------
file : :term:`path-like <path-like object>` or :term:`file-like <file object>`
The file to read. For example, it could be a :class:`str` representing
a file system path or a stream. If `file` is a Google Sheets spreadsheet
then `file` must end with ``.gsheet`` even if the ID of the spreadsheet
is specified.
**kwargs
If the file is an Excel spreadsheet then the keyword arguments are passed to
:func:`~msl.io.tables.read_table_excel`. If a Google Sheets spreadsheet then
the keyword arguments are passed to :func:`~msl.io.tables.read_table_gsheets`.
Otherwise, all keyword arguments are passed to :func:`~msl.io.tables.read_table_text`.
Returns
-------
:class:`~msl.io.dataset.Dataset`
The table as a :class:`~msl.io.dataset.Dataset`. The header is included as metadata.
"""
extn = Reader.get_extension(file).lower()
if extn.startswith('.xls'):
return read_table_excel(file, **kwargs)
elif extn == '.gsheet':
if hasattr(file, 'as_posix'): # a pathlib.Path object
file = str(file)
elif hasattr(file, 'name'): # a TextIOWrapper object
file = file.name
return read_table_gsheets(file[:-7], **kwargs) # ignore the extension
else:
return read_table_text(file, **kwargs)