|
7 | 7 |
|
8 | 8 | from poetry.core.constraints.version.empty_constraint import EmptyConstraint
|
9 | 9 | from poetry.core.constraints.version.version_constraint import VersionConstraint
|
| 10 | +from poetry.core.constraints.version.version_constraint import _is_wildcard_candidate |
| 11 | +from poetry.core.constraints.version.version_constraint import ( |
| 12 | + _single_wildcard_range_string, |
| 13 | +) |
10 | 14 | from poetry.core.constraints.version.version_range_constraint import (
|
11 | 15 | VersionRangeConstraint,
|
12 | 16 | )
|
@@ -256,168 +260,33 @@ def _exclude_single_wildcard_range_string(self) -> str:
|
256 | 260 | if not self.excludes_single_wildcard_range():
|
257 | 261 | raise ValueError("Not a valid wildcard range")
|
258 | 262 |
|
259 |
| - # we assume here that since it is a single exclusion range |
260 |
| - # that it is one of "< 2.0.0 || >= 2.1.0" or ">= 2.1.0 || < 2.0.0" |
261 |
| - # and the one with the max is the first part |
262 | 263 | idx_order = (0, 1) if self._ranges[0].max else (1, 0)
|
263 |
| - one = self._ranges[idx_order[0]].max |
264 |
| - assert one is not None |
265 |
| - two = self._ranges[idx_order[1]].min |
266 |
| - assert two is not None |
267 |
| - |
268 |
| - # versions can have both semver and non semver parts |
269 |
| - parts_one = [ |
270 |
| - one.major, |
271 |
| - one.minor or 0, |
272 |
| - one.patch or 0, |
273 |
| - *list(one.non_semver_parts or []), |
274 |
| - ] |
275 |
| - parts_two = [ |
276 |
| - two.major, |
277 |
| - two.minor or 0, |
278 |
| - two.patch or 0, |
279 |
| - *list(two.non_semver_parts or []), |
280 |
| - ] |
281 |
| - |
282 |
| - # we assume here that a wildcard range implies that the part following the |
283 |
| - # first part that is different in the second range is the wildcard, this means |
284 |
| - # that multiple wildcards are not supported right now. |
285 |
| - parts = [] |
286 |
| - |
287 |
| - for idx, part in enumerate(parts_one): |
288 |
| - parts.append(str(part)) |
289 |
| - if parts_two[idx] != part: |
290 |
| - # since this part is different the next one is the wildcard |
291 |
| - # for example, "< 2.0.0 || >= 2.1.0" gets us a wildcard range |
292 |
| - # 2.0.* |
293 |
| - parts.append("*") |
294 |
| - break |
295 |
| - else: |
296 |
| - # we should not ever get here, however it is likely that poorly |
297 |
| - # constructed metadata exists |
298 |
| - raise ValueError("Not a valid wildcard range") |
299 |
| - |
300 |
| - return f"!={'.'.join(parts)}" |
301 |
| - |
302 |
| - @staticmethod |
303 |
| - def _excludes_single_wildcard_range_check_is_valid_range( |
304 |
| - one: VersionRangeConstraint, two: VersionRangeConstraint |
305 |
| - ) -> bool: |
306 |
| - """ |
307 |
| - Helper method to determine if two versions define a single wildcard range. |
308 |
| -
|
309 |
| - In cases where !=2.0.* was parsed by us, the union is of the range |
310 |
| - <2.0.0 || >=2.1.0. In user defined ranges, precision might be different. |
311 |
| - For example, a union <2.0 || >= 2.1.0 is still !=2.0.*. In order to |
312 |
| - handle these cases we make sure that if precisions do not match, extra |
313 |
| - checks are performed to validate that the constraint is a valid single |
314 |
| - wildcard range. |
315 |
| - """ |
| 264 | + one = self._ranges[idx_order[0]] |
| 265 | + two = self._ranges[idx_order[1]] |
316 | 266 |
|
317 | 267 | assert one.max is not None
|
318 | 268 | assert two.min is not None
|
319 |
| - |
320 |
| - _max = one.max |
321 |
| - _min = two.min |
322 |
| - |
323 |
| - if _max.is_devrelease() and _max.dev is not None and _max.dev.number == 0: |
324 |
| - # handle <2.0.0.dev0 || >= 2.1.0 |
325 |
| - _max = _max.without_devrelease() |
326 |
| - |
327 |
| - if _min.is_devrelease(): |
328 |
| - assert _min.dev is not None |
329 |
| - |
330 |
| - if _min.dev.number != 0: |
331 |
| - # if both are dev releases, they should both have dev0 |
332 |
| - return False |
333 |
| - _min = _min.without_devrelease() |
334 |
| - |
335 |
| - max_precision = max(_max.precision, _min.precision) |
336 |
| - |
337 |
| - if max_precision <= 3: |
338 |
| - # In cases where both versions have a precision less than 3, |
339 |
| - # we can make use of the next major/minor/patch versions. |
340 |
| - return _min in { |
341 |
| - _max.next_major(), |
342 |
| - _max.next_minor(), |
343 |
| - _max.next_patch(), |
344 |
| - } |
345 |
| - else: |
346 |
| - # When there are non-semver parts in one of the versions, we need to |
347 |
| - # ensure we use zero padded version and in addition to next major/minor/ |
348 |
| - # patch versions, also check each next release for the extra parts. |
349 |
| - from_parts = _max.__class__.from_parts |
350 |
| - |
351 |
| - _extras: list[list[int]] = [] |
352 |
| - _versions: list[Version] = [] |
353 |
| - |
354 |
| - for _version in (_max, _min): |
355 |
| - _extra = list(_version.non_semver_parts or []) |
356 |
| - |
357 |
| - while len(_extra) < (max_precision - 3): |
358 |
| - # pad zeros for extra parts to ensure precisions are equal |
359 |
| - _extra.append(0) |
360 |
| - |
361 |
| - # create a new release with unspecified parts padded with zeros |
362 |
| - _padded_version: Version = from_parts( |
363 |
| - major=_version.major, |
364 |
| - minor=_version.minor or 0, |
365 |
| - patch=_version.patch or 0, |
366 |
| - extra=tuple(_extra), |
367 |
| - ) |
368 |
| - |
369 |
| - _extras.append(_extra) |
370 |
| - _versions.append(_padded_version) |
371 |
| - |
372 |
| - _extra_one = _extras[0] |
373 |
| - _padded_version_one = _versions[0] |
374 |
| - _padded_version_two = _versions[1] |
375 |
| - |
376 |
| - _check_versions = { |
377 |
| - _padded_version_one.next_major(), |
378 |
| - _padded_version_one.next_minor(), |
379 |
| - _padded_version_one.next_patch(), |
380 |
| - } |
381 |
| - |
382 |
| - # for each non-semver (extra) part, bump a version |
383 |
| - for idx, val in enumerate(_extra_one): |
384 |
| - _extra = [ |
385 |
| - *_extra_one[: idx - 1], |
386 |
| - (val + 1), |
387 |
| - *_extra_one[idx + 1 :], |
388 |
| - ] |
389 |
| - _check_versions.add( |
390 |
| - from_parts( |
391 |
| - _padded_version_one.major, |
392 |
| - _padded_version_one.minor, |
393 |
| - _padded_version_one.patch, |
394 |
| - tuple(_extra), |
395 |
| - ) |
396 |
| - ) |
397 |
| - |
398 |
| - return _padded_version_two in _check_versions |
| 269 | + return f"!={_single_wildcard_range_string(one.max, two.min)}" |
399 | 270 |
|
400 | 271 | def excludes_single_wildcard_range(self) -> bool:
|
401 |
| - from poetry.core.constraints.version.version_range import VersionRange |
402 |
| - |
403 | 272 | if len(self._ranges) != 2:
|
404 | 273 | return False
|
405 | 274 |
|
406 | 275 | idx_order = (0, 1) if self._ranges[0].max else (1, 0)
|
407 | 276 | one = self._ranges[idx_order[0]]
|
408 | 277 | two = self._ranges[idx_order[1]]
|
409 | 278 |
|
410 |
| - is_range_exclusion = ( |
411 |
| - one.max and not one.include_max and two.min and two.include_min |
412 |
| - ) |
413 |
| - |
414 |
| - if not is_range_exclusion: |
415 |
| - return False |
416 |
| - |
417 |
| - if not self._excludes_single_wildcard_range_check_is_valid_range(one, two): |
| 279 | + if ( |
| 280 | + one.max is None |
| 281 | + or one.include_max |
| 282 | + or one.min is not None |
| 283 | + or two.min is None |
| 284 | + or not two.include_min |
| 285 | + or two.max is not None |
| 286 | + ): |
418 | 287 | return False
|
419 | 288 |
|
420 |
| - return isinstance(VersionRange().difference(self), VersionRange) |
| 289 | + return _is_wildcard_candidate(two.min, one.max, inverted=True) |
421 | 290 |
|
422 | 291 | def excludes_single_version(self) -> bool:
|
423 | 292 | from poetry.core.constraints.version.version import Version
|
|
0 commit comments