def choose(args: argparse.Namespace) -> bool: menu = args.menu or get_default_menu() if not menu: error(f"No menu program found, please install one of: {AUTO_MENUS}") return False if menu == "applescript" and platform != "darwin": error(f"Menu applescript cannot be used on a {platform} host") return False profiles = [profile.name for profile in sorted(args.profile_dir.iterdir())] if len(profiles) == 0: error("No profiles") return False command = menu_command(menu, profiles, args) if not command: return False selection_cmd = subprocess.Popen( command, shell=True, stdout=subprocess.PIPE, stderr=None, ) out = selection_cmd.stdout selection = out and out.read().decode(errors="ignore").rstrip("\n") if selection: profile = Profile(selection, args.profile_dir) launch(profile, True, args.foreground, args.qb_args) else: error("No profile selected") return False return True
def desktop(profile: Profile) -> bool: exists = profile.exists() if exists: profiles.create_desktop_file(profile) else: error(f"profile {profile.name} not found at {profile.root}") return exists
def from_session( session: str, profile_name: Optional[str] = None, profile_dir: Optional[Path] = None, desktop_file: bool = True, overwrite: bool = False, ) -> Optional[Profile]: if session.endswith(".yml"): session_file = Path(session).expanduser() session_name = session_file.stem else: session_name = session session_file = user_data_dir() / "sessions" / (session_name + ".yml") if not session_file.is_file(): error(f"{session_file} is not a file") return None profile = Profile(profile_name or session_name, profile_dir) if not profiles.new_profile(profile, None, desktop_file, overwrite): return None session_dir = profile.root / "data" / "sessions" session_dir.mkdir(parents=True, exist_ok=overwrite) shutil.copy(session_file, session_dir / "_autosave.yml") return profile
def then_launch( args: argparse.Namespace, operation: Callable[[argparse.Namespace], Optional[Any]], ) -> bool: if result := operation(args): profile = result if isinstance(result, Profile) else Profile.of(args) return operations.launch(profile, False, args.foreground, args.qb_args)
def edit(profile: Profile) -> bool: if not profile.exists(): error(f"profile {profile.name} not found at {profile.root}") return False editor = os.environ.get("VISUAL") or os.environ.get("EDITOR") or "vim" os.execlp(editor, editor, str(profile.root / "config" / "config.py")) return True
def op(args: argparse.Namespace) -> Any: params = [ param.name for param in inspect.signature(operation).parameters.values() if param.kind == param.POSITIONAL_OR_KEYWORD ] kwargs = {param: getattr(args, param, None) for param in params} if "profile" in params: kwargs["profile"] = Profile.of(args) return operation(**kwargs)
def test_overwrite_config(tmp_path: Path): profile = Profile("test", tmp_path) url = "http://example.com" config_dir = profile.root / "config" config_dir.mkdir(parents=True) profiles.create_config(profile) profiles.create_config(profile, url, True) assert list(config_dir.iterdir()) == [config_dir / "config.py"] with open(config_dir / "config.py") as conf: for line in conf: if url in line: return assert False
def launch(profile: Profile, strict: bool, foreground: bool, qb_args: List[str]) -> bool: if not profiles.ensure_profile_exists(profile, not strict): return False args = profile.cmdline() + qb_args if not shutil.which(args[0]): error("qutebrowser is not installed") return False if foreground: return subprocess.run(args).returncode == 0 else: p = subprocess.Popen(args, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE) try: # give qb a chance to validate input before returning to shell stdout, stderr = p.communicate(timeout=0.1) print(stderr.decode(errors="ignore"), end="") except subprocess.TimeoutExpired: pass return True
def test_create_profile_parent(tmp_path: Path): profile = Profile("../test", tmp_path / "profiles") assert not profiles.create_profile(profile) assert not (tmp_path / "test").exists()
def test_ensure_profile_exists_create(tmp_path: Path): profile = Profile("test", tmp_path) assert profiles.ensure_profile_exists(profile, True) check_new_profile(profile)
def test_ensure_profile_exists_not_dir(tmp_path: Path): profile = Profile("test", tmp_path) profile.root.touch() assert not profiles.ensure_profile_exists(profile, False) assert not profiles.ensure_profile_exists(profile, True)
def test_ensure_profile_exists_does_not_exist(tmp_path: Path): assert not profiles.ensure_profile_exists(Profile("test", tmp_path), False) check_is_empty(tmp_path)
def test_ensure_profile_exists_exists(tmp_path: Path): profile = Profile("test", tmp_path) profile.root.mkdir() assert profiles.ensure_profile_exists(profile, False) assert profiles.ensure_profile_exists(profile, True) check_is_empty(profile.root)
def test_create_config(tmp_path: Path): profile = Profile("test", tmp_path) config_dir = profile.root / "config" config_dir.mkdir(parents=True) profiles.create_config(profile) assert list(config_dir.iterdir()) == [config_dir / "config.py"]
def test_create_profile_nested_conflict(tmp_path: Path): assert profiles.create_profile(Profile("test", tmp_path)) assert not profiles.create_profile(Profile("test/a", tmp_path))
def test_new_profile(tmp_path: Path): profile = Profile("test", tmp_path) assert profiles.new_profile(profile) check_new_profile(profile)
def test_create_profile_conflict(tmp_path: Path): (tmp_path / "test").touch() profile = Profile("test", tmp_path) assert not profiles.create_profile(profile)
def test_create_profile(tmp_path: Path): profile = Profile("test", tmp_path) assert profiles.create_profile(profile) assert list(tmp_path.iterdir()) == [profile.root] check_empty_profile(profile)
def test_set_profile(tmp_path: Path): assert Profile("test", tmp_path).root == tmp_path / "test"