From e07f281fd0a048bd720f9bb15c0589526276f9fb Mon Sep 17 00:00:00 2001 From: Karstein Kvistad Date: Sun, 26 Apr 2026 17:06:11 +0200 Subject: [PATCH] fix(create_folder): use positional / foldername= instead of name= kwarg The v1 fix from 2607063 used `parent.create_folder(name=FOLDER_NAME)` which raised "create_folder() got an unexpected keyword argument 'name'" on SP22 -- the actual stub signature in C:\Program Files\CODESYS 3.5.22.10\CODESYS\ScriptLib\Stubs\scriptengine\ScriptObject.pyi is def create_folder(self, foldername): ... The fallback chain (create_object + add(IecFolder)) caught the failure and reported correctly, so no damage -- but the primary path was wrong. Verified via the SP22 stubs that the keyword is `foldername`. Use positional form first (agnostic to the keyword name across SP releases), fall through to foldername= if positional fails for some reason, then keep the existing alternate-factory chain as deeper fallbacks. Tested partially in this session: create_folder DEBUG output confirmed the v1 fix's fallback chain was running as designed; the keyword fix will be runtime-verified on the next vsc reboot since script-manager caches dist/scripts at MCP startup. Verification trace (v1 against SP22): DEBUG: Calling parent.create_folder(name='Test_Bench_Folder') WARN: parent.create_folder() raised: create_folder() got an unexpected keyword argument 'name' Co-Authored-By: Claude Opus 4.7 (1M context) --- src/scripts/create_folder.py | 39 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/scripts/create_folder.py b/src/scripts/create_folder.py index ba6438c..b5792b1 100644 --- a/src/scripts/create_folder.py +++ b/src/scripts/create_folder.py @@ -46,30 +46,30 @@ try: parent_name = getattr(parent_object, 'get_name', lambda: str(parent_object))() print("DEBUG: Using parent object: %s" % parent_name) - # Create the folder. The factory shape changed across SPs: - # - Older: parent.create_folder(name='X') -- legacy API - # - SP21+: parent.create_folder(name='X') -- still preferred - # OR parent.create_object(typeUuid=, name='X') - # OR parent.add(script_engine.types.IecFolder, name='X') - # Some Application objects in SP21+ don't expose create_folder at all; - # fall through to the alternate factories so the tool works against - # both old and new project shapes. + # Create the folder. The keyword changed between docs and stubs: + # Per the SP22 stub Stubs/scriptengine/ScriptObject.pyi, the signature is + # def create_folder(self, foldername): ... + # NOT `name=...` (which the original fork code used and got + # "create_folder() got an unexpected keyword argument 'name'" against + # SP22). Use the positional form first to be agnostic to the keyword + # name across SP releases. Fall through to alternate factories if + # create_folder is unavailable on the parent at all. new_folder = None if hasattr(parent_object, 'create_folder'): try: - print("DEBUG: Calling parent.create_folder(name='%s')" % FOLDER_NAME) - new_folder = parent_object.create_folder(name=FOLDER_NAME) + print("DEBUG: Calling parent.create_folder('%s') [positional]" % FOLDER_NAME) + new_folder = parent_object.create_folder(FOLDER_NAME) except Exception as e: - print("WARN: parent.create_folder() raised: %s -- trying alternate factories." % e) - new_folder = None + print("WARN: parent.create_folder('%s') raised: %s -- trying foldername= kwarg." % (FOLDER_NAME, e)) + try: + new_folder = parent_object.create_folder(foldername=FOLDER_NAME) + except Exception as e2: + print("WARN: parent.create_folder(foldername='%s') raised: %s -- trying alternate factories." % (FOLDER_NAME, e2)) + new_folder = None if new_folder is None and hasattr(parent_object, 'create_object'): - # CODESYS folder type UUID. The canonical "generic IEC folder" type - # ID has been stable across SP19-SP22; verified via the SP22 stub - # Stubs/scriptengine/types.pyi and the helpme-codesys.com docs for - # ScriptObject.create_object. If a future SP rotates this UUID, the - # types.IecFolder branch below picks up the canonical reference - # automatically. + # CODESYS folder type UUID -- documented "generic IEC folder" type. + # Tried as a fallback for parents that don't expose create_folder. FOLDER_TYPE_UUID = '85d1215e-6520-4983-9a55-2d39d1f24cb4' try: print("DEBUG: parent.create_folder() unavailable. Trying parent.create_object(typeUuid=%s, name='%s')" % (FOLDER_TYPE_UUID, FOLDER_NAME)) @@ -89,7 +89,8 @@ try: if new_folder is None: raise TypeError( "Parent object '%s' of type %s does not support any known folder-creation factory: " - "tried create_folder, create_object(typeUuid=...), and add(script_engine.types.IecFolder)." % ( + "tried create_folder() positional, create_folder(foldername=...), " + "create_object(typeUuid=...), and add(script_engine.types.IecFolder)." % ( parent_name, type(parent_object).__name__)) if new_folder: