feat!: drop Python 3.8/3.9 support, add 3.11-3.13

BREAKING CHANGE: Minimum Python version is now 3.10

- Drop support for Python 3.8 (EOL Oct 2024) and 3.9 (EOL Oct 2025)
- Add support for Python 3.11, 3.12, and 3.13
- Modernize type hints to Python 3.10+ syntax
- Update pre-commit hooks to latest versions
- Update GitHub Actions to latest versions
- Bump version to 1.2.0
This commit is contained in:
Sugat Bajracharya committed 2026-01-30 22:23:46 +05:45
1 parent 31fd3020f4
commit a612c2988f
15 files changed
+82 -65

No files matched your search

+4 -4
View File
@@ -20,12 +20,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v3
uses: actions/setup-python@v5
with:
python-version: "3.x"
python-version: "3.12"
- name: Install dependencies
run: |
@@ -36,7 +36,7 @@ jobs:
run: python -m build
- name: Publish package
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ['3.8', '3.9', '3.10']
python-version: ['3.10', '3.11', '3.12', '3.13']
steps:
- uses: actions/checkout@v4
+1
View File
@@ -10,3 +10,4 @@ htmlcov
.DS_Store
venv/
.env
.python-version
+9 -9
View File
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v6.0.0
hooks:
- id: check-merge-conflict
- id: check-added-large-files
@@ -10,7 +10,7 @@ repos:
- id: trailing-whitespace
- repo: https://github.com/akaihola/darker
rev: 1.7.1
rev: v2.1.1
hooks:
- id: darker
args:
@@ -20,14 +20,14 @@ repos:
- --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.77
- isort==5.12.0
- mypy==1.3.0
- pylint==2.17.4
- black==26.1.0
- flake8==7.3.0
- flynt==1.0.6
- isort==7.0.0
- mypy==1.19.1
- pylint==4.0.4
- repo: https://github.com/opensource-nepal/commitlint
rev: v1.0.0
rev: v1.13.3
hooks:
- id: commitlint
+9
View File
@@ -1,5 +1,14 @@
# CHANGELOG
## v1.2.0
- **BREAKING**: Drop support for Python 3.8 and 3.9 (EOL)
- Add support for Python 3.11, 3.12, and 3.13
- Minimum Python version is now 3.10
- Modernize type hints to Python 3.10+ syntax (using `X | Y` instead of `Union[X, Y]`)
- Update pre-commit hooks to latest versions
- Update GitHub Actions workflows to use latest action versions
## v1.1.3
- Update months data for year 2082
+1 -1
View File
@@ -33,7 +33,7 @@ phone_number.parse("+977-9845217789")
## Requirements
Python >= 3
Python >= 3.10
## Installation
+6 -4
View File
@@ -1,13 +1,15 @@
from __future__ import annotations
from functools import cached_property
from typing import Any, Dict, Optional, Union
from typing import Any
from nepali.constants import NEPALI_MONTHS_EN, NEPALI_MONTHS_NE
class NepaliMonthMeta(type):
_cache: Dict[int, "nepalimonth"] = {}
_cache: dict[int, nepalimonth] = {}
def __call__(cls, month: Union[int, str], *args, **kwargs) -> "nepalimonth":
def __call__(cls, month: int | str, *args, **kwargs) -> nepalimonth:
"""
Parses the month data and manages the cache.
@@ -17,7 +19,7 @@ class NepaliMonthMeta(type):
:rtype: nepalimonth
:raises ValueError: If the given month is invalid.
"""
value: Optional[int] = None
value: int | None = None
value = None
if isinstance(month, int):
+6 -4
View File
@@ -1,13 +1,15 @@
from __future__ import annotations
from functools import cached_property
from typing import Any, Dict, Optional, Union
from typing import Any
from nepali.constants import WEEKS_ABBR_EN, WEEKS_ABBR_NE, WEEKS_EN, WEEKS_NE
class NepaliWeekMeta(type):
_cache: Dict[int, "nepaliweek"] = {}
_cache: dict[int, nepaliweek] = {}
def __call__(cls, week: Union[int, str], *args, **kwargs) -> "nepaliweek":
def __call__(cls, week: int | str, *args, **kwargs) -> nepaliweek:
"""
Parses the week data and manages the cache.
@@ -17,7 +19,7 @@ class NepaliWeekMeta(type):
:rtype: nepaliweek
:raises ValueError: If the given week is invalid.
"""
value: Optional[int] = None
value: int | None = None
if isinstance(week, int):
value = int(week)
+5 -4
View File
@@ -1,8 +1,9 @@
"""
validates parsing
"""
from __future__ import annotations
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
@@ -157,7 +158,7 @@ def __convert_12_hour_to_24_hour(hour: int, am_pm: str) -> int:
return hour
def __calculate_year(data: dict) -> Optional[int]:
def __calculate_year(data: dict) -> int | None:
"""Calculates the year value from given data.
:param data: The dictionary of the format:
@@ -217,7 +218,7 @@ def __calculate_day(data: dict) -> int:
return 1
def __calculate_hour_minute_seconds(data: dict) -> Tuple[int, int, int, int]:
def __calculate_hour_minute_seconds(data: dict) -> tuple[int, int, int, int]:
"""Calculates hour, minutes, seconds and microseconds from given data.
:param data: The dictionary of the format:
@@ -256,7 +257,7 @@ def __calculate_hour_minute_seconds(data: dict) -> Tuple[int, int, int, int]:
return hour, minute, second, fraction
def __calculate_weekday(data: dict) -> Optional[nepaliweek]:
def __calculate_weekday(data: dict) -> nepaliweek | None:
"""Calculates the weekday of the date given in data.
:param data: The data that describes the date.
+1 -3
View File
@@ -1,9 +1,7 @@
from typing import List, Tuple
from .models import District, Municipality, MunicipalityType, Province
def _loadData() -> Tuple[List[Province], List[District], List[Municipality]]:
def _loadData() -> tuple[list[Province], list[District], list[Municipality]]:
from ._data import _location_data
provinces = []
+3 -4
View File
@@ -1,5 +1,4 @@
from enum import Enum
from typing import List
class Location:
@@ -37,11 +36,11 @@ class Province(Location):
self.__municipalities.append(municipality)
@property
def districts(self) -> List["District"]:
def districts(self) -> list["District"]:
return self.__districts
@property
def municipalities(self) -> List["Municipality"]:
def municipalities(self) -> list["Municipality"]:
return self.__municipalities
@@ -61,7 +60,7 @@ class District(Location):
return self.__province
@property
def municipalities(self) -> List["Municipality"]:
def municipalities(self) -> list["Municipality"]:
return self.__municipalities
+28 -26
View File
@@ -2,7 +2,9 @@
Contains the class for the nepalinumber feature
"""
from typing import Any, Tuple, Type, Union
from __future__ import annotations
from typing import Any
from .utils import NP_NUMBERS, NP_NUMBERS_SET, english_to_nepali
@@ -21,7 +23,7 @@ class nepalinumber:
self.__value = self.__parse(value)
def get_parse_exception(
self, obj: object, ex_class: Type[Exception] = ValueError
self, obj: object, ex_class: type[Exception] = ValueError
) -> Exception:
"""
Returns the exception object to be raised when the parse is failed.
@@ -30,7 +32,7 @@ class nepalinumber:
: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
:type ex_class: type[Exception], optional
:return: Exception object to be raised
:rtype: Exception
"""
@@ -38,7 +40,7 @@ class nepalinumber:
f"could not convert {obj.__class__.__name__} to {self.__class__.__name__}: '{obj}'"
)
def __parse(self, value: Any) -> Union[int, float]:
def __parse(self, value: Any) -> int | float:
"""
Parses nepali number input into a valid value.
@@ -68,7 +70,7 @@ class nepalinumber:
return self.__parse_object(value)
def __parse_str(self, value: str) -> Union[int, float]:
def __parse_str(self, value: str) -> int | float:
"""
Parses str object into int and float.
This is a low level implementation.
@@ -112,7 +114,7 @@ class nepalinumber:
i += 1
return sign * result
def __parse_object(self, obj: Any) -> Union[int, float]:
def __parse_object(self, obj: Any) -> int | float:
"""
Parses object using __int__, __float__, and __str__.
@@ -129,7 +131,7 @@ class nepalinumber:
# object conversion must raise TypeError if fails
raise self.get_parse_exception(obj, ex_class=TypeError) from None
def __convert_or_return(self, obj) -> Union["nepalinumber", object]:
def __convert_or_return(self, obj) -> nepalinumber | object:
"""
Will try to parse the given object and convert to nepalinumber
else will return the same object
@@ -165,7 +167,7 @@ class nepalinumber:
"""
return float(self.__value)
def __add(self, other) -> Union[int, float]:
def __add(self, other) -> int | float:
"""
Adds the value in the object with the passed object
@@ -179,7 +181,7 @@ class nepalinumber:
return self.__value + other
def __mul(self, other) -> Union[int, float]:
def __mul(self, other) -> int | float:
"""
Multiplies the value in the object with the passed object
@@ -219,13 +221,13 @@ class nepalinumber:
return self.__value != other
def __neg__(self) -> "nepalinumber":
def __neg__(self) -> nepalinumber:
"""
Returns the negative value of the nepalinumber value
"""
return nepalinumber((-1) * self.__value)
def __add__(self, other) -> Union["nepalinumber", object]:
def __add__(self, other) -> nepalinumber | object:
"""
Called when the addition operator + is used after
the nepalinumber object
@@ -242,7 +244,7 @@ class nepalinumber:
except TypeError:
return NotImplemented
def __radd__(self, other) -> Union["nepalinumber", object]:
def __radd__(self, other) -> nepalinumber | object:
"""
Called when the addition operator + is used before
the nepalinumber object
@@ -259,7 +261,7 @@ class nepalinumber:
except TypeError:
return NotImplemented
def __sub__(self, other) -> Union["nepalinumber", object]:
def __sub__(self, other) -> nepalinumber | object:
"""
Called when the subtraction operator - is used after
the nepalinumber object
@@ -278,7 +280,7 @@ class nepalinumber:
except TypeError:
return NotImplemented
def __rsub__(self, other) -> Union["nepalinumber", object]:
def __rsub__(self, other) -> nepalinumber | object:
"""
Called when the subtraction operator - is used before
the nepalinumber object
@@ -298,7 +300,7 @@ class nepalinumber:
except TypeError:
return NotImplemented
def __mul__(self, other) -> Union["nepalinumber", object]:
def __mul__(self, other) -> nepalinumber | object:
"""
Called when the multiplication operator * is used after
the nepalinumber object
@@ -318,7 +320,7 @@ class nepalinumber:
except TypeError:
return NotImplemented
def __rmul__(self, other) -> Union["nepalinumber", object]:
def __rmul__(self, other) -> nepalinumber | object:
"""
Called when the multiplication operator * is used before
the nepalinumber object
@@ -338,7 +340,7 @@ class nepalinumber:
except TypeError:
return NotImplemented
def __truediv__(self, other) -> Union["nepalinumber", object]:
def __truediv__(self, other) -> nepalinumber | object:
"""
Called when the division operator / is used after
the nepalinumber object
@@ -357,7 +359,7 @@ class nepalinumber:
except TypeError:
return NotImplemented
def __rtruediv__(self, other) -> Union["nepalinumber", object]:
def __rtruediv__(self, other) -> nepalinumber | object:
"""
Called when the division operator / is used before
the nepalinumber object
@@ -377,7 +379,7 @@ class nepalinumber:
except TypeError:
return NotImplemented
def __floordiv__(self, other) -> Union["nepalinumber", object]:
def __floordiv__(self, other) -> nepalinumber | object:
"""
Called when the floor/integer division operator // is used
after the nepalinumber object
@@ -396,7 +398,7 @@ class nepalinumber:
except TypeError:
return NotImplemented
def __rfloordiv__(self, other) -> Union["nepalinumber", object]:
def __rfloordiv__(self, other) -> nepalinumber | object:
"""
Called when the floor/integer division operator // is used
before the nepalinumber object
@@ -416,7 +418,7 @@ class nepalinumber:
except TypeError:
return NotImplemented
def __mod__(self, other) -> Union["nepalinumber", object]:
def __mod__(self, other) -> nepalinumber | object:
"""
Called when the modulo operator % is used after
the nepalinumber object
@@ -436,7 +438,7 @@ class nepalinumber:
except TypeError:
return NotImplemented
def __rmod__(self, other) -> Union["nepalinumber", object]:
def __rmod__(self, other) -> nepalinumber | object:
"""
Called when the modulo operator % is used before
the nepalinumber object
@@ -458,7 +460,7 @@ class nepalinumber:
def __divmod__(
self, other
) -> Tuple[Union["nepalinumber", object], Union["nepalinumber", object]]:
) -> tuple[nepalinumber | object, nepalinumber | object]:
"""
Called when the built-in function divmod() is used
with nepalinumber as the dividend and other as divisor
@@ -483,7 +485,7 @@ class nepalinumber:
def __rdivmod__(
self, other
) -> Tuple[Union["nepalinumber", object], Union["nepalinumber", object]]:
) -> tuple[nepalinumber | object, nepalinumber | object]:
"""
Called when the built-in function divmod() is used
with nepalinumber as the divisor and other as dividend
@@ -506,7 +508,7 @@ class nepalinumber:
except TypeError:
return NotImplemented
def __pow__(self, other) -> Union["nepalinumber", object]:
def __pow__(self, other) -> nepalinumber | object:
"""
Called when the power operator ** is used after
the nepalinumber object
@@ -526,7 +528,7 @@ class nepalinumber:
except TypeError:
return NotImplemented
def __rpow__(self, other) -> Union["nepalinumber", object]:
def __rpow__(self, other) -> nepalinumber | object:
"""
Called when the power operator ** is used before
the nepalinumber object
+1 -2
View File
@@ -1,6 +1,5 @@
import re
from enum import Enum
from typing import Union
_mobile_number_re = re.compile(r"^(?:\+977|977)?(?:-)?(?:98|97|96)\d{8}$")
_landline_number_re = re.compile(
@@ -93,7 +92,7 @@ def parse(number: str):
return None
def _get_operator(number: str) -> Union[Operator, None]:
def _get_operator(number: str) -> Operator | None:
"""
Returns operator from the number.
NOTE: The number should be 10digit mobile number.
+1 -2
View File
@@ -1,5 +1,4 @@
import datetime
from typing import Union
from .constants import NEPAL_TIMEZONE
@@ -28,7 +27,7 @@ class NepaliTimeZone(datetime.tzinfo):
return isinstance(o, self.__class__)
def get_timezone() -> Union[datetime.tzinfo, None]:
def get_timezone() -> datetime.tzinfo | None:
"""
Returns current device's timezone.
Timezone of the machine.
+6 -1
View File
@@ -38,7 +38,7 @@ if sys.argv[-1] == "publish":
setuptools.setup(
name="nepali",
version="1.1.3",
version="1.2.0",
license="MIT",
author="opensource-nepal",
author_email="aj3sshh@gmail.com, sugatbajracharya49@gmail.com",
@@ -57,9 +57,14 @@ setuptools.setup(
url=GITHUB_URL,
packages=setuptools.find_packages(exclude=["tests*"]),
test_suite="nepali.tests",
python_requires=">=3.10",
install_requires=[],
classifiers=[
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],