diff --git a/lib/versioning/pep440/index.spec.ts b/lib/versioning/pep440/index.spec.ts
index 195cfef960f66fac8abe169701b3d886690d94ce..47d196a1be97adea199a56548eecb3556e787a86 100644
--- a/lib/versioning/pep440/index.spec.ts
+++ b/lib/versioning/pep440/index.spec.ts
@@ -84,70 +84,71 @@ describe('versioning/pep440/index', () => {
   );
 
   test.each`
-    currentValue          | rangeStrategy | currentVersion | newVersion | expected
-    ${'1.0.0'}            | ${'bump'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'1.2.3'}
-    ${'1.0.0'}            | ${'replace'}  | ${'1.0.0'}     | ${'1.2.3'} | ${'1.2.3'}
-    ${'1.0.0'}            | ${'pin'}      | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
-    ${'==1.0.3'}          | ${'bump'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
-    ${'==1.0.3'}          | ${'replace'}  | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
-    ${'==1.0.3'}          | ${'pin'}      | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
-    ${'>=1.2.0'}          | ${'bump'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'>=1.2.3'}
-    ${'>=1.2.0'}          | ${'replace'}  | ${'1.0.0'}     | ${'1.2.3'} | ${'>=1.2.0'}
-    ${'>=1.2.0'}          | ${'pin'}      | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
-    ${'~=1.2.0'}          | ${'bump'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'~=1.2.3'}
-    ${'~=1.2.0'}          | ${'replace'}  | ${'1.0.0'}     | ${'1.2.3'} | ${'~=1.2.0'}
-    ${'~=1.2.0'}          | ${'pin'}      | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
-    ${'~=1.0.3'}          | ${'bump'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'~=1.2.3'}
-    ${'~=1.0.3'}          | ${'replace'}  | ${'1.0.0'}     | ${'1.2.3'} | ${'~=1.2.3'}
-    ${'~=1.0.3'}          | ${'pin'}      | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
-    ${'==1.2.*'}          | ${'bump'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.*'}
-    ${'==1.2.*'}          | ${'replace'}  | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.*'}
-    ${'==1.2.*'}          | ${'pin'}      | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
-    ${'==1.0.*'}          | ${'bump'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.*'}
-    ${'==1.0.*'}          | ${'replace'}  | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.*'}
-    ${'==1.0.*'}          | ${'pin'}      | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
-    ${'<1.2.2.3'}         | ${'bump'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'<1.2.4.0'}
-    ${'<1.2.2.3'}         | ${'replace'}  | ${'1.0.0'}     | ${'1.2.3'} | ${'<1.2.4.0'}
-    ${'<1.2.2.3'}         | ${'pin'}      | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
-    ${'<1.2.3'}           | ${'bump'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'<1.2.4'}
-    ${'<1.2.3'}           | ${'replace'}  | ${'1.0.0'}     | ${'1.2.3'} | ${'<1.2.4'}
-    ${'<1.2.3'}           | ${'pin'}      | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
-    ${'<1.2'}             | ${'bump'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'<1.3'}
-    ${'<1.2'}             | ${'replace'}  | ${'1.0.0'}     | ${'1.2.3'} | ${'<1.3'}
-    ${'<1.2'}             | ${'pin'}      | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
-    ${'<1'}               | ${'bump'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'<2'}
-    ${'<1'}               | ${'replace'}  | ${'1.0.0'}     | ${'1.2.3'} | ${'<2'}
-    ${'<1'}               | ${'pin'}      | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
-    ${'<2.0.0'}           | ${'bump'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'<2.0.0'}
-    ${'<2.0.0'}           | ${'replace'}  | ${'1.0.0'}     | ${'1.2.3'} | ${'<2.0.0'}
-    ${'<2.0.0'}           | ${'pin'}      | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
-    ${'>0.9.8'}           | ${'bump'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'>0.9.8'}
-    ${'>0.9.8'}           | ${'replace'}  | ${'1.0.0'}     | ${'1.2.3'} | ${'>0.9.8'}
-    ${'>0.9.8'}           | ${'pin'}      | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
-    ${'>2.0.0'}           | ${'bump'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'>=1.2.3'}
-    ${'>2.0.0'}           | ${'replace'}  | ${'1.0.0'}     | ${'1.2.3'} | ${'>=1.2.3'}
-    ${'>2.0.0'}           | ${'pin'}      | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
-    ${'>=2.0.0'}          | ${'bump'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'>=1.2.3'}
-    ${'>=2.0.0'}          | ${'replace'}  | ${'1.0.0'}     | ${'1.2.3'} | ${'>=1.2.3'}
-    ${'>=2.0.0'}          | ${'pin'}      | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
-    ${'~=1.1.0, !=1.1.1'} | ${'bump'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'~=1.2.3, !=1.1.1'}
-    ${'~=1.1.0, !=1.1.1'} | ${'replace'}  | ${'1.0.0'}     | ${'1.2.3'} | ${'~=1.2.3, !=1.1.1'}
-    ${'~=1.1.0, !=1.1.1'} | ${'pin'}      | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
-    ${'~=1.1.0,!=1.1.1'}  | ${'bump'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'~=1.2.3,!=1.1.1'}
-    ${'~=1.1.0,!=1.1.1'}  | ${'replace'}  | ${'1.0.0'}     | ${'1.2.3'} | ${'~=1.2.3,!=1.1.1'}
-    ${'~=1.1.0,!=1.1.1'}  | ${'pin'}      | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
-    ${' '}                | ${'bump'}     | ${'1.0.0'}     | ${'1.2.3'} | ${' '}
-    ${' '}                | ${'replace'}  | ${'1.0.0'}     | ${'1.2.3'} | ${' '}
-    ${' '}                | ${'pin'}      | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
-    ${'invalid'}          | ${'bump'}     | ${'1.0.0'}     | ${'1.2.3'} | ${null}
-    ${'invalid'}          | ${'replace'}  | ${'1.0.0'}     | ${'1.2.3'} | ${null}
-    ${'invalid'}          | ${'pin'}      | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
-    ${'===1.0.3'}         | ${'bump'}     | ${'1.0.0'}     | ${'1.2.3'} | ${null}
-    ${'===1.0.3'}         | ${'replace'}  | ${'1.0.0'}     | ${'1.2.3'} | ${null}
-    ${'===1.0.3'}         | ${'pin'}      | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
-    ${'!=1.2.3'}          | ${'bump'}     | ${'1.0.0'}     | ${'1.2.3'} | ${null}
-    ${'!=1.2.3'}          | ${'replace'}  | ${'1.0.0'}     | ${'1.2.3'} | ${null}
-    ${'!=1.2.3'}          | ${'pin'}      | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    currentValue          | rangeStrategy    | currentVersion | newVersion | expected
+    ${'1.0.0'}            | ${'bump'}        | ${'1.0.0'}     | ${'1.2.3'} | ${'1.2.3'}
+    ${'1.0.0'}            | ${'replace'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'1.2.3'}
+    ${'1.0.0'}            | ${'pin'}         | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    ${'==1.0.3'}          | ${'bump'}        | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    ${'==1.0.3'}          | ${'replace'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    ${'==1.0.3'}          | ${'pin'}         | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    ${'>=1.2.0'}          | ${'bump'}        | ${'1.0.0'}     | ${'1.2.3'} | ${'>=1.2.3'}
+    ${'>=1.2.0'}          | ${'replace'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'>=1.2.0'}
+    ${'>=1.2.0'}          | ${'pin'}         | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    ${'~=1.2.0'}          | ${'bump'}        | ${'1.0.0'}     | ${'1.2.3'} | ${'~=1.2.3'}
+    ${'~=1.2.0'}          | ${'replace'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'~=1.2.0'}
+    ${'~=1.2.0'}          | ${'pin'}         | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    ${'~=1.0.3'}          | ${'bump'}        | ${'1.0.0'}     | ${'1.2.3'} | ${'~=1.2.3'}
+    ${'~=1.0.3'}          | ${'replace'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'~=1.2.3'}
+    ${'~=1.0.3'}          | ${'pin'}         | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    ${'==1.2.*'}          | ${'bump'}        | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.*'}
+    ${'==1.2.*'}          | ${'replace'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.*'}
+    ${'==1.2.*'}          | ${'pin'}         | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    ${'==1.0.*'}          | ${'bump'}        | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.*'}
+    ${'==1.0.*'}          | ${'replace'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.*'}
+    ${'==1.0.*'}          | ${'pin'}         | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    ${'<1.2.2.3'}         | ${'bump'}        | ${'1.0.0'}     | ${'1.2.3'} | ${'<1.2.4.0'}
+    ${'<1.2.2.3'}         | ${'replace'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'<1.2.4.0'}
+    ${'<1.2.2.3'}         | ${'pin'}         | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    ${'<1.2.3'}           | ${'bump'}        | ${'1.0.0'}     | ${'1.2.3'} | ${'<1.2.4'}
+    ${'<1.2.3'}           | ${'replace'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'<1.2.4'}
+    ${'<1.2.3'}           | ${'pin'}         | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    ${'<1.2'}             | ${'bump'}        | ${'1.0.0'}     | ${'1.2.3'} | ${'<1.3'}
+    ${'<1.2'}             | ${'replace'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'<1.3'}
+    ${'<1.2'}             | ${'pin'}         | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    ${'<1'}               | ${'bump'}        | ${'1.0.0'}     | ${'1.2.3'} | ${'<2'}
+    ${'<1'}               | ${'replace'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'<2'}
+    ${'<1'}               | ${'pin'}         | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    ${'<2.0.0'}           | ${'bump'}        | ${'1.0.0'}     | ${'1.2.3'} | ${'<2.0.0'}
+    ${'<2.0.0'}           | ${'replace'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'<2.0.0'}
+    ${'<2.0.0'}           | ${'pin'}         | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    ${'>0.9.8'}           | ${'bump'}        | ${'1.0.0'}     | ${'1.2.3'} | ${'>0.9.8'}
+    ${'>0.9.8'}           | ${'replace'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'>0.9.8'}
+    ${'>0.9.8'}           | ${'pin'}         | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    ${'>2.0.0'}           | ${'bump'}        | ${'1.0.0'}     | ${'1.2.3'} | ${'>=1.2.3'}
+    ${'>2.0.0'}           | ${'replace'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'>=1.2.3'}
+    ${'>2.0.0'}           | ${'pin'}         | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    ${'>=2.0.0'}          | ${'bump'}        | ${'1.0.0'}     | ${'1.2.3'} | ${'>=1.2.3'}
+    ${'>=2.0.0'}          | ${'replace'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'>=1.2.3'}
+    ${'>=2.0.0'}          | ${'pin'}         | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    ${'~=1.1.0, !=1.1.1'} | ${'bump'}        | ${'1.0.0'}     | ${'1.2.3'} | ${'~=1.2.3, !=1.1.1'}
+    ${'~=1.1.0, !=1.1.1'} | ${'replace'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'~=1.2.3, !=1.1.1'}
+    ${'~=1.1.0, !=1.1.1'} | ${'pin'}         | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    ${'~=1.1.0,!=1.1.1'}  | ${'bump'}        | ${'1.0.0'}     | ${'1.2.3'} | ${'~=1.2.3,!=1.1.1'}
+    ${'~=1.1.0,!=1.1.1'}  | ${'replace'}     | ${'1.0.0'}     | ${'1.2.3'} | ${'~=1.2.3,!=1.1.1'}
+    ${'~=1.1.0,!=1.1.1'}  | ${'pin'}         | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    ${' '}                | ${'bump'}        | ${'1.0.0'}     | ${'1.2.3'} | ${' '}
+    ${' '}                | ${'replace'}     | ${'1.0.0'}     | ${'1.2.3'} | ${' '}
+    ${' '}                | ${'pin'}         | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    ${'invalid'}          | ${'bump'}        | ${'1.0.0'}     | ${'1.2.3'} | ${null}
+    ${'invalid'}          | ${'replace'}     | ${'1.0.0'}     | ${'1.2.3'} | ${null}
+    ${'invalid'}          | ${'pin'}         | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    ${'===1.0.3'}         | ${'bump'}        | ${'1.0.0'}     | ${'1.2.3'} | ${null}
+    ${'===1.0.3'}         | ${'replace'}     | ${'1.0.0'}     | ${'1.2.3'} | ${null}
+    ${'===1.0.3'}         | ${'pin'}         | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    ${'!=1.2.3'}          | ${'bump'}        | ${'1.0.0'}     | ${'1.2.3'} | ${null}
+    ${'!=1.2.3'}          | ${'replace'}     | ${'1.0.0'}     | ${'1.2.3'} | ${null}
+    ${'!=1.2.3'}          | ${'pin'}         | ${'1.0.0'}     | ${'1.2.3'} | ${'==1.2.3'}
+    ${'~=1.1.0,!=1.1.1'}  | ${'unsupported'} | ${'1.0.0'}     | ${'1.2.3'} | ${'~=1.2.3,!=1.1.1'}
   `(
     'getNewValue("$currentValue", "$rangeStrategy", "$currentVersion", "$newVersion") === "$expected"',
     ({ currentValue, rangeStrategy, currentVersion, newVersion, expected }) => {
diff --git a/lib/versioning/pep440/range.ts b/lib/versioning/pep440/range.ts
index 11ff5228fb9d48aa6398f3609a795b413db1c4ab..128db98166b59d9fa58866d0000460ba196c61a4 100644
--- a/lib/versioning/pep440/range.ts
+++ b/lib/versioning/pep440/range.ts
@@ -8,7 +8,7 @@ import type { NewValueConfig } from '../types';
 function getFutureVersion(
   baseVersion: string,
   newVersion: string,
-  step: number
+  incrementValue: number
 ): string {
   const toRelease: number[] = parseVersion(newVersion)?.release ?? [];
   const baseRelease: number[] = parseVersion(baseVersion)?.release ?? [];
@@ -20,12 +20,12 @@ function getFutureVersion(
     const toPart = toRelease[index] || 0;
     if (toPart > basePart) {
       found = true;
-      return toPart + step;
+      return toPart + incrementValue;
     }
     return toPart;
   });
   if (!found) {
-    futureRelease[futureRelease.length - 1] += step;
+    futureRelease[futureRelease.length - 1] += incrementValue;
   }
   return futureRelease.join('.');
 }
@@ -42,106 +42,72 @@ export function getNewValue({
   currentVersion,
   newVersion,
 }: NewValueConfig): string | null {
-  // easy pin
+  let ranges: Range[];
+  let updatedRange: (string | null)[];
   if (rangeStrategy === 'pin') {
     return '==' + newVersion;
   }
+
+  // no symbol: accept only that specific version specified
   if (currentValue === currentVersion) {
     return newVersion;
   }
-  const ranges: Range[] = parseRange(currentValue);
-  if (!ranges) {
-    logger.warn({ currentValue }, 'Invalid pep440 currentValue');
-    return null;
-  }
-  if (!ranges.length) {
-    // an empty string is an allowed value for PEP440 range
-    // it means get any version
-    logger.warn('Empty currentValue: ' + currentValue);
-    return currentValue;
-  }
-  if (rangeStrategy === 'auto' || rangeStrategy === 'replace') {
-    if (satisfies(newVersion, currentValue)) {
+
+  try {
+    ranges = parseCurrentRange(currentValue);
+    if (!ranges.length) {
+      // an empty string is an allowed value for PEP440 range
+      // it means get any version
+      logger.warn('Empty currentValue: ' + currentValue);
       return currentValue;
     }
-  }
-  if (!['replace', 'bump'].includes(rangeStrategy)) {
-    logger.debug(
-      'Unsupported rangeStrategy: ' +
-        rangeStrategy +
-        '. Using "replace" instead.'
-    );
-    return getNewValue({
-      currentValue,
-      rangeStrategy: 'replace',
-      currentVersion,
-      newVersion,
-    });
-  }
-  if (ranges.some((range) => range.operator === '===')) {
-    // the operator "===" is used for legacy non PEP440 versions
-    logger.warn(
-      { currentValue },
-      'PEP440 arbitrary equality (===) not supported'
-    );
+  } catch (err) {
+    logger.warn({ currentValue, err }, 'Unexpected range error');
     return null;
   }
-  let result = ranges
-    .map((range) => {
-      // used to exclude versions,
-      // we assume that's for a good reason
-      if (range.operator === '!=') {
-        return range.operator + range.version;
-      }
-
-      // used to mark minimum supported version
-      if (['>', '>='].includes(range.operator)) {
-        if (lte(newVersion, range.version)) {
-          // this looks like a rollback
-          return '>=' + newVersion;
-        }
-        // this is similar to ~=
-        if (rangeStrategy === 'bump' && range.operator === '>=') {
-          return range.operator + newVersion;
-        }
-        // otherwise treat it same as exclude
-        return range.operator + range.version;
-      }
-
-      // this is used to exclude future versions
-      if (range.operator === '<') {
-        // if newVersion is that future version
-        if (gte(newVersion, range.version)) {
-          // now here things get tricky
-          // we calculate the new future version
-          const futureVersion = getFutureVersion(range.version, newVersion, 1);
-          return range.operator + futureVersion;
-        }
-        // otherwise treat it same as exclude
-        return range.operator + range.version;
-      }
-
-      // keep the .* suffix
-      if (range.prefix) {
-        const futureVersion = getFutureVersion(range.version, newVersion, 0);
-        return range.operator + futureVersion + '.*';
-      }
-
-      if (['==', '~=', '<='].includes(range.operator)) {
-        return range.operator + newVersion;
-      }
-
-      // unless PEP440 changes, this won't happen
-      // istanbul ignore next
-      logger.error(
-        { newVersion, currentValue, range },
-        'pep440: failed to process range'
+
+  switch (rangeStrategy) {
+    case 'auto':
+    case 'replace':
+      updatedRange = handleReplaceStrategy(
+        {
+          currentValue,
+          rangeStrategy,
+          currentVersion,
+          newVersion,
+        },
+        ranges
       );
-      // istanbul ignore next
-      return null;
-    })
-    .filter(Boolean)
-    .join(', ');
+      break;
+    case 'bump':
+      updatedRange = handleBumpStrategy(
+        {
+          currentValue,
+          rangeStrategy,
+          currentVersion,
+          newVersion,
+        },
+        ranges
+      );
+      break;
+    default:
+      // Unsupported rangeStrategy
+      // Valid rangeStrategy values are: bump, extend, pin, replace.
+      // https://docs.renovatebot.com/modules/versioning/#pep440-versioning
+      logger.debug(
+        'Unsupported rangeStrategy: ' +
+          rangeStrategy +
+          '. Using "replace" instead.'
+      );
+      return getNewValue({
+        currentValue,
+        rangeStrategy: 'auto',
+        currentVersion,
+        newVersion,
+      });
+  }
+
+  let result = updatedRange.filter(Boolean).join(', ');
 
   if (result.includes(', ') && !currentValue.includes(', ')) {
     result = result.replace(regEx(/, /g), ',');
@@ -155,7 +121,6 @@ export function getNewValue({
     );
     return null;
   }
-
   return result;
 }
 
@@ -193,3 +158,130 @@ export function isLessThanRange(input: string, range: string): boolean {
     return false;
   }
 }
+
+function parseCurrentRange(currentValue: string): Range[] {
+  const ranges: Range[] = parseRange(currentValue);
+  if (!ranges) {
+    throw new TypeError('Invalid pep440 currentValue');
+  }
+  if (ranges.some((range) => range.operator === '===')) {
+    // the operator "===" is used for legacy non PEP440 versions
+    throw new TypeError('PEP440 arbitrary equality (===) not supported');
+  }
+  return ranges;
+}
+
+function handleLowerBound(range: Range, newVersion: string): string | null {
+  // used to mark minimum supported version
+  // lower the bound if the new version is lower than current range
+  if (['>', '>='].includes(range.operator)) {
+    if (lte(newVersion, range.version)) {
+      // this looks like a rollback
+      return '>=' + newVersion;
+    }
+    // otherwise, treat it same as exclude
+    return range.operator + range.version;
+  }
+  // istanbul ignore next
+  return null;
+}
+
+function handleUpperBound(range: Range, newVersion: string): string | null {
+  // this is used to exclude future versions
+  if (range.operator === '<') {
+    // if newVersion is that future version
+    if (gte(newVersion, range.version)) {
+      // now here things get tricky
+      // we calculate the new future version
+      const futureVersion = getFutureVersion(range.version, newVersion, 1);
+      return range.operator + futureVersion;
+    }
+    // newVersion is in range, for other than "replace" strategies
+    return range.operator + range.version;
+  }
+  // istanbul ignore next
+  return null;
+}
+
+function updateRangeValue(
+  { currentValue, rangeStrategy, currentVersion, newVersion }: NewValueConfig,
+  range: Range
+): string | null {
+  // used to exclude versions,
+  // we assume that's for a good reason
+  if (range.operator === '!=') {
+    return range.operator + range.version;
+  }
+
+  // keep the .* suffix
+  if (range.prefix) {
+    const futureVersion = getFutureVersion(range.version, newVersion, 0);
+    return range.operator + futureVersion + '.*';
+  }
+
+  if (['==', '~=', '<='].includes(range.operator)) {
+    return range.operator + newVersion;
+  }
+
+  let output = handleUpperBound(range, newVersion);
+  if (output) {
+    // manged to update upperbound
+    // no need to try anything else
+    return output;
+  }
+  output = handleLowerBound(range, newVersion);
+  if (output) {
+    return output;
+  }
+
+  // unless PEP440 changes, this won't happen
+  // istanbul ignore next
+  logger.error(
+    { newVersion, currentValue, range },
+    'pep440: failed to process range'
+  );
+  // istanbul ignore next
+  return null;
+}
+
+function handleReplaceStrategy(
+  { currentValue, rangeStrategy, currentVersion, newVersion }: NewValueConfig,
+  ranges: Range[]
+): (string | null)[] {
+  // newVersion is within range
+  if (satisfies(newVersion, currentValue)) {
+    return [currentValue];
+  }
+  return ranges.map((range) =>
+    updateRangeValue(
+      {
+        currentValue,
+        rangeStrategy,
+        currentVersion,
+        newVersion,
+      },
+      range
+    )
+  );
+}
+
+function handleBumpStrategy(
+  { currentValue, rangeStrategy, currentVersion, newVersion }: NewValueConfig,
+  ranges: Range[]
+): (string | null)[] {
+  return ranges.map((range) => {
+    // bump lower bound to current new version
+    if (range.operator === '>=') {
+      return range.operator + newVersion;
+    }
+    return updateRangeValue(
+      {
+        currentValue,
+        rangeStrategy,
+        currentVersion,
+        newVersion,
+      },
+      range
+    );
+  });
+}