← back to ColonelPanicX__garmin-extract

Function bodies 373 total

All specs Real LLM only Function bodies
_do_both method · python · L285-L288 (4 LOC)
garmin_extract/gui/screens/automation.py
    def _do_both(self) -> None:
        self._set_buttons_enabled(False)
        self._feedback.setText("Uploading CSVs and syncing Sheets...")
        Thread(target=self._run_both, daemon=True).start()
_run_drive method · python · L290-L301 (12 LOC)
garmin_extract/gui/screens/automation.py
    def _run_drive(self) -> None:
        try:
            from garmin_extract._google_drive import upload_csvs_to_drive

            result = upload_csvs_to_drive()
            if result["ok"]:
                names = ", ".join(f["name"] for f in result["files"])
                self._signals.drive_op_done.emit(f"\u2713 Uploaded: {names}")
            else:
                self._signals.drive_op_done.emit(f"Error: {result['error']}")
        except Exception as exc:
            self._signals.drive_op_done.emit(f"Error: {exc}")
_run_sheets method · python · L303-L313 (11 LOC)
garmin_extract/gui/screens/automation.py
    def _run_sheets(self) -> None:
        try:
            from garmin_extract._google_drive import sync_to_sheets

            result = sync_to_sheets()
            if result["ok"]:
                self._signals.drive_op_done.emit("\u2713 Google Sheet updated")
            else:
                self._signals.drive_op_done.emit(f"Error: {result['error']}")
        except Exception as exc:
            self._signals.drive_op_done.emit(f"Error: {exc}")
_run_both method · python · L315-L335 (21 LOC)
garmin_extract/gui/screens/automation.py
    def _run_both(self) -> None:
        try:
            from garmin_extract._google_drive import sync_to_sheets, upload_csvs_to_drive

            lines = []
            drive_result = upload_csvs_to_drive()
            if drive_result["ok"]:
                names = ", ".join(f["name"] for f in drive_result["files"])
                lines.append(f"\u2713 Drive: {names}")
            else:
                lines.append(f"Drive error: {drive_result['error']}")

            sheets_result = sync_to_sheets()
            if sheets_result["ok"]:
                lines.append("\u2713 Sheets updated")
            else:
                lines.append(f"Sheets error: {sheets_result['error']}")

            self._signals.drive_op_done.emit("  |  ".join(lines))
        except Exception as exc:
            self._signals.drive_op_done.emit(f"Error: {exc}")
_on_drive_op_done method · python · L337-L340 (4 LOC)
garmin_extract/gui/screens/automation.py
    def _on_drive_op_done(self, text: str) -> None:
        self._feedback.setText(text)
        self._set_buttons_enabled(True)
        self.refresh_status()
_date_range_label function · python · L26-L30 (5 LOC)
garmin_extract/gui/screens/pull_data.py
def _date_range_label(days: int) -> str:
    today = date.today()
    start = today - timedelta(days=days)
    end = today - timedelta(days=1)
    return f"{start.isoformat()}  \u2192  {end.isoformat()}"
_parse_date function · python · L33-L39 (7 LOC)
garmin_extract/gui/screens/pull_data.py
def _parse_date(s: str) -> str | None:
    for fmt in ("%Y-%m-%d", "%m/%d/%Y", "%m/%d/%y", "%m-%d-%Y", "%m-%d-%y"):
        try:
            return datetime.strptime(s.strip(), fmt).strftime("%Y-%m-%d")
        except ValueError:
            continue
    return None
Citation: Repobility (2026). State of AI-Generated Code. https://repobility.com/research/
_find_fetch_new_range function · python · L42-L58 (17 LOC)
garmin_extract/gui/screens/pull_data.py
def _find_fetch_new_range() -> tuple[str, int] | None:
    """Returns (start_iso, days) or None if up to date. Raises FileNotFoundError."""
    import re

    data_dir = Path(__file__).parent.parent.parent.parent / "data" / "garmin"
    if not data_dir.exists():
        raise FileNotFoundError("no data directory")
    date_re = re.compile(r"^\d{4}-\d{2}-\d{2}\.json$")
    dates = sorted(f.stem for f in data_dir.glob("*.json") if date_re.match(f.name))
    if not dates:
        raise FileNotFoundError("no date files")
    latest = date.fromisoformat(dates[-1])
    yesterday = date.today() - timedelta(days=1)
    start = latest + timedelta(days=1)
    if start > yesterday:
        return None
    return start.isoformat(), (yesterday - start).days + 1
_SectionHeader class · python · L64-L73 (10 LOC)
garmin_extract/gui/screens/pull_data.py
class _SectionHeader(QLabel):
    """A dim section header label (SYNC, RECENT, CUSTOM, etc.)."""

    def __init__(self, text: str, parent: QWidget | None = None) -> None:
        super().__init__(text, parent)
        self.setStyleSheet(
            "font-size: 12px; font-weight: bold; color: #6c7086;"
            " letter-spacing: 1px; background: transparent;"
            " border-bottom: 1px solid #45475a; padding-bottom: 4px;"
        )
__init__ method · python · L67-L73 (7 LOC)
garmin_extract/gui/screens/pull_data.py
    def __init__(self, text: str, parent: QWidget | None = None) -> None:
        super().__init__(text, parent)
        self.setStyleSheet(
            "font-size: 12px; font-weight: bold; color: #6c7086;"
            " letter-spacing: 1px; background: transparent;"
            " border-bottom: 1px solid #45475a; padding-bottom: 4px;"
        )
_ActionButton class · python · L79-L103 (25 LOC)
garmin_extract/gui/screens/pull_data.py
class _ActionButton(QPushButton):
    """A menu-style button matching the TUI's pull options."""

    def __init__(self, label: str, hint: str = "", parent: QWidget | None = None) -> None:
        display = f"{label}    {hint}" if hint else label
        super().__init__(display, parent)
        self.setCursor(Qt.CursorShape.PointingHandCursor)
        self.setStyleSheet("""
            QPushButton {
                text-align: left;
                padding: 10px 16px;
                background-color: transparent;
                border: 1px solid transparent;
                border-radius: 6px;
                font-size: 14px;
                color: #cdd6f4;
            }
            QPushButton:hover {
                background-color: #313244;
                border-color: #45475a;
            }
            QPushButton:pressed {
                background-color: #45475a;
            }
            """)
__init__ method · python · L82-L103 (22 LOC)
garmin_extract/gui/screens/pull_data.py
    def __init__(self, label: str, hint: str = "", parent: QWidget | None = None) -> None:
        display = f"{label}    {hint}" if hint else label
        super().__init__(display, parent)
        self.setCursor(Qt.CursorShape.PointingHandCursor)
        self.setStyleSheet("""
            QPushButton {
                text-align: left;
                padding: 10px 16px;
                background-color: transparent;
                border: 1px solid transparent;
                border-radius: 6px;
                font-size: 14px;
                color: #cdd6f4;
            }
            QPushButton:hover {
                background-color: #313244;
                border-color: #45475a;
            }
            QPushButton:pressed {
                background-color: #45475a;
            }
            """)
_DateDialog class · python · L109-L188 (80 LOC)
garmin_extract/gui/screens/pull_data.py
class _DateDialog(QDialog):
    """Dialog for entering a start date and optional day count."""

    def __init__(
        self,
        title: str,
        show_days: bool = False,
        hint: str = "",
        parent: QWidget | None = None,
    ) -> None:
        super().__init__(parent)
        self.setWindowTitle(title)
        self.setMinimumWidth(400)
        self.setModal(True)

        self.result_start: str = ""
        self.result_days: int = 1

        layout = QVBoxLayout(self)
        layout.setSpacing(10)

        if hint:
            hint_label = QLabel(hint)
            hint_label.setWordWrap(True)
            hint_label.setStyleSheet("color: #6c7086; font-size: 13px;")
            layout.addWidget(hint_label)

        layout.addWidget(QLabel("Start date"))
        self._date_input = QLineEdit()
        self._date_input.setPlaceholderText("YYYY-MM-DD  or  MM/DD/YYYY")
        layout.addWidget(self._date_input)

        if show_days:
            layout.addWidget(QLabel(
__init__ method · python · L112-L164 (53 LOC)
garmin_extract/gui/screens/pull_data.py
    def __init__(
        self,
        title: str,
        show_days: bool = False,
        hint: str = "",
        parent: QWidget | None = None,
    ) -> None:
        super().__init__(parent)
        self.setWindowTitle(title)
        self.setMinimumWidth(400)
        self.setModal(True)

        self.result_start: str = ""
        self.result_days: int = 1

        layout = QVBoxLayout(self)
        layout.setSpacing(10)

        if hint:
            hint_label = QLabel(hint)
            hint_label.setWordWrap(True)
            hint_label.setStyleSheet("color: #6c7086; font-size: 13px;")
            layout.addWidget(hint_label)

        layout.addWidget(QLabel("Start date"))
        self._date_input = QLineEdit()
        self._date_input.setPlaceholderText("YYYY-MM-DD  or  MM/DD/YYYY")
        layout.addWidget(self._date_input)

        if show_days:
            layout.addWidget(QLabel("Number of days"))
            self._days_input = QLineEdit()
            self._days_input.setPl
_validate method · python · L166-L188 (23 LOC)
garmin_extract/gui/screens/pull_data.py
    def _validate(self) -> None:
        raw = self._date_input.text().strip()
        parsed = _parse_date(raw)
        if not parsed:
            self._error.setText(f"Cannot parse '{raw}' — try 2025-04-07")
            self._error.show()
            return

        self.result_start = parsed

        if self._days_input:
            days_raw = self._days_input.text().strip()
            self.result_days = int(days_raw) if days_raw.isdigit() and int(days_raw) > 0 else 1
        else:
            start_dt = datetime.strptime(parsed, "%Y-%m-%d").date()
            yesterday = date.today() - timedelta(days=1)
            self.result_days = (yesterday - start_dt).days + 1
            if self.result_days <= 0:
                self._error.setText("Start date must be before today.")
                self._error.show()
                return

        self.accept()
All rows scored by the Repobility analyzer (https://repobility.com)
PullDataPage class · python · L194-L366 (173 LOC)
garmin_extract/gui/screens/pull_data.py
class PullDataPage(QWidget):
    """The Pull Data page shown in the main window's stacked widget."""

    def __init__(self, parent: QWidget | None = None) -> None:
        super().__init__(parent)

        layout = QVBoxLayout(self)
        layout.setContentsMargins(40, 32, 40, 32)
        layout.setSpacing(4)

        heading = QLabel("Pull Data")
        heading.setObjectName("heading")
        layout.addWidget(heading)

        sub = QLabel("Download your Garmin health metrics")
        sub.setObjectName("subheading")
        layout.addWidget(sub)

        layout.addSpacing(16)

        # ── SYNC ──────────────────────────────────────
        layout.addWidget(_SectionHeader("SYNC"))
        btn = _ActionButton("Fetch new", "pull all dates not yet in local data")
        btn.clicked.connect(self._fetch_new)
        layout.addWidget(btn)

        layout.addSpacing(8)

        # ── RECENT ────────────────────────────────────
        layout.addWidget(_SectionHeader("RECENT"))
        b
__init__ method · python · L197-L264 (68 LOC)
garmin_extract/gui/screens/pull_data.py
    def __init__(self, parent: QWidget | None = None) -> None:
        super().__init__(parent)

        layout = QVBoxLayout(self)
        layout.setContentsMargins(40, 32, 40, 32)
        layout.setSpacing(4)

        heading = QLabel("Pull Data")
        heading.setObjectName("heading")
        layout.addWidget(heading)

        sub = QLabel("Download your Garmin health metrics")
        sub.setObjectName("subheading")
        layout.addWidget(sub)

        layout.addSpacing(16)

        # ── SYNC ──────────────────────────────────────
        layout.addWidget(_SectionHeader("SYNC"))
        btn = _ActionButton("Fetch new", "pull all dates not yet in local data")
        btn.clicked.connect(self._fetch_new)
        layout.addWidget(btn)

        layout.addSpacing(8)

        # ── RECENT ────────────────────────────────────
        layout.addWidget(_SectionHeader("RECENT"))
        btn = _ActionButton("Yesterday", _yesterday())
        btn.clicked.connect(self._pull_yesterday)
      
_start_pull method · python · L268-L281 (14 LOC)
garmin_extract/gui/screens/pull_data.py
    def _start_pull(self, start_date: str, days: int, label: str, **kwargs: object) -> None:
        """Open the pull progress dialog."""
        from garmin_extract.gui.screens.pull_progress import PullProgressDialog

        dlg = PullProgressDialog(
            start_date=start_date,
            days=days,
            label=label,
            no_skip=bool(kwargs.get("no_skip")),
            rebuild_only=bool(kwargs.get("rebuild_only")),
            zip_path=str(kwargs.get("zip_path", "")),
            parent=self,
        )
        dlg.exec()
_fetch_new method · python · L283-L309 (27 LOC)
garmin_extract/gui/screens/pull_data.py
    def _fetch_new(self) -> None:
        try:
            result = _find_fetch_new_range()
        except FileNotFoundError:
            dlg = _DateDialog(
                "Full History Pull",
                hint="No local data found. Choose a start date to begin pulling.",
                parent=self,
            )
            if dlg.exec() == QDialog.DialogCode.Accepted:
                end = date.fromisoformat(dlg.result_start) + timedelta(days=dlg.result_days - 1)
                self._start_pull(
                    dlg.result_start,
                    dlg.result_days,
                    f"Full history  ({dlg.result_start} \u2192 {end.isoformat()})",
                )
            return

        if result is None:
            QMessageBox.information(
                self, "Fetch New", "Already up to date \u2014 no new dates to pull."
            )
            return

        start, days = result
        end = (date.fromisoformat(start) + timedelta(days=days - 1)).isoformat()
 
_pull_yesterday method · python · L311-L313 (3 LOC)
garmin_extract/gui/screens/pull_data.py
    def _pull_yesterday(self) -> None:
        yest = _yesterday()
        self._start_pull(yest, 1, f"Yesterday  ({yest})")
_pull_7 method · python · L315-L317 (3 LOC)
garmin_extract/gui/screens/pull_data.py
    def _pull_7(self) -> None:
        start = (date.today() - timedelta(days=7)).isoformat()
        self._start_pull(start, 7, f"Last 7 days  ({_date_range_label(7)})")
_pull_30 method · python · L319-L321 (3 LOC)
garmin_extract/gui/screens/pull_data.py
    def _pull_30(self) -> None:
        start = (date.today() - timedelta(days=30)).isoformat()
        self._start_pull(start, 30, f"Last 30 days  ({_date_range_label(30)})")
_pull_custom method · python · L323-L335 (13 LOC)
garmin_extract/gui/screens/pull_data.py
    def _pull_custom(self) -> None:
        dlg = _DateDialog(
            "Custom Date Pull",
            show_days=True,
            hint="Formats: YYYY-MM-DD  \u00b7  MM/DD/YYYY  \u00b7  MM/DD/YY",
            parent=self,
        )
        if dlg.exec() == QDialog.DialogCode.Accepted:
            self._start_pull(
                dlg.result_start,
                dlg.result_days,
                f"Custom  ({dlg.result_start}, {dlg.result_days}d)",
            )
Open data scored by Repobility · https://repobility.com
_pull_history method · python · L337-L352 (16 LOC)
garmin_extract/gui/screens/pull_data.py
    def _pull_history(self) -> None:
        dlg = _DateDialog(
            "Full History Pull",
            hint=(
                "Pulls every day from your chosen start date through yesterday.\n"
                "Formats: YYYY-MM-DD  \u00b7  MM/DD/YYYY  \u00b7  MM/DD/YY"
            ),
            parent=self,
        )
        if dlg.exec() == QDialog.DialogCode.Accepted:
            yesterday = (date.today() - timedelta(days=1)).isoformat()
            self._start_pull(
                dlg.result_start,
                dlg.result_days,
                f"Full history  ({dlg.result_start} \u2192 {yesterday})",
            )
_import_zip method · python · L354-L363 (10 LOC)
garmin_extract/gui/screens/pull_data.py
    def _import_zip(self) -> None:
        path, _ = QFileDialog.getOpenFileName(
            self,
            "Select Garmin Export",
            "",
            "Zip files (*.zip);;All files (*)",
        )
        if not path:
            return
        self._start_pull("", 0, "Garmin bulk export import", zip_path=path)
_PullSignals class · python · L36-L43 (8 LOC)
garmin_extract/gui/screens/pull_progress.py
class _PullSignals(QObject):
    log_line = Signal(str)
    day_start = Signal(str, int)  # date_str, n_metrics
    day_skipped = Signal(str)  # date_str
    metric_done = Signal(str, bool)  # name, is_ok
    mfa_needed = Signal()
    finished = Signal(int)  # return code
    error = Signal(str)
_MfaDialog class · python · L49-L97 (49 LOC)
garmin_extract/gui/screens/pull_progress.py
class _MfaDialog(QDialog):
    """Modal dialog to capture an MFA code."""

    def __init__(self, parent: QWidget | None = None) -> None:
        super().__init__(parent)
        self.setWindowTitle("MFA Code Required")
        self.setMinimumWidth(400)
        self.setModal(True)

        layout = QVBoxLayout(self)
        layout.setSpacing(10)

        title = QLabel("MFA Code Required")
        title.setStyleSheet("font-size: 16px; font-weight: bold; color: #f9e2af;")
        layout.addWidget(title)

        hint = QLabel("Check your email for a 6-digit code and enter it below.")
        hint.setStyleSheet("color: #6c7086;")
        layout.addWidget(hint)

        self._code_input = QLineEdit()
        self._code_input.setPlaceholderText("000000")
        self._code_input.setMaxLength(6)
        self._code_input.returnPressed.connect(self._submit)
        layout.addWidget(self._code_input)

        self._error = QLabel()
        self._error.setStyleSheet("color: #f38ba8;")
        s
__init__ method · python · L52-L88 (37 LOC)
garmin_extract/gui/screens/pull_progress.py
    def __init__(self, parent: QWidget | None = None) -> None:
        super().__init__(parent)
        self.setWindowTitle("MFA Code Required")
        self.setMinimumWidth(400)
        self.setModal(True)

        layout = QVBoxLayout(self)
        layout.setSpacing(10)

        title = QLabel("MFA Code Required")
        title.setStyleSheet("font-size: 16px; font-weight: bold; color: #f9e2af;")
        layout.addWidget(title)

        hint = QLabel("Check your email for a 6-digit code and enter it below.")
        hint.setStyleSheet("color: #6c7086;")
        layout.addWidget(hint)

        self._code_input = QLineEdit()
        self._code_input.setPlaceholderText("000000")
        self._code_input.setMaxLength(6)
        self._code_input.returnPressed.connect(self._submit)
        layout.addWidget(self._code_input)

        self._error = QLabel()
        self._error.setStyleSheet("color: #f38ba8;")
        self._error.hide()
        layout.addWidget(self._error)

        btn_layout
_submit method · python · L90-L97 (8 LOC)
garmin_extract/gui/screens/pull_progress.py
    def _submit(self) -> None:
        code = self._code_input.text().strip()
        if not code:
            self._error.setText("Please enter the 6-digit code.")
            self._error.show()
            return
        MFA_FILE.write_text(code + "\n")
        self.accept()
_RuntimeCredsDialog class · python · L103-L164 (62 LOC)
garmin_extract/gui/screens/pull_progress.py
class _RuntimeCredsDialog(QDialog):
    """Dialog for entering credentials at runtime when none are saved."""

    def __init__(self, parent: QWidget | None = None) -> None:
        super().__init__(parent)
        self.setWindowTitle("Enter Garmin Connect Credentials")
        self.setMinimumWidth(450)
        self.setModal(True)

        self.result_email = ""
        self.result_password = ""

        layout = QVBoxLayout(self)
        layout.setSpacing(10)

        hint = QLabel("No saved credentials found. These will not be stored.")
        hint.setStyleSheet("color: #6c7086;")
        layout.addWidget(hint)

        layout.addWidget(QLabel("Email"))
        self._email = QLineEdit()
        self._email.setPlaceholderText("[email protected]")
        layout.addWidget(self._email)

        layout.addWidget(QLabel("Password"))
        self._password = QLineEdit()
        self._password.setEchoMode(QLineEdit.EchoMode.Password)
        self._password.setPlaceholderText("Garmin Connect 
__init__ method · python · L106-L147 (42 LOC)
garmin_extract/gui/screens/pull_progress.py
    def __init__(self, parent: QWidget | None = None) -> None:
        super().__init__(parent)
        self.setWindowTitle("Enter Garmin Connect Credentials")
        self.setMinimumWidth(450)
        self.setModal(True)

        self.result_email = ""
        self.result_password = ""

        layout = QVBoxLayout(self)
        layout.setSpacing(10)

        hint = QLabel("No saved credentials found. These will not be stored.")
        hint.setStyleSheet("color: #6c7086;")
        layout.addWidget(hint)

        layout.addWidget(QLabel("Email"))
        self._email = QLineEdit()
        self._email.setPlaceholderText("[email protected]")
        layout.addWidget(self._email)

        layout.addWidget(QLabel("Password"))
        self._password = QLineEdit()
        self._password.setEchoMode(QLineEdit.EchoMode.Password)
        self._password.setPlaceholderText("Garmin Connect password")
        self._password.returnPressed.connect(self._submit)
        layout.addWidget(self._password)
All rows above produced by Repobility · https://repobility.com
_submit method · python · L149-L164 (16 LOC)
garmin_extract/gui/screens/pull_progress.py
    def _submit(self) -> None:
        email = self._email.text().strip()
        password = self._password.text().strip()
        if not email:
            self._error.setText("Email is required.")
            self._error.show()
            self._email.setFocus()
            return
        if not password:
            self._error.setText("Password is required.")
            self._error.show()
            self._password.setFocus()
            return
        self.result_email = email
        self.result_password = password
        self.accept()
_DayState class · python · L171-L176 (6 LOC)
garmin_extract/gui/screens/pull_progress.py
class _DayState:
    date_str: str
    total: int = 0
    done: int = 0
    failed: int = 0
    status: str = "pending"  # pending | active | done | skipped
__init__ method · python · L185-L236 (52 LOC)
garmin_extract/gui/screens/pull_progress.py
    def __init__(
        self,
        start_date: str,
        days: int,
        label: str,
        no_skip: bool = False,
        rebuild_only: bool = False,
        zip_path: str = "",
        parent: QWidget | None = None,
    ) -> None:
        super().__init__(parent)
        self.setWindowTitle(label)
        self.setMinimumSize(900, 600)
        self.resize(1000, 700)
        self.setModal(True)

        self._start_date = start_date
        self._days = days
        self._label = label
        self._no_skip = no_skip
        self._rebuild_only = rebuild_only
        self._zip_path = zip_path
        self._proc: subprocess.Popen | None = None
        self._mfa_shown = False
        self._email = ""
        self._password = ""

        # Display mode
        if days > 1:
            self._mode = "day"
            self._day_states = self._init_day_states()
            self._current_day_index = -1
            self._metrics_per_day = 0
        elif days == 1:
            self._m
_build_ui method · python · L238-L331 (94 LOC)
garmin_extract/gui/screens/pull_progress.py
    def _build_ui(self) -> None:
        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)

        # ── Split view: log + metrics ─────────────────
        splitter = QSplitter(Qt.Orientation.Horizontal)

        # Log panel (left)
        self._log = QTextEdit()
        self._log.setReadOnly(True)
        self._log.setStyleSheet(
            "background-color: #1e1e2e; color: #cdd6f4; font-family: monospace;"
            " font-size: 13px; border: none; border-right: 1px solid #45475a;"
        )
        splitter.addWidget(self._log)

        # Metrics panel (right)
        right = QWidget()
        right_layout = QVBoxLayout(right)
        right_layout.setContentsMargins(12, 12, 12, 12)

        self._header = QLabel(self._label)
        self._header.setStyleSheet(
            "font-size: 16px; font-weight: bold; color: #89b4fa; background: transparent;"
        )
        right_layout.addWidget(self._header)

        self._subheade
_wire_signals method · python · L333-L341 (9 LOC)
garmin_extract/gui/screens/pull_progress.py
    def _wire_signals(self) -> None:
        self._signals = _PullSignals()
        self._signals.log_line.connect(self._on_log_line)
        self._signals.day_start.connect(self._on_day_start)
        self._signals.day_skipped.connect(self._on_day_skipped)
        self._signals.metric_done.connect(self._on_metric_done)
        self._signals.mfa_needed.connect(self._on_mfa_needed)
        self._signals.finished.connect(self._on_finished)
        self._signals.error.connect(self._on_error)
_check_creds_and_start method · python · L345-L360 (16 LOC)
garmin_extract/gui/screens/pull_progress.py
    def _check_creds_and_start(self) -> None:
        from garmin_extract._credentials import load_credentials

        email, password = load_credentials()
        if password:
            self._email = email
            self._password = password
            self._start_pull()
        else:
            dlg = _RuntimeCredsDialog(self)
            if dlg.exec() == QDialog.DialogCode.Accepted:
                self._email = dlg.result_email
                self._password = dlg.result_password
                self._start_pull()
            else:
                self.reject()
_start_pull method · python · L364-L366 (3 LOC)
garmin_extract/gui/screens/pull_progress.py
    def _start_pull(self) -> None:
        cmd = self._build_cmd()
        Thread(target=self._run_pull, args=(cmd,), daemon=True).start()
_build_cmd method · python · L368-L390 (23 LOC)
garmin_extract/gui/screens/pull_progress.py
    def _build_cmd(self) -> list[str]:
        if self._rebuild_only:
            return [sys.executable, "-u", str(SCRIPTS_ROOT / "reports" / "build_garmin_csvs.py")]
        if self._zip_path:
            return [
                sys.executable,
                "-u",
                str(SCRIPTS_ROOT / "pullers" / "garmin_import_export.py"),
                "--zip",
                self._zip_path,
            ]
        cmd = [
            sys.executable,
            "-u",
            str(SCRIPTS_ROOT / "pullers" / "garmin.py"),
            "--date",
            self._start_date,
            "--days",
            str(self._days),
        ]
        if self._no_skip:
            cmd.append("--no-skip")
        return cmd
Citation: Repobility (2026). State of AI-Generated Code. https://repobility.com/research/
_run_pull method · python · L392-L421 (30 LOC)
garmin_extract/gui/screens/pull_progress.py
    def _run_pull(self, cmd: list[str]) -> None:
        env = os.environ.copy()
        env["PYTHONUTF8"] = "1"  # force UTF-8 I/O in subprocess (Windows cp1252 can't encode ✓)
        if self._email:
            env["GARMIN_EMAIL"] = self._email
        if self._password:
            env["GARMIN_PASSWORD"] = self._password

        try:
            proc = subprocess.Popen(
                cmd,
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT,
                stdin=subprocess.DEVNULL,
                encoding="utf-8",
                cwd=str(ROOT),
                env=env,
            )
            self._proc = proc
            assert proc.stdout is not None
            for raw_line in iter(proc.stdout.readline, ""):
                line = raw_line.rstrip("\n")
                self._signals.log_line.emit(line)
                self._parse_line(line)
            proc.wait()
            self._proc = None
            self._signals.finished.emit(proc.returnc
_parse_line method · python · L423-L457 (35 LOC)
garmin_extract/gui/screens/pull_progress.py
    def _parse_line(self, line: str) -> None:
        """Parse subprocess output and emit appropriate signals."""
        stripped = line.strip()

        # "[2025-04-06] Pulling N metrics..."
        if stripped.startswith("[") and "] Pulling " in stripped and "metrics" in stripped:
            try:
                date_str = stripped[1 : stripped.index("]")]
                parts = stripped.split()
                idx = next((i for i, p in enumerate(parts) if p == "Pulling"), -1)
                n = int(parts[idx + 1]) if idx >= 0 else 0
                self._signals.day_start.emit(date_str, n)
            except (ValueError, IndexError):
                pass
            return

        # "[2025-04-06] Already pulled — skipping"
        if "Already pulled" in stripped and "skipping" in stripped:
            try:
                date_str = stripped[1 : stripped.index("]")]
                self._signals.day_skipped.emit(date_str)
            except ValueError:
                pass
    
_init_day_states method · python · L461-L469 (9 LOC)
garmin_extract/gui/screens/pull_progress.py
    def _init_day_states(self) -> list[_DayState]:
        states: list[_DayState] = []
        try:
            start = date.fromisoformat(self._start_date)
            for i in range(self._days):
                states.append(_DayState((start + timedelta(days=i)).isoformat()))
        except ValueError:
            pass
        return states
_initial_panel_body method · python · L471-L476 (6 LOC)
garmin_extract/gui/screens/pull_progress.py
    def _initial_panel_body(self) -> str:
        if self._mode == "day":
            return self._render_day_list()
        if self._mode == "metric":
            return "Waiting for first metric..."
        return "Starting..."
_on_day_start method · python · L483-L512 (30 LOC)
garmin_extract/gui/screens/pull_progress.py
    def _on_day_start(self, date_str: str, n_metrics: int) -> None:
        if self._mode == "day":
            idx = next(
                (i for i, s in enumerate(self._day_states) if s.date_str == date_str),
                -1,
            )
            if idx == -1:
                self._day_states.append(_DayState(date_str))
                idx = len(self._day_states) - 1
            self._current_day_index = idx
            self._day_states[idx].status = "active"
            self._day_states[idx].total = n_metrics

            if self._metrics_per_day == 0 and n_metrics > 0:
                self._metrics_per_day = n_metrics
                self._overall_total = self._days * n_metrics
                self._progress.setMaximum(self._overall_total)

            self._refresh_panel()
            self._status.setText(f"Day {idx + 1} of {self._days}  \u00b7  {date_str}")

        elif self._mode == "metric":
            self._day_total = n_metrics
            self._day_done = 0
       
_on_day_skipped method · python · L514-L526 (13 LOC)
garmin_extract/gui/screens/pull_progress.py
    def _on_day_skipped(self, date_str: str) -> None:
        if self._mode == "day":
            idx = next(
                (i for i, s in enumerate(self._day_states) if s.date_str == date_str),
                -1,
            )
            if idx >= 0:
                self._day_states[idx].status = "skipped"
                advance = self._metrics_per_day if self._metrics_per_day else 1
                self._overall_done += advance
                self._progress.setValue(self._overall_done)
                self._refresh_panel()
                self._status.setText(f"Skipped {date_str}  (already pulled)")
_on_metric_done method · python · L528-L556 (29 LOC)
garmin_extract/gui/screens/pull_progress.py
    def _on_metric_done(self, name: str, is_ok: bool) -> None:
        if self._mode == "metric":
            self._live_metrics.append((name, "done" if is_ok else "fail"))
            self._day_done += 1
            self._progress.setValue(self._day_done)
            self._refresh_panel()
            self._status.setText(f"{self._day_done} / {self._day_total or '?'} metrics")

        elif self._mode == "day" and self._current_day_index >= 0:
            ds = self._day_states[self._current_day_index]
            if is_ok:
                ds.done += 1
            else:
                ds.failed += 1

            tally = ds.done + ds.failed
            if ds.total == 0 or tally <= ds.total:
                self._overall_done += 1
                self._progress.setValue(self._overall_done)

            if ds.total > 0 and tally >= ds.total:
                ds.status = "done"

            self._refresh_panel()
            self._status.setText(
                f"Day {self._current_day_inde
_on_mfa_needed method · python · L558-L561 (4 LOC)
garmin_extract/gui/screens/pull_progress.py
    def _on_mfa_needed(self) -> None:
        if not self._mfa_shown:
            self._mfa_shown = True
            _MfaDialog(self).exec()
All rows scored by the Repobility analyzer (https://repobility.com)
_on_finished method · python · L563-L581 (19 LOC)
garmin_extract/gui/screens/pull_progress.py
    def _on_finished(self, returncode: int) -> None:
        if self._mode == "simple":
            self._progress.setMaximum(1)
            self._progress.setValue(1)
            if returncode == 0:
                self._metric_list.setText("\u2713 Complete")
            else:
                self._metric_list.setText("\u2717 Failed")

        if returncode == 0:
            self._status.setText("Complete \u2713")
            self._log.append("\nDone.")
        else:
            self._status.setText(f"Finished with errors (exit {returncode})")
            self._log.append(f"\nProcess exited with code {returncode}.")

        self._cancel_btn.setText("Close")
        self._cancel_btn.clicked.disconnect()
        self._cancel_btn.clicked.connect(self.accept)
_on_error method · python · L583-L588 (6 LOC)
garmin_extract/gui/screens/pull_progress.py
    def _on_error(self, msg: str) -> None:
        self._log.append(f"\nError: {msg}")
        self._status.setText("Error")
        self._cancel_btn.setText("Close")
        self._cancel_btn.clicked.disconnect()
        self._cancel_btn.clicked.connect(self.accept)
_refresh_panel method · python · L592-L596 (5 LOC)
garmin_extract/gui/screens/pull_progress.py
    def _refresh_panel(self) -> None:
        if self._mode == "day":
            self._metric_list.setText(self._render_day_list())
        elif self._mode == "metric":
            self._metric_list.setText(self._render_metric_list())
‹ prevpage 2 / 8next ›