def test_which(): assert runez.which(None) is None assert runez.which("/dev/null") is None assert runez.which("dev/null") is None pp = runez.which(runez.to_path("python")) ps = runez.which("python") assert pp == ps
def test_run(temp_folder): assert runez.program.added_env_paths(None) is None ls = runez.which("ls") with runez.CaptureOutput(dryrun=True) as logged: assert "Would run: /dev/null" in runez.run("/dev/null", fatal=False) assert "Would run: /dev/null" in logged.pop() assert "Would run:" in runez.run(ls, "--invalid-flag", None, ".") assert "Would run: %s ." % ls in logged.pop() with runez.CaptureOutput() as logged: assert runez.run("/dev/null", fatal=False) is False assert "/dev/null is not installed" in logged.pop() assert runez.touch("sample") == 1 assert runez.run(ls, "--invalid-flag", None, ".", path_env={"PATH": ":."}) == "sample" assert "Running: %s ." % ls in logged.pop() assert runez.run(ls, "some-file", fatal=False) is False assert "Running: %s some-file" % ls in logged assert "exited with code" in logged assert "No such file" in logged.pop()
def resolve_executable(self): """Resolve executable from given major/minor""" self._set_executable( self._resolve_from_configured( SETTINGS.get_value("python_installs"))) if not self.executable: self._set_executable( runez.which(self.program_name, ignore_own_venv=True))
def stop_profiler(cls): cls.profiler.disable() filepath = runez.DEV.project_path(".tox", "lastrun.profile") try: cls.profiler.dump_stats(filepath) if runez.which("qcachegrind") is None: print("run 'brew install qcachegrind'") return runez.run("pyprof2calltree", "-k", "-i", filepath, stdout=None, stderr=None) except Exception as e: print("Can't save %s: %s" % (filepath, e))
def version_check(programs): """Check that programs are present with a minimum version""" if not programs: runez.abort("Specify at least one program to check") specs = [] for program_spec in programs: program, _, min_version = program_spec.partition(":") min_version = Version(min_version) if not program or not min_version.is_valid: runez.abort( "Invalid argument '%s', expecting format <program>:<version>" % program_spec) specs.append((program, min_version)) overview = [] for program, min_version in specs: if runez.DRYRUN: runez.run(program, "--version") continue full_path = runez.which(program) if not full_path: runez.abort("%s is not installed" % program) r = runez.run(full_path, "--version", fatal=False, logger=None) if not r.succeeded: runez.abort("%s --version failed: %s" % (runez.short(full_path), runez.short(r.full_output))) version = Version.from_text(r.full_output) if not version or version < min_version: runez.abort("%s version too low: %s (need %s+)" % (runez.short(full_path), version, min_version)) overview.append("%s %s" % (program, version)) print(runez.short(runez.joined(overview, delimiter=" ; ")))
def test_capture(monkeypatch): with runez.CurrentFolder(os.path.dirname(CHATTER)): # Check which finds programs in current folder assert runez.which("chatter") == CHATTER assert runez.shell("chatter hello") == "hello" with runez.CaptureOutput(dryrun=True) as logged: # Dryrun mode doesn't fail (since it doesn't actually run the program) r = runez.run(CHATTER, "silent-fail", fatal=True) assert r.succeeded assert "[dryrun] " in r.output assert r.error == "" assert "Would run:" in logged.pop() r = runez.run(CHATTER, "silent-fail", stdout=None, stderr=None, fatal=True) assert r.succeeded assert r.output is None assert r.error is None assert "Would run:" in logged.pop() with runez.CaptureOutput(seed_logging=True) as logged: # Test success assert runez.run(CHATTER, "hello", fatal=False) == RunResult("hello", "", 0) assert runez.run(CHATTER, "hello", fatal=True) == RunResult("hello", "", 0) assert "chatter hello" in logged.pop() assert runez.run(CHATTER, stdout=None) == RunResult(None, "", 0) assert "Running:" in logged.pop() crasher = CrashingWrite() assert runez.run(CHATTER, "hello", fatal=True, passthrough=crasher) == RunResult("hello", "", 0) assert crasher.crash_counter assert "hello" in logged.pop() # Test no-wait r = runez.run(CHATTER, "hello", fatal=None, stdout=None, stderr=None) assert r.exit_code is None # We don't know exit code because we didn't wait assert r.pid r = runez.run(CHATTER, stdout=None, stderr=None) assert r assert str(r) == "RunResult(exit_code=0)" assert r.succeeded assert r.output is None assert r.error is None assert r.full_output is None r = runez.run(CHATTER, "hello", path_env={ "PATH": ":.", "CPPFLAGS": " -I/usr/local/opt/openssl/include" }) assert str(r) == "RunResult(exit_code=0)" assert r.succeeded assert r.output == "hello" assert r.error == "" assert r.full_output == "hello" # Test stderr r = runez.run(CHATTER, "complain") assert r.succeeded assert r.output == "" assert r.error == "complaining" assert r.full_output == "complaining" logged.pop() # Test failure with pytest.raises(Exception): runez.run(CHATTER, "fail") assert "Run failed:" in logged.pop() r = runez.run(CHATTER, "silent-fail", fatal=False) assert str(r) == "RunResult(exit_code=1)" assert r.failed assert r.error == "" assert r.output == "" assert r.full_output == r.error if hasattr(subprocess.Popen, "__enter__"): # Simulate an EIO with patch("runez.program._read_data", side_effect=simulate_os_error(errno.EIO)): r = runez.run(CHATTER, "fail", fatal=False, passthrough=True) assert r.failed assert r.exc_info is None assert r.output == "" assert r.error == "" # Simulate an OSError with patch("runez.program._read_data", side_effect=simulate_os_error(errno.EINTR)): r = runez.run(CHATTER, "fail", fatal=False, passthrough=True) assert r.failed assert r.output is None assert "failed: OSError(" in r.error # Verify no extra "exited with code ..." message is added when pass-through had some output logged.clear() with pytest.raises(SystemExit): runez.run(CHATTER, "fail", fatal=SystemExit, passthrough=True) assert "exited with code" not in logged.pop() with pytest.raises(runez.system.AbortException): runez.run(CHATTER, "fail", fatal=True, passthrough=True) assert "exited with code" not in logged.pop() # Verify that silent pass-through gets at least mention of exit code with pytest.raises(SystemExit): runez.run(CHATTER, "silent-fail", fatal=SystemExit, passthrough=True) assert "exited with code" in logged.pop() with pytest.raises(runez.system.AbortException): runez.run(CHATTER, "silent-fail", fatal=True, passthrough=True) assert "exited with code" in logged.pop() r = runez.run(CHATTER, "fail", fatal=False, passthrough=True) assert r.failed assert r.error == "failed" assert r.output == "hello there" assert r.full_output == "failed\nhello there" r = runez.run("foo/bar", fatal=False) assert r.exit_code == 1 assert "foo/bar is not an executable" in r.error r = runez.run("foo-bar-no-such-program", fatal=False) assert r.exit_code == 1 assert "is not installed (PATH=" in r.error with monkeypatch.context() as m: m.setattr(subprocess, "Popen", exception_raiser(OSError("testing"))) r = runez.run("python", "--version", fatal=False) assert not r assert r.failed assert "python failed: OSError(" in r.error assert r.output is None with pytest.raises(OSError): runez.run("python", "--version") # Test convenience arg None filtering logged.clear() assert runez.run(CHATTER, "hello", "-a", 0, "-b", None, 1, 2, None, "foo bar") == RunResult("hello -a 0 1 2 foo bar", "", 0) assert 'chatter hello -a 0 1 2 "foo bar"' in logged.pop()
def test_which(): assert runez.which(None) is None assert runez.which("/dev/null") is None assert runez.which("dev/null") is None assert runez.which("ls")
import re import sys import _pytest.logging import pytest import runez LOG = logging.getLogger(__name__) # Set DEBUG logging level when running tests, makes sure LOG.debug() calls get captured (for inspection in tests) logging.root.setLevel(logging.DEBUG) if sys.argv and "pycharm" in sys.argv[0].lower(): # pragma: no cover # Ignore PyCharm's special wrapper "_jb_pytest_runner"... pt = runez.which("pytest") if pt: sys.argv[0] = pt # Set logsetup defaults to stable/meaningful for pytest runs runez.log.override_spec( timezone="UTC", tmp=os.path.join("/", "tmp"), locations=["{tmp}/{basename}"], ) class IsolatedLogSetup(object): """Allows to isolate changes to logging setup. This should only be useful for testing (as in general, logging setup is a global thing).