Merge pull request #67 from aj3sh/refactor

Minor-level refactoring
This commit is contained in:
Sugat Bajracharya authored and GitHub committed 2023-06-09 21:18:53 +05:45
commit bf51c0d85b
12 files changed
+115 -97

No files matched your search

+5 -5
View File
@@ -15,13 +15,13 @@ repos:
args:
- --isort
- --flynt
- --lint=flake8 --max-line-length=88
- --lint=mypy --strict
- --lint=pylint --max-line-length=88
- --lint=flake8 --max-line-length=88 --ignore=E203,W503
- --lint=mypy # --strict # commenting strict for now as we haven't maintained typing completely
- --lint=pylint --max-line-length=88 --disable=W0511
additional_dependencies:
- black==23.3.0
- flake8==5.0.4
- flynt==0.78
- flynt==0.77
- isort==5.12.0
- mypy==1.2.0
- mypy==1.3.0
- pylint==2.17.4
@@ -1,4 +1,12 @@
MONTHS_EN = (
"""
This files contains constants for the py-Nepali project.
"""
# Nepali timezone
NEPAL_TIMEZONE = "Asia/Kathmandu"
# Nepali months in english
NEPALI_MONTHS_EN = (
"Baishakh",
"Jestha",
"Ashad",
@@ -13,7 +21,8 @@ MONTHS_EN = (
"Chaitra",
)
MONTHS_NE = (
# Nepali months in Nepali (devanagari)
NEPALI_MONTHS_NE = (
"बैशाख",
"जेठ",
"असार",
@@ -28,6 +37,7 @@ MONTHS_NE = (
"चैत",
)
# Week names in english
WEEKS_EN = (
"Sunday",
"Monday",
@@ -38,8 +48,10 @@ WEEKS_EN = (
"Saturday",
)
# Week abbreviation name in english
WEEKS_ABBR_EN = ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat")
# Weeks names in Nepali (devanagari)
WEEKS_NE = (
"आइतबार",
"सोमबार",
@@ -50,4 +62,5 @@ WEEKS_NE = (
"शनिबार",
)
# Week abbreviation name in Nepali (devanagari)
WEEKS_ABBR_NE = ("आइत", "सोम", "मंगल", "बुध", "बिही", "शुक्र", "शनि")
+11 -12
View File
@@ -17,31 +17,31 @@ class formatter_class_mixin:
@classmethod
def init_formatter_class(cls):
if not hasattr(cls, "__formatter_class__Cache"):
if not hasattr(cls, "_formatter_class_cache"):
from ._formatter import NepaliDateTimeFormatter
cls.__formatter_class__Cache = NepaliDateTimeFormatter
return cls.__formatter_class__Cache
cls._formatter_class_cache = NepaliDateTimeFormatter
return cls._formatter_class_cache
@classmethod
def get_strptime_method(cls):
if not hasattr(cls, "_strptime_method_CACHE"):
if not hasattr(cls, "_strptime_method_cache"):
from .parser import strptime
cls._strptime_method_CACHE = strptime
return cls._strptime_method_CACHE
cls._strptime_method_cache = strptime
return cls._strptime_method_cache
def strftime(self, format: str) -> str:
return self.strftime_en(format)
def strftime_en(self, format: str) -> str:
NepaliDateTimeFormatter = self.get_formatter_class()
formatter = NepaliDateTimeFormatter(self, devanagari=False)
nepali_datetime_formatter = self.get_formatter_class()
formatter = nepali_datetime_formatter(self, devanagari=False)
return formatter.get_str(format)
def strftime_ne(self, format: str) -> str:
NepaliDateTimeFormatter = self.get_formatter_class()
formatter = NepaliDateTimeFormatter(self, devanagari=True)
nepali_datetime_formatter = self.get_formatter_class()
formatter = nepali_datetime_formatter(self, devanagari=True)
return formatter.get_str(format)
@@ -194,12 +194,11 @@ class nepalidate(formatter_class_mixin):
@staticmethod
def from_date(date_object):
npDate = nepalidate(
return nepalidate(
*nepali_date_converter.english_to_nepali(
date_object.year, date_object.month, date_object.day
)
)
return npDate
@staticmethod
def from_nepalidatetime(datetime_object):
+14 -29
View File
@@ -1,10 +1,7 @@
import datetime as pythonDateTime
from nepali import number
from nepali.timezone import now, to_nepali_timezone
from nepali.exceptions import InvalidNepaliDateTimeObjectException
from nepali.timezone import now
from ._datetime import nepalidate, nepalidatetime
from .utils import to_nepalidatetime
class HumanizeDateTime:
@@ -29,20 +26,7 @@ class HumanizeDateTime:
threshold (kwargs): threshold to be humanize
format (kwargs): format to display behind threshold
"""
if type(datetime_obj) == nepalidatetime:
self.datetime_obj = datetime_obj.to_datetime()
elif type(datetime_obj) == nepalidate:
self.datetime_obj = nepalidatetime.from_nepali_date(
datetime_obj
).to_datetime()
elif type(datetime_obj) == pythonDateTime.date:
self.datetime_obj = nepalidatetime.from_date(datetime_obj).to_datetime()
elif type(datetime_obj) == pythonDateTime.datetime:
self.datetime_obj = to_nepali_timezone(datetime_obj)
else:
raise InvalidNepaliDateTimeObjectException(
"Argument must be instance of NepaliDate or NepaliDateTime or datetime.datetime or datetime.date"
)
self.datetime_obj = to_nepalidatetime(datetime_obj)
self.threshold = kwargs.get("threshold")
self.format = kwargs.get("format")
@@ -53,8 +37,11 @@ class HumanizeDateTime:
def __calc_seconds(self):
"""calculates total seconds from now"""
current_date_time = now()
date = self.datetime_obj
self.seconds = int((current_date_time - date).total_seconds())
# TODO (@aj3sh): support datetime - nepalidatetime
self.seconds = int(
(current_date_time - self.datetime_obj.to_datetime()).total_seconds()
)
self.interval_tense = self.__past_text
if self.seconds < 0:
@@ -67,13 +54,12 @@ class HumanizeDateTime:
"""returns humanize string"""
seconds = self.__calc_seconds() # calculating seconds
if self.threshold is not None:
if seconds >= self.threshold:
return self.get_datetime().strip()
if self.threshold is not None and seconds >= self.threshold:
return self._get_datetime_str().strip()
return self.get_humanize().strip()
return self._get_humanize_str().strip()
def get_humanize(self):
def _get_humanize_str(self):
"""
returns humanize datetime
"""
@@ -118,14 +104,13 @@ class HumanizeDateTime:
str(interval_value) + " " + str(interval_text) + " " + self.interval_tense
)
def get_datetime(self):
def _get_datetime_str(self):
"""
returns date in nepali characters
"""
if not self.format:
self.format = "%B %d, %Y"
ndt = nepalidatetime.from_datetime(self.datetime_obj)
return ndt.strftime_ne(self.format)
return self.datetime_obj.strftime_ne(self.format)
def __str__(self):
return self.to_str()
+6 -5
View File
@@ -1,7 +1,7 @@
from functools import cached_property
from typing import Any, Dict, Optional, Union
from .constants import MONTHS_EN, MONTHS_NE
from nepali.constants import NEPALI_MONTHS_EN, NEPALI_MONTHS_NE
class NepaliMonthMeta(type):
@@ -40,7 +40,8 @@ class NepaliMonthMeta(type):
return cls._cache[value]
def _parse_str(cls, month: str) -> int:
@staticmethod
def _parse_str(month: str) -> int:
"""
Parses str value of the month and returns int.
@@ -54,7 +55,7 @@ class NepaliMonthMeta(type):
return int(month)
month = month.capitalize()
month_names = MONTHS_EN + MONTHS_NE
month_names = NEPALI_MONTHS_EN + NEPALI_MONTHS_NE
try:
index = month_names.index(month)
except ValueError:
@@ -107,9 +108,9 @@ class nepalimonth(metaclass=NepaliMonthMeta):
@cached_property
def name(self) -> str:
"""Month's english name"""
return MONTHS_EN[self.__value - 1]
return NEPALI_MONTHS_EN[self.__value - 1]
@cached_property
def name_ne(self) -> str:
"""Month's nepali name"""
return MONTHS_NE[self.__value - 1]
return NEPALI_MONTHS_NE[self.__value - 1]
+4 -3
View File
@@ -1,7 +1,7 @@
from functools import cached_property
from typing import Any, Dict, Optional, Union
from .constants import WEEKS_EN, WEEKS_NE, WEEKS_ABBR_EN, WEEKS_ABBR_NE
from nepali.constants import WEEKS_ABBR_EN, WEEKS_ABBR_NE, WEEKS_EN, WEEKS_NE
class NepaliWeekMeta(type):
@@ -28,7 +28,7 @@ class NepaliWeekMeta(type):
pass
# checking if week is valid
if value is None or not (0 <= value <= 6):
if value is None or not 0 <= value <= 6:
raise ValueError(f"Invalid week: {week}")
# checking cache
@@ -37,7 +37,8 @@ class NepaliWeekMeta(type):
return cls._cache[value]
def _parse_str(cls, week: str) -> int:
@staticmethod
def _parse_str(week: str) -> int:
"""
Parses str value of the week and returns int.
+4 -4
View File
@@ -65,10 +65,10 @@ def parse(datetime_str):
eg. parse('2078-10-12') => <NepaliDateTime: 2078-10-12>
"""
standard_formats = _get_standard_formats()
nepalidatetime_object = None
for format in standard_formats:
nepalidatetime_object = validate(datetime_str, format=format)
if nepalidatetime_object is not None:
return nepalidatetime_object
try:
return strptime(datetime_str, format=format)
except FormatNotMatchException:
pass
raise InvalidDateTimeFormatException("Invalid format to parse nepali datetime.")
+22 -19
View File
@@ -5,8 +5,8 @@ import re
from typing import Optional, Tuple
from nepali.char import nepali_to_english_text
from nepali.constants import NEPALI_MONTHS_EN, WEEKS_ABBR_EN, WEEKS_EN
from nepali.datetime import nepalidatetime, nepalimonth, nepaliweek
from nepali.datetime.constants import MONTHS_EN, WEEKS_ABBR_EN, WEEKS_EN
__nepali_time_re__CACHE = None
@@ -41,8 +41,8 @@ class NepaliTimeRE(dict):
"z": r"(?P<z>[+-]\d\d:?[0-5]\d(:?[0-5]\d(\.\d{1,6})?)?|(?-i:Z))",
"A": self.__seqToRE(WEEKS_EN, "A"),
"a": self.__seqToRE(WEEKS_ABBR_EN, "a"),
"B": self.__seqToRE(MONTHS_EN, "B"),
"b": self.__seqToRE(MONTHS_EN, "b"),
"B": self.__seqToRE(NEPALI_MONTHS_EN, "B"),
"b": self.__seqToRE(NEPALI_MONTHS_EN, "b"),
"p": self.__seqToRE(
(
"AM",
@@ -71,36 +71,39 @@ class NepaliTimeRE(dict):
regex = f"(?P<{directive}>{regex}"
return f"{regex})"
def pattern(self, format):
def pattern(self, date_format):
"""
Handle conversion from format directives to regex.
"""
processed_format = ""
regex_chars = re.compile(r"([\\.^$*+?\(\){}\[\]|])")
format = regex_chars.sub(r"\\\1", format)
date_format = regex_chars.sub(r"\\\1", date_format)
whitespace_replacement = re.compile(r"\s+")
format = whitespace_replacement.sub(r"\\s+", format)
while "%" in format:
directive_index = format.index("%") + 1
date_format = whitespace_replacement.sub(r"\\s+", date_format)
while "%" in date_format:
directive_index = date_format.index("%") + 1
index_increment = 1
if format[directive_index] == "-":
if date_format[directive_index] == "-":
index_increment = 2
if format[directive_index : directive_index + index_increment] not in self:
if (
date_format[directive_index : directive_index + index_increment]
not in self
):
return None
processed_format = "%s%s%s" % (
processed_format,
format[: directive_index - 1],
self[format[directive_index : directive_index + index_increment]],
date_format[: directive_index - 1],
self[date_format[directive_index : directive_index + index_increment]],
)
format = format[directive_index + index_increment :]
return f"^{processed_format}{format}$"
date_format = date_format[directive_index + index_increment :]
return f"^{processed_format}{date_format}$"
def compile(self, format):
def compile(self, date_format):
"""Return a compiled re object for the format string."""
return re.compile(self.pattern(format), re.IGNORECASE)
return re.compile(self.pattern(date_format), re.IGNORECASE)
def get_nepali_time_re_object():
@@ -131,7 +134,7 @@ def extract(datetime_str, format):
# converting datetime_str to english if any exists
datetime_str = nepali_to_english_text(datetime_str)
re_compiled_format = get_nepali_time_re_object().compile(format=format)
re_compiled_format = get_nepali_time_re_object().compile(format)
match = re_compiled_format.match(datetime_str)
if match is None:
return {}
@@ -250,7 +253,7 @@ def __calculate_hour_minute_seconds(data: dict) -> Tuple[int, int, int, int]:
s += "0" * (6 - len(s))
fraction = int(s)
return (hour, minute, second, fraction)
return hour, minute, second, fraction
def __calculate_weekday(data: dict) -> Optional[nepaliweek]:
@@ -320,7 +323,7 @@ def validate(datetime_str, format):
"""
# 1. validate if format is correct.
if get_nepali_time_re_object().pattern(format=format) is None:
if get_nepali_time_re_object().pattern(format) is None:
# regex pattern generation failed
return None
+21 -8
View File
@@ -19,10 +19,23 @@ class nepalinumber:
"""
self.__value = self.__parse(value)
def _raise_parse_exception(self, obj, ex_class: Type[Exception] = ValueError):
raise ex_class(
def get_parse_exception(
self, obj: object, ex_class: Type[Exception] = ValueError
) -> Exception:
"""
Returns the exception object to be raised when the parse is failed.
The methods also sets a proper message to the exception class.
:param obj: Object that is failed during the parse
:type obj: object
:param ex_class: Exception class type to be returned, defaults to ValueError
:type ex_class: Type[Exception], optional
:return: Exception object to be raised
:rtype: Exception
"""
return ex_class(
f"could not convert {obj.__class__.__name__} to {self.__class__.__name__}: '{obj}'"
) from None
)
def __parse(self, value: Any) -> Union[int, float]:
"""
@@ -61,10 +74,10 @@ class nepalinumber:
:raises ValueError: If the value is invalid
"""
result = 0
result: float = 0
sign = 1
decimal_found = False
decimal_place = 1
decimal_place: float = 1
i = 0
# for negative sign
@@ -77,7 +90,7 @@ class nepalinumber:
if value[i] == ".":
if decimal_found:
# decimal was already found
self._raise_parse_exception(value)
raise self.get_parse_exception(value) from None
decimal_found = True
i += 1
continue
@@ -86,7 +99,7 @@ class nepalinumber:
if digit < 0 or digit > 9:
# checking nepali character
if value[i] not in NP_NUMBERS_SET:
self._raise_parse_exception(value)
raise self.get_parse_exception(value) from None
digit = NP_NUMBERS.index(value[i])
if decimal_found:
@@ -113,7 +126,7 @@ class nepalinumber:
return self.__parse_str(str(obj))
except (ValueError, TypeError):
# object conversion must raise TypeError if fails
self._raise_parse_exception(obj, ex_class=TypeError)
raise self.get_parse_exception(obj, ex_class=TypeError) from None
def __convert_or_return(self, obj) -> Union["nepalinumber", object]:
"""
+2 -2
View File
@@ -3,9 +3,9 @@ from enum import Enum
from typing import Union
_mobile_number_re = re.compile(r"^(?:\+977|977)?(?:-)?(?:98|97|96)[0-9]{8}$")
_mobile_number_re = re.compile(r"^(?:\+977|977)?(?:-)?(?:98|97|96)\d{8}$")
_landline_number_re = re.compile(
r"^(?:\+977|977)?(?:-)?(?:0)?(?:[01][1-9]|2[13-9]|[3-9][0-9])[0-9]{6,7}$"
r"^(?:\+977|977)?(?:-)?(?:0)?(?:[01][1-9]|2[13-9]|[3-9]\d)\d{6,7}$"
)
+6 -5
View File
@@ -7,13 +7,14 @@ import datetime
import unittest
from unittest.mock import patch
from nepali.constants import NEPAL_TIMEZONE
from nepali.timezone import (
NepaliTimeZone,
get_timezone,
now,
to_nepali_timezone,
to_utc_timezone,
utc_now,
now,
get_timezone,
)
@@ -32,13 +33,13 @@ class TestNepaliTimeZone(unittest.TestCase):
)
def test_nepali_timezone_tzname(self):
self.assertEqual(self.nepali_timezone.tzname(None), "Asia/Kathmandu")
self.assertEqual(self.nepali_timezone.tzname(None), NEPAL_TIMEZONE)
def test_nepali_timezone_str(self):
self.assertEqual(str(self.nepali_timezone), "Asia/Kathmandu")
self.assertEqual(str(self.nepali_timezone), NEPAL_TIMEZONE)
def test_nepali_timezone_repr(self):
self.assertEqual(repr(self.nepali_timezone), "Asia/Kathmandu")
self.assertEqual(repr(self.nepali_timezone), NEPAL_TIMEZONE)
def test_datetime_with_nepali_timezone(self):
dt = datetime.datetime(2015, 10, 14, tzinfo=self.nepali_timezone)
+5 -3
View File
@@ -1,6 +1,8 @@
import datetime
from typing import Union
from .constants import NEPAL_TIMEZONE
class NepaliTimeZone(datetime.tzinfo):
"""
@@ -14,13 +16,13 @@ class NepaliTimeZone(datetime.tzinfo):
return datetime.timedelta(0)
def tzname(self, dt):
return "Asia/Kathmandu"
return NEPAL_TIMEZONE
def __str__(self):
return "Asia/Kathmandu"
return NEPAL_TIMEZONE
def __repr__(self):
return "Asia/Kathmandu"
return NEPAL_TIMEZONE
def __eq__(self, o: object) -> bool:
return isinstance(o, self.__class__)