chore(python): remove dead helpers and a stale dependency

None of these had a caller:
- pkgman: is_supported_path, extract_zip, cleanup and set_version, left over
  from the single-directory install. cleanup() would have deleted every
  installed browser version.
- multiversion.get_cached_repo_names, CONSTRAINTS.as_range,
  fingerprints._load_os_voices, utils._clean_locals, and unused imports.

Also:
- The "Apify Fingerprints" row in `camoufox version`, which has read "?"
  since fpgen replaced BrowserForge.
- lxml is no longer a dependency; nothing imports it.
- The geoip extra now names maxminddb, the module geolocation.py actually
  imports, rather than getting it transitively through geoip2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jake Writer
2026-09-25 15:20:45 -06:00
co-authored by Claude Opus 5.5
parent be9f38b08e
commit e425dddcfd
11 changed files with 8 additions and 106 deletions
+1 -3
View File
@@ -36,7 +36,6 @@ from .multiversion import (
remove_version,
save_config,
save_repo_cache,
set_active,
)
from .pkgman import (
INSTALL_DIR,
@@ -866,7 +865,6 @@ class VersionInfo:
self._header("Python Packages")
self._pkg("Camoufox", "camoufox")
self._pkg("fpgen", "fpgen")
self._pkg("Apify Fingerprints", "apify_fingerprint_datapoints")
self._pkg("Playwright", "playwright")
def browser(self):
@@ -952,7 +950,7 @@ class VersionInfo:
self._header("GeoIP")
if not ALLOW_GEOIP:
# geoip2 package not installed
# maxminddb not installed
self._row("Status", "Not supported (install camoufox[geoip])", style="dim")
else:
mmdb_path = get_mmdb_path()
-6
View File
@@ -29,9 +29,3 @@ class CONSTRAINTS:
# actually break get moved.
PLAYWRIGHT_BROWSER_FLOORS = (((1, 61), 'beta.30'),)
@staticmethod
def as_range() -> str:
"""
Returns the version range as a string.
"""
return f">={CONSTRAINTS.MIN_VERSION}, <{CONSTRAINTS.MAX_VERSION}"
+1 -1
View File
@@ -2,7 +2,7 @@ import asyncio
import json as _json
import urllib.request
from functools import partial
from typing import Any, Dict, List, Optional, Union, overload
from typing import Any, Dict, Optional, Union, overload
from urllib.parse import urlparse
from playwright.async_api import (
+1 -1
View File
@@ -141,7 +141,7 @@ class UnknownLanguage(InvalidLocale):
class NotInstalledGeoIPExtra(ImportError):
"""
Raised when the geoip2 module is not installed.
Raised when the maxminddb module is not installed.
"""
...
+1 -39
View File
@@ -6,7 +6,7 @@ import secrets
import unicodedata
from dataclasses import asdict, dataclass, is_dataclass
from pathlib import Path
from random import Random, choice, randint, randrange, random, sample, shuffle
from random import Random, choice, randint, randrange
from typing import Any, Dict, FrozenSet, List, Optional, Set, Tuple
from camoufox.pkgman import load_yaml
@@ -595,44 +595,6 @@ def _generate_random_font_subset(
return result
# OS voice lists loaded from voices.json, parsed into "Name:lang:type" tuples.
_OS_VOICES_CACHE: Optional[Dict[str, List[Tuple[str, str, str]]]] = None
def _load_os_voices() -> Dict[str, List[Tuple[str, str, str]]]:
"""Load OS voice lists from voices.json as (name, lang, type) tuples.
Each entry is "Name:lang:type" (type is "local" or "remote"). Voice names
may contain parens/commas but not colons, so a last-two-colons split is
safe.
"""
global _OS_VOICES_CACHE
if _OS_VOICES_CACHE is not None:
return _OS_VOICES_CACHE
voices_path = os.path.join(os.path.dirname(__file__), 'voices.json')
with open(voices_path, 'rb') as f:
import orjson
raw = orjson.loads(f.read())
_OS_VOICES_CACHE = {}
for os_key, entries in raw.items():
parsed: List[Tuple[str, str, str]] = []
for entry in entries:
last = entry.rfind(':')
if last < 0:
continue
vtype = entry[last + 1:]
before = entry[:last]
langsep = before.rfind(':')
if langsep < 0:
continue
lang = before[langsep + 1:]
name = before[:langsep]
if name and lang:
parsed.append((name, lang, vtype))
_OS_VOICES_CACHE[os_key] = parsed
return _OS_VOICES_CACHE
# Essential speech voices per OS that must always be included in subsets
_ESSENTIAL_VOICES_MACOS = [
'Samantha', 'Alex', 'Fred', 'Victoria', 'Karen', 'Daniel',
+1 -1
View File
@@ -119,7 +119,7 @@ def get_mmdb_path(ip_version: str = 'ipv4', config: Optional[Dict] = None) -> Pa
def geoip_allowed() -> None:
"""
Checks if the geoip2 module is available
Checks if the maxminddb module is available
"""
if not ALLOW_GEOIP:
raise NotInstalledGeoIPExtra(
-8
View File
@@ -123,14 +123,6 @@ def latest_per_build(versions: List[Dict]) -> List[Dict]:
)
def get_cached_repo_names() -> List[str]:
"""
Get list of repo names in cache
"""
cache = load_repo_cache()
return [r['name'] for r in cache.get('repos', [])]
def get_repo_name(github_repo: str) -> str:
"""
Get display name for a repo from repos.yml, lowercased
-33
View File
@@ -2,7 +2,6 @@ import hashlib
import os
import platform
import re
import shutil
import sys
import tempfile
from dataclasses import dataclass
@@ -393,13 +392,6 @@ class Version:
version=version_data.get('version'),
)
@staticmethod
def is_supported_path(path: Path) -> bool:
"""
Check if the version at the given path is supported
"""
return Version.from_path(path) >= VERSION_MIN
@staticmethod
def build_minmax() -> Tuple['Version', 'Version']:
return Version(build=CONSTRAINTS.MIN_VERSION), Version(build=CONSTRAINTS.MAX_VERSION)
@@ -629,31 +621,6 @@ class CamoufoxFetcher(GitHubDownloader):
rprint(f'Downloading package: {url}')
return webdl(url, buffer=file)
def extract_zip(self, zip_file: DownloadBuffer) -> None:
"""
Extract a zip file to the installation directory
"""
rprint(f'Extracting Camoufox: {INSTALL_DIR}')
unzip(zip_file, str(INSTALL_DIR))
@staticmethod
def cleanup() -> bool:
"""
Clean up the old installation
"""
if INSTALL_DIR.exists():
rprint(f'Cleaning up cache: {INSTALL_DIR}')
shutil.rmtree(INSTALL_DIR)
return True
return False
def set_version(self) -> None:
"""
Write version.json to INSTALL_DIR
"""
with open(INSTALL_DIR / 'version.json', 'wb') as f:
f.write(orjson.dumps({'version': self.version, 'build': self.build}))
def install(self, replace: bool = False) -> None:
"""
Download and install camoufox to a versioned subdirectory
+1 -1
View File
@@ -1,6 +1,6 @@
import json as _json
import urllib.request
from typing import Any, Dict, List, Optional, Union, overload
from typing import Any, Dict, Optional, Union, overload
from urllib.parse import urlparse
from playwright.sync_api import (
-10
View File
@@ -8,7 +8,6 @@ from os import environ
from os.path import abspath
from pathlib import Path
from pprint import pprint
from random import randint
from typing import Any, Dict, List, Literal, Optional, Tuple, Union
import numpy as np
@@ -515,15 +514,6 @@ def check_valid_os(os: ListOrString) -> None:
raise InvalidOS(f"Camoufox does not support the OS: '{os}'")
def _clean_locals(data: Dict[str, Any]) -> Dict[str, Any]:
"""
Gets the launch options from the locals of the function.
"""
del data['playwright']
del data['persistent_context']
return data
def merge_into(target: Dict[str, Any], source: Dict[str, Any]) -> None:
"""
Merges new keys/values from the source dictionary into the target dictionary.
+2 -3
View File
@@ -45,15 +45,14 @@ numpy = "*"
ua_parser = "*"
typing_extensions = "*"
screeninfo = "*"
lxml = "*"
language-tags = "*"
pysocks = "*"
inquirer = "*"
geoip2 = {version = "*", optional = true}
maxminddb = {version = "*", optional = true}
PySide6 = {version = "*", optional = true}
[tool.poetry.extras]
geoip = ["geoip2"]
geoip = ["maxminddb"]
gui = ["PySide6"]
[tool.poetry.scripts]