diff --git a/language_tool_python/download_lt.py b/language_tool_python/download_lt.py index 717f02e..fd75d13 100755 --- a/language_tool_python/download_lt.py +++ b/language_tool_python/download_lt.py @@ -22,8 +22,6 @@ import requests import tqdm -from packaging import version -from packaging.version import Version from ._compat import deprecated, toml_loads from .exceptions import JavaError, PathError @@ -32,6 +30,7 @@ LTP_JAR_DIR_PATH_ENV_VAR, get_env_int, get_language_tool_download_path, + version_tuple, ) if TYPE_CHECKING: @@ -275,7 +274,7 @@ def confirm_java_compatibility( is_old_version = language_tool_version != LTP_DOWNLOAD_VERSION and ( re.match(r"^\d+\.\d+$", language_tool_version) - and Version(language_tool_version) < Version("6.6") + and version_tuple(language_tool_version) < (6, 6) # 6.6 ) # Some installs of java show the version number like '14.0.1' @@ -765,15 +764,15 @@ def version_name(self) -> str: @property @abstractmethod - def version_into(self) -> Version | datetime: + def version_into(self) -> tuple[int, int] | datetime: """Get the version as a comparable object. This abstract property must be implemented by subclasses to return the version - as either a Version object (for releases) or datetime object (for snapshots) for - comparison purposes. + as either a tuple of integers (for releases) or datetime object (for snapshots) + for comparison purposes. - :return: A Version object for releases or datetime for snapshots. - :rtype: Version | datetime + :return: A tuple of integers for releases or datetime for snapshots. + :rtype: tuple[int, int] | datetime :raises NotImplementedError: Always, unless implemented by a subclass. """ raise NotImplementedError @@ -835,8 +834,7 @@ def __lt__(self, other: object) -> bool: self_version = self.version_into other_version = other.version_into if ( - isinstance(self_version, Version) - and isinstance(other_version, Version) + isinstance(self_version, tuple) and isinstance(other_version, tuple) ) or ( isinstance(self_version, datetime) and isinstance(other_version, datetime) @@ -919,13 +917,13 @@ def version_name(self) -> str: return self._version_name @property - def version_into(self) -> Version: - """Get the version as a Version object for comparison. + def version_into(self) -> tuple[int, int]: + """Get the version as a tuple of integers for comparison. - :return: A parsed Version object from the version string. - :rtype: Version + :return: A tuple of integers representing the version. + :rtype: tuple[int, int] """ - return version.parse(self._version_name) + return version_tuple(self._version_name) @property def download_url(self) -> str: @@ -941,16 +939,16 @@ def download_url(self) -> str: :rtype: str :raises PathError: If the version is below 4.0 (unsupported). """ - version_num = Version(self._version_name) + version_num = version_tuple(self._version_name) filename = FILENAME_RELEASE.format(version=self._version_name) # Versions >= 6.7 from new release page - if version_num >= Version("6.7"): + if version_num >= (6, 7): # 6.7 base_url = BASE_URL_NEW_RELEASES.format(version=self._version_name) return urljoin(base_url, filename) # Versions >= 6.0 from main download page - if version_num >= Version("6.0"): + if version_num >= (6, 0): # 6.0 return urljoin(BASE_URL_RELEASE, filename) - if version_num < Version("4.0"): + if version_num < (4, 0): # 4.0 err = ( "LanguageTool versions below 4.0 are no longer supported for download." " Below version 4.0, the API changed significantly and is " diff --git a/language_tool_python/server.py b/language_tool_python/server.py index 2fb094c..a9dda64 100644 --- a/language_tool_python/server.py +++ b/language_tool_python/server.py @@ -19,7 +19,6 @@ import psutil import requests -from packaging.version import Version from .api_types import ( is_check_response, @@ -41,6 +40,7 @@ get_locale_language, kill_process_force, parse_url, + version_tuple, ) startupinfo: object | None = None @@ -1136,8 +1136,8 @@ def _wait_for_server_ready(self, timeout: int = 15) -> None: url = ( urllib.parse.urljoin(self._url, "check?text=healthcheck&language=en") if re.match(r"^\d+\.\d+$", self._language_tool_download_version) - and Version(self._language_tool_download_version) - < Version("4.2") # healthcheck endpoint added in 4.2 + and version_tuple(self._language_tool_download_version) + < (4, 2) # healthcheck endpoint added in 4.2 else urllib.parse.urljoin(self._url, "healthcheck") ) start = time.time() diff --git a/language_tool_python/utils.py b/language_tool_python/utils.py index 4dae297..4cfeab6 100644 --- a/language_tool_python/utils.py +++ b/language_tool_python/utils.py @@ -14,7 +14,6 @@ from typing import TYPE_CHECKING, Protocol, runtime_checkable import psutil -from packaging import version from ._compat import deprecated from .exceptions import JavaError, PathError @@ -221,7 +220,7 @@ def find_existing_language_tool_downloads(download_folder: Path) -> list[Path]: "This function is no longer used internally and will be removed in 4.0.", stacklevel=2, ) -def _extract_version(path: Path) -> version.Version: +def _extract_version(path: Path) -> tuple[int, int]: """Extract the version number from a LanguageTool directory path. This function parses the directory name to extract the version information @@ -230,8 +229,8 @@ def _extract_version(path: Path) -> version.Version: :param path: The path to the LanguageTool directory :type path: Path - :return: The parsed version object extracted from the directory name - :rtype: version.Version + :return: The parsed version tuple extracted from the directory name + :rtype: tuple[int, int] :raises ValueError: If the directory name doesn't start with 'LanguageTool-' .. deprecated:: 3.3.0 @@ -244,7 +243,7 @@ def _extract_version(path: Path) -> version.Version: version_str = path.name.removeprefix("LanguageTool-") # Handle both -SNAPSHOT and -snapshot suffixes version_str = version_str.removesuffix("-SNAPSHOT").removesuffix("-snapshot") - return version.parse(version_str) + return version_tuple(version_str) @deprecated( @@ -471,3 +470,20 @@ class SupportsFloat(Protocol): def __float__(self) -> float: """Define the interface for types that can be converted to a float.""" ... + + +def version_tuple(v: str) -> tuple[int, int]: + """Convert a version string into a tuple of integers. + + This function takes a version string in the format 'X.Y' and converts it into a + tuple of integers (X, Y). This can be useful for comparing version numbers. + + :param v: The version string to be converted, expected in the format 'X.Y'. + :type v: str + :return: A tuple of integers representing the version, in the format (X, Y). + :rtype: tuple[int, int] + :raises ValueError: If the version string is not in the expected format or contains + non-integer components. + """ + major, minor = v.split(".") + return int(major), int(minor) diff --git a/pyproject.toml b/pyproject.toml index 9316188..08f59d4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,6 @@ keywords = ["python", "nlp", "grammar", "languagetool", "grammar-checker", "spel dependencies = [ "requests", "tqdm", - "packaging", "psutil", "tomli; python_version < '3.11'", # only needed for py < 3.11 because tomllib added in 3.11 is used in the codebase, needs a fallback "typing_extensions; python_version < '3.13'", # only needed for py < 3.13 because warnings.deprecated added in 3.13 is used in the codebase diff --git a/uv.lock b/uv.lock index f6796ae..bb8cdec 100644 --- a/uv.lock +++ b/uv.lock @@ -432,7 +432,6 @@ name = "language-tool-python" version = "3.4.0" source = { editable = "." } dependencies = [ - { name = "packaging" }, { name = "psutil" }, { name = "requests" }, { name = "tomli", marker = "python_full_version < '3.11'" }, @@ -465,7 +464,6 @@ types = [ [package.metadata] requires-dist = [ - { name = "packaging" }, { name = "psutil" }, { name = "requests" }, { name = "tomli", marker = "python_full_version < '3.11'" }, @@ -797,7 +795,7 @@ wheels = [ [[package]] name = "pytest" -version = "9.0.3" +version = "9.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, @@ -808,9 +806,9 @@ dependencies = [ { name = "pygments" }, { name = "tomli", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18.027Z" } +sdist = { url = "https://files.pythonhosted.org/packages/84/0e/b5858858d74958632c49b72cb25a3976ff9f632397626715be71c89d3971/pytest-9.1.0.tar.gz", hash = "sha256:41dd9148c08072446394cefd3d79701701335a9f4cae69ba92e39f6c7f5c061c", size = 1634181, upload-time = "2026-06-13T18:52:45.983Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" }, + { url = "https://files.pythonhosted.org/packages/8b/5a/ba30a81239b909821b3153e303e7def45178bf353da4f72380e6c5e8793b/pytest-9.1.0-py3-none-any.whl", hash = "sha256:8ebb0e7888bdf2bdfc602ec51f8f62d50200af37356c74e503c79a94f5c81f32", size = 386453, upload-time = "2026-06-13T18:52:44.045Z" }, ] [[package]]