Skip to content
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

Introduce USet and UInterval classes with withrepr decorator #59

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
4 changes: 4 additions & 0 deletions ufpy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,7 @@ def new_func(*args, **kwargs):
# GitHub package
__github_version__ = '0.1'
from ufpy.github import *

# Algebra package
__algebra_version = '0.1'
from ufpy.algebra import *
1 change: 1 addition & 0 deletions ufpy/algebra/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from ufpy.algebra.sets import *
105 changes: 105 additions & 0 deletions ufpy/algebra/sets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
from __future__ import annotations
from os import environ

from ufpy.math_op import i_generator, r_generator
from ufpy.utils import withrepr

__all__ = (
'USet',
'U'
)

from typing import Iterable, Iterator, Optional, TypeVar, overload

T = TypeVar('T')
OT = TypeVar('OT')

@i_generator
@r_generator
class USet[T]:
@overload
def __init__(self, *values: T) -> None: ...
@overload
def __init__(self, *values: T, auto_update_U: bool) -> None: ...
@overload
def __init__(self, *, iterable: Iterable[T]) -> None: ...
@overload
def __init__(self, *, iterable: Iterable[T], auto_update_U: bool) -> None: ...

def __init__(self, *values: T, iterable: Optional[Iterable[T]] = None, auto_update_U: bool = True) -> None:
self.__set = set(iterable) if iterable else set(values)
self.__auto_update_U = auto_update_U
self.__update__()

@property
def set(self) -> set[T]:
return self.__set

@set.setter
def set(self, value: Iterable[T]):
self.__set = set(value)
self.__update__()

# When USet updates (not required, that new USet must be not same that old one)
def __update__(self):
bleudev marked this conversation as resolved.
Show resolved Hide resolved
if self.__auto_update_U:
U(iterable=_get_U() | self)

# Convert to other types
def __repr__(self) -> str:
return f'u{self.set if self.set else '{}'}'
bleudev marked this conversation as resolved.
Show resolved Hide resolved

def __str__(self) -> str:
return repr(self.set) if self.set else '{}'

# Iteration
def __iter__(self) -> Iterator[T]:
return iter(self.__set)

# Or
def __or__(self, other: Iterable[OT]) -> USet[T | OT]:
return USet(iterable=set(self) | set(other), auto_update_U=self.__auto_update_U)

def __add__(self, other: Iterable[OT]) -> USet[T | OT]:
return self | other

# Substract
def __sub__(self, other: Iterable[OT]) -> USet[T]:
return USet(iterable=set(self) - set(other), auto_update_U=self.__auto_update_U)

def __div__(self, other: Iterable[OT]) -> USet[T]:
bleudev marked this conversation as resolved.
Show resolved Hide resolved
return self - other

# And
def __and__(self, other: Iterable[OT]) -> USet:
return USet(iterable=set(self) & set(other), auto_update_U=self.__auto_update_U)

def __mul__(self, other: Iterable[OT]) -> USet:
return self & other

# Not
def __neg__(self) -> USet:
return _get_U() - self

environ["ufpy_USet_U"] = "{}"
bleudev marked this conversation as resolved.
Show resolved Hide resolved

@overload
def U(*values: T) -> None: ...
@overload
def U(*, iterable: Iterable[T]) -> None: ...

@withrepr(lambda _: repr(_get_U()))
def U(*values: T, iterable: Optional[Iterable[T]] = None) -> None:
environ["ufpy_USet_U"] = str(_get_U() + (USet(iterable=iterable, auto_update_U=False)
if iterable else
USet(*values, auto_update_U=False)))

def _convert_type(s: str):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Type conversion logic is fragile and could lead to incorrect interpretations

The current string-based type guessing could lead to ambiguous or incorrect conversions. Consider implementing a more robust type conversion system with explicit type information.

if "'" in s or '"' in s: return s.replace("'", '').replace('"', '')
elif s.replace('-', '').isdigit(): return int(s)
else: return s

def _get_U():
s = environ["ufpy_USet_U"].replace('{', '').replace('}', '').replace('(', '').replace(')', '')
st = s.split(', ')
return USet(iterable=[x for i in st if (x := _convert_type(i))], auto_update_U=False)
24 changes: 23 additions & 1 deletion ufpy/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
'get_items_for_several_keys',
'set_items_for_several_keys',
'del_items_for_several_keys',
'withrepr'
)

from typing import TypeVar
from ast import Call
from typing import Any, Callable, TypeVar
import functools

from ufpy.typ import SupportsGet, SupportsSetItem, SupportsDelItem, AnyCollection

Expand All @@ -31,3 +34,22 @@ def del_items_for_several_keys(o: SupportsDelItem[KT, VT], keys: AnyCollection[K
for k in keys:
del res[k]
return res

# Useful decorators

class __reprwrapper:
def __init__(self, repr, func):
self._repr = repr
self._func = func
functools.update_wrapper(self, func)
def __call__(self, *args, **kw):
return self._func(*args, **kw)
def __repr__(self):
return self._repr(self._func)

T = TypeVar('T', bound=Callable)

def withrepr(f: Callable[[T], str]):
def _wrap(func: T):
return __reprwrapper(f, func)
return _wrap
Loading