{"record":{"id":"dda4a280e168f95c","repo":"google/python-fire","slug":"fire-can-only-be-called-on-py-files","errorCode":null,"errorMessage":"Fire can only be called on .py files.","messagePattern":"Fire can only be called on \\.py files\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fire/__main__.py","lineNumber":102,"sourceCode":"  Args:\n    module_or_filename (str): string name of path or module.\n\n  Raises:\n    ValueError: if the given file is invalid.\n    IOError: if the file or module can not be found or imported.\n\n  Returns:\n    Tuple[ModuleType, str]: returns the imported module and the module name,\n      usually extracted from the path itself.\n  \"\"\"\n\n  if os.path.exists(module_or_filename):\n    # importlib.util.spec_from_file_location requires .py\n    if not module_or_filename.endswith('.py'):\n      try:  # try as module instead\n        return import_from_module_name(module_or_filename)\n      except ImportError:\n        raise ValueError('Fire can only be called on .py files.')\n\n    return import_from_file_path(module_or_filename)\n\n  if os.path.sep in module_or_filename:  # Use / to detect if it was a filename.\n    raise OSError('Fire was passed a filename which could not be found.')\n\n  return import_from_module_name(module_or_filename)  # Assume it's a module.\n\n\ndef main(args):\n  \"\"\"Entrypoint for fire when invoked as a module with python -m fire.\"\"\"\n\n  if len(args) < 2:\n    print(cli_string)\n    sys.exit(1)\n\n  module_or_filename = args[1]\n  module, module_name = import_module(module_or_filename)","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/google/python-fire/blob/716bbc23d7eca949fdb682172283c8d18f742cb6/fire/__main__.py#L84-L120","documentation":"fire.import_module accepts either an existing path or a dotted module name. If the argument exists on disk but does not end in .py, fire first tries to interpret it as a module name; when that also raises ImportError, it gives up with ValueError('Fire can only be called on .py files.'). It deliberately restricts file-based loading to .py because importlib.util.spec_from_file_location requires .py files.","triggerScenarios":"python -m fire <existing-non-py-path> where the path exists, lacks the .py extension, and is not importable as a dotted module — e.g. `python -m fire ./serve.sh` or a directory-style path to a non-Python file.","commonSituations":"Passing shell scripts, config files, or extensionless executables to fire; forgetting to rename a Python file that was saved without the .py extension.","solutions":["Rename the target so it ends in .py.","If the target is a module inside a package, use the dotted module name: `python -m fire mypkg.mymodule`.","If the target is not Python at all, invoke fire from within a Python entry point instead of passing the file to python -m fire."],"exampleFix":"// before\npython -m fire ./tools/backup serve\n// after\npython -m fire tools/backup.py serve   # or: python -m fire tools.backup serve","handlingStrategy":"validation","validationCode":"import os\narg = './tools/backup'\nif os.path.exists(arg) and not arg.endswith('.py'):\n    raise SystemExit('Fire file targets must end in .py; use a dotted module name otherwise')","typeGuard":"def is_py_file_target(arg: str) -> bool:\n    return os.path.exists(arg) and arg.endswith('.py')","tryCatchPattern":"try:\n    module, name = fire_import.import_module(arg)\nexcept ValueError as e:\n    print(f'{arg}: {e} — rename to .py or pass pkg.mod'); sys.exit(2)","preventionTips":["Ensure all CLI entry scripts end in .py.","For packages, pass dotted module names (pkg.mod), not paths.","Do not pass shell scripts or configs to python -m fire."],"tags":["python","cli","file-extension","import"],"backgroundTag":"file-extension-not-supported","analyzedSha":"716bbc23d7eca949fdb682172283c8d18f742cb6","analyzedAt":"2026-08-28T21:57:47.200Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}