From ba0f3d75a65677207f55e254f2fdcf610f8f9e19 Mon Sep 17 00:00:00 2001 From: Andrey Shur Date: Sun, 21 Aug 2022 15:49:04 +0300 Subject: [PATCH 1/9] Cleanup --- omninumeric/omninumeric.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/omninumeric/omninumeric.py b/omninumeric/omninumeric.py index 48ce585..f267993 100644 --- a/omninumeric/omninumeric.py +++ b/omninumeric/omninumeric.py @@ -92,10 +92,8 @@ def _getNumeral(cls, numeral, fallback): def _purgeEmptyGroups(self): "Remove empty groups from numeral groups collection." - print(self._groups) while self._groups.count(""): self._groups.remove("") # Purge empty groups - print(self._groups) return self def convert(self): From d2d5e5849c8f63de0cd5f06e96c8a6351032e939 Mon Sep 17 00:00:00 2001 From: Andrey Shur Date: Sun, 21 Aug 2022 15:50:11 +0300 Subject: [PATCH 2/9] Improved interface --- omninumeric/cyrillic/__init__.py | 6 ++---- omninumeric/cyrillic/cyrillic.py | 24 ++++++++++++++++++++++-- tests/test_cyrillic.py | 1 + 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/omninumeric/cyrillic/__init__.py b/omninumeric/cyrillic/__init__.py index 183c143..8fd61ab 100644 --- a/omninumeric/cyrillic/__init__.py +++ b/omninumeric/cyrillic/__init__.py @@ -8,15 +8,13 @@ CU_ALLDOT, ArabicNumber, CyrillicNumber, + Cyrillic, to_cu, to_arab, ) __all__ = [ - "ArabicNumber", - "CyrillicNumber", - "to_cu", - "to_arab", + "Cyrillic", "CU_PLAIN", "CU_DELIM", "CU_NOTITLO", diff --git a/omninumeric/cyrillic/cyrillic.py b/omninumeric/cyrillic/cyrillic.py index 7f83149..64d2f81 100644 --- a/omninumeric/cyrillic/cyrillic.py +++ b/omninumeric/cyrillic/cyrillic.py @@ -199,13 +199,33 @@ def convert(self): ) +class Cyrillic: + def read(number, flags=0): + """ + Convert from Cyrillic numeral system. + + Requires a non-empty string. + """ + + return CyrillicNumber(number, flags).convert() + + def write(number, flags=0): + """ + Convert into Cyrillic numeral system. Uses plain style by default. + + Requires a non-zero integer. + """ + + return ArabicNumber(number, flags).convert() + + def to_cu(integer, flags=0): "Deprecated. Use ArabicNumber().convert() instead." - return ArabicNumber(integer, flags).convert() + return Cyrillic.write(integer, flags) def to_arab(alphabetic, flags=0): "Deprecated. Use CyrillicNumber().convert() instead." - return CyrillicNumber(alphabetic).convert() + return Cyrillic.read(alphabetic, flags) diff --git a/tests/test_cyrillic.py b/tests/test_cyrillic.py index a59a863..82a4104 100644 --- a/tests/test_cyrillic.py +++ b/tests/test_cyrillic.py @@ -1,6 +1,7 @@ # -*- coding: UTF-8 -*- import unittest from omninumeric.cyrillic import * +from omninumeric.cyrillic import to_cu, to_arab class ToCUPlainTestCase(unittest.TestCase): From 4634f0013258edb33faf925c584ac7a6e58b626c Mon Sep 17 00:00:00 2001 From: Andrey Shur Date: Sun, 21 Aug 2022 22:56:59 +0300 Subject: [PATCH 3/9] Revert e831081f "privatise" --- omninumeric/cyrillic/cyrillic.py | 118 +++++++++++++++---------------- omninumeric/greek/greek.py | 58 +++++++-------- omninumeric/greek/old.py | 26 +++---- omninumeric/omninumeric.py | 58 +++++++-------- 4 files changed, 127 insertions(+), 133 deletions(-) diff --git a/omninumeric/cyrillic/cyrillic.py b/omninumeric/cyrillic/cyrillic.py index 64d2f81..304901a 100644 --- a/omninumeric/cyrillic/cyrillic.py +++ b/omninumeric/cyrillic/cyrillic.py @@ -18,7 +18,7 @@ CU_ALLDOT = CU_ENDDOT | CU_PREDOT | CU_DELIMDOT # Wrapper and delimeter dots flag -class _CyrillicDictionary(DictionaryGreek): +class CyrillicDictionary(DictionaryGreek): "Cyrillic numerals ditcionary." а = 1 @@ -56,68 +56,68 @@ class _CyrillicDictionary(DictionaryGreek): class ArabicNumber(IntNumberConverterGreek): "Number converter into Cyrillic numeral system." - _dict = _CyrillicDictionary + dict = CyrillicDictionary - def _ambiguityCheck(self, cond, flag): + def ambiguityCheck(self, cond, flag): if cond: try: - if (self._groups[0] // 10 % 10 == 1) and ( - self._groups[1] // 10 % 10 == 0 + if (self.groups[0] // 10 % 10 == 1) and ( + self.groups[1] // 10 % 10 == 0 ): - self._flags = self._flags | flag + self.flags = self.flags | flag finally: return self else: return self - def _swapDigits(self): + def swapDigits(self): "Swap digits for values 11-19 (unless separated)." - for i, k in enumerate(self._groups): + for i, k in enumerate(self.groups): - self._groups[i] = re.sub( - "({0})([{1}])".format(self._dict.get(10), self._dict.digits()), + self.groups[i] = re.sub( + "({0})([{1}])".format(self.dict.get(10), self.dict.digits()), "\g<2>\g<1>", - self._groups[i], + self.groups[i], ) return self - def _appendTitlo(self, cond): + def appendTitlo(self, cond): 'Apply "titlo" decorator unless appropriate flag is set.' if not cond: result = re.subn( "([\S]+)(?{0}\g<2>".format(self._dict.get("TITLO")), - self._target, + "\g<1>{0}\g<2>".format(self.dict.get("TITLO")), + self.target, ) - self._target = ( + self.target = ( result[0] if result[1] > 0 - else "{0}{1}".format(self._target, self._dict.get("TITLO")) + else "{0}{1}".format(self.target, self.dict.get("TITLO")) ) return self - def _delimDots(self, cond): + def delimDots(self, cond): "Insert dots between numeral groups if appropriate flag is set." if cond: - for i, k in enumerate(self._groups[1:]): - self._groups[i + 1] = "{0}{1}".format(k, self._dict.get("DOT")) + for i, k in enumerate(self.groups[1:]): + self.groups[i + 1] = "{0}{1}".format(k, self.dict.get("DOT")) return self - def _wrapDot(self, cond_a, cond_b): + def wrapDot(self, cond_a, cond_b): "Prepend and/or append a dot if appropriate flags are set." - self._target = "{0}{1}{2}".format( - self._dict.get("DOT") if cond_a else "", - self._target, - self._dict.get("DOT") if cond_b else "", + self.target = "{0}{1}{2}".format( + self.dict.get("DOT") if cond_a else "", + self.target, + self.dict.get("DOT") if cond_b else "", ) return self @@ -130,51 +130,51 @@ def convert(self): """ return ( - self._validate() - ._breakIntoGroups() - ._ambiguityCheck(self._hasFlag(CU_DELIM), CU_DOT) - ._translateGroups() - ._appendThousandMarks(self._hasFlag(CU_DELIM)) - ._purgeEmptyGroups() - ._swapDigits() - ._delimDots(self._hasFlag(CU_DOT)) - ._build() - ._appendTitlo(self._hasFlag(CU_NOTITLO)) - ._wrapDot(self._hasFlag(CU_PREDOT), self._hasFlag(CU_ENDDOT)) - ._get() + self.validate() + .breakIntoGroups() + .ambiguityCheck(self.hasFlag(CU_DELIM), CU_DOT) + .translateGroups() + .appendThousandMarks(self.hasFlag(CU_DELIM)) + .purgeEmptyGroups() + .swapDigits() + .delimDots(self.hasFlag(CU_DOT)) + .build() + .appendTitlo(self.hasFlag(CU_NOTITLO)) + .wrapDot(self.hasFlag(CU_PREDOT), self.hasFlag(CU_ENDDOT)) + .get() ) class CyrillicNumber(StrNumberConverterGreek): "Number converter from Cyrillic numeral system." - _dict = _CyrillicDictionary + dict = CyrillicDictionary - _regex = "({0}*[{1}]?(?:(?:{0}*[{3}])?{4}|(?:{0}*[{2}])?(?:{0}*[{3}])?))".format( - _dict.get("THOUSAND"), - _dict.hundreds(), - _dict.tens(2), - _dict.digits(), - _dict.get(10), + regex = "({0}*[{1}]?(?:(?:{0}*[{3}])?{4}|(?:{0}*[{2}])?(?:{0}*[{3}])?))".format( + dict.get("THOUSAND"), + dict.hundreds(), + dict.tens(2), + dict.digits(), + dict.get(10), ) # Regular expression for typical Cyrillic numeral system number - def _prepare(self): + def prepare(self): "Prepare source number for conversion." - super()._prepare() - self._source = re.sub( - "[{0}\{1}]".format(self._dict.get("TITLO"), self._dict.get("DOT")), + super().prepare() + self.source = re.sub( + "[{0}\{1}]".format(self.dict.get("TITLO"), self.dict.get("DOT")), "", - self._source, + self.source, ) # Strip ҃decorators return self - def _validate(self): + def validate(self): "Validate that source number is a non-empty string and matches the pattern for Cyrillic numeral system numbers." - super()._validate() - if not re.fullmatch("{0}+".format(self._regex), self._source): + super().validate() + if not re.fullmatch("{0}+".format(self.regex), self.source): raise ValueError( "String does not match any pattern for Cyrillic numeral system numbers" ) @@ -189,13 +189,13 @@ def convert(self): """ return ( - self._prepare() - ._validate() - ._breakIntoGroups(self._regex) - ._purgeEmptyGroups() - ._translateGroups() - ._build() - ._get() + self.prepare() + .validate() + .breakIntoGroups(self.regex) + .purgeEmptyGroups() + .translateGroups() + .build() + .get() ) diff --git a/omninumeric/greek/greek.py b/omninumeric/greek/greek.py index d60f09f..f203fed 100644 --- a/omninumeric/greek/greek.py +++ b/omninumeric/greek/greek.py @@ -23,7 +23,7 @@ class DictionaryGreek(Dictionary): """ @classmethod - def _getmany(cls, start=1, end=10, step=1): + def getmany(cls, start=1, end=10, step=1): """ Look a range of numerals up in dictionary. @@ -45,7 +45,7 @@ def digits(cls, start=1, end=9): @start - starting numeral value (i.e. 5 for range of 5, 6, 7...) @end - ending numeral value (i.e. 5 for range of ...3, 4, 5) """ - return cls._getmany(start, end, 1) + return cls.getmany(start, end, 1) @classmethod def tens(cls, start=1, end=9): @@ -55,7 +55,7 @@ def tens(cls, start=1, end=9): @start - starting numeral value (i.e. 5 for range of 50, 60, 70...) @end - ending numeral value (i.e. 5 for range of ...30, 40, 50) """ - return cls._getmany(start, end, 10) + return cls.getmany(start, end, 10) @classmethod def hundreds(cls, start=1, end=9): @@ -65,7 +65,7 @@ def hundreds(cls, start=1, end=9): @start - starting numeral value (i.e. 5 for range of 500, 600, 700...) @end - ending numeral value (i.e. 5 for range of ...300, 400, 500) """ - return cls._getmany(start, end, 100) + return cls.getmany(start, end, 100) class IntNumberConverterGreek(IntNumberConverter): @@ -75,50 +75,50 @@ class IntNumberConverterGreek(IntNumberConverter): Derive from this class to define converters into Greek-type alphabetic numeral systems. """ - def _appendThousandMarks(self, cond): + def appendThousandMarks(self, cond): "Append thousand marks according to chosen style (plain or delimeter)." - for i, k in enumerate(self._groups): + for i, k in enumerate(self.groups): if k: if cond: - result = "{0}{1}".format(self._dict.get("THOUSAND") * i, k) + result = "{0}{1}".format(self.dict.get("THOUSAND") * i, k) else: result = "" for l in k: result = "{0}{1}{2}".format( - result, self._dict.get("THOUSAND") * i, l + result, self.dict.get("THOUSAND") * i, l ) - self._groups[i] = result + self.groups[i] = result return self - def _translateGroups(self): + def translateGroups(self): "Translate groups of numerals one by one." - for i, k in enumerate(self._groups): + for i, k in enumerate(self.groups): result = "" index = 0 while k > 0: - result = self._getNumeral(k % 10 * pow(10, index)) + result + result = self.getNumeral(k % 10 * pow(10, index)) + result index = index + 1 k = k // 10 - self._groups[i] = result + self.groups[i] = result return self - def _breakIntoGroups(self): + def breakIntoGroups(self): "Break source number into groups of 3 numerals." - while self._source > 0: - self._groups.append(self._source % 1000) - self._source = self._source // 1000 + while self.source > 0: + self.groups.append(self.source % 1000) + self.source = self.source // 1000 return self @@ -131,37 +131,37 @@ class StrNumberConverterGreek(StrNumberConverter): """ @classmethod - def _calculateMultiplier(cls, index, group): + def calculateMultiplier(cls, index, group): 'Calculate multiplier for a numerals group, according to group index or "thousand" marks present in the group.' multiplier = ( - re.match("({0}*)".format(cls._dict.get("THOUSAND")), group) + re.match("({0}*)".format(cls.dict.get("THOUSAND")), group) .groups()[0] - .count(cls._dict.get("THOUSAND")) + .count(cls.dict.get("THOUSAND")) ) # Count trailing thousand marks in the group multiplier = pow(1000, multiplier if multiplier else index) # Use thousand marks if present, otherwise use group index return multiplier - def _translateGroups(self): + def translateGroups(self): "Translate groups of numerals one by one." - for i, k in enumerate(self._groups): + for i, k in enumerate(self.groups): total = 0 # Current group total value - multiplier = self._calculateMultiplier(i, k) - k = re.sub(self._dict.get("THOUSAND"), "", k) # Strip thousand marks + multiplier = self.calculateMultiplier(i, k) + k = re.sub(self.dict.get("THOUSAND"), "", k) # Strip thousand marks for l in k: - total += self._getNumeral(l) + total += self.getNumeral(l) - self._groups[i] = total * multiplier + self.groups[i] = total * multiplier return self - def _breakIntoGroups(self, regex=""): + def breakIntoGroups(self, regex=""): "Break source number in groups of 1-3 numerals." - self._groups = re.split(regex, self._source) # Break into groups - self._groups.reverse() # Reverse groups (to ascending order) + self.groups = re.split(regex, self.source) # Break into groups + self.groups.reverse() # Reverse groups (to ascending order) return self diff --git a/omninumeric/greek/old.py b/omninumeric/greek/old.py index b14c7ed..45f8d0d 100644 --- a/omninumeric/greek/old.py +++ b/omninumeric/greek/old.py @@ -16,7 +16,7 @@ from omninumeric.greek import * -class _OldGreekDictionary(DictionaryGreek): +class OldGreekDictionary(DictionaryGreek): "Old Greek numerals dictionary" α = 1 @@ -55,7 +55,7 @@ class _OldGreekDictionary(DictionaryGreek): class ArabicNumber(IntNumberConverterGreek): "Number converter into Old Greek numeral system." - _dict = _OldGreekDictionary + dict = OldGreekDictionary def convert(self): """ @@ -64,19 +64,19 @@ def convert(self): Requires a non-zero integer. """ return ( - self._breakIntoGroups() - ._translateGroups() - ._appendThousandMarks(self._hasFlag(DELIM)) - ._purgeEmptyGroups() - ._build() - ._get() + self.breakIntoGroups() + .translateGroups() + .appendThousandMarks(self.hasFlag(DELIM)) + .purgeEmptyGroups() + .build() + .get() ) class OldGreekNumber(StrNumberConverterGreek): "Number converter from Old Greek numeral system." - _dict = _OldGreekDictionary + dict = OldGreekDictionary def convert(self): """ @@ -85,10 +85,4 @@ def convert(self): Requires a non-empty string. """ - return ( - self._breakIntoGroups() - ._purgeEmptyGroups() - ._translateGroups() - ._build() - ._get() - ) + return self.breakIntoGroups().purgeEmptyGroups().translateGroups().build().get() diff --git a/omninumeric/omninumeric.py b/omninumeric/omninumeric.py index f267993..81a32b8 100644 --- a/omninumeric/omninumeric.py +++ b/omninumeric/omninumeric.py @@ -52,34 +52,34 @@ class NumberConverter: Derive from this class to define converters into and from alphabetic numeral systems. """ - _dict = NotImplemented + dict = NotImplemented def __init__(self, source, target, flags=0): - self._source = source - self._target = target - self._flags = flags - self._groups = [] + self.source = source + self.target = target + self.flags = flags + self.groups = [] - def _hasFlag(self, flag): + def hasFlag(self, flag): "Check if a flag is set." - return self._flags & flag + return self.flags & flag # return False if self._flags & flag == 0 else True - def _get(self): + def get(self): "Return the converted number." - return self._target + return self.target - def _build(self): + def build(self): "Build the converted number from groups of numerals." - for k in self._groups: - self._target = k + self._target + for k in self.groups: + self.target = k + self.target return self @classmethod - def _getNumeral(cls, numeral, fallback): + def getNumeral(cls, numeral, fallback): """ Look a numeral up in dictionary. @@ -87,13 +87,13 @@ def _getNumeral(cls, numeral, fallback): @fallback - value to return if @numeral is not found """ - return cls._dict.get(numeral) or fallback + return cls.dict.get(numeral) or fallback - def _purgeEmptyGroups(self): + def purgeEmptyGroups(self): "Remove empty groups from numeral groups collection." - while self._groups.count(""): - self._groups.remove("") # Purge empty groups + while self.groups.count(""): + self.groups.remove("") # Purge empty groups return self def convert(self): @@ -110,21 +110,21 @@ class IntNumberConverter(NumberConverter): def __init__(self, value, flags=0): super().__init__(value, "", flags) - def _validate(self): + def validate(self): "Validate that source number is a natural number." - isinstanceEx(self._source, int, "Integer required, got {0}") + isinstanceEx(self.source, int, "Integer required, got {0}") - if self._source <= 0: + if self.source <= 0: raise ValueError("Natural number required") return self @classmethod - def _getNumeral(cls, numeral): + def getNumeral(cls, numeral): "Get alphabetic digit for given value." - return super()._getNumeral(numeral, "") + return super().getNumeral(numeral, "") class StrNumberConverter(NumberConverter): @@ -137,24 +137,24 @@ class StrNumberConverter(NumberConverter): def __init__(self, alphabetic, flags=0): super().__init__(alphabetic, 0, flags) - def _validate(self): + def validate(self): "Validate that source number is a non-empty string." - isinstanceEx(self._source, str, "String required, got {0}") + isinstanceEx(self.source, str, "String required, got {0}") - if not self._source: + if not self.source: raise ValueError("Non-empty string required") return self - def _prepare(self): + def prepare(self): "Prepare source number for further operations." - self._source = str.lower(str.strip(self._source)) + self.source = str.lower(str.strip(self.source)) return self @classmethod - def _getNumeral(cls, numeral): + def getNumeral(cls, numeral): "Get value for given alphabetic digit." - return super()._getNumeral(numeral, 0) + return super().getNumeral(numeral, 0) From 235aaaba88698cb2ba6552d87350d3e3807a9865 Mon Sep 17 00:00:00 2001 From: Andrey Shur Date: Sun, 21 Aug 2022 23:10:30 +0300 Subject: [PATCH 4/9] Streamline class names --- omninumeric/cyrillic/cyrillic.py | 32 ++++++++++++++++---------------- omninumeric/greek/greek.py | 12 ++++-------- omninumeric/greek/old.py | 16 ++++++---------- omninumeric/omninumeric.py | 4 ++-- 4 files changed, 28 insertions(+), 36 deletions(-) diff --git a/omninumeric/cyrillic/cyrillic.py b/omninumeric/cyrillic/cyrillic.py index 304901a..aaf3333 100644 --- a/omninumeric/cyrillic/cyrillic.py +++ b/omninumeric/cyrillic/cyrillic.py @@ -4,11 +4,11 @@ "This module provides tools for reading and writing numbers in Cyrillic numeral system." import re -from omninumeric.greek import * +from omninumeric import greek -CU_PLAIN = PLAIN # Write in plain style flag -CU_DELIM = DELIM # Read/write in delim style flag +CU_PLAIN = greek.PLAIN # Write in plain style flag +CU_DELIM = greek.DELIM # Read/write in delim style flag CU_NOTITLO = 0b10 # DO NOT append titlo flag CU_ENDDOT = 0b100 # Append dot flag CU_PREDOT = 0b1000 # Prepend dot flag @@ -18,7 +18,7 @@ CU_ALLDOT = CU_ENDDOT | CU_PREDOT | CU_DELIMDOT # Wrapper and delimeter dots flag -class CyrillicDictionary(DictionaryGreek): +class Dictionary(greek.Dictionary): "Cyrillic numerals ditcionary." а = 1 @@ -53,10 +53,10 @@ class CyrillicDictionary(DictionaryGreek): DOT = "." # Dot decorator -class ArabicNumber(IntNumberConverterGreek): +class IntConverter(greek.IntConverter): "Number converter into Cyrillic numeral system." - dict = CyrillicDictionary + dict = Dictionary def ambiguityCheck(self, cond, flag): if cond: @@ -145,10 +145,10 @@ def convert(self): ) -class CyrillicNumber(StrNumberConverterGreek): +class StrConverter(greek.StrConverter): "Number converter from Cyrillic numeral system." - dict = CyrillicDictionary + dict = Dictionary regex = "({0}*[{1}]?(?:(?:{0}*[{3}])?{4}|(?:{0}*[{2}])?(?:{0}*[{3}])?))".format( dict.get("THOUSAND"), @@ -200,23 +200,23 @@ def convert(self): class Cyrillic: - def read(number, flags=0): + def write(number, flags=0): """ - Convert from Cyrillic numeral system. + Convert into Cyrillic numeral system. Uses plain style by default. - Requires a non-empty string. + Requires a non-zero integer. """ - return CyrillicNumber(number, flags).convert() + return IntConverter(number, flags).convert() - def write(number, flags=0): + def read(number, flags=0): """ - Convert into Cyrillic numeral system. Uses plain style by default. + Convert from Cyrillic numeral system. - Requires a non-zero integer. + Requires a non-empty string. """ - return ArabicNumber(number, flags).convert() + return StrConverter(number, flags).convert() def to_cu(integer, flags=0): diff --git a/omninumeric/greek/greek.py b/omninumeric/greek/greek.py index f203fed..124d657 100644 --- a/omninumeric/greek/greek.py +++ b/omninumeric/greek/greek.py @@ -4,18 +4,14 @@ import re -from omninumeric import ( - Dictionary, - IntNumberConverter, - StrNumberConverter, -) +import omninumeric PLAIN = 0 # Write in plain style flag DELIM = 0b1 # Read/write in delim style flag -class DictionaryGreek(Dictionary): +class Dictionary(omninumeric.Dictionary): """ ABC for Greek-type alphabetic numeral systems ditcionaries. @@ -68,7 +64,7 @@ def hundreds(cls, start=1, end=9): return cls.getmany(start, end, 100) -class IntNumberConverterGreek(IntNumberConverter): +class IntConverter(omninumeric.IntConverter): """ ABC for number conversion into Greek-type alphabetic numeral systems. @@ -123,7 +119,7 @@ def breakIntoGroups(self): return self -class StrNumberConverterGreek(StrNumberConverter): +class StrConverter(omninumeric.StrConverter): """ ABC for number conversion from Greek-type alphabetic numeral systems. diff --git a/omninumeric/greek/old.py b/omninumeric/greek/old.py index 45f8d0d..5a9353e 100644 --- a/omninumeric/greek/old.py +++ b/omninumeric/greek/old.py @@ -9,14 +9,10 @@ __all__ = ["ArabicNumber", "OldGreekNumber"] -from omninumeric import ( - StrNumberConverter, - IntNumberConverter, -) -from omninumeric.greek import * +from omninumeric import greek -class OldGreekDictionary(DictionaryGreek): +class Dictionary(greek.Dictionary): "Old Greek numerals dictionary" α = 1 @@ -52,10 +48,10 @@ class OldGreekDictionary(DictionaryGreek): DOT = "." # Dot decorator -class ArabicNumber(IntNumberConverterGreek): +class IntConverter(greek.IntConverter): "Number converter into Old Greek numeral system." - dict = OldGreekDictionary + dict = Dictionary def convert(self): """ @@ -73,10 +69,10 @@ def convert(self): ) -class OldGreekNumber(StrNumberConverterGreek): +class StrConverter(greek.StrConverter): "Number converter from Old Greek numeral system." - dict = OldGreekDictionary + dict = Dictionary def convert(self): """ diff --git a/omninumeric/omninumeric.py b/omninumeric/omninumeric.py index 81a32b8..b1bf027 100644 --- a/omninumeric/omninumeric.py +++ b/omninumeric/omninumeric.py @@ -100,7 +100,7 @@ def convert(self): raise NotImplementedError -class IntNumberConverter(NumberConverter): +class IntConverter(NumberConverter): """ ABC for number conversion into alphabetic numeral systems. @@ -127,7 +127,7 @@ def getNumeral(cls, numeral): return super().getNumeral(numeral, "") -class StrNumberConverter(NumberConverter): +class StrConverter(NumberConverter): """ ABC for number conversion from alphabetic numeral systems. From f6b9474774ef69882485195843fe26b1f452cba5 Mon Sep 17 00:00:00 2001 From: Andrey Shur Date: Mon, 22 Aug 2022 00:58:12 +0300 Subject: [PATCH 5/9] Refactoring. Improved interface --- omninumeric/cyrillic/cyrillic.py | 114 +++++++++++------------- omninumeric/greek/greek.py | 12 ++- omninumeric/greek/old.py | 4 +- omninumeric/omninumeric.py | 7 +- tests/test_cyrillic.py | 143 ++++++++++++++++--------------- 5 files changed, 133 insertions(+), 147 deletions(-) diff --git a/omninumeric/cyrillic/cyrillic.py b/omninumeric/cyrillic/cyrillic.py index aaf3333..4fb2576 100644 --- a/omninumeric/cyrillic/cyrillic.py +++ b/omninumeric/cyrillic/cyrillic.py @@ -7,15 +7,15 @@ from omninumeric import greek -CU_PLAIN = greek.PLAIN # Write in plain style flag -CU_DELIM = greek.DELIM # Read/write in delim style flag -CU_NOTITLO = 0b10 # DO NOT append titlo flag -CU_ENDDOT = 0b100 # Append dot flag -CU_PREDOT = 0b1000 # Prepend dot flag -CU_DOT = 0b10000 # Delimeter dots flag -CU_DELIMDOT = CU_DOT | CU_DELIM # Delimeter dots flag (forces delim style) -CU_WRAPDOT = CU_ENDDOT | CU_PREDOT # Wrap in dots flag -CU_ALLDOT = CU_ENDDOT | CU_PREDOT | CU_DELIMDOT # Wrapper and delimeter dots flag +PLAIN = greek.PLAIN # Write in plain style flag +DELIM = greek.DELIM # Read/write in delim style flag +NOTITLO = 0b10 # DO NOT append titlo flag +ENDDOT = 0b100 # Append dot flag +PREDOT = 0b1000 # Prepend dot flag +DOT = 0b10000 # Delimeter dots flag +DELIMDOT = DOT | DELIM # Delimeter dots flag (forces delim style) +WRAPDOT = ENDDOT | PREDOT # Wrap in dots flag +ALLDOT = ENDDOT | PREDOT | DELIMDOT # Wrapper and delimeter dots flag class Dictionary(greek.Dictionary): @@ -48,17 +48,22 @@ class Dictionary(greek.Dictionary): ѱ = 700 ѿ = 800 ц = 900 + + +class Const: THOUSAND = "҂" # "Thousand" mark TITLO = "҃" # "Titlo" decorator - DOT = "." # Dot decorator + DELIMETER = "." # Dot decorator class IntConverter(greek.IntConverter): "Number converter into Cyrillic numeral system." - dict = Dictionary + dict_ = Dictionary + const = Const def ambiguityCheck(self, cond, flag): + "Force delimeter for ambiguous numbers (i.e. ҂а҃і and ҂а.і҃)." if cond: try: if (self.groups[0] // 10 % 10 == 1) and ( @@ -76,7 +81,7 @@ def swapDigits(self): for i, k in enumerate(self.groups): self.groups[i] = re.sub( - "({0})([{1}])".format(self.dict.get(10), self.dict.digits()), + "({0})([{1}])".format(self.dict_.get(10), self.dict_.digits()), "\g<2>\g<1>", self.groups[i], ) @@ -89,15 +94,15 @@ def appendTitlo(self, cond): if not cond: result = re.subn( "([\S]+)(?{0}\g<2>".format(self.dict.get("TITLO")), + "\g<1>{0}\g<2>".format(self.const.TITLO), self.target, ) self.target = ( result[0] if result[1] > 0 - else "{0}{1}".format(self.target, self.dict.get("TITLO")) + else "{0}{1}".format(self.target, self.const.TITLO) ) return self @@ -107,7 +112,7 @@ def delimDots(self, cond): if cond: for i, k in enumerate(self.groups[1:]): - self.groups[i + 1] = "{0}{1}".format(k, self.dict.get("DOT")) + self.groups[i + 1] = "{0}{1}".format(k, self.const.DELIMETER) return self @@ -115,32 +120,28 @@ def wrapDot(self, cond_a, cond_b): "Prepend and/or append a dot if appropriate flags are set." self.target = "{0}{1}{2}".format( - self.dict.get("DOT") if cond_a else "", + self.const.DELIMETER if cond_a else "", self.target, - self.dict.get("DOT") if cond_b else "", + self.const.DELIMETER if cond_b else "", ) return self def convert(self): - """ - Convert into Cyrillic numeral system. Uses plain style by default. - - Requires a non-zero integer. - """ + "Convert into Cyrillic numeral system. Uses plain style by default." return ( self.validate() .breakIntoGroups() - .ambiguityCheck(self.hasFlag(CU_DELIM), CU_DOT) + .ambiguityCheck(self.hasFlag(DELIM), DOT) .translateGroups() - .appendThousandMarks(self.hasFlag(CU_DELIM)) + .appendThousandMarks(self.hasFlag(DELIM)) .purgeEmptyGroups() .swapDigits() - .delimDots(self.hasFlag(CU_DOT)) + .delimDots(self.hasFlag(DOT)) .build() - .appendTitlo(self.hasFlag(CU_NOTITLO)) - .wrapDot(self.hasFlag(CU_PREDOT), self.hasFlag(CU_ENDDOT)) + .appendTitlo(self.hasFlag(NOTITLO)) + .wrapDot(self.hasFlag(PREDOT), self.hasFlag(ENDDOT)) .get() ) @@ -148,14 +149,15 @@ def convert(self): class StrConverter(greek.StrConverter): "Number converter from Cyrillic numeral system." - dict = Dictionary + dict_ = Dictionary + const = Const regex = "({0}*[{1}]?(?:(?:{0}*[{3}])?{4}|(?:{0}*[{2}])?(?:{0}*[{3}])?))".format( - dict.get("THOUSAND"), - dict.hundreds(), - dict.tens(2), - dict.digits(), - dict.get(10), + const.THOUSAND, + dict_.hundreds(), + dict_.tens(2), + dict_.digits(), + dict_.get(10), ) # Regular expression for typical Cyrillic numeral system number def prepare(self): @@ -163,7 +165,7 @@ def prepare(self): super().prepare() self.source = re.sub( - "[{0}\{1}]".format(self.dict.get("TITLO"), self.dict.get("DOT")), + "[{0}\{1}]".format(self.const.TITLO, self.const.DELIMETER), "", self.source, ) # Strip ҃decorators @@ -182,11 +184,7 @@ def validate(self): return self def convert(self): - """ - Convert from Cyrillic numeral system. - - Requires a non-empty string. - """ + "Convert from Cyrillic numeral system." return ( self.prepare() @@ -199,33 +197,21 @@ def convert(self): ) -class Cyrillic: - def write(number, flags=0): - """ - Convert into Cyrillic numeral system. Uses plain style by default. - - Requires a non-zero integer. - """ - - return IntConverter(number, flags).convert() - - def read(number, flags=0): - """ - Convert from Cyrillic numeral system. - - Requires a non-empty string. - """ - - return StrConverter(number, flags).convert() +def write(number, flags=0): + """ + Convert into Cyrillic numeral system. Uses plain style by default. + Requires a non-zero integer. + """ -def to_cu(integer, flags=0): - "Deprecated. Use ArabicNumber().convert() instead." + return IntConverter(number, flags).convert() - return Cyrillic.write(integer, flags) +def read(number, flags=0): + """ + Convert from Cyrillic numeral system. -def to_arab(alphabetic, flags=0): - "Deprecated. Use CyrillicNumber().convert() instead." + Requires a non-empty string. + """ - return Cyrillic.read(alphabetic, flags) + return StrConverter(number, flags).convert() diff --git a/omninumeric/greek/greek.py b/omninumeric/greek/greek.py index 124d657..c509d76 100644 --- a/omninumeric/greek/greek.py +++ b/omninumeric/greek/greek.py @@ -78,15 +78,13 @@ def appendThousandMarks(self, cond): if k: if cond: - result = "{0}{1}".format(self.dict.get("THOUSAND") * i, k) + result = "{0}{1}".format(self.const.THOUSAND * i, k) else: result = "" for l in k: - result = "{0}{1}{2}".format( - result, self.dict.get("THOUSAND") * i, l - ) + result = "{0}{1}{2}".format(result, self.const.THOUSAND * i, l) self.groups[i] = result @@ -131,9 +129,9 @@ def calculateMultiplier(cls, index, group): 'Calculate multiplier for a numerals group, according to group index or "thousand" marks present in the group.' multiplier = ( - re.match("({0}*)".format(cls.dict.get("THOUSAND")), group) + re.match("({0}*)".format(cls.const.THOUSAND), group) .groups()[0] - .count(cls.dict.get("THOUSAND")) + .count(cls.const.THOUSAND) ) # Count trailing thousand marks in the group multiplier = pow(1000, multiplier if multiplier else index) # Use thousand marks if present, otherwise use group index @@ -145,7 +143,7 @@ def translateGroups(self): for i, k in enumerate(self.groups): total = 0 # Current group total value multiplier = self.calculateMultiplier(i, k) - k = re.sub(self.dict.get("THOUSAND"), "", k) # Strip thousand marks + k = re.sub(self.const.THOUSAND, "", k) # Strip thousand marks for l in k: total += self.getNumeral(l) diff --git a/omninumeric/greek/old.py b/omninumeric/greek/old.py index 5a9353e..af2c25a 100644 --- a/omninumeric/greek/old.py +++ b/omninumeric/greek/old.py @@ -51,8 +51,6 @@ class Dictionary(greek.Dictionary): class IntConverter(greek.IntConverter): "Number converter into Old Greek numeral system." - dict = Dictionary - def convert(self): """ Convert into Old Greek numeral system. Uses plain style by default. @@ -62,7 +60,7 @@ def convert(self): return ( self.breakIntoGroups() .translateGroups() - .appendThousandMarks(self.hasFlag(DELIM)) + .appendThousandMarks(self.hasFlag(self.flag.DELIM)) .purgeEmptyGroups() .build() .get() diff --git a/omninumeric/omninumeric.py b/omninumeric/omninumeric.py index b1bf027..d442a8e 100644 --- a/omninumeric/omninumeric.py +++ b/omninumeric/omninumeric.py @@ -52,7 +52,8 @@ class NumberConverter: Derive from this class to define converters into and from alphabetic numeral systems. """ - dict = NotImplemented + dict_ = NotImplemented + const = NotImplemented def __init__(self, source, target, flags=0): self.source = source @@ -87,7 +88,7 @@ def getNumeral(cls, numeral, fallback): @fallback - value to return if @numeral is not found """ - return cls.dict.get(numeral) or fallback + return cls.dict_.get(numeral) or fallback def purgeEmptyGroups(self): "Remove empty groups from numeral groups collection." @@ -131,7 +132,7 @@ class StrConverter(NumberConverter): """ ABC for number conversion from alphabetic numeral systems. - Derive from this class to define converters from ABS. + Derive from this class to define converters from alphabetic numeral systems. """ def __init__(self, alphabetic, flags=0): diff --git a/tests/test_cyrillic.py b/tests/test_cyrillic.py index 82a4104..fcbd31c 100644 --- a/tests/test_cyrillic.py +++ b/tests/test_cyrillic.py @@ -1,140 +1,143 @@ # -*- coding: UTF-8 -*- import unittest from omninumeric.cyrillic import * -from omninumeric.cyrillic import to_cu, to_arab class ToCUPlainTestCase(unittest.TestCase): def testToCUDigits(self): - self.assertEqual(to_cu(1), "а҃") - self.assertEqual(to_cu(9), "ѳ҃") + self.assertEqual(write(1), "а҃") + self.assertEqual(write(9), "ѳ҃") def testToCUTens(self): - self.assertEqual(to_cu(10), "і҃") - self.assertEqual(to_cu(18), "и҃і") - self.assertEqual(to_cu(22), "к҃в") + self.assertEqual(write(10), "і҃") + self.assertEqual(write(18), "и҃і") + self.assertEqual(write(22), "к҃в") def testToCUHundreds(self): - self.assertEqual(to_cu(100), "р҃") - self.assertEqual(to_cu(207), "с҃з") - self.assertEqual(to_cu(333), "тл҃г") + self.assertEqual(write(100), "р҃") + self.assertEqual(write(207), "с҃з") + self.assertEqual(write(333), "тл҃г") def testToCUThousand(self): - self.assertEqual(to_cu(1000), "҂а҃") - self.assertEqual(to_cu(1006), "҂а҃ѕ") - self.assertEqual(to_cu(1010), "҂а҃і") - self.assertEqual(to_cu(1015), "҂ає҃і") - self.assertEqual(to_cu(1444), "҂аум҃д") - self.assertEqual(to_cu(11000), "҂і҂а҃") + self.assertEqual(write(1000), "҂а҃") + self.assertEqual(write(1006), "҂а҃ѕ") + self.assertEqual(write(1010), "҂а҃і") + self.assertEqual(write(1015), "҂ає҃і") + self.assertEqual(write(1444), "҂аум҃д") + self.assertEqual(write(11000), "҂і҂а҃") def testToCUBig(self): - self.assertEqual(to_cu(10001010001), "҂҂҂і҂҂а҂і҃а") - self.assertEqual(to_cu(50000000000), "҂҂҂н҃") - self.assertEqual(to_cu(60000070000), "҂҂҂ѯ҂ѻ҃") - self.assertEqual(to_cu(111111111), "҂҂р҂҂і҂҂а҂р҂і҂ара҃і") + self.assertEqual(write(10001010001), "҂҂҂і҂҂а҂і҃а") + self.assertEqual(write(50000000000), "҂҂҂н҃") + self.assertEqual(write(60000070000), "҂҂҂ѯ҂ѻ҃") + self.assertEqual(write(111111111), "҂҂р҂҂і҂҂а҂р҂і҂ара҃і") class ToCUDelimTestCase(unittest.TestCase): def testToCUDelimAmbiguity(self): - self.assertEqual(to_cu(1010, CU_DELIM), "҂а.і҃") - self.assertEqual(to_cu(11000, CU_DELIM), "҂а҃і") - self.assertEqual(to_cu(10010, CU_DELIM), "҂і҃і") - self.assertEqual(to_cu(110010, CU_DELIM), "҂рі҃і") - self.assertEqual(to_cu(100010, CU_DELIM), "҂р.і҃") - self.assertEqual(to_cu(110000, CU_DELIM), "҂р҃і") - self.assertEqual(to_cu(100011, CU_DELIM), "҂р.а҃і") - self.assertEqual(to_cu(111000, CU_DELIM), "҂ра҃і") + self.assertEqual(write(1010, DELIM), "҂а.і҃") + self.assertEqual(write(11000, DELIM), "҂а҃і") + self.assertEqual(write(10010, DELIM), "҂і҃і") + self.assertEqual(write(110010, DELIM), "҂рі҃і") + self.assertEqual(write(100010, DELIM), "҂р.і҃") + self.assertEqual(write(110000, DELIM), "҂р҃і") + self.assertEqual(write(100011, DELIM), "҂р.а҃і") + self.assertEqual(write(111000, DELIM), "҂ра҃і") def testToCUDelimBig(self): - self.assertEqual(to_cu(10001010001, CU_DELIM), "҂҂҂і҂҂а҂і҃а") - self.assertEqual(to_cu(50000000000, CU_DELIM), "҂҂҂н҃") - self.assertEqual(to_cu(60000070000, CU_DELIM), "҂҂҂ѯ҂ѻ҃") - self.assertEqual(to_cu(111111111, CU_DELIM), "҂҂раі҂раіра҃і") + self.assertEqual(write(10001010001, DELIM), "҂҂҂і҂҂а҂і҃а") + self.assertEqual(write(50000000000, DELIM), "҂҂҂н҃") + self.assertEqual(write(60000070000, DELIM), "҂҂҂ѯ҂ѻ҃") + self.assertEqual(write(111111111, DELIM), "҂҂раі҂раіра҃і") class ToCUFlagsTestCase(unittest.TestCase): def testToCUNotitlo(self): - self.assertEqual(to_cu(1, CU_NOTITLO), "а") - self.assertEqual(to_cu(11000, CU_NOTITLO), "҂і҂а") + self.assertEqual(write(1, NOTITLO), "а") + self.assertEqual(write(11000, NOTITLO), "҂і҂а") def testToCUEnddot(self): - self.assertEqual(to_cu(1, CU_ENDDOT), "а҃.") + self.assertEqual(write(1, ENDDOT), "а҃.") def testToCUWrapdot(self): - self.assertEqual(to_cu(1, CU_WRAPDOT), ".а҃.") + self.assertEqual(write(1, WRAPDOT), ".а҃.") def testToCUDelimdot(self): - self.assertEqual(to_cu(1001, CU_DELIMDOT), "҂а.а҃") - self.assertEqual(to_cu(1010, CU_DELIMDOT), "҂а.і҃") - self.assertEqual(to_cu(11000, CU_DELIMDOT), "҂а҃і") - self.assertEqual(to_cu(111111111, CU_DELIMDOT), "҂҂раі.҂раі.ра҃і") + self.assertEqual(write(1001, DELIMDOT), "҂а.а҃") + self.assertEqual(write(1010, DELIMDOT), "҂а.і҃") + self.assertEqual(write(11000, DELIMDOT), "҂а҃і") + self.assertEqual( + write(111111111, DELIMDOT), "҂҂раі.҂раі.ра҃і" + ) def testToCUAlldot(self): - self.assertEqual(to_cu(1001, CU_ALLDOT), ".҂а.а҃.") + self.assertEqual(write(1001, ALLDOT), ".҂а.а҃.") def testToCUDotscustom(self): - self.assertEqual(to_cu(1001, CU_ENDDOT + CU_DELIMDOT), "҂а.а҃.") + self.assertEqual( + write(1001, ENDDOT + DELIMDOT), "҂а.а҃." + ) class ToArabDelimTestCase(unittest.TestCase): def testToArabDigits(self): - self.assertEqual(1, to_arab("а҃")) - self.assertEqual(9, to_arab("ѳ")) + self.assertEqual(1, read("а҃")) + self.assertEqual(9, read("ѳ")) def testToArabTens(self): - self.assertEqual(10, to_arab("і҃")) - self.assertEqual(18, to_arab("и҃і")) - self.assertEqual(22, to_arab("к҃в")) + self.assertEqual(10, read("і҃")) + self.assertEqual(18, read("и҃і")) + self.assertEqual(22, read("к҃в")) def testToArabHundreds(self): - self.assertEqual(100, to_arab("р҃")) - self.assertEqual(207, to_arab("с҃з")) - self.assertEqual(333, to_arab("тл҃г")) + self.assertEqual(100, read("р҃")) + self.assertEqual(207, read("с҃з")) + self.assertEqual(333, read("тл҃г")) def testToArabThousands(self): - self.assertEqual(1000, to_arab("҂а҃")) - self.assertEqual(1006, to_arab("҂а҃ѕ")) - self.assertEqual(1015, to_arab("҂ає҃і")) - self.assertEqual(1444, to_arab("҂аум҃д")) + self.assertEqual(1000, read("҂а҃")) + self.assertEqual(1006, read("҂а҃ѕ")) + self.assertEqual(1015, read("҂ає҃і")) + self.assertEqual(1444, read("҂аум҃д")) def testToArabBig(self): - self.assertEqual(10001010001, to_arab("҂҂҂і҂҂а҂і҃а")) - self.assertEqual(50000000000, to_arab("҂҂҂н҃")) - self.assertEqual(60000070000, to_arab("҂҂҂ѯ҂ѻ҃")) + self.assertEqual(10001010001, read("҂҂҂і҂҂а҂і҃а")) + self.assertEqual(50000000000, read("҂҂҂н҃")) + self.assertEqual(60000070000, read("҂҂҂ѯ҂ѻ҃")) def testToArabNoTsnd(self): - self.assertEqual(80500690700, to_arab("пфхч҃ѱ")) + self.assertEqual(80500690700, read("пфхч҃ѱ")) def testToArabNotitlo(self): - self.assertEqual(1, to_arab("а")) + self.assertEqual(1, read("а")) def testToArabSpaced(self): - self.assertEqual(1, to_arab("а҃ ")) + self.assertEqual(1, read("а҃ ")) def testToArabUppercase(self): - self.assertEqual(1, to_arab("А҃")) + self.assertEqual(1, read("А҃")) def testToArabMixed(self): - self.assertEqual(2021, to_arab(" вКА")) + self.assertEqual(2021, read(" вКА")) class ToArabPlainTestCase(unittest.TestCase): def testToArabPlainBig(self): - self.assertEqual(11000, to_arab("҂і҂а")) - self.assertEqual(111111111, to_arab("҂҂р҂҂і҂҂а҂р҂і҂ара҃і")) + self.assertEqual(11000, read("҂і҂а")) + self.assertEqual(111111111, read("҂҂р҂҂і҂҂а҂р҂і҂ара҃і")) class ErrorTestCase(unittest.TestCase): def testToCUError(self): - self.assertRaises(TypeError, to_cu, "String") - self.assertRaises(TypeError, to_cu, 9.75) - self.assertRaises(ValueError, to_cu, 0) - self.assertRaises(ValueError, to_cu, -69) + self.assertRaises(TypeError, write, "String") + self.assertRaises(TypeError, write, 9.75) + self.assertRaises(ValueError, write, 0) + self.assertRaises(ValueError, write, -69) def testToArabError(self): - self.assertRaises(TypeError, to_arab, 420) - self.assertRaises(ValueError, to_arab, "") - self.assertRaises(ValueError, to_arab, "A113") + self.assertRaises(TypeError, read, 420) + self.assertRaises(ValueError, read, "") + self.assertRaises(ValueError, read, "A113") if __name__ == "__main__": From 9a30e9ea3a5bc10706ccc48b9658e668bd5b7668 Mon Sep 17 00:00:00 2001 From: Andrey Shur Date: Mon, 22 Aug 2022 01:09:26 +0300 Subject: [PATCH 6/9] Refactor flag checks and some argument logic --- omninumeric/cyrillic/cyrillic.py | 35 ++++++++++++++++++++++---------- omninumeric/greek/greek.py | 18 ++++++++-------- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/omninumeric/cyrillic/cyrillic.py b/omninumeric/cyrillic/cyrillic.py index 4fb2576..2304d02 100644 --- a/omninumeric/cyrillic/cyrillic.py +++ b/omninumeric/cyrillic/cyrillic.py @@ -64,7 +64,7 @@ class IntConverter(greek.IntConverter): def ambiguityCheck(self, cond, flag): "Force delimeter for ambiguous numbers (i.e. ҂а҃і and ҂а.і҃)." - if cond: + if self.hasFlag(cond): try: if (self.groups[0] // 10 % 10 == 1) and ( self.groups[1] // 10 % 10 == 0 @@ -91,7 +91,7 @@ def swapDigits(self): def appendTitlo(self, cond): 'Apply "titlo" decorator unless appropriate flag is set.' - if not cond: + if not self.hasFlag(cond): result = re.subn( "([\S]+)(? Date: Sun, 21 Aug 2022 23:03:46 +0300 Subject: [PATCH 7/9] Define exports --- omninumeric/__init__.py | 8 ++------ omninumeric/cyrillic/__init__.py | 34 +++++++++++--------------------- omninumeric/greek/__init__.py | 16 ++------------- 3 files changed, 16 insertions(+), 42 deletions(-) diff --git a/omninumeric/__init__.py b/omninumeric/__init__.py index 00b16dd..67a4f68 100644 --- a/omninumeric/__init__.py +++ b/omninumeric/__init__.py @@ -1,7 +1,3 @@ -from .omninumeric import ( - Dictionary, - IntNumberConverter, - StrNumberConverter, -) +from .omninumeric import * -__all__ = ["Dictionary", "IntNumberConverter", "StrNumberConverter"] +__all__ = ["Dictionary", "IntConverter", "StrConverter"] diff --git a/omninumeric/cyrillic/__init__.py b/omninumeric/cyrillic/__init__.py index 8fd61ab..bc82b84 100644 --- a/omninumeric/cyrillic/__init__.py +++ b/omninumeric/cyrillic/__init__.py @@ -1,25 +1,15 @@ -from .cyrillic import ( - CU_PLAIN, - CU_DELIM, - CU_NOTITLO, - CU_ENDDOT, - CU_DELIMDOT, - CU_WRAPDOT, - CU_ALLDOT, - ArabicNumber, - CyrillicNumber, - Cyrillic, - to_cu, - to_arab, -) +from .cyrillic import * __all__ = [ - "Cyrillic", - "CU_PLAIN", - "CU_DELIM", - "CU_NOTITLO", - "CU_ENDDOT", - "CU_DELIMDOT", - "CU_WRAPDOT", - "CU_ALLDOT", + "PLAIN", + "DELIM", + "NOTITLO", + "ENDDOT", + "PREDOT", + "DOT", + "DELIMDOT", + "WRAPDOT", + "ALLDOT", + "read", + "write", ] diff --git a/omninumeric/greek/__init__.py b/omninumeric/greek/__init__.py index 57c6f1b..f499ba8 100644 --- a/omninumeric/greek/__init__.py +++ b/omninumeric/greek/__init__.py @@ -1,15 +1,3 @@ -from .greek import ( - PLAIN, - DELIM, - DictionaryGreek, - IntNumberConverterGreek, - StrNumberConverterGreek, -) +from .greek import * -__all__ = [ - "PLAIN", - "DELIM", - "DictionaryGreek", - "IntNumberConverterGreek", - "StrNumberConverterGreek", -] +__all__ = ["PLAIN", "DELIM", "Dictionary", "IntConverter", "StrConverter"] From e4218b1d86847866f056883c88eb0f3907997862 Mon Sep 17 00:00:00 2001 From: Andrey Shur Date: Mon, 22 Aug 2022 01:34:36 +0300 Subject: [PATCH 8/9] Update doco --- docs/CHANGELOG.md | 5 +++++ docs/CHANGELOG.ru.md | 5 +++++ docs/README.md | 22 +++++++++++----------- docs/README.ru.md | 22 +++++++++++----------- setup.py | 2 +- tests/test_cyrillic.py | 8 ++------ 6 files changed, 35 insertions(+), 29 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 9d8d7a3..3b77ef0 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -2,6 +2,11 @@ 🌏 English [Русский](./CHANGELOG.ru.md) +## 2.0.0 + +- Refactoring +- Interface overhaul + ## 1.0.0 diff --git a/docs/CHANGELOG.ru.md b/docs/CHANGELOG.ru.md index 2703993..ded9aaf 100644 --- a/docs/CHANGELOG.ru.md +++ b/docs/CHANGELOG.ru.md @@ -2,6 +2,11 @@ 🌏 [English](./CHANGELOG.md) Русский +## 2.0.0 + +- Рефакторинг +- Переработка интерфейсов + ## 1.0.0 diff --git a/docs/README.md b/docs/README.md index 460ee1a..1006c75 100644 --- a/docs/README.md +++ b/docs/README.md @@ -26,36 +26,36 @@ See [Introduction](./INTRODUCTION.md) to learn about Cyrillic numeral system. ## Usage - import omninumeric.cyrillic as CU + from omninumeric import cyrillic # Convert a number into Cyrillic # Requires non-zero int, returns str - a = CU.ArabicNumber(1).convert() + a = cyrillic.write(1) # Convert a Cyrillic number to Arabic # Requires non-empty str, returns int - b = CU.CyrillicNumber("а҃").convert() + b = cyrillic.read("а҃") "Delimiter" and "plain" style numbers are supported both for reading and writing, "plain" style is used by default for writing. When writing into Cyrillic, several falgs can be used: - # CU_DELIM flag sets conversion to "delimeter" style + # DELIM flag sets conversion to "delimeter" style - c = cu.to_alphabetic(111111, CU_DELIM) + c = cyrillic.write(111111, cyrillic.DELIM) - # CU_NOTITLO flag omits "titlo" decorator + # NOTITLO flag omits "titlo" decorator - d = cu.to_alphabetic(11000, CU_DELIM | CU_NOTITLO) + d = cyrillic.write(11000, cyrillic.DELIM | cyrillic.NOTITLO) # Following flags control dot styling: # - # CU_ENDDOT - append dot at the end - # CU_WRAPDOT - append dot at both ends - # CU_DELIMDOT - add dot separator between digit groups. Sets conversion to "delim" style - # CU_ALLDOT - combine CU_WRAPDOT and CU_DELIMDOT + # ENDDOT - append dot at the end + # WRAPDOT - append dot at both ends + # DELIMDOT - add dot separator between digit groups. Sets conversion to "delim" style + # ALLDOT - combine WRAPDOT and DELIMDOT ## Contributing diff --git a/docs/README.ru.md b/docs/README.ru.md index 632688f..0fd1313 100644 --- a/docs/README.ru.md +++ b/docs/README.ru.md @@ -26,36 +26,36 @@ ## Использование - import omninumeric.cyrillic as cu + from omninumeric import cyrillic # Преобразовать арабское число в церковнославянское # Принимает ненулевой int, возвращает str - a = CU.ArabicNumber(1).convert() + a = cyrillic.write(1) # Преобразовать церковнославянское число в арабское # Принимает непустой str, возвращает int - b = CU.CyrillicNumber("а҃").convert() + b = cyrillic.read("а҃") В обоих направлениях поддерживаются варианты записи "сплошной" и "по группам", "сплошная" запись используется по умолчанию. При записи в ЦСЯ возможно использование слеедующих флагов: - # CU_DELIM устанавливает вариант записи в ЦСЯ "по группам" + # DELIM устанавливает вариант записи в ЦСЯ "по группам" - c = cu.to_alphabetic(111111, CU_DELIM) + c = cyrillic.write(111111, cyrillic.DELIM) - # CU_NOTITLO опускает вывод знака "титло" + # NOTITLO опускает вывод знака "титло" - d = cu.to_alphabetic(11000, CU_DELIM | CU_NOTITLO) + d = cyrillic.write(11000, cyrillic.DELIM | cyrillic.NOTITLO) # Следующие флаги управляют декорированием точками: # - # CU_ENDDOT - выводит точку в конце - # CU_WRAPDOT - выводит точки с обеих сторон - # CU_DELIMDOT - выводит точки-разделители разрядов. Устанавливает вариант записи "по группам" - # CU_ALLDOT - комбинация флагов CU_WRAPDOT и CU_DELIMDOT + # ENDDOT - выводит точку в конце + # WRAPDOT - выводит точки с обеих сторон + # DELIMDOT - выводит точки-разделители разрядов. Устанавливает вариант записи "по группам" + # ALLDOT - комбинация флагов WRAPDOT и DELIMDOT ## Принять участие diff --git a/setup.py b/setup.py index ec58b24..8b0b94f 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name="omninumeric", - version="1.0.0", + version="2.0.0", author="Andrei Shur", author_email="amshoor@gmail.com", description="Read and write numbers in alphabetic numeral systems", diff --git a/tests/test_cyrillic.py b/tests/test_cyrillic.py index fcbd31c..490ee17 100644 --- a/tests/test_cyrillic.py +++ b/tests/test_cyrillic.py @@ -66,17 +66,13 @@ def testToCUDelimdot(self): self.assertEqual(write(1001, DELIMDOT), "҂а.а҃") self.assertEqual(write(1010, DELIMDOT), "҂а.і҃") self.assertEqual(write(11000, DELIMDOT), "҂а҃і") - self.assertEqual( - write(111111111, DELIMDOT), "҂҂раі.҂раі.ра҃і" - ) + self.assertEqual(write(111111111, DELIMDOT), "҂҂раі.҂раі.ра҃і") def testToCUAlldot(self): self.assertEqual(write(1001, ALLDOT), ".҂а.а҃.") def testToCUDotscustom(self): - self.assertEqual( - write(1001, ENDDOT + DELIMDOT), "҂а.а҃." - ) + self.assertEqual(write(1001, ENDDOT + DELIMDOT), "҂а.а҃.") class ToArabDelimTestCase(unittest.TestCase): From afe49c5eebb0f91ae60db7d3b472cc74b87d36f4 Mon Sep 17 00:00:00 2001 From: Andrey Shur Date: Mon, 22 Aug 2022 01:40:28 +0300 Subject: [PATCH 9/9] Update test cases names --- tests/test_cyrillic.py | 62 +++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/tests/test_cyrillic.py b/tests/test_cyrillic.py index 490ee17..d040251 100644 --- a/tests/test_cyrillic.py +++ b/tests/test_cyrillic.py @@ -3,22 +3,22 @@ from omninumeric.cyrillic import * -class ToCUPlainTestCase(unittest.TestCase): - def testToCUDigits(self): +class WritePlainTestCase(unittest.TestCase): + def testWriteDigits(self): self.assertEqual(write(1), "а҃") self.assertEqual(write(9), "ѳ҃") - def testToCUTens(self): + def testWriteTens(self): self.assertEqual(write(10), "і҃") self.assertEqual(write(18), "и҃і") self.assertEqual(write(22), "к҃в") - def testToCUHundreds(self): + def testWriteHundreds(self): self.assertEqual(write(100), "р҃") self.assertEqual(write(207), "с҃з") self.assertEqual(write(333), "тл҃г") - def testToCUThousand(self): + def testWriteThousand(self): self.assertEqual(write(1000), "҂а҃") self.assertEqual(write(1006), "҂а҃ѕ") self.assertEqual(write(1010), "҂а҃і") @@ -26,15 +26,15 @@ def testToCUThousand(self): self.assertEqual(write(1444), "҂аум҃д") self.assertEqual(write(11000), "҂і҂а҃") - def testToCUBig(self): + def testWriteBig(self): self.assertEqual(write(10001010001), "҂҂҂і҂҂а҂і҃а") self.assertEqual(write(50000000000), "҂҂҂н҃") self.assertEqual(write(60000070000), "҂҂҂ѯ҂ѻ҃") self.assertEqual(write(111111111), "҂҂р҂҂і҂҂а҂р҂і҂ара҃і") -class ToCUDelimTestCase(unittest.TestCase): - def testToCUDelimAmbiguity(self): +class WriteDelimTestCase(unittest.TestCase): + def testWriteDelimAmbiguity(self): self.assertEqual(write(1010, DELIM), "҂а.і҃") self.assertEqual(write(11000, DELIM), "҂а҃і") self.assertEqual(write(10010, DELIM), "҂і҃і") @@ -44,93 +44,93 @@ def testToCUDelimAmbiguity(self): self.assertEqual(write(100011, DELIM), "҂р.а҃і") self.assertEqual(write(111000, DELIM), "҂ра҃і") - def testToCUDelimBig(self): + def testWriteDelimBig(self): self.assertEqual(write(10001010001, DELIM), "҂҂҂і҂҂а҂і҃а") self.assertEqual(write(50000000000, DELIM), "҂҂҂н҃") self.assertEqual(write(60000070000, DELIM), "҂҂҂ѯ҂ѻ҃") self.assertEqual(write(111111111, DELIM), "҂҂раі҂раіра҃і") -class ToCUFlagsTestCase(unittest.TestCase): - def testToCUNotitlo(self): +class WriteFlagsTestCase(unittest.TestCase): + def testWriteNotitlo(self): self.assertEqual(write(1, NOTITLO), "а") self.assertEqual(write(11000, NOTITLO), "҂і҂а") - def testToCUEnddot(self): + def testWriteEnddot(self): self.assertEqual(write(1, ENDDOT), "а҃.") - def testToCUWrapdot(self): + def testWriteWrapdot(self): self.assertEqual(write(1, WRAPDOT), ".а҃.") - def testToCUDelimdot(self): + def testWriteDelimdot(self): self.assertEqual(write(1001, DELIMDOT), "҂а.а҃") self.assertEqual(write(1010, DELIMDOT), "҂а.і҃") self.assertEqual(write(11000, DELIMDOT), "҂а҃і") self.assertEqual(write(111111111, DELIMDOT), "҂҂раі.҂раі.ра҃і") - def testToCUAlldot(self): + def testWriteAlldot(self): self.assertEqual(write(1001, ALLDOT), ".҂а.а҃.") - def testToCUDotscustom(self): + def testWriteDotscustom(self): self.assertEqual(write(1001, ENDDOT + DELIMDOT), "҂а.а҃.") -class ToArabDelimTestCase(unittest.TestCase): - def testToArabDigits(self): +class ReadDelimTestCase(unittest.TestCase): + def testReadDigits(self): self.assertEqual(1, read("а҃")) self.assertEqual(9, read("ѳ")) - def testToArabTens(self): + def testReadTens(self): self.assertEqual(10, read("і҃")) self.assertEqual(18, read("и҃і")) self.assertEqual(22, read("к҃в")) - def testToArabHundreds(self): + def testReadHundreds(self): self.assertEqual(100, read("р҃")) self.assertEqual(207, read("с҃з")) self.assertEqual(333, read("тл҃г")) - def testToArabThousands(self): + def testReadThousands(self): self.assertEqual(1000, read("҂а҃")) self.assertEqual(1006, read("҂а҃ѕ")) self.assertEqual(1015, read("҂ає҃і")) self.assertEqual(1444, read("҂аум҃д")) - def testToArabBig(self): + def testReadBig(self): self.assertEqual(10001010001, read("҂҂҂і҂҂а҂і҃а")) self.assertEqual(50000000000, read("҂҂҂н҃")) self.assertEqual(60000070000, read("҂҂҂ѯ҂ѻ҃")) - def testToArabNoTsnd(self): + def testReadNoTsnd(self): self.assertEqual(80500690700, read("пфхч҃ѱ")) - def testToArabNotitlo(self): + def testReadNotitlo(self): self.assertEqual(1, read("а")) - def testToArabSpaced(self): + def testReadSpaced(self): self.assertEqual(1, read("а҃ ")) - def testToArabUppercase(self): + def testReadUppercase(self): self.assertEqual(1, read("А҃")) - def testToArabMixed(self): + def testReadMixed(self): self.assertEqual(2021, read(" вКА")) -class ToArabPlainTestCase(unittest.TestCase): - def testToArabPlainBig(self): +class ReadPlainTestCase(unittest.TestCase): + def testReadPlainBig(self): self.assertEqual(11000, read("҂і҂а")) self.assertEqual(111111111, read("҂҂р҂҂і҂҂а҂р҂і҂ара҃і")) class ErrorTestCase(unittest.TestCase): - def testToCUError(self): + def testWriteError(self): self.assertRaises(TypeError, write, "String") self.assertRaises(TypeError, write, 9.75) self.assertRaises(ValueError, write, 0) self.assertRaises(ValueError, write, -69) - def testToArabError(self): + def testReadError(self): self.assertRaises(TypeError, read, 420) self.assertRaises(ValueError, read, "") self.assertRaises(ValueError, read, "A113")