{"record":{"id":"11b2b5e8e4b014bd","repo":"microsoft/autogen","slug":"module-name-must-be-a-valid-python-identifier-11b2b5","errorCode":null,"errorMessage":"Module name must be a valid Python identifier","messagePattern":"Module name must be a valid Python identifier","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/packages/autogen-ext/src/autogen_ext/code_executors/local/__init__.py","lineNumber":198,"sourceCode":"                    \"Using the current directory as work_dir is deprecated.\",\n                    DeprecationWarning,\n                    stacklevel=2,\n                )\n            if isinstance(work_dir, str):\n                self._work_dir = Path(work_dir)\n            else:\n                self._work_dir = work_dir\n            self._work_dir.mkdir(exist_ok=True)\n\n        self._functions = functions\n        # Setup could take some time so we intentionally wait for the first code block to do it.\n        if len(functions) > 0:\n            self._setup_functions_complete = False\n        else:\n            self._setup_functions_complete = True\n\n        if not functions_module.isidentifier():\n            raise ValueError(\"Module name must be a valid Python identifier\")\n        self._functions_module = functions_module\n\n        self._cleanup_temp_files = cleanup_temp_files\n        self._virtual_env_context: Optional[SimpleNamespace] = virtual_env_context\n\n        self._temp_dir: Optional[tempfile.TemporaryDirectory[str]] = None\n        self._started = False\n\n        # Check the current event loop policy if on windows.\n        if sys.platform == \"win32\":\n            current_policy = asyncio.get_event_loop_policy()\n            if hasattr(asyncio, \"WindowsProactorEventLoopPolicy\") and not isinstance(\n                current_policy, asyncio.WindowsProactorEventLoopPolicy\n            ):\n                warnings.warn(\n                    \"The current event loop policy is not WindowsProactorEventLoopPolicy. \"\n                    \"This may cause issues with subprocesses. \"\n                    \"Try setting the event loop policy to WindowsProactorEventLoopPolicy. \"","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/microsoft/autogen/blob/027ecf0a379bcc1d09956d46d12d44a3ad9cee14/python/packages/autogen-ext/src/autogen_ext/code_executors/local/__init__.py#L180-L216","documentation":"Constructor validation in LocalCommandLineCodeExecutor: functions_module (the module name under which generated function files are saved and imported) must be a valid Python identifier - it becomes the filename of the generated .py module that gets executed during setup.","triggerScenarios":"Passing functions_module values like 'my-functions', 'functions.py', 'my functions', or an empty string - anything failing str.isidentifier(). Names starting with a digit also fail; keywords like 'import' pass this check but break at import time.","commonSituations":"Deriving the module name from file paths or user input, including the '.py' extension by mistake, hyphenated project names, sanitizing config strings down to an empty string.","solutions":["Use a plain identifier like 'functions' (the default) or 'my_functions'.","Strip '.py' and replace invalid characters before passing, e.g. re.sub(r'\\W|^(?=\\d)', '_', name).","Avoid Python keywords ('import', 'class', ...); pick a descriptive non-keyword name."],"exampleFix":"# before\nexecutor = LocalCommandLineCodeExecutor(functions_module=\"my-functions.py\")\n\n# after\nimport re\nname = re.sub(r\"\\W\", \"_\", \"my-functions.py\")\nexecutor = LocalCommandLineCodeExecutor(functions_module=name)","handlingStrategy":"validation","validationCode":"import re\n\ndef to_identifier(name: str) -> str:\n    ident = re.sub(r\"\\W\", \"_\", name.strip())\n    if not ident or ident[0].isdigit():\n        ident = f\"_{ident}\"\n    assert ident.isidentifier()\n    return ident","typeGuard":"import keyword\n\ndef is_valid_module_name(name: object) -> bool:\n    return isinstance(name, str) and name.isidentifier() and not keyword.iskeyword(name)","tryCatchPattern":"try:\n    LocalCommandLineCodeExecutor(functions_module=name)\nexcept ValueError as e:\n    if \"valid Python identifier\" in str(e):\n        import re\n        executor = LocalCommandLineCodeExecutor(functions_module=re.sub(r\"\\W\", \"_\", name))\n    else:\n        raise","preventionTips":["Use the default 'functions' module name unless you need multiple executors.","Sanitize user-derived names with str.isidentifier() checks before passing."],"tags":["validation","constructor","local-executor","naming"],"backgroundTag":null,"analyzedSha":"027ecf0a379bcc1d09956d46d12d44a3ad9cee14","analyzedAt":"2026-08-15T03:38:00.719Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}