lib.version.Dependency: Reject unsupported spec operators #95

Merged
Jan Lindemann merged 1 commit from jan/feature/20260911-lib-version-dependency-reject-unsupported-spec-operators into master 2026-09-11 11:44:44 +02:00 AGit
3 changed files with 31 additions and 12 deletions

View file

@ -209,8 +209,9 @@ class App(Base):
scope: Scope, scope: Scope,
names_only: bool, names_only: bool,
) -> None: ) -> None:
name = self.strip_module_from_spec(spec) dep = Dependency(spec)
mod = re.split('([=><]+)', spec)[0].strip() name = dep.base_name
mod = dep.full_name
if names_only: if names_only:
spec = name spec = name
if spec in buf: if spec in buf:

View file

@ -22,7 +22,7 @@ class Dependency: # export
class Error(ValueError): class Error(ValueError):
pass pass
__SPLIT_RE: ClassVar[re.Pattern[str]] = re.compile('([=><]+)') __SPLIT_RE: ClassVar[re.Pattern[str]] = re.compile('([~=><!]+)')
@property @property
def __target_prefix(self) -> str: def __target_prefix(self) -> str:
@ -45,6 +45,12 @@ class Dependency: # export
case 3: case 3:
if not parts[0] or not parts[2]: if not parts[0] or not parts[2]:
self.__raise(f'Invalid dependency spec "{self.__spec}"') self.__raise(f'Invalid dependency spec "{self.__spec}"')
if parts[1] not in ('=', '<', '<=', '>', '>='):
self.__raise(
f'Spec "{self.__spec}": unsupported operator '
f'"{parts[1]}", supported operators are =, <, '
'<=, > and >='
)
if parts[2] == 'REVISION': if parts[2] == 'REVISION':
self.__raise( self.__raise(
f'Spec "{self.__spec}": a bare REVISION renders as a ' f'Spec "{self.__spec}": a bare REVISION renders as a '

View file

@ -40,7 +40,7 @@ assert d.base_name == 'dev'
assert d.full_name == 'dev' assert d.full_name == 'dev'
# Operators with and without whitespace # Operators with and without whitespace
for op in ['=', '==', '<', '<=', '>', '>=']: for op in ['=', '<', '<=', '>', '>=']:
d = Dependency(f'foo {op} 1.0') d = Dependency(f'foo {op} 1.0')
assert d.base_name == 'foo' assert d.base_name == 'foo'
assert d.full_name == 'foo' assert d.full_name == 'foo'
@ -135,14 +135,6 @@ d = Dependency('foo = 1.2.3', app.get_version)
assert d.constraint_str(as_range = True) == 'foo = 1.2.3' assert d.constraint_str(as_range = True) == 'foo = 1.2.3'
d = Dependency('foo = 1.0-rc1', app.get_version) d = Dependency('foo = 1.0-rc1', app.get_version)
assert d.constraint_str(as_range = True) == 'foo = 1.0-rc1' assert d.constraint_str(as_range = True) == 'foo = 1.0-rc1'
# unimplemented operators raise
d = Dependency('foo == 1.2.3-45', app.get_version)
try:
d.constraint_str(as_range = True)
assert False, 'Should have raised'
except NotImplementedError:
pass
# Default syntax is SEM_VER # Default syntax is SEM_VER
d = Dependency('foo < 2.0') d = Dependency('foo < 2.0')
assert d.constraint_str(untemplated = False) == 'foo < 2.0' assert d.constraint_str(untemplated = False) == 'foo < 2.0'
@ -238,6 +230,26 @@ for bad in ['', 'foo =', ' = 1.0']:
except Dependency.Error: except Dependency.Error:
pass pass
# Operators outside the supported set are rejected when parsed,
# not folded into the package name or deferred to expansion
for bad in [
'foo ~= 1.0',
'foo~=1.0',
'foo ~ 1.0',
'foo != 1.0',
'foo!=1.0',
'foo == 1.0',
'foo==1.0',
'foo === 1.0',
'foo << 1.0',
'foo >> 1.0',
]:
try:
Dependency(bad).full_name
assert False, f'Should have raised for {bad!r}'
except Dependency.Error as e:
assert 'unsupported operator' in str(e)
# str # str
assert str(Dependency('foo-devel >= 1.0')) == 'foo-devel >= 1.0' assert str(Dependency('foo-devel >= 1.0')) == 'foo-devel >= 1.0'
assert str(Dependency('foo')) == 'foo' assert str(Dependency('foo')) == 'foo'