From ddb77ead08cb26f9bc2984c9bfe3fbb3c31fadab Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Fri, 19 Jun 2026 20:14:14 +0000 Subject: [PATCH 1/3] fix: accept "out" as valid manifest_type for Python SDK compatibility The Python SDK (keboola.component) writes manifest_type: "out" in native mode, but ManifestOptions only accepted "output". This caused failures when PHP-based processors (e.g. processor-create-manifest) tried to read manifests generated by Python components. Accept "out" as input and normalize it to "output" internally so the canonical value is preserved in all outputs. Co-Authored-By: olena.marchuk --- .../Options/OutTable/ManifestOptions.php | 9 +++++-- .../Options/OutTableManifestOptionsTest.php | 27 +++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/Manifest/ManifestManager/Options/OutTable/ManifestOptions.php b/src/Manifest/ManifestManager/Options/OutTable/ManifestOptions.php index 8b2708f..ce3f90b 100644 --- a/src/Manifest/ManifestManager/Options/OutTable/ManifestOptions.php +++ b/src/Manifest/ManifestManager/Options/OutTable/ManifestOptions.php @@ -16,8 +16,13 @@ class ManifestOptions { - private const ALLOWED_MANIFEST_TYPES = [self::MANIFEST_TYPE_OUTPUT]; + private const ALLOWED_MANIFEST_TYPES = [self::MANIFEST_TYPE_OUTPUT, self::MANIFEST_TYPE_OUT]; public const MANIFEST_TYPE_OUTPUT = 'output'; + public const MANIFEST_TYPE_OUT = 'out'; + + private const MANIFEST_TYPE_NORMALIZATION_MAP = [ + self::MANIFEST_TYPE_OUT => self::MANIFEST_TYPE_OUTPUT, + ]; private ?string $destination = null; private ?bool $incremental = null; @@ -158,7 +163,7 @@ public function setManifestType(string $manifestType): ManifestOptions )); } - $this->manifestType = $manifestType; + $this->manifestType = self::MANIFEST_TYPE_NORMALIZATION_MAP[$manifestType] ?? $manifestType; return $this; } diff --git a/tests/Manifest/ManifestManager/Options/OutTableManifestOptionsTest.php b/tests/Manifest/ManifestManager/Options/OutTableManifestOptionsTest.php index 239b619..bb01b89 100644 --- a/tests/Manifest/ManifestManager/Options/OutTableManifestOptionsTest.php +++ b/tests/Manifest/ManifestManager/Options/OutTableManifestOptionsTest.php @@ -159,6 +159,33 @@ public function provideOptions(): array ]; } + public function testFromArrayWithPythonSdkManifestType(): void + { + $options = ManifestOptions::fromArray([ + 'delimiter' => ',', + 'enclosure' => '"', + 'manifest_type' => 'out', + 'schema' => [ + [ + 'name' => 'id', + 'nullable' => true, + 'primary_key' => false, + ], + ], + ]); + + $this->assertSame(ManifestOptions::MANIFEST_TYPE_OUTPUT, $options->getManifestType()); + + $array = $options->toArray(false); + $this->assertSame('output', $array['manifest_type']); + } + + public function testSetManifestTypeOutIsNormalized(): void + { + $options = (new ManifestOptions())->setManifestType('out'); + $this->assertSame(ManifestOptions::MANIFEST_TYPE_OUTPUT, $options->getManifestType()); + } + /** @dataProvider validNamesProvider */ public function testManifestOptionsSchemaValidNames(string $name): void { From 7119364ecd924e9da096074e8d8f7d08000a67c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maty=C3=A1=C5=A1=20Jir=C3=A1t?= Date: Mon, 22 Jun 2026 18:33:05 +0200 Subject: [PATCH 2/3] chore: drop abandoned devedge/sami-github dev dependency The devedge/sami-github package (Sami API doc generator) is abandoned and its upstream source now returns 404, which breaks `composer install` in the CI Docker build before any test step runs. It is not used by `composer ci` (legacy doc generation only), so removing it unblocks the build for the whole repo. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01EVw2ASBABBmYrgrQYMZC54 --- composer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/composer.json b/composer.json index 3cdec06..b57149d 100644 --- a/composer.json +++ b/composer.json @@ -37,7 +37,6 @@ "symfony/serializer": "^5.4|^6.0|^7.0" }, "require-dev": { - "devedge/sami-github": "^1.0.6", "keboola/coding-standard": "^15.0.1", "keboola/php-temp": "^2.0.1", "phpstan/phpstan": "^1.12.24", From 06a01af94d3a6ff69c8017c3ede95dc7230fa77f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maty=C3=A1=C5=A1=20Jir=C3=A1t?= Date: Mon, 22 Jun 2026 18:33:17 +0200 Subject: [PATCH 3/3] fix: accept "in" manifest_type and normalize to "input" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #96 added "out" -> "output" but the input side was still rejected. The Python SDK writes the stage value ("in"/"out") into manifest_type — the form the platform has accepted for over a year — while php-component only accepted the canonical "output". getTableManifest() routes every table manifest, including input-stage manifests read by writers, through this single validator, so a manifest carrying "in" still threw OptionsValidationException. Accept "in" as an alias and normalize it to the canonical "input", symmetric with the existing "out" -> "output" handling. Adds tests for the input path, canonical pass-through, and rejection of unknown values. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01EVw2ASBABBmYrgrQYMZC54 --- .../Options/OutTable/ManifestOptions.php | 13 ++++- .../Options/OutTableManifestOptionsTest.php | 47 +++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/src/Manifest/ManifestManager/Options/OutTable/ManifestOptions.php b/src/Manifest/ManifestManager/Options/OutTable/ManifestOptions.php index ce3f90b..fde6a69 100644 --- a/src/Manifest/ManifestManager/Options/OutTable/ManifestOptions.php +++ b/src/Manifest/ManifestManager/Options/OutTable/ManifestOptions.php @@ -16,12 +16,23 @@ class ManifestOptions { - private const ALLOWED_MANIFEST_TYPES = [self::MANIFEST_TYPE_OUTPUT, self::MANIFEST_TYPE_OUT]; public const MANIFEST_TYPE_OUTPUT = 'output'; + public const MANIFEST_TYPE_INPUT = 'input'; public const MANIFEST_TYPE_OUT = 'out'; + public const MANIFEST_TYPE_IN = 'in'; + private const ALLOWED_MANIFEST_TYPES = [ + self::MANIFEST_TYPE_OUTPUT, + self::MANIFEST_TYPE_INPUT, + self::MANIFEST_TYPE_OUT, + self::MANIFEST_TYPE_IN, + ]; + + // The Python SDK writes the stage value ("in"/"out") into manifest_type, while the canonical + // values are "input"/"output". Accept the stage aliases and normalize them to the canonical form. private const MANIFEST_TYPE_NORMALIZATION_MAP = [ self::MANIFEST_TYPE_OUT => self::MANIFEST_TYPE_OUTPUT, + self::MANIFEST_TYPE_IN => self::MANIFEST_TYPE_INPUT, ]; private ?string $destination = null; diff --git a/tests/Manifest/ManifestManager/Options/OutTableManifestOptionsTest.php b/tests/Manifest/ManifestManager/Options/OutTableManifestOptionsTest.php index bb01b89..12fbabc 100644 --- a/tests/Manifest/ManifestManager/Options/OutTableManifestOptionsTest.php +++ b/tests/Manifest/ManifestManager/Options/OutTableManifestOptionsTest.php @@ -186,6 +186,53 @@ public function testSetManifestTypeOutIsNormalized(): void $this->assertSame(ManifestOptions::MANIFEST_TYPE_OUTPUT, $options->getManifestType()); } + public function testFromArrayWithPythonSdkInputManifestType(): void + { + $options = ManifestOptions::fromArray([ + 'delimiter' => ',', + 'enclosure' => '"', + 'manifest_type' => 'in', + 'schema' => [ + [ + 'name' => 'id', + 'nullable' => true, + 'primary_key' => false, + ], + ], + ]); + + $this->assertSame(ManifestOptions::MANIFEST_TYPE_INPUT, $options->getManifestType()); + + $array = $options->toArray(false); + $this->assertSame('input', $array['manifest_type']); + } + + public function testSetManifestTypeInIsNormalized(): void + { + $options = (new ManifestOptions())->setManifestType('in'); + $this->assertSame(ManifestOptions::MANIFEST_TYPE_INPUT, $options->getManifestType()); + } + + public function testSetManifestTypeCanonicalValuesArePreserved(): void + { + $this->assertSame( + ManifestOptions::MANIFEST_TYPE_OUTPUT, + (new ManifestOptions())->setManifestType('output')->getManifestType(), + ); + $this->assertSame( + ManifestOptions::MANIFEST_TYPE_INPUT, + (new ManifestOptions())->setManifestType('input')->getManifestType(), + ); + } + + public function testSetManifestTypeRejectsUnknownValue(): void + { + $this->expectException(OptionsValidationException::class); + $this->expectExceptionMessage('Manifest type "invalid" is not allowed'); + + (new ManifestOptions())->setManifestType('invalid'); + } + /** @dataProvider validNamesProvider */ public function testManifestOptionsSchemaValidNames(string $name): void {