"""Collection of utilities specifically for the lyrics scraping project.
.. _default logging configuration file: https://bit.ly/2oPJSr4
.. _default main configuration file: https://bit.ly/2n764MV
.. _user-defined logging configuration file: https://bit.ly/2niTDgY
.. _user-defined main configuration file: https://bit.ly/2oyt0VJ
.. _SQL schema file music.sql: https://bit.ly/2kIMYvn
"""
from collections import namedtuple
import os
import yaml
from lyrics_scraping import data
from pyutils.genutils import load_yaml
# TODO: explain
_CFG_EXT = "yaml"
_LOG_CFG_FILENAME = 'logging_cfg'
_MAIN_CFG_FILENAME = 'main_cfg'
_SCHEMA_FILENAME = "music.sql"
_data_filenames = namedtuple("data_filenames", "user_cfg default_cfg schema")
def _add_data_filenames():
"""TODO
"""
_data_filenames.user_cfg = {
'log': '{}.'.format(_LOG_CFG_FILENAME) + _CFG_EXT,
'main': '{}.'.format(_MAIN_CFG_FILENAME) + _CFG_EXT}
_data_filenames.default_cfg = dict(
[("default_" + k, "default_" + v)
for k, v in _data_filenames.user_cfg.items()])
_data_filenames.schema = _SCHEMA_FILENAME
_add_data_filenames()
# TODO: change it to plural
[docs]def plural(obj, plural_end="s", singular_end=""):
"""Add plural ending if a number is greater than 1 or there are many
values in a list.
If the number is greater than one or more than one item is found in the
list, the function returns by default 's'. If not, then the empty string is
returned.
Parameters
----------
obj : int, float or list
The number or list that will be checked if a plural or singular ending
will be returned.
plural_end : str, optional
The plural ending (the default value is "s" which implies that "s'" will
be returned in the case that the number is greater than 1 or the list
contains more than one item).
singular_end : str, optional
The singular ending (the default value is "" which implies that an
empty string will be returned in the case that the number is 1 or less,
or the list contains 1 item).
Returns
-------
str : "s" or ""
"s" if number is greater than 1 or more than one item is found in the
list, "" (empty string) otherwise.
Raises
------
TypeError
TODO
"""
# TODO: explain
if isinstance(obj, list):
num = len(obj)
else:
if not (isinstance(obj, int) or isinstance(obj, float)):
raise TypeError("obj must be a list, int or float")
num = obj
return plural_end if num > 1 else singular_end
[docs]def get_backup_cfg_filepath(cfg_type):
"""TODO
Parameters
----------
cfg_type
Returns
-------
"""
# TODO: explain
valid_cfg_types = list(_data_filenames.user_cfg.keys())
assert cfg_type in valid_cfg_types, \
"Wrong type of data file: '{}' (choose from {})".format(
cfg_type, ", ".join(valid_cfg_types))
filename = '.{}_cfg.bak'.format(cfg_type)
return os.path.join(get_data_dirpath(), filename)
[docs]def get_data_dirpath():
"""TODO
Returns
-------
"""
return data.__path__[0]
[docs]def get_data_filepath(file_type):
"""Return the path to a data file used by :mod:`lyrics_scraping`.
The data file can either be the:
- **default_log**: refers to the `default logging configuration file`_ used
to setup the logging for all custom modules.
- **default_main**: refers to the `default main configuration file`_ used to
setup a lyrics scraper.
- **log**: refers to the `user-defined logging configuration file`_ which is
used to setup the logging for all custom modules.
- **main**: refers to the `user-defined main configuration file`_ used to
setup a lyrics scraper.
- **schema**: refers to the `SQL schema file music.sql`_ used for creating the SQLite
database which stores the scraped data.
Parameters
----------
file_type : str, {'default_log', 'default_main', 'log', 'main', 'schema'}
The type of data file for which we want the path.
Returns
-------
filepath : str
The path to the data file.
Raises
------
AssertionError
Raised if the wrong type of data file is given to the function. Only
{'default_log', 'default_main', 'log', 'main', 'schema'} are accepted
for `file_type`.
"""
# TODO: explain
valid_file_types = list(_data_filenames.user_cfg.keys()) \
+ list(_data_filenames.default_cfg.keys())
valid_file_types.append("schema")
assert file_type in valid_file_types, \
"Wrong type of data file: '{}' (choose from {})".format(
file_type, ", ".join(valid_file_types))
if file_type == 'schema':
filename = _data_filenames.schema
elif file_type.startswith('default'):
filename = _data_filenames.default_cfg[file_type]
else:
filename = _data_filenames.user_cfg[file_type]
return os.path.join(get_data_dirpath(), filename)
[docs]def load_cfg(cfg_type):
"""TODO
Parameters
----------
cfg_type
Returns
-------
Raises
------
"""
# TODO: explain
valid_cfg_types = list(_data_filenames.user_cfg.keys()) + \
list(_data_filenames.default_cfg.keys())
assert cfg_type in valid_cfg_types, \
"Wrong type of data file: '{}' (choose from {})".format(
cfg_type, ", ".join(valid_cfg_types))
if _CFG_EXT == 'yaml':
return load_yaml(get_data_filepath(cfg_type))
else:
# TODO: raise error
print("File EXTENSION '{}' not supported".format(_CFG_EXT))
return None
[docs]def dump_cfg(filepath, cfg_dict):
"""TODO
Parameters
----------
filepath
cfg_dict
Raises
------
"""
# TODO: explain
if _CFG_EXT == 'yaml':
with open(filepath, 'w') as f:
yaml.dump(cfg_dict, f)
else:
# TODO: raise error
print("File EXTENSION '{}' not supported".format(_CFG_EXT))