def test_files(temp_folder): """yolo""" # Exercise download code path sample = Path("README.txt") r = EXAMPLE.download("README", sample, fatal=False) assert r.status_code == 404 assert r.url == "https://example.com/README" with EXAMPLE.mock({"README": "hello"}) as mm: assert str(mm) == "tests.test_http.test_files started, 1 specs" assert str( mm.stack) == "RequestsHandler mock active, 1 specs [depth: 5]" EXAMPLE.download("README", sample) assert list(runez.readlines(sample)) == ["hello"] # Use local README.txt, which should get opened/closed appropriately # Exercise data=Path(...) code path, headers are temporarily used r = EXAMPLE.post("README", headers={"foo": "bar"}, data=sample) assert isinstance(r, RestResponse) assert r.ok # Exercise filepaths= code path r = EXAMPLE.post("README", filepaths={"sample": sample}) assert isinstance(r, RestResponse) assert r.ok
def _find_top_level(base, dist): name = dist.key.replace("-", "_").replace(".", "_") top_level = os.path.join(base, "%s-%s.dist-info" % (name, dist.version), "top_level.txt") for line in runez.readlines(top_level): if not line.startswith("_") and line: return line
def test_pathlib(temp_folder): subfolder = Path("subfolder") assert runez.to_path(subfolder) is subfolder assert not subfolder.is_dir() runez.ensure_folder(subfolder) assert subfolder.is_dir() with pytest.raises(Exception): runez.to_path("foo bar", no_spaces=Exception) with runez.CurrentFolder(subfolder, anchor=True): path = Path("foo") assert runez.short(path) == "foo" assert runez.short(path.absolute()) == "foo" assert runez.resolved_path(path) assert runez.parent_folder(path) == os.path.join(temp_folder, "subfolder") assert runez.touch(path) == 1 assert runez.copy(path, Path("bar")) == 1 assert runez.copy(Path("bar"), Path("baz")) == 1 foo_json = Path("foo.json") runez.write(path, '{"a": "b"}') runez.symlink(path, foo_json) assert runez.read_json(foo_json) == {"a": "b"} assert list(runez.readlines(foo_json)) == ['{"a": "b"}'] assert runez.basename(foo_json.absolute()) == "foo"
def test_download(temp_folder, logged): assert str(EXAMPLE) == "https://example.com" client = EXAMPLE.sub_client("test/") assert str(client) == "https://example.com/test/" r = client.put("README.txt", data=Path("foo"), fatal=False, dryrun=True) assert r.ok assert r.json() == { "message": "dryrun PUT https://example.com/test/README.txt" } assert "Would PUT" in logged.pop() with pytest.raises(FileNotFoundError): # fatal=False addresses http(s) communications only, not existence of files that are referred to by caller client.put("README.txt", data=Path("foo"), fatal=False, dryrun=False) assert not logged assert client.download("test.zip", "test.zip", dryrun=True).ok assert "Would download" in logged.pop() assert client.download("foo/test.zip", "test.zip", fatal=False).status_code == 404 assert "404" in logged.pop() assert client.download("README.txt", "README.txt", fatal=False).ok assert "GET https://example.com/test/README.txt [200]" in logged.pop() assert list(runez.readlines("README.txt")) == ["Hello"] # With checksum validation assert client.download("README.txt#sha256=a123", "README.txt", fatal=False) is None assert "Deleted README.txt" in logged assert "sha256 differs for README.txt: expecting a123, got " in logged.pop( ) r = client.download( "README.txt#sha256=185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969", "README.txt", fatal=False) assert r.ok assert client.download("README.txt#md5=8b1a9953c4611296a827abf8c47804d7", "README.txt", fatal=False).ok assert client.download( "README.txt#sha1=f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0", "README.txt", fatal=False).ok c = "3615f80c9d293ed7402687f94b22d58e529b8cc7916f8fac7fddf7fbd5af4cf777d3d795a7a00a16bf7e7f3fb9561ee9baae480da9fe7a18769e71886b03f315" assert client.download(f"README.txt#sha512={c}", "README.txt", fatal=False).ok # Not considered checksum, url fragment left as-is assert client.download("README.txt#sha2=bar", "README.txt", fatal=False).status_code == 404 client.decompress("foo/test.tar.gz#sha256=123", "my-folder", dryrun=True) assert "Would untar test.tar.gz -> my-folder" in logged.pop()
def test_relocate_venv(temp_base): with patch("pickley.delivery.relocate_venv", return_value=-1): assert _relocator("source", "destination") == " (relocation failed)" with runez.CaptureOutput() as logged: original = "line 1: source\nline 2\n" runez.write("foo/bar/bin/baz", original, logger=logging.debug) runez.write("foo/bar/bin/empty", "", logger=logging.debug) runez.write("foo/bar/bin/python", "", logger=logging.debug) runez.make_executable("foo/bar/bin/baz") runez.make_executable("foo/bar/bin/empty") runez.make_executable("foo/bar/bin/python") assert "Created" in logged.pop() # Simulate already seen expected = ["line 1: source", "line 2"] assert relocate_venv("foo", "source", "dest", fatal=False, _seen={"foo"}) == 0 assert list(runez.readlines("foo/bar/bin/baz")) == expected assert not logged # Simulate failure to write with patch("runez.write", return_value=-1): assert relocate_venv("foo", "source", "dest", fatal=False) == -1 assert list(runez.readlines("foo/bar/bin/baz")) == expected assert not logged # Simulate effective relocation, by folder expected = ["line 1: dest", "line 2"] assert relocate_venv("foo", "source", "dest", fatal=False) == 1 assert list(runez.readlines("foo/bar/bin/baz")) == expected assert not logged # Second relocation is a no-op assert relocate_venv("foo", "source", "dest", fatal=False) == 0 # Test relocating a single file runez.write("foo/bar/bin/baz", original, logger=logging.debug) assert relocate_venv("foo/bar/bin/baz", "source", "dest", fatal=False) == 1 assert list(runez.readlines("foo/bar/bin/baz")) == expected
def _locked(self): """ :return bool: True if lock is held by another process """ if not runez.file.is_younger(self.lock, self.invalid): # Lock file does not exist or invalidation age reached return False # Consider locked if pid stated in lock file is still valid for line in runez.readlines(self.lock, errors="ignore", fatal=False): return runez.check_pid(runez.to_int(line))
def check_is_wrapper(path, is_wrapper): if is_wrapper: assert not os.path.islink(path) contents = runez.readlines(path) assert WRAPPER_MARK in contents else: assert os.path.islink(path) r = runez.run(path, "--version") assert r.succeeded
def is_venv_exe(self, path): """ Args: path (str): Path to file to examine Returns: (bool): True if 'path' points to a python executable part of this venv """ if runez.is_executable(path): for line in runez.readlines(path, first=1): if line.startswith("#!"): if path.startswith(self.folder): return True
def relocate_venv(path, source, destination, fatal=True, _seen=None): """ :param str path: Path of file or folder to relocate (change mentions of 'source' to 'destination') :param str source: Where venv used to be :param str destination: Where venv is moved to :param bool fatal: Abort execution on failure if True :return int: Number of relocated files (0 if no-op, -1 on failure) """ original_call = False if _seen is None: original_call = True _seen = set() if not path or path in _seen: return 0 _seen.add(path) if os.path.isdir(path): relocated = 0 if original_call: for bin_folder in find_venvs(path): for name in os.listdir(bin_folder): fpath = os.path.join(bin_folder, name) r = relocate_venv(fpath, source, destination, fatal=fatal, _seen=_seen) if r < 0: return r relocated += r return relocated modified = False lines = [] try: for line in runez.readlines(path): if source in line: line = line.replace(source, destination) modified = True lines.append(line) except Exception: return 0 # If binary file, skip if not modified: return 0 return runez.write(path, "\n".join(lines), fatal=fatal)
def show_lines(cls, content, header=None): if hasattr(content, "path"): header = header or str(content) content = runez.readlines(content.path) elif hasattr(content, "splitlines"): content = content.splitlines() result = [] for n, line in enumerate(content, start=1): line = line.rstrip("\n") result.append("%s%s" % (runez.dim("%3s: " % n) if cls.line_numbers else "", line)) if header: print("======== %s ========" % header) print("\n".join(result))
def _locked_by(self): """ Returns: (str): CLI args of process holding the lock, if any """ if self.invalid and self.invalid > 0 and not runez.file.is_younger( self.lock_path, self.invalid): return None # Lock file does not exist or invalidation age reached pid = None for line in runez.readlines(self.lock_path): if pid is not None: return line # 2nd line hold CLI args process was invoked with pid = runez.to_int(line) if not runez.check_pid(pid): return None # PID is no longer active
def is_clear_for_installation(self): """ Returns: (bool): True if we can proceed with installation without needing to uninstall anything """ if self.is_already_installed_by_pickley: return True target = self.exe_path(self.dashed) if not target or not os.path.exists(target): return True path = os.path.realpath(target) if path.startswith(self.cfg.meta.path): return True # Pickley symlink if os.path.isfile(target): if os.path.getsize(target) == 0 or not runez.is_executable(target): return True # Empty file or not executable for line in runez.readlines(target, first=5): if PICKLEY in line: return True # Pickley wrapper
def find_uninstaller(target): if not target or not os.path.exists(target): # Bogus path, or dangling symlink return runez.delete path = os.path.realpath(target) if path.startswith(os.path.realpath(system.SETTINGS.meta.path)): # Pickley symlink, can be simply deleted return runez.delete if os.path.isfile(target) and os.path.getsize(target) == 0: # Empty file return runez.delete for line in runez.readlines(target, first=10, fatal=False): if line.startswith(system.WRAPPER_MARK): # pickley's own wrapper also fine to simply delete return runez.delete brew, name = find_brew_name(target) if brew and name: return brew_uninstall return None
def test_lock(temp_cfg, logged): pspec = PackageSpec(temp_cfg, "foo") lock_path = dot_meta("foo.lock") with SoftLock(pspec, give_up=600) as lock: assert str(lock) == "lock foo" assert os.path.exists(lock_path) try: # Try to grab same lock a seconds time, give up after 1 second with SoftLock(pspec, give_up=1, invalid=600): assert False, "Should not grab same lock twice!" except SoftLockException as e: assert "giving up" in str(e) assert not os.path.exists(lock_path) # Check that lock was released # Check that lock detects bogus (or dead) PID runez.write(lock_path, "0\nbar\n") with SoftLock(pspec, give_up=600): lines = list(runez.readlines(lock_path)) assert lines[0] == str( os.getpid()) # Lock file replaced with correct stuff assert not os.path.exists(lock_path) # Lock released
def test_bootstrap(cli, monkeypatch): with patch("pickley.bstrap.which", side_effect=mocked_which): with patch("pickley.bstrap.os.path.expanduser", side_effect=mocked_expanduser): runez.write( ".local/bin/pickley", "#!/bin/sh\necho 0.1") # Pretend we have an old pickley runez.make_executable(".local/bin/pickley") with patch("pickley.bstrap.get_python_version", return_value=(3, 6)): # urllib fails monkeypatch.setenv("__PYVENV_LAUNCHER__", "oh apple, why?" ) # macos oddity env var, should be removed cli.run("-n", main=bstrap.main) assert cli.succeeded assert "__PYVENV_LAUNCHER__" not in os.environ assert "Replacing older pickley 0.1" in cli.logged assert "Would run: python virtualenv.pyz" in cli.logged assert "Would run: .local/bin/.pickley/pickley/pickley-" in cli.logged # Simulate multiple base candidates given cli.run("-n", "-b", "~/.local/bin:foo/bar", main=bstrap.main) assert cli.failed assert "not suitable: ~/.local/bin, foo/bar" in cli.logged # Simulate seeding cli.run("0.1", "-b", "~/.local/bin", "-m", "my-mirror", "-c", '{"pyenv":"~/.pyenv"}', main=bstrap.main) assert cli.succeeded assert "Seeding .local/bin/.pickley/config.json with {'pyenv': '~/.pyenv'}" in cli.logged assert "Seeding .config/pip/pip.conf with my-mirror" in cli.logged assert "pickley version 0.1 is already installed" in cli.logged assert list(runez.readlines(".config/pip/pip.conf")) == [ "[global]", "index-url = my-mirror" ] assert list( runez.readlines(".local/bin/.pickley/config.json")) == [ "{", ' "pyenv": "~/.pyenv"', "}" ] monkeypatch.setenv("PATH", "foo/bar:%s" % os.environ["PATH"]) runez.ensure_folder("foo/bar", logger=None) cli.run("-n", "-b", "~/.local/bin:foo/bar", main=bstrap.main) assert cli.succeeded assert "base: foo/bar" in cli.logged with patch("pickley.bstrap.which", return_value=None): with patch("pickley.bstrap.is_executable", return_value=False): # Simulate no python 3 cli.run("-n", main=bstrap.main) assert cli.failed assert "Could not find python3 on this machine" in cli.logged with patch("pickley.bstrap.get_python_version", return_value=(3, 9)): # urllib fails cli.run("-n", main=bstrap.main) assert cli.succeeded assert " -mvenv " in cli.logged
def dir_contents(path=None): path = runez.to_path(path or ".") return {f.name: dir_contents(f) if f.is_dir() else list(runez.readlines(f)) for f in runez.ls_dir(path)}
def test_file_inspection(temp_folder, logged): assert runez.touch("sample") == 1 assert runez.delete("sample") == 1 assert "Deleted sample" in logged.pop() assert runez.ensure_folder("sample") == 1 assert runez.delete("sample") == 1 assert "Deleted sample" in logged.pop() sample = runez.DEV.tests_path("sample.txt") assert len(list(runez.readlines(sample))) == 4 assert len(list(runez.readlines(sample, first=1))) == 1 assert not logged cc = "%s\n" % "\n".join(runez.readlines(sample)) assert runez.write("sample", cc, fatal=False, logger=logging.debug) == 1 cc2 = "%s\n" % "\n".join(runez.readlines("sample")) assert cc2 == cc assert "bytes to sample" in logged.pop() # Wrote 13 bytes on linux... but 14 on windows... assert list(runez.readlines("sample", first=2)) == ["", "Fred"] assert runez.file.is_younger("sample", age=10) assert not runez.file.is_younger("sample", age=-1) # Verify that readlines() can ignore encoding errors with io.open("not-a-text-file", "wb") as fh: fh.write(b"\x89 hello\nworld") assert list(runez.readlines("not-a-text-file", first=1)) == [" hello"] assert not logged assert runez.copy("bar", "baz", fatal=False) == -1 assert "does not exist" in logged.pop() assert runez.move("bar", "baz", fatal=False) == -1 assert "does not exist" in logged.pop() assert runez.symlink("bar", "baz", fatal=False) == -1 assert "does not exist" in logged.pop() # Creating dangling symlinks is possible assert runez.symlink("s/bar", "s/baz", fatal=False, must_exist=False) == 1 assert "Symlink s/bar <- s/baz" in logged.pop() assert os.path.islink("s/baz") assert not os.path.exists("s/baz") runez.touch("s/bar") assert os.path.exists("s/baz") assert runez.copy("sample", "x/y/sample") == 1 assert runez.symlink("sample", "x/y/sample3", fatal=False) == 1 assert os.path.exists("sample") assert runez.move("sample", "x/y/sample2") == 1 assert not os.path.exists("sample") assert runez.copy("x/y", "x/z1") == 1 assert os.path.exists("x/z1/sample") assert os.path.exists("x/z1/sample2") assert os.path.exists("x/z1/sample3") assert os.path.islink("x/z1/sample3") assert runez.copy("x/y", "x/z2", ignore={"sample2"}) == 1 assert os.path.exists("x/z2/sample") assert not os.path.exists("x/z2/sample2") assert os.path.exists("x/z2/sample3") assert os.path.islink("x/z2/sample3") def should_ignore(src, dest): if src == "x/y" and "sample3" in dest: return {"sample3"} assert runez.copy("x/y", "x/z3", ignore=should_ignore) == 1 assert os.path.exists("x/z3/sample") assert os.path.exists("x/z3/sample2") assert not os.path.exists("x/z3/sample3") assert runez.copy("x/y", "x/z2") == 1 assert os.path.exists("x/z2/sample2") # Copy a folder over an existing file runez.touch("x2") assert not os.path.exists("x2/z2/sample2") assert runez.copy("x", "x2") == 1 assert os.path.exists("x2/z2/sample2")