fix: fixed script work on distributed apps

This commit is contained in:
2026-02-24 21:31:56 +01:00
parent d1a730cef8
commit a8b50d610f
2 changed files with 68 additions and 3 deletions

View File

@@ -1,5 +1,45 @@
import { BDS_PYTHON_API_CONTRACT_V1 } from './pythonApiContractV1'; import { BDS_PYTHON_API_CONTRACT_V1 } from './pythonApiContractV1';
const PYTHON_RESERVED_KEYWORDS = new Set([
'false',
'none',
'true',
'and',
'as',
'assert',
'async',
'await',
'break',
'class',
'continue',
'def',
'del',
'elif',
'else',
'except',
'finally',
'for',
'from',
'global',
'if',
'import',
'in',
'is',
'lambda',
'nonlocal',
'not',
'or',
'pass',
'raise',
'return',
'try',
'while',
'with',
'yield',
'match',
'case',
]);
function toSnakeCase(value: string): string { function toSnakeCase(value: string): string {
return value return value
.replace(/([a-z0-9])([A-Z])/g, '$1_$2') .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
@@ -12,6 +52,23 @@ function quotePython(value: string): string {
return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"'); return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
} }
function toPythonIdentifier(value: string): string {
let identifier = toSnakeCase(value);
if (!identifier) {
identifier = '_';
}
if (/^[0-9]/.test(identifier)) {
identifier = `_${identifier}`;
}
if (PYTHON_RESERVED_KEYWORDS.has(identifier)) {
identifier = `${identifier}_`;
}
return identifier;
}
function buildPythonMethod(method: { function buildPythonMethod(method: {
method: string; method: string;
description: string; description: string;
@@ -22,10 +79,10 @@ function buildPythonMethod(method: {
return ''; return '';
} }
const pythonMethodName = toSnakeCase(member); const pythonMethodName = toPythonIdentifier(member);
const pythonParams = method.params.map((param) => ({ const pythonParams = method.params.map((param) => ({
sourceName: param.name, sourceName: param.name,
pythonName: toSnakeCase(param.name), pythonName: toPythonIdentifier(param.name),
required: param.required, required: param.required,
})); }));
@@ -90,7 +147,7 @@ export function generatePythonApiModuleV1(): string {
const namespaceAssignments = Array.from(namespaceMap.keys()) const namespaceAssignments = Array.from(namespaceMap.keys())
.sort((left, right) => left.localeCompare(right)) .sort((left, right) => left.localeCompare(right))
.map((namespace) => ` self.${toSnakeCase(namespace)} = ${namespace[0].toUpperCase()}${namespace.slice(1)}Api(transport)`) .map((namespace) => ` self.${toPythonIdentifier(namespace)} = ${namespace[0].toUpperCase()}${namespace.slice(1)}Api(transport)`)
.join('\n'); .join('\n');
return [ return [

View File

@@ -78,4 +78,12 @@ describe('generatePythonApiModuleV1', () => {
expect(moduleCode).toContain('class BdsApi:'); expect(moduleCode).toContain('class BdsApi:');
expect(moduleCode).toContain('bds = BdsApi(_transport)'); expect(moduleCode).toContain('bds = BdsApi(_transport)');
}); });
it('escapes python keyword method names to valid identifiers', () => {
const moduleCode = generatePythonApiModuleV1();
expect(moduleCode).toContain('return await self._transport.call("media.import", { "sourcePath": source_path, "metadata": metadata })');
expect(moduleCode).toContain('async def import_(self, source_path, metadata=None):');
expect(moduleCode).not.toContain('async def import(self, source_path, metadata=None):');
});
}); });