univers icon indicating copy to clipboard operation
univers copied to clipboard

`PyPiVersionRange.from_native` not working

Open Hritik14 opened this issue 4 years ago • 3 comments

https://github.com/nexB/univers/blob/aa2253d17a11be3af36278be37e898c05fdbc4fd/src/univers/version_range.py#L501-L504

and PEP 440 shows an example for version specifier as follows:

~= 0.9, >= 1.0, != 1.3.4.*, < 2.0

See: https://www.python.org/dev/peps/pep-0440/#version-specifiers

Let's try:

>>> from univers.version_range import PypiVersionRange
>>> rng_from_native = PypiVersionRange.from_native("~= 0.9, >= 1.0, != 1.3.4.*, < 2.0")
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-22-af3412ff72fa> in <module>
----> 1 rng_from_native = PypiVersionRange.from_native("~= 0.9, >= 1.0, != 1.3.4.*, < 2.0")

~/Contrib/univers/src/univers/version_range.py in from_native(cls, string)
    514             operator = spec.operator
    515             version = spec.version
--> 516             assert isinstance(version, cls.version_class)
    517             comparator = cls.vers_by_native_comparators[operator]
    518             constraint = VersionConstraint(comparator=comparator, version=version)

AssertionError:

Something is not right

Hritik14 avatar Jan 11 '22 19:01 Hritik14

I have programmed a small piece of code that solves the problem with the ~= operator and the versions ending in *. I have disregarded the === operator as mentioned within the TODOs of the PypiVersionRange class as PEP 440 considers it a non-recommended approach. I haven't had time to add it to a pull request as I needed to add this to a project of my own, but if needed I could do so and contribute to the project.

def sanitize_pip_constraints(raw_constraints: str) -> str:
    constraints = []
    for raw_constraint in raw_constraints.split(','):
        operator, version = raw_constraint.strip().split(' ')
        if '==' in operator and '*' in version:
            pos = version.find('*')
            version = version[:pos - 1]
            constraints.append('>= ' + version)
            constraints.append('< ' + version[:pos - 2] + str(int(version[pos - 2]) + 1))
        elif '!=' in operator and '*' in version:
            pos = version.find('*')
            version = version[:pos - 1]
            constraints.append('< ' + version)
            constraints.append('>= ' + version[:pos - 2] + str(int(version[pos - 2]) + 1))
        elif '~=' in operator:
            parts = version.split('.')
            parts[-2] = str(int(parts[-2]) + 1)
            parts.pop()
            constraints.append('>= ' + version)
            constraints.append('< ' + '.'.join(parts))
        else:
            constraints.append(operator + ' ' + version)
    return ', '.join(constraints)

raw_constraints = '~= 0.9, >= 1.0, != 1.3.4.*, == 2.3.*, < 2.0'

print(sanitize_pip_constraints(raw_constraints))

GermanMT avatar Aug 26 '23 00:08 GermanMT

@GermanMT This looks good! A PR with some tests would certainly be welcome and more discussion-able.

Hritik14 avatar Aug 28 '23 05:08 Hritik14

I have make a pull request, sorry for the delay.

GermanMT avatar Oct 19 '23 15:10 GermanMT