rbarrois / python-semanticversion

Semantic version comparison for Python (see http://semver.org/)
BSD 2-Clause "Simplified" License
281 stars 74 forks source link

feat: SimpleSpec support set operations #105

Open yxliang01 opened 4 years ago

yxliang01 commented 4 years ago

SimpleSpec essentially is a semver set expression to specify a set of version numbers. So, it is natural to support set operations to the class, e.g. intersection and union. Such operations can be useful, e.g. to check whether two SimpleSpecs are compatible and what are the versions fulfilling both.

rbarrois commented 4 years ago

Indeed, under the hood a SimpleSpec is just a thin wrapper around a Clause (an internal class), which supports set operations.

Thus, one could do (SimpleSpec('>=1.1').clause & SimpleSpec('<2.0').clause).match(Version('1.3.4'))

However, before adding that feature, I'll have to think how it should be documented and supported in the long term. Could you help me by providing snippets for how you would expect this new feature to be used in practice? It would help in desiging a reasonable, easy-to-use API ;)

NB: Since it's a feature of the BaseSpec, it is actually available for all variants: SimpleSpec, NPMSpec, and future variants.

yxliang01 commented 4 years ago

E.g. the environment supports >0.5.0 while the codebase might support >0.6.0, then we can try to see whether environment is compatible with the codebase by creating two SimpleSpecs and check if their intersection set is empty.

rbarrois commented 4 years ago

@yxliang01 yes, I do see the use case :) My question is, how would you write some code using it :)

Some options:

# Use boolean operations to combine specs
>>> Version('0.7.0') in (Spec('>0.5.0') & Sepc('>0.6.0'))
True

# Use set operations on lists of versions
>>> Spec('>0.5.0') & [Version('0.4.0'), Version('0.5.0'), Version('0.6.0')]
[Version('0.6.0')]

# Can we combine specs from different "worlds"?
>>> SimpleSpec('>0.5.0') & NpmSpec('<0.6.0')
<CombinedSpec>
yxliang01 commented 4 years ago

I think the three use cases are great and not conflicting :) Meanwhile, I believe my use case is also common, it will fit the most for my case to add a compatibleWith(BaseSpec) method to the Spec classes and return bool indicating whether the intersection contains any element.

supersergiy commented 2 years ago

I'm facing the same need as @yxliang01 -- I need to know if the intersection is empty. Is there a straightforward way to do it?

Combining clauses produces an AllOf object, and I initially hoped that it will be clear whether or not it represents an empty set by calling .simplify(), but unfortunately that didn't work out.