@functools.cache
def dirs_in_zip(archive):
- with ZipFile(archive) as zip:
- return set(itertools.chain.from_iterable(
- Path(file).parents for file in zip.namelist()))
+ try:
+ with ZipFile(archive) as zip_:
+ return set(itertools.chain.from_iterable(
+ Path(file).parents for file in zip_.namelist()))
+ except FileNotFoundError:
+ pass
+ except Exception as e:
+ write_string(f'WARNING: Could not read zip file {archive}: {e}\n')
+ return set()
class PluginFinder(importlib.abc.MetaPathFinder):
def _get_package_paths(*root_paths, containing_folder='plugins'):
for config_dir in orderedSet(map(Path, root_paths), lazy=True):
- plugin_dir = config_dir / containing_folder
- if not plugin_dir.is_dir():
- continue
- yield from plugin_dir.iterdir()
+ with contextlib.suppress(OSError):
+ yield from (config_dir / containing_folder).iterdir()
# Load from yt-dlp config folders
candidate_locations.extend(_get_package_paths(
containing_folder='yt-dlp-plugins'))
candidate_locations.extend(map(Path, sys.path)) # PYTHONPATH
+ with contextlib.suppress(ValueError): # Added when running __main__.py directly
+ candidate_locations.remove(Path(__file__).parent)
parts = Path(*fullname.split('.'))
- locations = set()
- for path in dict.fromkeys(candidate_locations):
+ for path in orderedSet(candidate_locations, lazy=True):
candidate = path / parts
if candidate.is_dir():
- locations.add(str(candidate))
- elif path.name and any(path.with_suffix(suffix).is_file() for suffix in {'.zip', '.egg', '.whl'}):
- with contextlib.suppress(FileNotFoundError):
- if parts in dirs_in_zip(path):
- locations.add(str(candidate))
- return locations
+ yield candidate
+ elif path.suffix in ('.zip', '.egg', '.whl') and path.is_file():
+ if parts in dirs_in_zip(path):
+ yield candidate
def find_spec(self, fullname, path=None, target=None):
if fullname not in self.packages:
return None
- search_locations = self.search_locations(fullname)
+ search_locations = list(map(str, self.search_locations(fullname)))
if not search_locations:
return None