Fixing local imports.

This commit is contained in:
Roland 2025-12-02 16:07:32 -07:00 • committed by lrnselfreliance
parent fa9fb9ab08
commit 79e0700609
6 changed files with 33 additions and 23 deletions

View file

@ -372,6 +372,7 @@ async def perpetual_check_for_updates():
Updates shared_ctx with update info for the /api/status endpoint.
Only runs on native installs (not Docker).
"""
# Local import to avoid loading upgrade module at startup
from wrolpi.upgrade import check_for_update
# Don't check for updates in Docker environments

View file

@ -81,6 +81,7 @@ async def get_upload_singlefile(request: Request):
@register_switch_handler('singlefile_upload_switch_handler')
async def singlefile_upload_switch_handler(url=None):
"""Used by `post_upload_singlefile` to upload a single file"""
# Local imports to avoid circular import: downloader -> archive -> api -> downloader
from wrolpi.downloader import Download
from . import ArchiveDownloader
@ -153,7 +154,6 @@ async def generate_screenshot_switch_handler(archive_id=None):
try:
await lib.generate_archive_screenshot(archive_id)
# Always send success event since exceptions are raised on failure
from modules.archive import Archive
archive = lib.get_archive(archive_id=archive_id)
location = archive.location
name = archive.file_group.title or archive.file_group.url

View file

@ -1,5 +1,4 @@
import base64
import base64
import gzip
import json
import os
@ -14,19 +13,21 @@ from typing import Optional, Tuple, List, Union
from urllib.parse import urlparse
import pytz
from sqlalchemy import asc
from sqlalchemy import asc, func, BigInteger
from sqlalchemy.orm import Session
from modules.archive.models import Archive
from wrolpi import dates
from wrolpi.cmd import READABILITY_BIN, run_command
from wrolpi.collections import Collection
from wrolpi.common import get_media_directory, logger, extract_domain, escape_file_name, aiohttp_post, \
format_html_string, split_lines_by_length, get_html_soup, get_title_from_html, get_wrolpi_config, html_screenshot, \
ConfigFile
from wrolpi.common import get_media_directory, get_relative_to_media_directory, logger, extract_domain, \
escape_file_name, aiohttp_post, format_html_string, split_lines_by_length, get_html_soup, get_title_from_html, \
get_wrolpi_config, html_screenshot, ConfigFile
from wrolpi.dates import now, Seconds
from wrolpi.db import get_db_session, get_db_curs, optional_session
from wrolpi.errors import UnknownArchive, InvalidOrderBy, InvalidDatetime
from wrolpi.files.lib import handle_file_group_search_results
from wrolpi.files.models import FileGroup
from wrolpi.events import Events
from wrolpi.switches import register_switch_handler, ActivateSwitchMethod
from wrolpi.tags import tag_append_sub_select_where
@ -607,8 +608,8 @@ def link_domain_and_downloads(session: Session):
- Recurring downloads whose destination is within the domain collection's directory (including subdirectories)
- RSS downloads with sub_downloader='archive' (matched by URL domain)
"""
# Local import to avoid circular import: downloader -> archive -> downloader
from wrolpi.downloader import Download
from wrolpi.collections.models import Collection
# Only Downloads with a frequency can be a Collection Download.
downloads = list(session.query(Download).filter(Download.frequency.isnot(None)).all())
@ -855,9 +856,6 @@ def get_domains():
This is a thin wrapper around Collection queries that adds archive-specific statistics.
Returns a list of dicts with collection id, domain name, url_count, and total size.
"""
from sqlalchemy import func, BigInteger
from wrolpi.files.models import FileGroup
with get_db_session() as session:
# Query all domain collections with archive statistics in a single query
# This uses ORM for better maintainability while keeping performance
@ -1032,7 +1030,6 @@ def search_archives(search_str: str, domain: str, limit: int, offset: int, order
'''.strip()
logger.debug(stmt, params)
from wrolpi.files.lib import handle_file_group_search_results
results, total = handle_file_group_search_results(stmt, params)
return results, total
@ -1058,7 +1055,6 @@ async def search_domains_by_name(name: str, limit: int = 5, session: Session = N
.all()
# Convert to old Domain format for backward compatibility
from wrolpi.common import get_relative_to_media_directory
archive_dir = get_archive_directory()
return [
{
@ -1155,8 +1151,6 @@ async def generate_archive_screenshot(archive_id: int) -> pathlib.Path:
ValueError: If Archive has no singlefile
RuntimeError: If screenshot generation fails
"""
from wrolpi.db import get_db_session
with get_db_session() as session:
archive = Archive.find_by_id(archive_id, session=session)

View file

@ -91,6 +91,7 @@ class Archive(Base, ModelHelper):
@staticmethod
def can_model(file_group: FileGroup) -> bool:
# Local import to avoid circular import within archive module
from modules.archive.lib import is_singlefile_file
if file_group.mimetype.startswith('text') and is_singlefile_file(file_group.primary_path):
return True
@ -98,6 +99,7 @@ class Archive(Base, ModelHelper):
@staticmethod
def do_model(file_group: FileGroup, session: Session) -> 'Archive':
# Local import to avoid circular import within archive module
from modules.archive import model_archive
archive = model_archive(file_group, session)
archive.validate()
@ -155,6 +157,7 @@ class Archive(Base, ModelHelper):
@property
def singlefile_file(self) -> Optional[dict]:
# Local import to avoid circular import within archive module
from modules.archive.lib import is_singlefile_file
for file in self.file_group.my_html_files():
if is_singlefile_file(file['path']):
@ -315,6 +318,7 @@ class Archive(Base, ModelHelper):
def apply_domain(self):
"""Get the domain collection from the URL."""
# Local import to avoid circular import within archive module
from modules.archive.lib import get_or_create_domain_collection
collection = None
if self.file_group.url:
@ -332,6 +336,7 @@ class Archive(Base, ModelHelper):
def apply_metadata(self):
"""Read and apply <meta> (and more) data from the Singlefile HTML."""
# Local import to avoid circular import within archive module
from modules.archive import lib
contents = self.singlefile_path.read_bytes()
@ -365,6 +370,7 @@ class Archive(Base, ModelHelper):
"""Create a new Archive and FileGroup from the provided paths.
The files will be read and Archive data extracted."""
# Local import to avoid circular import within archive module
from modules.archive import model_archive
file_group = FileGroup.from_paths(session, *paths)
archive = model_archive(file_group, session)

View file

@ -16,7 +16,7 @@ from wrolpi.errors import ValidationError
from wrolpi.events import Events
from wrolpi.tags import Tag
from .errors import UnknownCollection
from .models import Collection
from .models import Collection, validate_collection_directory
logger = logger.getChild(__name__)
@ -68,6 +68,7 @@ def get_collections(kind: Optional[str] = None, session: Session = None) -> List
# Add type-specific statistics
if collection.kind == 'domain':
# Add archive statistics for domain collections
# Local imports to avoid circular import: collections -> archive -> collections
from modules.archive import Archive
from wrolpi.files.models import FileGroup
@ -86,6 +87,7 @@ def get_collections(kind: Optional[str] = None, session: Session = None) -> List
elif collection.kind == 'channel':
# Add video statistics for channel collections
# Local imports to avoid circular import: collections -> videos -> collections
from modules.videos.models import Video, Channel
from wrolpi.files.models import FileGroup
@ -144,6 +146,7 @@ def get_collection_with_stats(collection_id: int, session: Session = None) -> di
# This can be extended for different collection types
if collection.kind == 'domain':
# Add archive statistics for domain collections
# Local imports to avoid circular import: collections -> archive -> collections
from modules.archive import Archive
from wrolpi.files.models import FileGroup
@ -162,6 +165,7 @@ def get_collection_with_stats(collection_id: int, session: Session = None) -> di
elif collection.kind == 'channel':
# Add video statistics for channel collections
# Local imports to avoid circular import: collections -> videos -> collections
from modules.videos.models import Video, Channel
from wrolpi.files.models import FileGroup
@ -329,7 +333,6 @@ def update_collection(
if directory is not None:
if directory:
# Convert relative path to absolute with validation
from .models import validate_collection_directory
directory_path = validate_collection_directory(directory)
collection.directory = directory_path
else:
@ -362,6 +365,7 @@ def update_collection(
# Trigger domain config save if this is a domain collection
if collection.kind == 'domain':
# Local import to avoid circular import: collections -> archive -> collections
from modules.archive.lib import save_domains_config
save_domains_config.activate_switch()
@ -380,6 +384,7 @@ def refresh_collection(collection_id: int, send_events: bool = True) -> None:
UnknownCollection: If collection not found
ValidationError: If collection has no directory
"""
# Local import to avoid circular import: collections -> files -> collections
from wrolpi.files.lib import refresh_files
with get_db_session() as session:
@ -439,6 +444,7 @@ def tag_collection(
# Trigger domain config save if this is a domain collection
if collection.kind == 'domain':
# Local import to avoid circular import: collections -> archive -> collections
from modules.archive.lib import save_domains_config
save_domains_config.activate_switch()
@ -462,7 +468,6 @@ def tag_collection(
# Determine target directory
if directory:
# User specified a directory - validate it
from .models import validate_collection_directory
target_directory = validate_collection_directory(directory)
elif collection.directory:
# Use existing directory
@ -470,6 +475,7 @@ def tag_collection(
else:
# Suggest a directory based on collection type and name
if collection.kind == 'domain':
# Local import to avoid circular import: collections -> archive -> collections
from modules.archive.lib import get_archive_directory
base_dir = get_archive_directory()
else:
@ -485,6 +491,7 @@ def tag_collection(
# Trigger domain config save if this is a domain collection
if collection.kind == 'domain':
# Local import to avoid circular import: collections -> archive -> collections
from modules.archive.lib import save_domains_config
save_domains_config.activate_switch()
@ -595,14 +602,15 @@ def delete_collection(
# Orphan child Archives if this is a domain collection
if collection.kind == 'domain':
# Local imports to avoid circular import: collections -> archive -> collections
from modules.archive.models import Archive
from modules.archive.lib import save_domains_config
archives = session.query(Archive).filter_by(collection_id=collection_id).all()
for archive in archives:
archive.collection_id = None
session.flush()
# Trigger domain config save
from modules.archive.lib import save_domains_config
save_domains_config.activate_switch()
# Delete the collection

View file

@ -5,8 +5,9 @@ from sqlalchemy import Column, Integer, String, ForeignKey, Text, DateTime, Inde
from sqlalchemy.orm import relationship, Session
from sqlalchemy.orm.collections import InstrumentedList
from wrolpi.common import Base, ModelHelper, logger, get_media_directory
from wrolpi.common import Base, ModelHelper, logger, get_media_directory, get_relative_to_media_directory
from wrolpi.db import optional_session
from wrolpi.errors import ValidationError
from wrolpi.files.models import FileGroup
from wrolpi.media_path import MediaPathType
from wrolpi.tags import Tag
@ -30,8 +31,6 @@ def validate_collection_directory(directory: pathlib.Path) -> pathlib.Path:
Raises:
ValidationError: If absolute path is outside media directory
"""
from wrolpi.errors import ValidationError
media_directory = get_media_directory()
directory = pathlib.Path(directory)
@ -197,6 +196,7 @@ class Collection(ModelHelper, Base):
Raises:
InvalidDownload: If url or frequency is missing
"""
# Local imports to avoid circular import: collections -> downloader -> collections
from wrolpi.downloader import Download, download_manager
from wrolpi.errors import InvalidDownload
@ -683,8 +683,6 @@ class Collection(ModelHelper, Base):
Returns directory as a string relative to media directory if applicable.
"""
from wrolpi.common import get_relative_to_media_directory
# Get directory as string, relative to media directory
directory_str = None
if self.directory:
@ -717,10 +715,12 @@ class Collection(ModelHelper, Base):
archive/<Tag>/<Domain Name>
"""
if self.kind == 'channel':
# Local import to avoid circular import: collections -> videos -> collections
from modules.videos.lib import format_videos_destination
return format_videos_destination(self.name, tag_name, None)
elif self.kind == 'domain':
# Use configured archive directory for domain collections
# Local import to avoid circular import: collections -> archive -> collections
from modules.archive.lib import get_archive_directory
base = get_archive_directory()
if tag_name:
@ -737,6 +737,7 @@ class Collection(ModelHelper, Base):
Similar to Channel.move_channel but without download management.
"""
# Local imports to avoid circular import: collections -> files/events/flags -> collections
from wrolpi.files.lib import move as move_files, refresh_files
from wrolpi.events import Events
from wrolpi import flags