ai-content-maker/.venv/Lib/site-packages/dateparser/conf.py

269 lines
8.2 KiB
Python

import hashlib
from datetime import datetime
from functools import wraps
from dateparser.data.languages_info import language_order
from .parser import date_order_chart
from .utils import registry
@registry
class Settings:
"""Control and configure default parsing behavior of dateparser.
Currently, supported settings are:
* `DATE_ORDER`
* `PREFER_LOCALE_DATE_ORDER`
* `TIMEZONE`
* `TO_TIMEZONE`
* `RETURN_AS_TIMEZONE_AWARE`
* `PREFER_DAY_OF_MONTH`
* `PREFER_DATES_FROM`
* `RELATIVE_BASE`
* `STRICT_PARSING`
* `REQUIRE_PARTS`
* `SKIP_TOKENS`
* `NORMALIZE`
* `RETURN_TIME_AS_PERIOD`
* `PARSERS`
* `DEFAULT_LANGUAGES`
* `LANGUAGE_DETECTION_CONFIDENCE_THRESHOLD`
* `CACHE_SIZE_LIMIT`
"""
_default = True
_pyfile_data = None
_mod_settings = dict()
def __init__(self, settings=None):
if settings:
self._updateall(settings.items())
else:
self._updateall(self._get_settings_from_pyfile().items())
@classmethod
def get_key(cls, settings=None):
if not settings:
return 'default'
keys = sorted(['%s-%s' % (key, str(settings[key])) for key in settings])
return hashlib.md5(''.join(keys).encode('utf-8')).hexdigest()
@classmethod
def _get_settings_from_pyfile(cls):
if not cls._pyfile_data:
from dateparser_data import settings
cls._pyfile_data = settings.settings
return cls._pyfile_data
def _updateall(self, iterable):
for key, value in iterable:
setattr(self, key, value)
def replace(self, mod_settings=None, **kwds):
for k, v in kwds.items():
if v is None:
raise TypeError('Invalid {{"{}": {}}}'.format(k, v))
for x in self._get_settings_from_pyfile().keys():
kwds.setdefault(x, getattr(self, x))
kwds['_default'] = False
if mod_settings:
kwds['_mod_settings'] = mod_settings
return self.__class__(settings=kwds)
settings = Settings()
def apply_settings(f):
@wraps(f)
def wrapper(*args, **kwargs):
mod_settings = kwargs.get('settings')
kwargs['settings'] = mod_settings or settings
if isinstance(kwargs['settings'], dict):
kwargs['settings'] = settings.replace(mod_settings=mod_settings, **kwargs['settings'])
if not isinstance(kwargs['settings'], Settings):
raise TypeError("settings can only be either dict or instance of Settings class")
return f(*args, **kwargs)
return wrapper
class SettingValidationError(ValueError):
pass
def _check_repeated_values(setting_name, setting_value):
if len(setting_value) != len(set(setting_value)):
raise SettingValidationError(
'There are repeated values in the "{}" setting'.format(setting_name)
)
return
def _check_require_part(setting_name, setting_value):
"""Returns `True` if the provided list of parts contains valid values"""
invalid_values = set(setting_value) - {'day', 'month', 'year'}
if invalid_values:
raise SettingValidationError(
'"{}" setting contains invalid values: {}'.format(
setting_name, ', '.join(invalid_values)
)
)
_check_repeated_values(setting_name, setting_value)
def _check_parsers(setting_name, setting_value):
"""Returns `True` if the provided list of parsers contains valid values"""
existing_parsers = [
'timestamp', 'relative-time', 'custom-formats', 'absolute-time', 'no-spaces-time', 'negative-timestamp'
] # FIXME: Extract the list of existing parsers from another place (#798)
unknown_parsers = set(setting_value) - set(existing_parsers)
if unknown_parsers:
raise SettingValidationError(
'Found unknown parsers in the "{}" setting: {}'.format(
setting_name, ', '.join(unknown_parsers)
)
)
_check_repeated_values(setting_name, setting_value)
def _check_default_languages(setting_name, setting_value):
unsupported_languages = set(setting_value) - set(language_order)
if unsupported_languages:
raise SettingValidationError(
"Found invalid languages in the '{}' setting: {}".format(
setting_name, ', '.join(map(repr, unsupported_languages))
)
)
_check_repeated_values(setting_name, setting_value)
def _check_between_0_and_1(setting_name, setting_value):
is_valid = 0 <= setting_value <= 1
if not is_valid:
raise SettingValidationError(
'{} is not a valid value for {}. It can take values between 0 and '
'1.'.format(
setting_value, setting_name,
)
)
def check_settings(settings):
"""
Check if provided settings are valid, if not it raises `SettingValidationError`.
Only checks for the modified settings.
"""
settings_values = {
'DATE_ORDER': {
'values': tuple(date_order_chart.keys()),
'type': str,
},
'TIMEZONE': {
# we don't check invalid Timezones as they raise an error
'type': str,
},
'TO_TIMEZONE': {
# It defaults to None, but it's not allowed to use it directly
# "values" can take unlimited options
'type': str
},
'RETURN_AS_TIMEZONE_AWARE': {
# It defaults to 'default', but it's not allowed to use it directly
'type': bool
},
'PREFER_DAY_OF_MONTH': {
'values': ('current', 'first', 'last'),
'type': str
},
'PREFER_DATES_FROM': {
'values': ('current_period', 'past', 'future'),
'type': str,
},
'RELATIVE_BASE': {
# "values" can take unlimited options
'type': datetime
},
'STRICT_PARSING': {
'type': bool
},
'REQUIRE_PARTS': {
# "values" covered by the 'extra_check'
'type': list,
'extra_check': _check_require_part
},
'SKIP_TOKENS': {
# "values" can take unlimited options
'type': list,
},
'NORMALIZE': {
'type': bool
},
'RETURN_TIME_AS_PERIOD': {
'type': bool
},
'PARSERS': {
# "values" covered by the 'extra_check'
'type': list,
'extra_check': _check_parsers
},
'FUZZY': {
'type': bool
},
'PREFER_LOCALE_DATE_ORDER': {
'type': bool
},
'DEFAULT_LANGUAGES': {
'type': list,
'extra_check': _check_default_languages
},
'LANGUAGE_DETECTION_CONFIDENCE_THRESHOLD': {
'type': float,
'extra_check': _check_between_0_and_1
},
'CACHE_SIZE_LIMIT': {
'type': int,
},
}
modified_settings = settings._mod_settings # check only modified settings
# check settings keys:
for setting in modified_settings:
if setting not in settings_values:
raise SettingValidationError('"{}" is not a valid setting'.format(setting))
for setting_name, setting_value in modified_settings.items():
setting_type = type(setting_value)
setting_props = settings_values[setting_name]
# check type:
if not setting_type == setting_props['type']:
raise SettingValidationError(
'"{}" must be "{}", not "{}".'.format(
setting_name, setting_props['type'].__name__, setting_type.__name__
)
)
# check values:
if setting_props.get('values') and setting_value not in setting_props['values']:
raise SettingValidationError(
'"{}" is not a valid value for "{}", it should be: "{}" or "{}"'.format(
setting_value,
setting_name,
'", "'.join(setting_props['values'][:-1]),
setting_props['values'][-1],
)
)
# specific checks
extra_check = setting_props.get('extra_check')
if extra_check:
extra_check(setting_name, setting_value)