diff --git a/lib/modules/manager/pep621/artifacts.spec.ts b/lib/modules/manager/pep621/artifacts.spec.ts
index f48d42050a816d16003fa7bef9625c34af7be0d8..ebcc935879894b23ffed81adacca8b1e73521af9 100644
--- a/lib/modules/manager/pep621/artifacts.spec.ts
+++ b/lib/modules/manager/pep621/artifacts.spec.ts
@@ -1,3 +1,4 @@
+import { codeBlock } from 'common-tags';
 import { join } from 'upath';
 import { mockExecAll } from '../../../../test/exec-util';
 import { fs, mockedFunction } from '../../../../test/util';
@@ -36,6 +37,25 @@ describe('modules/manager/pep621/artifacts', () => {
       expect(result).toBeNull();
     });
 
+    it('return artifact error if newPackageFile content is not valid', async () => {
+      const updatedDeps = [
+        {
+          packageName: 'dep1',
+        },
+      ];
+      const result = await updateArtifacts({
+        packageFileName: 'pyproject.toml',
+        newPackageFileContent: '--test string--',
+        config,
+        updatedDeps,
+      });
+      expect(result).toEqual([
+        {
+          artifactError: { stderr: 'Failed to parse new package file content' },
+        },
+      ]);
+    });
+
     it('return processor result', async () => {
       const execSnapshots = mockExecAll();
       GlobalConfig.set({ ...adminConfig, binarySource: 'docker' });
@@ -44,7 +64,11 @@ describe('modules/manager/pep621/artifacts', () => {
       fs.readLocalFile.mockResolvedValueOnce('new test content');
       // python
       getPkgReleases.mockResolvedValueOnce({
-        releases: [{ version: '3.11.1' }, { version: '3.11.2' }],
+        releases: [
+          { version: '3.7.1' },
+          { version: '3.8.1' },
+          { version: '3.11.2' },
+        ],
       });
       // pdm
       getPkgReleases.mockResolvedValueOnce({
@@ -54,7 +78,12 @@ describe('modules/manager/pep621/artifacts', () => {
       const updatedDeps = [{ packageName: 'dep1' }];
       const result = await updateArtifacts({
         packageFileName: 'pyproject.toml',
-        newPackageFileContent: '',
+        newPackageFileContent: codeBlock`
+[project]
+name = "pdm"
+dynamic = ["version"]
+requires-python = "<3.9"
+        `,
         config: {},
         updatedDeps,
       });
@@ -90,7 +119,7 @@ describe('modules/manager/pep621/artifacts', () => {
             '-w "/tmp/github/some/repo" ' +
             'containerbase/sidecar ' +
             'bash -l -c "' +
-            'install-tool python 3.11.2 ' +
+            'install-tool python 3.8.1 ' +
             '&& ' +
             'install-tool pdm v2.5.0 ' +
             '&& ' +
diff --git a/lib/modules/manager/pep621/artifacts.ts b/lib/modules/manager/pep621/artifacts.ts
index 21145c463c14e2abbfb921057ea22dc39c7f6313..2d913a805015fd643d9c222bc87506f9ecb939d4 100644
--- a/lib/modules/manager/pep621/artifacts.ts
+++ b/lib/modules/manager/pep621/artifacts.ts
@@ -2,6 +2,7 @@ import is from '@sindresorhus/is';
 import { writeLocalFile } from '../../../util/fs';
 import type { UpdateArtifact, UpdateArtifactsResult } from '../types';
 import { processors } from './processors';
+import { parsePyProject } from './utils';
 
 export async function updateArtifacts(
   updateArtifact: UpdateArtifact
@@ -10,10 +11,24 @@ export async function updateArtifacts(
 
   await writeLocalFile(packageFileName, newPackageFileContent);
 
+  const project = parsePyProject(packageFileName, newPackageFileContent);
+  if (is.nullOrUndefined(project)) {
+    return [
+      {
+        artifactError: {
+          stderr: 'Failed to parse new package file content',
+        },
+      },
+    ];
+  }
+
   // process specific tool sets
   const result: UpdateArtifactsResult[] = [];
   for (const processor of processors) {
-    const artifactUpdates = await processor.updateArtifacts(updateArtifact);
+    const artifactUpdates = await processor.updateArtifacts(
+      updateArtifact,
+      project
+    );
     if (is.array(artifactUpdates)) {
       result.push(...artifactUpdates);
     }
diff --git a/lib/modules/manager/pep621/extract.spec.ts b/lib/modules/manager/pep621/extract.spec.ts
index bc23878672d80cc39fa3df884f4ccfbb95180040..4c14791d1db938b51be0d18d6291496de9e07b3f 100644
--- a/lib/modules/manager/pep621/extract.spec.ts
+++ b/lib/modules/manager/pep621/extract.spec.ts
@@ -26,6 +26,11 @@ describe('modules/manager/pep621/extract', () => {
     it('should return dependencies for valid content', function () {
       const result = extractPackageFile(pdmPyProject, 'pyproject.toml');
 
+      expect(result).toMatchObject({
+        extractedConstraints: {
+          python: '>=3.7',
+        },
+      });
       const dependencies = result?.deps.filter(
         (dep) => dep.depType === 'project.dependencies'
       );
diff --git a/lib/modules/manager/pep621/extract.ts b/lib/modules/manager/pep621/extract.ts
index f062fec0ba3c69eb33bacf7ef92ae448e0f61135..f0710934a01771ee935b7e31f2bea985d9e64ffd 100644
--- a/lib/modules/manager/pep621/extract.ts
+++ b/lib/modules/manager/pep621/extract.ts
@@ -1,4 +1,4 @@
-import toml from '@iarna/toml';
+import is from '@sindresorhus/is';
 import { logger } from '../../../logger';
 import type {
   ExtractConfig,
@@ -6,8 +6,11 @@ import type {
   PackageFileContent,
 } from '../types';
 import { processors } from './processors';
-import { PyProject, PyProjectSchema } from './schema';
-import { parseDependencyGroupRecord, parseDependencyList } from './utils';
+import {
+  parseDependencyGroupRecord,
+  parseDependencyList,
+  parsePyProject,
+} from './utils';
 
 export function extractPackageFile(
   content: string,
@@ -18,17 +21,14 @@ export function extractPackageFile(
 
   const deps: PackageDependency[] = [];
 
-  let def: PyProject;
-  try {
-    const jsonMap = toml.parse(content);
-    def = PyProjectSchema.parse(jsonMap);
-  } catch (err) {
-    logger.debug(
-      { packageFile, err },
-      `Failed to parse and validate pyproject file`
-    );
+  const def = parsePyProject(packageFile, content);
+  if (is.nullOrUndefined(def)) {
     return null;
   }
+  const pythonConstraint = def.project?.['requires-python'];
+  const constraints = is.nonEmptyString(pythonConstraint)
+    ? { extractedConstraints: { python: pythonConstraint } }
+    : {};
 
   // pyProject standard definitions
   deps.push(
@@ -47,5 +47,5 @@ export function extractPackageFile(
     processedDeps = processor.process(def, processedDeps);
   }
 
-  return processedDeps.length ? { deps: processedDeps } : null;
+  return processedDeps.length ? { ...constraints, deps: processedDeps } : null;
 }
diff --git a/lib/modules/manager/pep621/processors/pdm.spec.ts b/lib/modules/manager/pep621/processors/pdm.spec.ts
index c5b1523a35db19a38056c381423495435132ae81..a09f5082e40e235527a4febc553a034b304aa900 100644
--- a/lib/modules/manager/pep621/processors/pdm.spec.ts
+++ b/lib/modules/manager/pep621/processors/pdm.spec.ts
@@ -26,12 +26,15 @@ describe('modules/manager/pep621/processors/pdm', () => {
     it('return null if there is no lock file', async () => {
       fs.getSiblingFileName.mockReturnValueOnce('pdm.lock');
       const updatedDeps = [{ packageName: 'dep1' }];
-      const result = await processor.updateArtifacts({
-        packageFileName: 'pyproject.toml',
-        newPackageFileContent: '',
-        config,
-        updatedDeps,
-      });
+      const result = await processor.updateArtifacts(
+        {
+          packageFileName: 'pyproject.toml',
+          newPackageFileContent: '',
+          config,
+          updatedDeps,
+        },
+        {}
+      );
       expect(result).toBeNull();
     });
 
@@ -51,12 +54,15 @@ describe('modules/manager/pep621/processors/pdm', () => {
       });
 
       const updatedDeps = [{ packageName: 'dep1' }];
-      const result = await processor.updateArtifacts({
-        packageFileName: 'pyproject.toml',
-        newPackageFileContent: '',
-        config: {},
-        updatedDeps,
-      });
+      const result = await processor.updateArtifacts(
+        {
+          packageFileName: 'pyproject.toml',
+          newPackageFileContent: '',
+          config: {},
+          updatedDeps,
+        },
+        {}
+      );
       expect(result).toBeNull();
       expect(execSnapshots).toMatchObject([
         {
@@ -94,12 +100,15 @@ describe('modules/manager/pep621/processors/pdm', () => {
       });
 
       const updatedDeps = [{ packageName: 'dep1' }];
-      const result = await processor.updateArtifacts({
-        packageFileName: 'pyproject.toml',
-        newPackageFileContent: '',
-        config: {},
-        updatedDeps,
-      });
+      const result = await processor.updateArtifacts(
+        {
+          packageFileName: 'pyproject.toml',
+          newPackageFileContent: '',
+          config: {},
+          updatedDeps,
+        },
+        {}
+      );
       expect(result).toEqual([
         { artifactError: { lockFile: 'pdm.lock', stderr: 'test error' } },
       ]);
@@ -122,12 +131,15 @@ describe('modules/manager/pep621/processors/pdm', () => {
       });
 
       const updatedDeps = [{ packageName: 'dep1' }, { packageName: 'dep2' }];
-      const result = await processor.updateArtifacts({
-        packageFileName: 'pyproject.toml',
-        newPackageFileContent: '',
-        config: {},
-        updatedDeps,
-      });
+      const result = await processor.updateArtifacts(
+        {
+          packageFileName: 'pyproject.toml',
+          newPackageFileContent: '',
+          config: {},
+          updatedDeps,
+        },
+        {}
+      );
       expect(result).toEqual([
         {
           file: {
@@ -159,14 +171,17 @@ describe('modules/manager/pep621/processors/pdm', () => {
         releases: [{ version: 'v2.6.1' }, { version: 'v2.5.0' }],
       });
 
-      const result = await processor.updateArtifacts({
-        packageFileName: 'folder/pyproject.toml',
-        newPackageFileContent: '',
-        config: {
-          updateType: 'lockFileMaintenance',
+      const result = await processor.updateArtifacts(
+        {
+          packageFileName: 'folder/pyproject.toml',
+          newPackageFileContent: '',
+          config: {
+            updateType: 'lockFileMaintenance',
+          },
+          updatedDeps: [],
         },
-        updatedDeps: [],
-      });
+        {}
+      );
       expect(result).toEqual([
         {
           file: {
diff --git a/lib/modules/manager/pep621/processors/pdm.ts b/lib/modules/manager/pep621/processors/pdm.ts
index c82330e6d05e2d36ab268e48ecd84b441c0e2ae7..3730cd8b33e9bcbed307b020e08cd1162dde2e30 100644
--- a/lib/modules/manager/pep621/processors/pdm.ts
+++ b/lib/modules/manager/pep621/processors/pdm.ts
@@ -50,7 +50,8 @@ export class PdmProcessor implements PyProjectProcessor {
   }
 
   async updateArtifacts(
-    updateArtifact: UpdateArtifact
+    updateArtifact: UpdateArtifact,
+    project: PyProject
   ): Promise<UpdateArtifactsResult[] | null> {
     const { config, updatedDeps, packageFileName } = updateArtifact;
 
@@ -64,9 +65,11 @@ export class PdmProcessor implements PyProjectProcessor {
         logger.debug('No pdm.lock found');
         return null;
       }
+
       const pythonConstraint: ToolConstraint = {
         toolName: 'python',
-        constraint: config.constraints?.python,
+        constraint:
+          config.constraints?.python ?? project.project?.['requires-python'],
       };
       const pdmConstraint: ToolConstraint = {
         toolName: 'pdm',
diff --git a/lib/modules/manager/pep621/processors/types.ts b/lib/modules/manager/pep621/processors/types.ts
index 37798951b7e161b6e1975952222add0962f0a759..bfbf0357e9ef5e7dda8e857c0d6be76f0926f2b9 100644
--- a/lib/modules/manager/pep621/processors/types.ts
+++ b/lib/modules/manager/pep621/processors/types.ts
@@ -7,7 +7,8 @@ import type { PyProject } from '../schema';
 
 export interface PyProjectProcessor {
   updateArtifacts(
-    updateArtifact: UpdateArtifact
+    updateArtifact: UpdateArtifact,
+    project: PyProject
   ): Promise<UpdateArtifactsResult[] | null>;
 
   /**
diff --git a/lib/modules/manager/pep621/schema.ts b/lib/modules/manager/pep621/schema.ts
index 04dcc6609ce98c672b6153266bf1fe138ecd2c6b..c4a7443ebbf8ede971a981aeb97cdbc83bd05bbb 100644
--- a/lib/modules/manager/pep621/schema.ts
+++ b/lib/modules/manager/pep621/schema.ts
@@ -10,6 +10,7 @@ const DependencyRecordSchema = z
 export const PyProjectSchema = z.object({
   project: z
     .object({
+      'requires-python': z.string().optional(),
       dependencies: DependencyListSchema,
       'optional-dependencies': DependencyRecordSchema,
     })
diff --git a/lib/modules/manager/pep621/utils.ts b/lib/modules/manager/pep621/utils.ts
index 9c8149cfc7318f96bf019526d722c3e5e6d34a46..bc1ac4cce252a36bbcc6c66715b964dcff35ebb9 100644
--- a/lib/modules/manager/pep621/utils.ts
+++ b/lib/modules/manager/pep621/utils.ts
@@ -1,8 +1,10 @@
+import toml from '@iarna/toml';
 import is from '@sindresorhus/is';
 import { logger } from '../../../logger';
 import { regEx } from '../../../util/regex';
 import { PypiDatasource } from '../../datasource/pypi';
 import type { PackageDependency } from '../types';
+import { PyProject, PyProjectSchema } from './schema';
 import type { Pep508ParseResult } from './types';
 
 const pep508Regex = regEx(
@@ -99,3 +101,19 @@ export function parseDependencyList(
   }
   return deps;
 }
+
+export function parsePyProject(
+  packageFile: string,
+  content: string
+): PyProject | null {
+  try {
+    const jsonMap = toml.parse(content);
+    return PyProjectSchema.parse(jsonMap);
+  } catch (err) {
+    logger.debug(
+      { packageFile, err },
+      `Failed to parse and validate pyproject file`
+    );
+    return null;
+  }
+}