Skip to content

Add type hints to package #157

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 26 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c1c2792
Add py.typed
jaimergp Jun 15, 2025
bc21626
Add type hints for univers.versions
jaimergp Jun 15, 2025
8a374e7
Add type hints for univers.utils
jaimergp Jun 15, 2025
db837cf
Add type hints for univers.version_constraint
jaimergp Jun 15, 2025
30c4a7c
wip version_range
jaimergp Jun 25, 2025
9b7660a
Raise NotImplementedError instead of returning it (#158)
JonoYang Jun 24, 2025
81249bc
add type hints for univers.conan.errors
jaimergp Jul 3, 2025
a1d685e
type hints for univers.conan.version_range
jaimergp Jul 3, 2025
29452dc
add type hints for univers.conan.version
jaimergp Jul 3, 2025
86f3b2a
add type hints for univers.debian
jaimergp Jul 3, 2025
a534ef4
add type hints for univers.gem
jaimergp Jul 3, 2025
cdb5399
add type hints for univers.gentoo
jaimergp Jul 3, 2025
d252325
add type hints for univers.maven
jaimergp Jul 3, 2025
4eaf01c
add type hints for univers.nuget
jaimergp Jul 3, 2025
1edacea
add type hints for univers.rpm
jaimergp Jul 3, 2025
58dadc8
add type hints for univers.univers_semver
jaimergp Jul 3, 2025
8167e08
add type hints for univers.version_range
jaimergp Jul 3, 2025
99a0799
bump typing-extensions dev requirement
jaimergp Jul 3, 2025
8d90139
bump black too
jaimergp Jul 3, 2025
99672d1
move to setup.cfg
jaimergp Jul 3, 2025
6b3d837
relax?
jaimergp Jul 3, 2025
0f03c09
bump packaging
jaimergp Jul 3, 2025
e146125
typing-extensions 4.1.0 might be enough
jaimergp Jul 3, 2025
55cf830
fix tests
jaimergp Jul 3, 2025
b011cc6
run black
jaimergp Jul 3, 2025
bcb7e6d
run isort
jaimergp Jul 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
Changelog
=========

Version v31.0.0
----------------

- Raise instead of returning ``NotImplementedError`` in ``version_range.VersionRange`` methods. https://github.com/aboutcode-org/univers/pull/158

Version v30.12.1
----------------

Expand Down
3 changes: 1 addition & 2 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ pytest==7.2.0
pytest-forked==1.4.0
pytest-xdist==3.2.0
toml==0.10.2
typing-extensions==3.10.0.2
typing-extensions==4.1.0
zipp==3.6.0
black==22.3.0
typed-ast==1.4.3
pathspec==0.9.0
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
attrs==21.2.0
packaging==21.0
packaging==25.0
pyparsing==2.4.7
semantic-version==2.8.5
semver==2.13.0
Expand Down
2 changes: 2 additions & 0 deletions src/univers/arch.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#
# Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download.

from __future__ import annotations

import re
from itertools import zip_longest
from typing import Dict
Expand Down
44 changes: 31 additions & 13 deletions src/univers/conan/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,42 @@
# Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download.

"""
Exceptions raised and handled in Conan
These exceptions are mapped between server (as an HTTP response) and client
through the REST API. When an error happens in server its translated to an HTTP
error code that its sent to client. Client reads the server code and raise the
matching exception.
Exceptions raised and handled in Conan
These exceptions are mapped between server (as an HTTP response) and client
through the REST API. When an error happens in server its translated to an HTTP
error code that its sent to client. Client reads the server code and raise the
matching exception.

see return_plugin.py
see return_plugin.py

"""
from __future__ import annotations

from contextlib import contextmanager
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from collections.abc import Iterable
from collections.abc import Iterator
from typing import Any
from typing import Callable

try:
from typing import Never
except ImportError:
from typing_extensions import Never


@contextmanager
def conanfile_remove_attr(conanfile, names, method):
def conanfile_remove_attr(
conanfile: Any, names: Iterable[str], method: Callable[..., Any]
) -> Iterator[Never]:
"""remove some self.xxxx attribute from the class, so it raises an exception if used
within a given conanfile method
"""
original_class = type(conanfile)

def _prop(attr_name):
def _prop(attr_name: str) -> property:
def _m(_):
raise ConanException(f"'self.{attr_name}' access in '{method}()' method is forbidden")

Expand All @@ -41,7 +57,7 @@ def _m(_):


@contextmanager
def conanfile_exception_formatter(conanfile_name, func_name):
def conanfile_exception_formatter(conanfile_name: str, func_name: str) -> Iterator[Never]:
"""
Decorator to throw an exception formatted with the line of the conanfile where the error ocurrs.
"""
Expand Down Expand Up @@ -74,7 +90,9 @@ def _raise_conanfile_exc(e):
_raise_conanfile_exc(exc)


def _format_conanfile_exception(scope, method, exception):
def _format_conanfile_exception(
scope: str, method: Callable[..., Any], exception: BaseException
) -> str:
"""
It will iterate the traceback lines, when it finds that the source code is inside the users
conanfile it "start recording" the messages, when the trace exits the conanfile we return
Expand Down Expand Up @@ -125,12 +143,12 @@ def __init__(self, *args, **kwargs):
self.remote = kwargs.pop("remote", None)
super(ConanException, self).__init__(*args, **kwargs)

def remote_message(self):
def remote_message(self) -> str:
if self.remote:
return " [Remote: {}]".format(self.remote.name)
return ""

def __str__(self):
def __str__(self) -> str:

msg = super(ConanException, self).__str__()

Expand Down Expand Up @@ -242,7 +260,7 @@ class UserInterfaceErrorException(RequestErrorException):
pass


EXCEPTION_CODE_MAPPING = {
EXCEPTION_CODE_MAPPING: dict[ConanException, int] = {
InternalErrorException: 500,
RequestErrorException: 400,
AuthenticationException: 401,
Expand Down
53 changes: 31 additions & 22 deletions src/univers/conan/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,52 @@
#
# Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download.

from __future__ import annotations

from functools import total_ordering
from typing import TYPE_CHECKING

from univers.conan.errors import ConanException

if TYPE_CHECKING:
try:
from typing import Self
except ImportError:
from typing_extensions import Self


@total_ordering
class _VersionItem:
"""a single "digit" in a version, like X.Y.Z all X and Y and Z are VersionItems
They can be int or strings
"""

def __init__(self, item):
def __init__(self, item: str | int | Self):
try:
self._v = int(item)
except ValueError:
self._v = item

@property
def value(self):
def value(self) -> int:
return self._v

def __str__(self):
def __str__(self) -> str:
return str(self._v)

def __add__(self, other):
def __add__(self, other: Self) -> int:
# necessary for the "bump()" functionality. Other aritmetic operations are missing
return self._v + other

def __eq__(self, other):
def __eq__(self, other: str | int | Self) -> bool:
if not isinstance(other, _VersionItem):
other = _VersionItem(other)
return self._v == other._v

def __hash__(self):
def __hash__(self) -> int:
return hash(self._v)

def __lt__(self, other):
def __lt__(self, other: str | int | Self) -> bool:
"""
@type other: _VersionItem
"""
Expand All @@ -59,7 +68,7 @@ class Version:
It is just a helper to parse "." or "-" and compare taking into account integers when possible
"""

def __init__(self, value):
def __init__(self, value: int | str | Self):
value = str(value)
self._value = value

Expand All @@ -85,7 +94,7 @@ def __init__(self, value):
del items[-1]
self._nonzero_items = tuple(items)

def bump(self, index):
def bump(self, index: int) -> Self:
"""
:meta private:
Bump the version
Expand All @@ -110,7 +119,7 @@ def bump(self, index):
result = Version(v)
return result

def upper_bound(self, index):
def upper_bound(self, index: int) -> Self:
items = list(self._items[:index])
try:
items.append(self._items[index] + 1)
Expand All @@ -123,52 +132,52 @@ def upper_bound(self, index):
return result

@property
def pre(self):
def pre(self) -> Self | None:
return self._pre

@property
def build(self):
def build(self) -> Self | None:
return self._build

@property
def main(self):
def main(self) -> tuple[_VersionItem, ...]:
return self._items

@property
def major(self):
def major(self) -> _VersionItem | None:
try:
return self.main[0]
except IndexError:
return None

@property
def minor(self):
def minor(self) -> _VersionItem | None:
try:
return self.main[1]
except IndexError:
return None

@property
def patch(self):
def patch(self) -> _VersionItem | None:
try:
return self.main[2]
except IndexError:
return None

@property
def micro(self):
def micro(self) -> _VersionItem | None:
try:
return self.main[3]
except IndexError:
return None

def __str__(self):
def __str__(self) -> str:
return self._value

def __repr__(self):
def __repr__(self) -> str:
return self._value

def __eq__(self, other):
def __eq__(self, other: int | str | Self | None) -> bool:
if other is None:
return False
if not isinstance(other, Version):
Expand All @@ -180,10 +189,10 @@ def __eq__(self, other):
other._build,
)

def __hash__(self):
def __hash__(self) -> int:
return hash((self._nonzero_items, self._pre, self._build))

def __lt__(self, other):
def __lt__(self, other: int | str | Self | None) -> bool:
if other is None:
return False
if not isinstance(other, Version):
Expand Down
14 changes: 8 additions & 6 deletions src/univers/conan/version_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#
# Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download.

from __future__ import annotations

from collections import namedtuple

from univers.conan.errors import ConanException
Expand All @@ -13,7 +15,7 @@


class _ConditionSet:
def __init__(self, expression, prerelease):
def __init__(self, expression: str, prerelease: bool):
expressions = expression.split()
self.prerelease = prerelease
self.conditions = []
Expand All @@ -25,7 +27,7 @@ def __init__(self, expression, prerelease):
self.conditions.extend(self._parse_expression(e))

@staticmethod
def _parse_expression(expression):
def _parse_expression(expression: str) -> list[_Condition | ConanVersion]:
if expression == "" or expression == "*":
return [_Condition(">=", ConanVersion("0.0.0"))]

Expand Down Expand Up @@ -60,7 +62,7 @@ def first_non_zero(main):
else:
return [_Condition(operator, ConanVersion(version))]

def valid(self, version):
def valid(self, version: ConanVersion) -> bool:
if version.pre:
if not self.prerelease:
return False
Expand All @@ -84,7 +86,7 @@ def valid(self, version):


class VersionRange:
def __init__(self, expression):
def __init__(self, expression: str):
self._expression = expression
tokens = expression.split(",")
prereleases = None
Expand All @@ -97,10 +99,10 @@ def __init__(self, expression):
for alternative in version_expr.split("||"):
self.condition_sets.append(_ConditionSet(alternative, prereleases))

def __str__(self):
def __str__(self) -> str:
return self._expression

def __contains__(self, version):
def __contains__(self, version: ConanVersion) -> bool:
assert isinstance(version, ConanVersion), type(version)
for condition_set in self.condition_sets:
if condition_set.valid(version):
Expand Down
Loading