Sourcing python-remove-tests-dir-hook Sourcing python-catch-conflicts-hook.sh Sourcing python-remove-bin-bytecode-hook.sh Sourcing pypa-build-hook Using pypaBuildPhase Sourcing python-runtime-deps-check-hook Using pythonRuntimeDepsCheckHook Sourcing pypa-install-hook Using pypaInstallPhase Sourcing python-imports-check-hook.sh Using pythonImportsCheckPhase Sourcing python-namespaces-hook Sourcing python-catch-conflicts-hook.sh Sourcing pytest-check-hook Using pytestCheckPhase Running phase: unpackPhase unpacking source archive /nix/store/92q287ar3njqi8x54ib1ap60df8m9720-source source root is source setting SOURCE_DATE_EPOCH to timestamp 315619200 of file "source/tests/test_watch.py" Running phase: patchPhase Running phase: updateAutotoolsGnuConfigScriptsPhase Running phase: configurePhase no configure script, doing nothing Running phase: buildPhase Executing pypaBuildPhase Creating a wheel... pypa build flags: --no-isolation --outdir dist/ --wheel * Getting build dependencies for wheel... /nix/store/gyficbimx12q5975523ps3kjzz8ys4pq-python3.14-setuptools-83.0.0/lib/python3.14/site-packages/setuptools/config/_apply_pyprojecttoml.py:82: SetuptoolsDeprecationWarning: `project.license` as a TOML table is deprecated !! ******************************************************************************** Please use a simple string containing a SPDX expression for `project.license`. You can also use `project.license-files`. (Both options available on setuptools>=77.0.0). By 2027-Feb-18, you need to update your project and remove deprecated calls or your builds will no longer be supported. See https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#license for details. ******************************************************************************** !! corresp(dist, value, root_dir) /nix/store/gyficbimx12q5975523ps3kjzz8ys4pq-python3.14-setuptools-83.0.0/lib/python3.14/site-packages/setuptools/config/_apply_pyprojecttoml.py:61: SetuptoolsDeprecationWarning: License classifiers are deprecated. !! ******************************************************************************** Please consider removing the following classifiers in favor of a SPDX license expression: License :: OSI Approved :: Apache Software License See https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#license for details. ******************************************************************************** !! dist._finalize_license_expression() /nix/store/gyficbimx12q5975523ps3kjzz8ys4pq-python3.14-setuptools-83.0.0/lib/python3.14/site-packages/setuptools/dist.py:765: SetuptoolsDeprecationWarning: License classifiers are deprecated. !! ******************************************************************************** Please consider removing the following classifiers in favor of a SPDX license expression: License :: OSI Approved :: Apache Software License See https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#license for details. ******************************************************************************** !! self._finalize_license_expression() running egg_info creating src/mcptoon.egg-info writing src/mcptoon.egg-info/PKG-INFO writing dependency_links to src/mcptoon.egg-info/dependency_links.txt writing entry points to src/mcptoon.egg-info/entry_points.txt writing requirements to src/mcptoon.egg-info/requires.txt writing top-level names to src/mcptoon.egg-info/top_level.txt writing manifest file 'src/mcptoon.egg-info/SOURCES.txt' reading manifest file 'src/mcptoon.egg-info/SOURCES.txt' adding license file 'LICENSE' adding license file 'NOTICE' writing manifest file 'src/mcptoon.egg-info/SOURCES.txt' * Building wheel... /nix/store/gyficbimx12q5975523ps3kjzz8ys4pq-python3.14-setuptools-83.0.0/lib/python3.14/site-packages/setuptools/config/_apply_pyprojecttoml.py:82: SetuptoolsDeprecationWarning: `project.license` as a TOML table is deprecated !! ******************************************************************************** Please use a simple string containing a SPDX expression for `project.license`. You can also use `project.license-files`. (Both options available on setuptools>=77.0.0). By 2027-Feb-18, you need to update your project and remove deprecated calls or your builds will no longer be supported. See https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#license for details. ******************************************************************************** !! corresp(dist, value, root_dir) /nix/store/gyficbimx12q5975523ps3kjzz8ys4pq-python3.14-setuptools-83.0.0/lib/python3.14/site-packages/setuptools/config/_apply_pyprojecttoml.py:61: SetuptoolsDeprecationWarning: License classifiers are deprecated. !! ******************************************************************************** Please consider removing the following classifiers in favor of a SPDX license expression: License :: OSI Approved :: Apache Software License See https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#license for details. ******************************************************************************** !! dist._finalize_license_expression() /nix/store/gyficbimx12q5975523ps3kjzz8ys4pq-python3.14-setuptools-83.0.0/lib/python3.14/site-packages/setuptools/dist.py:765: SetuptoolsDeprecationWarning: License classifiers are deprecated. !! ******************************************************************************** Please consider removing the following classifiers in favor of a SPDX license expression: License :: OSI Approved :: Apache Software License See https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#license for details. ******************************************************************************** !! self._finalize_license_expression() running bdist_wheel running build running build_py creating build/lib/mcptoon copying src/mcptoon/__main__.py -> build/lib/mcptoon copying src/mcptoon/usage.py -> build/lib/mcptoon copying src/mcptoon/errors.py -> build/lib/mcptoon copying src/mcptoon/demo_server.py -> build/lib/mcptoon copying src/mcptoon/sync.py -> build/lib/mcptoon copying src/mcptoon/discover.py -> build/lib/mcptoon copying src/mcptoon/serve.py -> build/lib/mcptoon copying src/mcptoon/output.py -> build/lib/mcptoon copying src/mcptoon/plugin.py -> build/lib/mcptoon copying src/mcptoon/demo.py -> build/lib/mcptoon copying src/mcptoon/toon_vendored.py -> build/lib/mcptoon copying src/mcptoon/skills.py -> build/lib/mcptoon copying src/mcptoon/client.py -> build/lib/mcptoon copying src/mcptoon/manifest.py -> build/lib/mcptoon copying src/mcptoon/config.py -> build/lib/mcptoon copying src/mcptoon/__init__.py -> build/lib/mcptoon copying src/mcptoon/installer.py -> build/lib/mcptoon copying src/mcptoon/cache.py -> build/lib/mcptoon copying src/mcptoon/router.py -> build/lib/mcptoon copying src/mcptoon/bench.py -> build/lib/mcptoon copying src/mcptoon/native_tools.py -> build/lib/mcptoon copying src/mcptoon/watch.py -> build/lib/mcptoon copying src/mcptoon/schema_simplifier.py -> build/lib/mcptoon copying src/mcptoon/health.py -> build/lib/mcptoon copying src/mcptoon/cli.py -> build/lib/mcptoon running egg_info writing src/mcptoon.egg-info/PKG-INFO writing dependency_links to src/mcptoon.egg-info/dependency_links.txt writing entry points to src/mcptoon.egg-info/entry_points.txt writing requirements to src/mcptoon.egg-info/requires.txt writing top-level names to src/mcptoon.egg-info/top_level.txt reading manifest file 'src/mcptoon.egg-info/SOURCES.txt' adding license file 'LICENSE' adding license file 'NOTICE' writing manifest file 'src/mcptoon.egg-info/SOURCES.txt' installing to build/bdist.linux-x86_64/wheel running install running install_lib creating build/bdist.linux-x86_64/wheel creating build/bdist.linux-x86_64/wheel/mcptoon copying build/lib/mcptoon/__init__.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/demo_server.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/config.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/cli.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/sync.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/router.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/native_tools.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/serve.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/health.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/demo.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/toon_vendored.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/usage.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/installer.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/output.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/plugin.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/__main__.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/schema_simplifier.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/errors.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/discover.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/watch.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/bench.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/skills.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/manifest.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/client.py -> build/bdist.linux-x86_64/wheel/./mcptoon copying build/lib/mcptoon/cache.py -> build/bdist.linux-x86_64/wheel/./mcptoon running install_egg_info Copying src/mcptoon.egg-info to build/bdist.linux-x86_64/wheel/./mcptoon-0.7.17-py3.14.egg-info running install_scripts creating build/bdist.linux-x86_64/wheel/mcptoon-0.7.17.dist-info/WHEEL creating '/build/source/dist/.tmp-za7rm42m/mcptoon-0.7.17-py3-none-any.whl' and adding 'build/bdist.linux-x86_64/wheel' to it adding 'mcptoon/__init__.py' adding 'mcptoon/__main__.py' adding 'mcptoon/bench.py' adding 'mcptoon/cache.py' adding 'mcptoon/cli.py' adding 'mcptoon/client.py' adding 'mcptoon/config.py' adding 'mcptoon/demo.py' adding 'mcptoon/demo_server.py' adding 'mcptoon/discover.py' adding 'mcptoon/errors.py' adding 'mcptoon/health.py' adding 'mcptoon/installer.py' adding 'mcptoon/manifest.py' adding 'mcptoon/native_tools.py' adding 'mcptoon/output.py' adding 'mcptoon/plugin.py' adding 'mcptoon/router.py' adding 'mcptoon/schema_simplifier.py' adding 'mcptoon/serve.py' adding 'mcptoon/skills.py' adding 'mcptoon/sync.py' adding 'mcptoon/toon_vendored.py' adding 'mcptoon/usage.py' adding 'mcptoon/watch.py' adding 'mcptoon-0.7.17.dist-info/licenses/LICENSE' adding 'mcptoon-0.7.17.dist-info/licenses/NOTICE' adding 'mcptoon-0.7.17.dist-info/METADATA' adding 'mcptoon-0.7.17.dist-info/WHEEL' adding 'mcptoon-0.7.17.dist-info/entry_points.txt' adding 'mcptoon-0.7.17.dist-info/top_level.txt' adding 'mcptoon-0.7.17.dist-info/RECORD' removing build/bdist.linux-x86_64/wheel Successfully built mcptoon-0.7.17-py3-none-any.whl Finished creating a wheel... Finished executing pypaBuildPhase Running phase: pythonRuntimeDepsCheckHook Executing pythonRuntimeDepsCheck Checking runtime dependencies for mcptoon-0.7.17-py3-none-any.whl Finished executing pythonRuntimeDepsCheck Running phase: installPhase Executing pypaInstallPhase Successfully installed mcptoon-0.7.17-py3-none-any.whl Finished executing pypaInstallPhase Running phase: pythonOutputDistPhase Executing pythonOutputDistPhase Finished executing pythonOutputDistPhase Running phase: fixupPhase shrinking RPATHs of ELF executables and libraries in /nix/store/wfil1bf753n2g832mxmwx5qcjfyk9w0v-mcptoon-0.7.17 checking for references to /build/ in /nix/store/wfil1bf753n2g832mxmwx5qcjfyk9w0v-mcptoon-0.7.17... patching script interpreter paths in /nix/store/wfil1bf753n2g832mxmwx5qcjfyk9w0v-mcptoon-0.7.17 stripping (with command strip and flags -S -p) in /nix/store/wfil1bf753n2g832mxmwx5qcjfyk9w0v-mcptoon-0.7.17/lib /nix/store/wfil1bf753n2g832mxmwx5qcjfyk9w0v-mcptoon-0.7.17/bin shrinking RPATHs of ELF executables and libraries in /nix/store/7nrcv55v6z2xwqjmzhlqw48yd16icds6-mcptoon-0.7.17-dist checking for references to /build/ in /nix/store/7nrcv55v6z2xwqjmzhlqw48yd16icds6-mcptoon-0.7.17-dist... patching script interpreter paths in /nix/store/7nrcv55v6z2xwqjmzhlqw48yd16icds6-mcptoon-0.7.17-dist Rewriting #!/nix/store/d64q19q1xjdwfhqx6czvrjgrhq0n3lcc-python3-3.14.7/bin/python3.14 to #!/nix/store/d64q19q1xjdwfhqx6czvrjgrhq0n3lcc-python3-3.14.7 wrapping `/nix/store/wfil1bf753n2g832mxmwx5qcjfyk9w0v-mcptoon-0.7.17/bin/mcptoon'... Executing pythonRemoveTestsDir Finished executing pythonRemoveTestsDir Running phase: installCheckPhase no Makefile or custom installCheckPhase, doing nothing Running phase: pythonCatchConflictsPhase Running phase: pythonRemoveBinBytecodePhase Running phase: pythonImportsCheckPhase Executing pythonImportsCheckPhase Check whether the following modules can be imported: mcptoon Running phase: pytestCheckPhase Executing pytestCheckPhase pytest flags: -m pytest ============================= test session starts ============================== platform linux -- Python 3.14.7, pytest-9.1.1, pluggy-1.6.0 rootdir: /build/source configfile: pyproject.toml testpaths: tests collected 1050 items tests/test_bench.py ............. [ 1%] tests/test_cache.py .... [ 1%] tests/test_calculator.py .......................... [ 4%] tests/test_claude_plugin_package.py ............. [ 5%] tests/test_cli_flags.py ........... [ 6%] tests/test_client.py .............................. [ 9%] tests/test_command_coverage.py .... [ 9%] tests/test_completion.py ........ [ 10%] tests/test_config.py ........ [ 11%] tests/test_dead_server_diagnostics.py ... [ 11%] tests/test_demo.py ..................... [ 13%] tests/test_demo_dead_package.py ........ [ 14%] tests/test_demo_server.py .............................................. [ 18%] ..... [ 19%] tests/test_discover.py ................................ [ 22%] tests/test_doctor_star_hint.py ..... [ 22%] tests/test_envelope.py ........ [ 23%] tests/test_fallback_json.py ...... [ 23%] tests/test_footprint_claims.py ............ [ 25%] tests/test_gemini_manifest.py ...... [ 25%] tests/test_health.py ............. [ 26%] tests/test_help_shortcircuit.py ......... [ 27%] tests/test_llms_txt.py ...... [ 28%] tests/test_native_tools.py ........................... [ 30%] tests/test_output.py ................................................... [ 35%] ........................................................................ [ 42%] ................ [ 44%] tests/test_plugin_install.py .......... [ 45%] tests/test_plugin_scan.py ............................... [ 48%] tests/test_policy_overrides.py ................ [ 49%] tests/test_readme_links.py ... [ 49%] tests/test_registry_sync.py ............ [ 50%] tests/test_router.py ............................................ [ 55%] tests/test_search.py ................................ [ 58%] tests/test_serve.py .................................................... [ 63%] ... [ 63%] tests/test_serve_perf.py .......... [ 64%] tests/test_serve_prompts.py ........ [ 65%] tests/test_skills.py ................................................... [ 70%] ................................FFF....... [ 74%] tests/test_stats_toggle.py ......... [ 74%] tests/test_sync.py ................ [ 76%] tests/test_tier_claims_consistent.py .... [ 76%] tests/test_toml_config.py .......................... [ 79%] tests/test_toon_cross_validate.py ............................... [ 82%] tests/test_v02_features.py .................................... [ 85%] tests/test_v04_features.py ................ [ 87%] tests/test_v05_features.py ...................... [ 89%] tests/test_v072_delight.py ..........s.. [ 90%] tests/test_v073_http_security.py .............................. [ 93%] tests/test_v074_stdio_timeout.py ............ [ 94%] tests/test_v076_stateless_serve.py ................... [ 96%] tests/test_v07_spec2026.py ..................... [ 98%] tests/test_watch.py .................. [100%] =================================== FAILURES =================================== _____ TombstoneTests.test_removal_uses_the_shared_graveyard_when_given_one _____ self = def setUp(self): self.tmp = tempfile.TemporaryDirectory() self.base = Path(self.tmp.name) self.repo = self.base / "repo" (self.repo / "skills" / "alpha").mkdir(parents=True) (self.repo / "skills" / "alpha" / "SKILL.md").write_text( "---\nname: alpha\ndescription: d\n---\n", encoding="utf-8") (self.repo / "unrelated.txt").write_text("keep me\n", encoding="utf-8") > self._git("init") tests/test_skills.py:940: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ tests/test_skills.py:951: in _git return subprocess.run(["git", *args], cwd=str(self.repo), /nix/store/d64q19q1xjdwfhqx6czvrjgrhq0n3lcc-python3-3.14.7/lib/python3.14/subprocess.py:555: in run with Popen(*popenargs, **kwargs) as process: ^^^^^^^^^^^^^^^^^^^^^^^^^^^ /nix/store/d64q19q1xjdwfhqx6czvrjgrhq0n3lcc-python3-3.14.7/lib/python3.14/subprocess.py:1039: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = , args = ['git', 'init'] executable = b'git', preexec_fn = None, close_fds = True, pass_fds = () cwd = '/build/tmpqv_q5v69/repo', env = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 12, errread = 13, errwrite = 14, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = -1 def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, os.PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [args] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ('/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/nix/store/svx59425zxp552p2b8gm11qj5r09b56i-bash-5.3p15/bin/sh') args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] sys.audit("subprocess.Popen", executable, args, cwd, env) if (_USE_POSIX_SPAWN and os.path.dirname(executable) and preexec_fn is None and (not close_fds or _HAVE_POSIX_SPAWN_CLOSEFROM) and not pass_fds and cwd is None and (p2cread == -1 or p2cread > 2) and (c2pwrite == -1 or c2pwrite > 2) and (errwrite == -1 or errwrite > 2) and not start_new_session and process_group == -1 and gid is None and gids is None and uid is None and umask < 0): self._posix_spawn(args, executable, env, restore_signals, close_fds, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite) return orig_executable = executable # For transferring possible exec failure from child to parent. # Data format: "exception name:hex errno:description" # Pickle is not used; it is complex and involves memory allocation. errpipe_read, errpipe_write = os.pipe() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: # We must avoid complex work that could involve # malloc or free in the child process to avoid # potential deadlocks, thus we do all this here. # and pass it to fork_exec() if env is not None: env_list = [] for k, v in env.items(): k = os.fsencode(k) if b'=' in k: raise ValueError("illegal environment variable name") env_list.append(k + b'=' + os.fsencode(v)) else: env_list = None # Use execv instead of execve. executable = os.fsencode(executable) if os.path.dirname(executable): executable_list = (executable,) else: # This matches the behavior of os._execvpe(). executable_list = tuple( os.path.join(os.fsencode(dir), executable) for dir in os.get_exec_path(env)) fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self.pid = _fork_exec( args, executable_list, close_fds, tuple(sorted(map(int, fds_to_keep))), cwd, env_list, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, errpipe_read, errpipe_write, restore_signals, start_new_session, process_group, gid, gids, uid, umask, preexec_fn) self._child_created = True finally: # be sure the FD is closed no matter what os.close(errpipe_write) self._close_pipe_fds(p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite) # Wait for exec to fail or succeed; possibly raising an # exception (limited in size) errpipe_data = bytearray() while True: part = os.read(errpipe_read, 50000) errpipe_data += part if not part or len(errpipe_data) > 50000: break finally: # be sure the FD is closed no matter what os.close(errpipe_read) if errpipe_data: try: pid, sts = os.waitpid(self.pid, 0) if pid == self.pid: self._handle_exitstatus(sts) else: self.returncode = sys.maxsize except ChildProcessError: pass try: exception_name, hex_errno, err_msg = ( errpipe_data.split(b':', 2)) # The encoding here should match the encoding # written in by the subprocess implementations # like _posixsubprocess err_msg = err_msg.decode() except ValueError: exception_name = b'SubprocessError' hex_errno = b'0' err_msg = 'Bad exception data from child: {!r}'.format( bytes(errpipe_data)) child_exception_type = getattr( builtins, exception_name.decode('ascii'), SubprocessError) if issubclass(child_exception_type, OSError) and hex_errno: errno_num = int(hex_errno, 16) if err_msg == "noexec:chdir": err_msg = "" # The error must be from chdir(cwd). err_filename = cwd elif err_msg == "noexec": err_msg = "" err_filename = None else: err_filename = orig_executable if errno_num != 0: err_msg = os.strerror(errno_num) if err_filename is not None: > raise child_exception_type(errno_num, err_msg, err_filename) E FileNotFoundError: [Errno 2] No such file or directory: 'git' /nix/store/d64q19q1xjdwfhqx6czvrjgrhq0n3lcc-python3-3.14.7/lib/python3.14/subprocess.py:1990: FileNotFoundError __________ TombstoneTests.test_removal_without_a_repo_still_archives ___________ self = def setUp(self): self.tmp = tempfile.TemporaryDirectory() self.base = Path(self.tmp.name) self.repo = self.base / "repo" (self.repo / "skills" / "alpha").mkdir(parents=True) (self.repo / "skills" / "alpha" / "SKILL.md").write_text( "---\nname: alpha\ndescription: d\n---\n", encoding="utf-8") (self.repo / "unrelated.txt").write_text("keep me\n", encoding="utf-8") > self._git("init") tests/test_skills.py:940: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ tests/test_skills.py:951: in _git return subprocess.run(["git", *args], cwd=str(self.repo), /nix/store/d64q19q1xjdwfhqx6czvrjgrhq0n3lcc-python3-3.14.7/lib/python3.14/subprocess.py:555: in run with Popen(*popenargs, **kwargs) as process: ^^^^^^^^^^^^^^^^^^^^^^^^^^^ /nix/store/d64q19q1xjdwfhqx6czvrjgrhq0n3lcc-python3-3.14.7/lib/python3.14/subprocess.py:1039: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = , args = ['git', 'init'] executable = b'git', preexec_fn = None, close_fds = True, pass_fds = () cwd = '/build/tmp1742pfpt/repo', env = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 12, errread = 13, errwrite = 14, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = -1 def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, os.PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [args] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ('/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/nix/store/svx59425zxp552p2b8gm11qj5r09b56i-bash-5.3p15/bin/sh') args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] sys.audit("subprocess.Popen", executable, args, cwd, env) if (_USE_POSIX_SPAWN and os.path.dirname(executable) and preexec_fn is None and (not close_fds or _HAVE_POSIX_SPAWN_CLOSEFROM) and not pass_fds and cwd is None and (p2cread == -1 or p2cread > 2) and (c2pwrite == -1 or c2pwrite > 2) and (errwrite == -1 or errwrite > 2) and not start_new_session and process_group == -1 and gid is None and gids is None and uid is None and umask < 0): self._posix_spawn(args, executable, env, restore_signals, close_fds, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite) return orig_executable = executable # For transferring possible exec failure from child to parent. # Data format: "exception name:hex errno:description" # Pickle is not used; it is complex and involves memory allocation. errpipe_read, errpipe_write = os.pipe() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: # We must avoid complex work that could involve # malloc or free in the child process to avoid # potential deadlocks, thus we do all this here. # and pass it to fork_exec() if env is not None: env_list = [] for k, v in env.items(): k = os.fsencode(k) if b'=' in k: raise ValueError("illegal environment variable name") env_list.append(k + b'=' + os.fsencode(v)) else: env_list = None # Use execv instead of execve. executable = os.fsencode(executable) if os.path.dirname(executable): executable_list = (executable,) else: # This matches the behavior of os._execvpe(). executable_list = tuple( os.path.join(os.fsencode(dir), executable) for dir in os.get_exec_path(env)) fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self.pid = _fork_exec( args, executable_list, close_fds, tuple(sorted(map(int, fds_to_keep))), cwd, env_list, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, errpipe_read, errpipe_write, restore_signals, start_new_session, process_group, gid, gids, uid, umask, preexec_fn) self._child_created = True finally: # be sure the FD is closed no matter what os.close(errpipe_write) self._close_pipe_fds(p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite) # Wait for exec to fail or succeed; possibly raising an # exception (limited in size) errpipe_data = bytearray() while True: part = os.read(errpipe_read, 50000) errpipe_data += part if not part or len(errpipe_data) > 50000: break finally: # be sure the FD is closed no matter what os.close(errpipe_read) if errpipe_data: try: pid, sts = os.waitpid(self.pid, 0) if pid == self.pid: self._handle_exitstatus(sts) else: self.returncode = sys.maxsize except ChildProcessError: pass try: exception_name, hex_errno, err_msg = ( errpipe_data.split(b':', 2)) # The encoding here should match the encoding # written in by the subprocess implementations # like _posixsubprocess err_msg = err_msg.decode() except ValueError: exception_name = b'SubprocessError' hex_errno = b'0' err_msg = 'Bad exception data from child: {!r}'.format( bytes(errpipe_data)) child_exception_type = getattr( builtins, exception_name.decode('ascii'), SubprocessError) if issubclass(child_exception_type, OSError) and hex_errno: errno_num = int(hex_errno, 16) if err_msg == "noexec:chdir": err_msg = "" # The error must be from chdir(cwd). err_filename = cwd elif err_msg == "noexec": err_msg = "" err_filename = None else: err_filename = orig_executable if errno_num != 0: err_msg = os.strerror(errno_num) if err_filename is not None: > raise child_exception_type(errno_num, err_msg, err_filename) E FileNotFoundError: [Errno 2] No such file or directory: 'git' /nix/store/d64q19q1xjdwfhqx6czvrjgrhq0n3lcc-python3-3.14.7/lib/python3.14/subprocess.py:1990: FileNotFoundError _________ TombstoneTests.test_tombstone_commits_only_the_removed_path __________ self = def setUp(self): self.tmp = tempfile.TemporaryDirectory() self.base = Path(self.tmp.name) self.repo = self.base / "repo" (self.repo / "skills" / "alpha").mkdir(parents=True) (self.repo / "skills" / "alpha" / "SKILL.md").write_text( "---\nname: alpha\ndescription: d\n---\n", encoding="utf-8") (self.repo / "unrelated.txt").write_text("keep me\n", encoding="utf-8") > self._git("init") tests/test_skills.py:940: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ tests/test_skills.py:951: in _git return subprocess.run(["git", *args], cwd=str(self.repo), /nix/store/d64q19q1xjdwfhqx6czvrjgrhq0n3lcc-python3-3.14.7/lib/python3.14/subprocess.py:555: in run with Popen(*popenargs, **kwargs) as process: ^^^^^^^^^^^^^^^^^^^^^^^^^^^ /nix/store/d64q19q1xjdwfhqx6czvrjgrhq0n3lcc-python3-3.14.7/lib/python3.14/subprocess.py:1039: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = , args = ['git', 'init'] executable = b'git', preexec_fn = None, close_fds = True, pass_fds = () cwd = '/build/tmp2ty_d45n/repo', env = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 12, errread = 13, errwrite = 14, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = -1 def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, os.PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [args] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ('/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/nix/store/svx59425zxp552p2b8gm11qj5r09b56i-bash-5.3p15/bin/sh') args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] sys.audit("subprocess.Popen", executable, args, cwd, env) if (_USE_POSIX_SPAWN and os.path.dirname(executable) and preexec_fn is None and (not close_fds or _HAVE_POSIX_SPAWN_CLOSEFROM) and not pass_fds and cwd is None and (p2cread == -1 or p2cread > 2) and (c2pwrite == -1 or c2pwrite > 2) and (errwrite == -1 or errwrite > 2) and not start_new_session and process_group == -1 and gid is None and gids is None and uid is None and umask < 0): self._posix_spawn(args, executable, env, restore_signals, close_fds, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite) return orig_executable = executable # For transferring possible exec failure from child to parent. # Data format: "exception name:hex errno:description" # Pickle is not used; it is complex and involves memory allocation. errpipe_read, errpipe_write = os.pipe() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: # We must avoid complex work that could involve # malloc or free in the child process to avoid # potential deadlocks, thus we do all this here. # and pass it to fork_exec() if env is not None: env_list = [] for k, v in env.items(): k = os.fsencode(k) if b'=' in k: raise ValueError("illegal environment variable name") env_list.append(k + b'=' + os.fsencode(v)) else: env_list = None # Use execv instead of execve. executable = os.fsencode(executable) if os.path.dirname(executable): executable_list = (executable,) else: # This matches the behavior of os._execvpe(). executable_list = tuple( os.path.join(os.fsencode(dir), executable) for dir in os.get_exec_path(env)) fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self.pid = _fork_exec( args, executable_list, close_fds, tuple(sorted(map(int, fds_to_keep))), cwd, env_list, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, errpipe_read, errpipe_write, restore_signals, start_new_session, process_group, gid, gids, uid, umask, preexec_fn) self._child_created = True finally: # be sure the FD is closed no matter what os.close(errpipe_write) self._close_pipe_fds(p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite) # Wait for exec to fail or succeed; possibly raising an # exception (limited in size) errpipe_data = bytearray() while True: part = os.read(errpipe_read, 50000) errpipe_data += part if not part or len(errpipe_data) > 50000: break finally: # be sure the FD is closed no matter what os.close(errpipe_read) if errpipe_data: try: pid, sts = os.waitpid(self.pid, 0) if pid == self.pid: self._handle_exitstatus(sts) else: self.returncode = sys.maxsize except ChildProcessError: pass try: exception_name, hex_errno, err_msg = ( errpipe_data.split(b':', 2)) # The encoding here should match the encoding # written in by the subprocess implementations # like _posixsubprocess err_msg = err_msg.decode() except ValueError: exception_name = b'SubprocessError' hex_errno = b'0' err_msg = 'Bad exception data from child: {!r}'.format( bytes(errpipe_data)) child_exception_type = getattr( builtins, exception_name.decode('ascii'), SubprocessError) if issubclass(child_exception_type, OSError) and hex_errno: errno_num = int(hex_errno, 16) if err_msg == "noexec:chdir": err_msg = "" # The error must be from chdir(cwd). err_filename = cwd elif err_msg == "noexec": err_msg = "" err_filename = None else: err_filename = orig_executable if errno_num != 0: err_msg = os.strerror(errno_num) if err_filename is not None: > raise child_exception_type(errno_num, err_msg, err_filename) E FileNotFoundError: [Errno 2] No such file or directory: 'git' /nix/store/d64q19q1xjdwfhqx6czvrjgrhq0n3lcc-python3-3.14.7/lib/python3.14/subprocess.py:1990: FileNotFoundError =========================== short test summary info ============================ FAILED tests/test_skills.py::TombstoneTests::test_removal_uses_the_shared_graveyard_when_given_one - FileNotFoundError: [Errno 2] No such file or directory: 'git' FAILED tests/test_skills.py::TombstoneTests::test_removal_without_a_repo_still_archives - FileNotFoundError: [Errno 2] No such file or directory: 'git' FAILED tests/test_skills.py::TombstoneTests::test_tombstone_commits_only_the_removed_path - FileNotFoundError: [Errno 2] No such file or directory: 'git' ============= 3 failed, 1046 passed, 1 skipped in 62.70s (0:01:02) =============