proxywhirl.tui

Terminal User Interface (TUI) for ProxyWhirl.

Full-featured TUI with proxy sourcing, validation, analytics, health monitoring, exports, and configuration management.

## Features

  • Overview Tab: Real-time metrics dashboard and proxy table with color-coded health status

  • Fetch & Validate: Auto-fetch from all built-in proxy sources with batch validation

  • Export: Save proxy lists in CSV, JSON, YAML, or plain text formats

  • Test: Send HTTP requests (GET/POST/PUT/DELETE/HEAD/PATCH/OPTIONS) through proxies

  • Analytics: Statistics by protocol, country, and source

  • Health Tab: Circuit breaker status and health check controls

## Usage

Launch via CLI:

$ proxywhirl tui

Or programmatically:
>>> from proxywhirl import ProxyWhirl, run_tui
>>> rotator = ProxyWhirl()
>>> run_tui(rotator=rotator)

## Keyboard Shortcuts

  • Ctrl+C: Quit

  • Ctrl+R: Refresh all data

  • Ctrl+F: Go to Fetch & Validate tab

  • Ctrl+E: Go to Export tab

  • Ctrl+T: Go to Test tab

  • Delete: Delete selected proxy

  • Enter: View proxy details

  • F1: Show help

## Architecture

The TUI uses Textual framework with the following components: - MetricsPanel: Reactive metrics display - RetryMetricsPanel: Retry statistics display - ProxyTable: DataTable with health status indicators, filtering, and sorting - FilterPanel: Search and filter controls - SourceFetcherPanel: Multi-source proxy fetching - ExportPanel: Multi-format export functionality - StrategyPanel: Rotation strategy management - RequestTesterPanel: HTTP request testing with custom headers/body - AnalyticsPanel: Statistics and insights - ProxyControlPanel: Manual proxy management - HealthCheckPanel: Batch health checking with progress - CircuitBreakerPanel: Circuit breaker status display - ProxyDetailsScreen: Modal for detailed proxy information - ConfirmDeleteScreen: Deletion confirmation dialog

Classes

AnalyticsPanel

Panel for analytics and statistics.

CircuitBreakerPanel

Panel for displaying circuit breaker states.

ConfirmDeleteScreen

Modal screen for confirming proxy deletion.

ExportPanel

Panel for exporting proxy lists.

FilterPanel

Panel for filtering the proxy table.

HealthCheckPanel

Panel for running health checks.

HelpScreen

Modal screen showing comprehensive help information.

MetricsPanel

Display real-time metrics with sparkline visualization.

ProxyControlPanel

Panel for manually adding and removing proxies.

ProxyDetailsScreen

Modal screen showing detailed proxy information.

ProxyTable

DataTable widget for displaying proxies with row selection and sorting.

ProxyWhirlTUI

ProxyWhirl TUI Application.

RequestTesterPanel

Panel for testing proxy requests.

RetryMetricsPanel

Panel for displaying retry metrics.

SourceFetcherPanel

Panel for fetching proxies from sources.

StatusBar

Status bar showing current app state and quick stats.

StrategyPanel

Panel for managing rotation strategies.

Functions

run_tui([rotator])

Run the TUI application.

Module Contents

class proxywhirl.tui.AnalyticsPanel(content='', *, expand=False, shrink=False, markup=True, name=None, id=None, classes=None, disabled=False)[source]

Bases: textual.widgets.Static

Panel for analytics and statistics.

Initialize a Widget.

Parameters:
  • *children – Child widgets.

  • name (str | None) – The name of the widget.

  • id (str | None) – The ID of the widget in the DOM.

  • classes (str | None) – The CSS classes for the widget.

  • disabled (bool) – Whether the widget is disabled or not.

  • markup (bool) – Enable content markup?

  • content (textual.visual.VisualType)

  • expand (bool)

  • shrink (bool)

compose()[source]

Create analytics UI.

Return type:

textual.app.ComposeResult

class proxywhirl.tui.CircuitBreakerPanel(content='', *, expand=False, shrink=False, markup=True, name=None, id=None, classes=None, disabled=False)[source]

Bases: textual.widgets.Static

Panel for displaying circuit breaker states.

Initialize a Widget.

Parameters:
  • *children – Child widgets.

  • name (str | None) – The name of the widget.

  • id (str | None) – The ID of the widget in the DOM.

  • classes (str | None) – The CSS classes for the widget.

  • disabled (bool) – Whether the widget is disabled or not.

  • markup (bool) – Enable content markup?

  • content (textual.visual.VisualType)

  • expand (bool)

  • shrink (bool)

compose()[source]

Create circuit breaker UI.

Return type:

textual.app.ComposeResult

class proxywhirl.tui.ConfirmDeleteScreen(proxy_url, *args, **kwargs)[source]

Bases: textual.screen.ModalScreen

Modal screen for confirming proxy deletion.

Initialize with proxy URL to delete.

Parameters:

proxy_url (str)

action_confirm()[source]

Confirm deletion.

Return type:

None

async action_dismiss(result=None)[source]

Cancel and close modal.

Parameters:

result (textual.screen.ScreenResultType | None)

Return type:

None

compose()[source]

Create confirmation dialog.

Return type:

textual.app.ComposeResult

BINDINGS = [('escape', 'dismiss', 'Cancel'), ('enter', 'confirm', 'Confirm')][source]

A list of key bindings.

class proxywhirl.tui.ExportPanel(content='', *, expand=False, shrink=False, markup=True, name=None, id=None, classes=None, disabled=False)[source]

Bases: textual.widgets.Static

Panel for exporting proxy lists.

Initialize a Widget.

Parameters:
  • *children – Child widgets.

  • name (str | None) – The name of the widget.

  • id (str | None) – The ID of the widget in the DOM.

  • classes (str | None) – The CSS classes for the widget.

  • disabled (bool) – Whether the widget is disabled or not.

  • markup (bool) – Enable content markup?

  • content (textual.visual.VisualType)

  • expand (bool)

  • shrink (bool)

compose()[source]

Create export UI.

Return type:

textual.app.ComposeResult

class proxywhirl.tui.FilterPanel(content='', *, expand=False, shrink=False, markup=True, name=None, id=None, classes=None, disabled=False)[source]

Bases: textual.widgets.Static

Panel for filtering the proxy table.

Initialize a Widget.

Parameters:
  • *children – Child widgets.

  • name (str | None) – The name of the widget.

  • id (str | None) – The ID of the widget in the DOM.

  • classes (str | None) – The CSS classes for the widget.

  • disabled (bool) – Whether the widget is disabled or not.

  • markup (bool) – Enable content markup?

  • content (textual.visual.VisualType)

  • expand (bool)

  • shrink (bool)

compose()[source]

Create filter UI.

Return type:

textual.app.ComposeResult

class proxywhirl.tui.HealthCheckPanel(content='', *, expand=False, shrink=False, markup=True, name=None, id=None, classes=None, disabled=False)[source]

Bases: textual.widgets.Static

Panel for running health checks.

Initialize a Widget.

Parameters:
  • *children – Child widgets.

  • name (str | None) – The name of the widget.

  • id (str | None) – The ID of the widget in the DOM.

  • classes (str | None) – The CSS classes for the widget.

  • disabled (bool) – Whether the widget is disabled or not.

  • markup (bool) – Enable content markup?

  • content (textual.visual.VisualType)

  • expand (bool)

  • shrink (bool)

compose()[source]

Create health check UI.

Return type:

textual.app.ComposeResult

class proxywhirl.tui.HelpScreen(name=None, id=None, classes=None)[source]

Bases: textual.screen.ModalScreen

Modal screen showing comprehensive help information.

Initialize the screen.

Parameters:
  • name (str | None) – The name of the screen.

  • id (str | None) – The ID of the screen in the DOM.

  • classes (str | None) – The CSS classes for the screen.

async action_dismiss(result=None)[source]

Close the help modal.

Parameters:

result (textual.screen.ScreenResultType | None)

Return type:

None

close_help()[source]

Close help modal.

Return type:

None

compose()[source]

Create help modal content.

Return type:

textual.app.ComposeResult

BINDINGS = [('escape', 'dismiss', 'Close'), ('enter', 'dismiss', 'Close'), ('q', 'dismiss', 'Close')][source]

A list of key bindings.

class proxywhirl.tui.MetricsPanel(content='', *, expand=False, shrink=False, markup=True, name=None, id=None, classes=None, disabled=False)[source]

Bases: textual.widgets.Static

Display real-time metrics with sparkline visualization.

Initialize a Widget.

Parameters:
  • *children – Child widgets.

  • name (str | None) – The name of the widget.

  • id (str | None) – The ID of the widget in the DOM.

  • classes (str | None) – The CSS classes for the widget.

  • disabled (bool) – Whether the widget is disabled or not.

  • markup (bool) – Enable content markup?

  • content (textual.visual.VisualType)

  • expand (bool)

  • shrink (bool)

render()[source]

Render metrics display with sparklines and trends.

Return type:

rich.text.Text

update_history(latency, success_rate)[source]

Update metric history for sparklines.

Parameters:
Return type:

None

class proxywhirl.tui.ProxyControlPanel(content='', *, expand=False, shrink=False, markup=True, name=None, id=None, classes=None, disabled=False)[source]

Bases: textual.widgets.Static

Panel for manually adding and removing proxies.

Initialize a Widget.

Parameters:
  • *children – Child widgets.

  • name (str | None) – The name of the widget.

  • id (str | None) – The ID of the widget in the DOM.

  • classes (str | None) – The CSS classes for the widget.

  • disabled (bool) – Whether the widget is disabled or not.

  • markup (bool) – Enable content markup?

  • content (textual.visual.VisualType)

  • expand (bool)

  • shrink (bool)

compose()[source]

Create proxy control UI.

Return type:

textual.app.ComposeResult

class proxywhirl.tui.ProxyDetailsScreen(proxy, *args, **kwargs)[source]

Bases: textual.screen.ModalScreen

Modal screen showing detailed proxy information.

Initialize with proxy data.

Parameters:

proxy (proxywhirl.models.Proxy)

async action_dismiss(result=None)[source]

Dismiss the modal.

Parameters:

result (textual.screen.ScreenResultType | None)

Return type:

None

compose()[source]

Create modal content.

Return type:

textual.app.ComposeResult

copy_url_to_clipboard()[source]

Copy proxy URL to clipboard.

Return type:

None

BINDINGS = [('escape', 'dismiss', 'Close')][source]

A list of key bindings.

class proxywhirl.tui.ProxyTable(*args, **kwargs)[source]

Bases: textual.widgets.DataTable

DataTable widget for displaying proxies with row selection and sorting.

Initialize with row cursor for selection.

get_selected_proxy()[source]

Get the currently selected proxy.

Return type:

proxywhirl.models.Proxy | None

on_mount()[source]

Set up table columns.

Return type:

None

set_sort(column)[source]

Set sort column, toggling direction if same column.

Parameters:

column (str)

Return type:

None

toggle_favorite(proxy_url)[source]

Toggle favorite status for a proxy. Returns new favorite state.

Parameters:

proxy_url (str)

Return type:

bool

update_proxies(proxies, filter_text='', filter_protocol='all', filter_health='all', filter_country='all', filter_favorites_only=False)[source]

Update table with proxy data, applying filters and sorting.

Parameters:
  • proxies (list[proxywhirl.models.Proxy])

  • filter_text (str)

  • filter_protocol (str)

  • filter_health (str)

  • filter_country (str)

  • filter_favorites_only (bool)

Return type:

None

class proxywhirl.tui.ProxyWhirlTUI(rotator=None)[source]

Bases: textual.app.App

ProxyWhirl TUI Application.

Initialize TUI.

Parameters:

rotator (proxywhirl.rotator.ProxyWhirl | None)

action_analytics()[source]

Focus analytics tab.

Return type:

None

action_copy_url()[source]

Copy selected proxy URL to clipboard.

Return type:

None

action_cursor_bottom()[source]

Move cursor to last row (vim G key).

Return type:

None

action_cursor_down()[source]

Move cursor down in proxy table (vim j key).

Return type:

None

action_cursor_top()[source]

Move cursor to first row (vim g key).

Return type:

None

action_cursor_up()[source]

Move cursor up in proxy table (vim k key).

Return type:

None

action_delete_proxy()[source]

Delete key action to remove selected proxy.

Return type:

None

action_delete_unhealthy()[source]

Delete all unhealthy/dead proxies.

Return type:

None

action_export()[source]

Focus export tab.

Return type:

None

action_fetch()[source]

Focus fetch tab.

Return type:

None

Focus the search input box.

Return type:

None

action_health()[source]

Focus health tab.

Return type:

None

action_help()[source]

Show help message.

Return type:

None

action_import_proxies()[source]

Import proxies from clipboard or show import dialog.

Return type:

None

action_quick_test()[source]

Quick test selected proxy with httpbin.

Return type:

None

action_refresh()[source]

Refresh all data.

Return type:

None

action_show_help_modal()[source]

Show the comprehensive help modal.

Return type:

None

action_tab_1()[source]

Switch to tab 1 (Overview).

Return type:

None

action_tab_2()[source]

Switch to tab 2 (Fetch).

Return type:

None

action_tab_3()[source]

Switch to tab 3 (Export).

Return type:

None

action_tab_4()[source]

Switch to tab 4 (Test).

Return type:

None

action_tab_5()[source]

Switch to tab 5 (Analytics).

Return type:

None

action_tab_6()[source]

Switch to tab 6 (Health).

Return type:

None

action_test()[source]

Focus test tab.

Return type:

None

action_toggle_auto_refresh()[source]

Toggle auto-refresh on/off.

Return type:

None

action_toggle_favorite()[source]

Toggle favorite status for selected proxy.

Return type:

None

action_view_details()[source]

Enter key action to view proxy details.

Return type:

None

add_proxy()[source]

Add a proxy manually. Supports multiple proxies separated by newlines.

Return type:

None

apply_strategy()[source]

Apply selected rotation strategy.

Return type:

None

auto_refresh()[source]

Auto-refresh data every 5 seconds (if enabled).

Return type:

None

cancel_delete()[source]

Cancel proxy deletion.

Return type:

None

cancel_health_check()[source]

Cancel ongoing health check.

Return type:

None

clear_all_proxies()[source]

Clear all proxies from the pool.

Return type:

None

close_details()[source]

Close details modal.

Return type:

None

compose()[source]

Create TUI layout.

Return type:

textual.app.ComposeResult

confirm_delete()[source]

Confirm proxy deletion.

Return type:

None

export_all_proxies()[source]

Export all proxies.

Return type:

None

export_healthy_proxies()[source]

Export only healthy proxies.

Return type:

None

export_proxies(healthy_only=False)[source]

Export proxies to file.

Parameters:

healthy_only (bool)

Return type:

None

fetch_proxies()[source]

Fetch proxies from selected sources.

Return type:

None

async fetch_proxies_async()[source]

Async worker to fetch proxies.

Return type:

None

filter_country_changed(event)[source]

Handle country filter change.

Parameters:

event (textual.widgets.Select.Changed)

Return type:

None

filter_favorites_changed(event)[source]

Handle favorites filter change.

Parameters:

event (textual.widgets.Checkbox.Changed)

Return type:

None

filter_health_changed(event)[source]

Handle health filter change.

Parameters:

event (textual.widgets.Select.Changed)

Return type:

None

filter_protocol_changed(event)[source]

Handle protocol filter change.

Parameters:

event (textual.widgets.Select.Changed)

Return type:

None

filter_search_changed(event)[source]

Handle search filter change.

Parameters:

event (textual.widgets.Input.Changed)

Return type:

None

async health_check_async()[source]

Async worker to run health checks.

Return type:

None

on_mount()[source]

Called when app is mounted.

Return type:

None

preview_export()[source]

Show preview of export format.

Return type:

None

async quick_test_proxy_async(proxy)[source]

Async worker for quick proxy test.

Parameters:

proxy (proxywhirl.models.Proxy)

Return type:

None

refresh_all_data()[source]

Refresh all data displays.

Return type:

None

refresh_analytics()[source]

Refresh analytics display with histogram.

Return type:

None

refresh_analytics_button()[source]

Refresh analytics on button click.

Return type:

None

refresh_circuit_breakers()[source]

Refresh circuit breaker status display.

Return type:

None

refresh_metrics()[source]

Refresh metrics panel.

Return type:

None

refresh_retry_metrics()[source]

Refresh retry metrics panel.

Return type:

None

refresh_status_bar()[source]

Refresh the status bar.

Return type:

None

refresh_table()[source]

Refresh the proxy table with current filters.

Return type:

None

remove_selected_proxy()[source]

Remove the selected proxy from the pool.

Return type:

None

reset_all_circuit_breakers()[source]

Reset all circuit breakers.

Return type:

None

run_health_check()[source]

Run health check on all proxies.

Return type:

None

send_request()[source]

Send test request through proxy.

Return type:

None

async send_request_async()[source]

Async worker to send test request.

Return type:

None

sort_column(event)[source]

Handle column header click for sorting.

Parameters:

event (textual.widgets.DataTable.HeaderSelected)

Return type:

None

test_all_proxies()[source]

Test all healthy proxies.

Return type:

None

async test_all_proxies_async()[source]

Async worker to test all proxies.

Return type:

None

test_proxy_from_details()[source]

Test proxy from details modal.

Return type:

None

validate_all_proxies()[source]

Validate all proxies.

Return type:

None

async validate_proxies_async()[source]

Async worker to validate proxies.

Return type:

None

BINDINGS = [('ctrl+c', 'quit', 'Quit'), ('ctrl+r', 'refresh', 'Refresh'), ('ctrl+f', 'fetch', 'Fetch...[source]

The default key bindings.

CSS_PATH = 'tui.tcss'[source]

File paths to load CSS from.

SUB_TITLE = 'Intelligent Proxy Rotation'[source]

A class variable to set the default sub-title for the application.

To update the sub-title while the app is running, you can set the [sub_title][textual.app.App.sub_title] attribute. See also [the Screen.SUB_TITLE attribute][textual.screen.Screen.SUB_TITLE].

TITLE = '🌀 ProxyWhirl'[source]

A class variable to set the default title for the application.

To update the title while the app is running, you can set the [title][textual.app.App.title] attribute. See also [the Screen.TITLE attribute][textual.screen.Screen.TITLE].

class proxywhirl.tui.RequestTesterPanel(content='', *, expand=False, shrink=False, markup=True, name=None, id=None, classes=None, disabled=False)[source]

Bases: textual.widgets.Static

Panel for testing proxy requests.

Initialize a Widget.

Parameters:
  • *children – Child widgets.

  • name (str | None) – The name of the widget.

  • id (str | None) – The ID of the widget in the DOM.

  • classes (str | None) – The CSS classes for the widget.

  • disabled (bool) – Whether the widget is disabled or not.

  • markup (bool) – Enable content markup?

  • content (textual.visual.VisualType)

  • expand (bool)

  • shrink (bool)

compose()[source]

Create request tester UI.

Return type:

textual.app.ComposeResult

class proxywhirl.tui.RetryMetricsPanel(content='', *, expand=False, shrink=False, markup=True, name=None, id=None, classes=None, disabled=False)[source]

Bases: textual.widgets.Static

Panel for displaying retry metrics.

Initialize a Widget.

Parameters:
  • *children – Child widgets.

  • name (str | None) – The name of the widget.

  • id (str | None) – The ID of the widget in the DOM.

  • classes (str | None) – The CSS classes for the widget.

  • disabled (bool) – Whether the widget is disabled or not.

  • markup (bool) – Enable content markup?

  • content (textual.visual.VisualType)

  • expand (bool)

  • shrink (bool)

render()[source]

Render retry metrics display.

Return type:

rich.text.Text

class proxywhirl.tui.SourceFetcherPanel(content='', *, expand=False, shrink=False, markup=True, name=None, id=None, classes=None, disabled=False)[source]

Bases: textual.widgets.Static

Panel for fetching proxies from sources.

Initialize a Widget.

Parameters:
  • *children – Child widgets.

  • name (str | None) – The name of the widget.

  • id (str | None) – The ID of the widget in the DOM.

  • classes (str | None) – The CSS classes for the widget.

  • disabled (bool) – Whether the widget is disabled or not.

  • markup (bool) – Enable content markup?

  • content (textual.visual.VisualType)

  • expand (bool)

  • shrink (bool)

compose()[source]

Create source fetcher UI.

Return type:

textual.app.ComposeResult

class proxywhirl.tui.StatusBar(content='', *, expand=False, shrink=False, markup=True, name=None, id=None, classes=None, disabled=False)[source]

Bases: textual.widgets.Static

Status bar showing current app state and quick stats.

Initialize a Widget.

Parameters:
  • *children – Child widgets.

  • name (str | None) – The name of the widget.

  • id (str | None) – The ID of the widget in the DOM.

  • classes (str | None) – The CSS classes for the widget.

  • disabled (bool) – Whether the widget is disabled or not.

  • markup (bool) – Enable content markup?

  • content (textual.visual.VisualType)

  • expand (bool)

  • shrink (bool)

render()[source]

Render status bar.

Return type:

rich.text.Text

auto_refresh[source]

Number of seconds between automatic refresh, or None for no automatic refresh.

class proxywhirl.tui.StrategyPanel(content='', *, expand=False, shrink=False, markup=True, name=None, id=None, classes=None, disabled=False)[source]

Bases: textual.widgets.Static

Panel for managing rotation strategies.

Initialize a Widget.

Parameters:
  • *children – Child widgets.

  • name (str | None) – The name of the widget.

  • id (str | None) – The ID of the widget in the DOM.

  • classes (str | None) – The CSS classes for the widget.

  • disabled (bool) – Whether the widget is disabled or not.

  • markup (bool) – Enable content markup?

  • content (textual.visual.VisualType)

  • expand (bool)

  • shrink (bool)

compose()[source]

Create strategy management UI.

Return type:

textual.app.ComposeResult

proxywhirl.tui.run_tui(rotator=None)[source]

Run the TUI application.

Parameters:

rotator (proxywhirl.rotator.ProxyWhirl | None)

Return type:

None