From b88a741f85dbbd736aaddc538ad45e61d37656cd Mon Sep 17 00:00:00 2001 From: jaakko Date: Mon, 13 Apr 2026 12:43:39 +0300 Subject: [PATCH] =?UTF-8?q?Template=20pipeline:=20JS=E2=86=92Python=20-arv?= =?UTF-8?q?omuunnokset=20korjattu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ongelma: generoiduissa Python-tiedostoissa JS-booleanit (false/true) päätyvät sellaisenaan Python-koodiin, jossa ne eivät ole valideja. Lisäksi datetime-importit puuttuivat kun LLM antoi extra_imports-kentässä pelkän "datetime"-merkkijonon eikä kokonaista import-lausetta. Korjaukset: - pyLiteral(): muuntaa JS-arvot Python-literaaleiksi (false→False jne.) - pyJsonLiteral(): testidatan serialisointi Python-dict-muodossa - tmplSchemas: datetime-importit tunnistetaan automaattisesti kentistä - tmplModels + tmplSchemas: oletusarvot pyLiteral()-funktion kautta - tmplTests: JSON.stringify korvattu pyJsonLiteral():lla - Validaattori: tunnistaa nyt datetime-import-puutteet ja JS-booleanit Testattu: molemmat aiemmin rikkinäiset speksit generoivat nyt toimivan koodin — 6/6 pytest-testiä läpi molemmilla. --- network-poc/frontend/src/pages/index.astro | 60 ++++++++++++++++-- .../luodut/rest-api-kyttjhallinnalle (1).zip | Bin 0 -> 49917 bytes .../luodut/rest-api-kyttjhallinnalle.zip | Bin 0 -> 50597 bytes 3 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 projektit/luodut/rest-api-kyttjhallinnalle (1).zip create mode 100644 projektit/luodut/rest-api-kyttjhallinnalle.zip diff --git a/network-poc/frontend/src/pages/index.astro b/network-poc/frontend/src/pages/index.astro index 14f59cf..d38660c 100644 --- a/network-poc/frontend/src/pages/index.astro +++ b/network-poc/frontend/src/pages/index.astro @@ -193,6 +193,19 @@ import Settings from "../components/Settings.astro"; if (fname === 'schemas.py') { if (/:\s*date\b/.test(code) && !/from datetime import/.test(code)) issues.push('ISSUE: schemas.py: käyttää date-tyyppiä mutta "from datetime import date" puuttuu'); + if (/:\s*datetime\b/.test(code) && !/from datetime import/.test(code)) + issues.push('ISSUE: schemas.py: käyttää datetime-tyyppiä mutta "from datetime import datetime" puuttuu'); + } + + // 4b. Python-syntaksi: JS-booleanit (false/true ilman isoa alkukirjainta) + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + if (/^\s*#/.test(line) || /^\s*$/.test(line)) continue; + // Etsi false/true joita ei ole merkkijonon sisällä ja jotka eivät ole osa isompaa sanaa + if (/(? { + let pyVal; + if (v === true) pyVal = 'True'; + else if (v === false) pyVal = 'False'; + else if (v === null) pyVal = 'None'; + else if (typeof v === 'string') pyVal = `"${v}"`; + else pyVal = String(v); + return `"${k}":${pyVal}`; + }); + return '{' + parts.join(',') + '}'; + } + const SPEC_SYSTEM = `You are a software architect who designs database schemas for Python web applications. THINK STEP BY STEP before outputting JSON: @@ -1179,7 +1215,7 @@ Blog → Author: name,email,bio(Text|None) / Post: title, content(Text), author_ for (const f of e.fields) { let parts = [`Column(${f.sa_type}`]; if (!f.nullable) parts.push('nullable=False'); - if (f.default !== null && f.default !== undefined) parts.push(typeof f.default === 'string' ? `default="${f.default}"` : `default=${f.default}`); + if (f.default !== null && f.default !== undefined) parts.push(`default=${pyLiteral(f.default)}`); code += ` ${f.name} = ${parts.join(', ')})\n`; } code += '\n'; @@ -1189,13 +1225,27 @@ Blog → Author: name,email,bio(Text|None) / Post: title, content(Text), author_ } function tmplSchemas(spec) { + // Tunnista tarvittavat datetime-importit kenttätyypeistä + const dtTypes = new Set(); + for (const e of spec.entities) for (const f of e.fields) { + if (/\bdate\b/i.test(f.py_type) && !/datetime/.test(f.py_type)) dtTypes.add('date'); + if (/\bdatetime\b/i.test(f.py_type)) dtTypes.add('datetime'); + } + let code = 'from pydantic import BaseModel\n'; - for (const imp of (spec.extra_imports || [])) code += imp + '\n'; + if (dtTypes.size > 0) code += `from datetime import ${[...dtTypes].sort().join(', ')}\n`; + + // extra_imports: suodata pois pelkät nimet kuten "datetime" (jo käsitelty yllä) + for (const imp of (spec.extra_imports || [])) { + if (/^(date|datetime)$/.test(imp.trim())) continue; // käsitelty jo + if (/^from\s/.test(imp) || /^import\s/.test(imp)) code += imp + '\n'; + } code += '\n'; + for (const e of spec.entities) { code += `class ${e.name}Create(BaseModel):\n`; for (const f of e.fields) { - if (f.default !== null && f.default !== undefined) code += ` ${f.name}: ${f.py_type} = ${typeof f.default === 'string' ? '"'+f.default+'"' : f.default}\n`; + if (f.default !== null && f.default !== undefined) code += ` ${f.name}: ${f.py_type} = ${pyLiteral(f.default)}\n`; else if (f.nullable && f.py_type.includes('None')) code += ` ${f.name}: ${f.py_type} = None\n`; else code += ` ${f.name}: ${f.py_type}\n`; } @@ -1253,11 +1303,11 @@ Blog → Author: name,email,bio(Text|None) / Post: title, content(Text), author_ else if (f.py_type.includes('bool')) testData[f.name] = true; else if (f.py_type.includes('date')) testData[f.name] = '2024-01-15'; } - const td = JSON.stringify(testData); + const td = pyJsonLiteral(testData); const firstStr = e.fields.find(f => f.py_type.includes('str') && f.name !== 'status'); const updateData = {...testData}; if (firstStr) updateData[firstStr.name] = `Updated ${firstStr.name}`; - const ud = JSON.stringify(updateData); + const ud = pyJsonLiteral(updateData); code += `def test_create_${lo}():\n response = client.post('/${tb}/', json=${td})\n assert response.status_code == 201\n assert 'id' in response.json()\n\n`; code += `def test_list_${lo}s():\n client.post('/${tb}/', json=${td})\n response = client.get('/${tb}/')\n assert response.status_code == 200\n assert len(response.json()) >= 1\n\n`; diff --git a/projektit/luodut/rest-api-kyttjhallinnalle (1).zip b/projektit/luodut/rest-api-kyttjhallinnalle (1).zip new file mode 100644 index 0000000000000000000000000000000000000000..00e8e4e341d028bee53e261eeeb1c8972f9fc9af GIT binary patch literal 49917 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 literal 0 HcmV?d00001 diff --git a/projektit/luodut/rest-api-kyttjhallinnalle.zip b/projektit/luodut/rest-api-kyttjhallinnalle.zip new file mode 100644 index 0000000000000000000000000000000000000000..bc4c418cbb550e979286cb76b499db59a3e20c2a GIT binary patch literal 50597 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 s8LZ