Skip to content

Commit 1feb739

Browse files
committed
chore: set PYTHONPATH for workspace modules
1 parent 5f49df4 commit 1feb739

File tree

2 files changed

+32
-29
lines changed

2 files changed

+32
-29
lines changed

src/bundling.ts

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,6 @@ export const DEFAULT_ASSET_EXCLUDES = [
2323
'.git/',
2424
];
2525

26-
const userCustomizePy = `
27-
import sys
28-
import os
29-
from pathlib import Path
30-
31-
base_path = Path(__file__).parent
32-
33-
for pth_file in base_path.glob('*.pth'):
34-
print('Adding', pth_file, base_path)
35-
with open(pth_file, 'r') as f:
36-
for line in f:
37-
module_path_str = str(base_path / line.strip())
38-
print('...', module_path_str)
39-
if module_path_str not in sys.path:
40-
sys.path.insert(0, module_path_str)
41-
42-
print('sys.path', sys.path)
43-
44-
`;
45-
4626
interface BundlingCommandOptions {
4727
readonly rootDir: string;
4828
readonly workspacePackage?: string;
@@ -164,21 +144,16 @@ export class Bundling {
164144
...options.commandHooks?.beforeBundling(options.inputDir, options.outputDir) ?? [],
165145
);
166146
commands.push(...[
167-
`while [ -e ${options.inputDir}/wait.txt ]; do sleep 2; echo Waiting; done`,
168147
`rsync -rLv ${excludeArgs.join(' ')} ${options.inputDir}/ ${options.outputDir}`,
169148
`cd ${options.outputDir}`, // uv pip install needs to be run from here for editable deps to relative paths to be resolved
170149
`VIRTUAL_ENV=/tmp/venv uv sync ${uvCommonArgs} ${uvPackageArgs} --compile-bytecode --no-dev --frozen --no-editable --link-mode=copy`,
171150
`VIRTUAL_ENV=/tmp/venv uv export ${uvCommonArgs} ${uvPackageArgs} --no-dev --frozen --no-editable > ${reqsFile}`,
172151
`uv pip install -r ${reqsFile} --target ${options.outputDir} --reinstall --compile-bytecode --link-mode=copy --editable $(grep -e "^\./" ${reqsFile})`,
173-
`sed -i 's|${options.outputDir}/|.|g' ${options.outputDir}/*.pth`,
174152
`rm -rf ${options.outputDir}/.venv`,
175-
`echo ${Buffer.from(userCustomizePy).toString('base64')} | base64 -d > ${options.outputDir}/usercustomize.py`,
176-
`while [ -e ${options.inputDir}/wait2.txt ]; do sleep 2; echo Waiting; done`,
177153
]);
178154
commands.push(
179155
...options.commandHooks?.afterBundling(options.inputDir, options.outputDir) ?? [],
180156
);
181-
console.log('Bundling commands', { options, commands });
182157

183158
return commands;
184159
}

src/function.ts

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import * as fs from 'node:fs';
12
import * as path from 'node:path';
23
import { Stack } from 'aws-cdk-lib';
34
import {
45
Architecture,
6+
type CfnFunction,
57
// biome-ignore lint/suspicious/noShadowRestrictedNames: shadows 'function'
68
Function,
79
type FunctionOptions,
@@ -57,16 +59,14 @@ export class PythonFunction extends Function {
5759
const {
5860
workspacePackage,
5961
handler = 'handler',
62+
index = 'index.py',
6063
runtime = Runtime.PYTHON_3_12,
6164
} = props;
6265

6366
const architecture = props.architecture ?? Architecture.ARM_64;
6467
const rootDir = path.resolve(props.rootDir);
6568

66-
let resolvedHandler = handler;
67-
if (workspacePackage) {
68-
resolvedHandler = `${workspacePackage.replace(/-/g, '_')}.${handler}`;
69-
}
69+
const resolvedHandler = `${index.slice(0, -3)}.${handler}`.replace(/\//g, '.');
7070

7171
if (runtime.family !== RuntimeFamily.PYTHON) {
7272
throw new Error('Only Python runtimes are supported');
@@ -80,12 +80,40 @@ export class PythonFunction extends Function {
8080
workspacePackage,
8181
...props.bundling,
8282
});
83+
84+
const environment = props.environment ?? {};
85+
8386
super(scope, id, {
8487
...props,
88+
environment,
8589
architecture,
8690
runtime,
8791
code,
8892
handler: resolvedHandler,
8993
});
94+
95+
const assetPath = ((this.node.defaultChild) as CfnFunction).getMetadata('aws:asset:path');
96+
const codePath = path.join(process.env.CDK_OUTDIR as string, assetPath);
97+
98+
const pythonPaths = getPthFilePaths(codePath);
99+
100+
if (pythonPaths.length > 0) {
101+
let pythonPathValue = environment.PYTHONPATH;
102+
const addedPaths = pythonPaths.join(':');
103+
pythonPathValue = pythonPathValue ? `${pythonPathValue}:${addedPaths}` : addedPaths;
104+
this.addEnvironment('PYTHONPATH', pythonPathValue);
105+
}
106+
}
107+
}
108+
109+
function getPthFilePaths(basePath: string): string[] {
110+
const pthFiles = fs.readdirSync(basePath).filter(file => file.endsWith('.pth'));
111+
const pythonPaths: string[] = [];
112+
for (const pthFile of pthFiles) {
113+
const filePath = path.join(basePath, pthFile);
114+
const content = fs.readFileSync(filePath, 'utf-8');
115+
const dirs = content.split('\n').filter(line => line.trim() !== '');
116+
pythonPaths.push(...dirs.map(dir => path.join('/var/task', path.relative('/asset-output', dir))));
90117
}
118+
return pythonPaths;
91119
}

0 commit comments

Comments
 (0)