refactor: Fix __init__.py - remove duplicates, add lazy loading for Qt deps

This commit is contained in:
devmatrix 2026-02-16 20:59:05 +00:00
parent b2ec4e2f0f
commit 6f3b6f6781
5 changed files with 1230 additions and 6 deletions

533
ARCHITECTURE.md Normal file
View File

@ -0,0 +1,533 @@
# EU-Utility Architecture
> System architecture, component design, and data flow documentation
---
## System Overview
EU-Utility is built on a **modular plugin architecture** with clear separation of concerns. The system is organized into three main layers:
1. **Core Layer** - Foundation services and APIs
2. **Plugin Layer** - Extensible functionality modules
3. **UI Layer** - User interface components and overlays
```
┌─────────────────────────────────────────────────────────────────┐
│ UI Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
│ │ Overlay │ │ Widgets │ │ Activity Bar │ │
│ │ Window │ │ (Draggable)│ │ (Taskbar + App Drawer) │ │
│ └──────┬──────┘ └──────┬──────┘ └───────────┬─────────────┘ │
└─────────┼────────────────┼─────────────────────┼────────────────┘
│ │ │
└────────────────┴──────────┬──────────┘
┌─────────────────────────────────────┼─────────────────────────────┐
│ Plugin Layer │ │
│ ┌──────────────────────────────────┘ │
│ │ │
│ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ │ Search │ │ Calculator│ │ Tracker │ │ Scanner │ │
│ │ │ Plugins │ │ Plugins │ │ Plugins │ │ Plugins │ │
│ │ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ │
│ │ │ │ │ │ │
│ │ └─────────────┴──────┬──────┴─────────────┘ │
│ │ │ │
│ │ ┌────────┴────────┐ │
│ │ │ BasePlugin API │ │
│ │ │ (Base Class) │ │
│ │ └────────┬────────┘ │
│ └─────────────────────────────┼─────────────────────────────────┘
└────────────────────────────────┼─────────────────────────────────┘
┌────────────────────────────────┼─────────────────────────────────┐
│ Core Layer│ │
│ ┌─────────────────────────────┘ │
│ │ │
│ │ ┌──────────────────────────────────────────────────────┐ │
│ │ │ Three-Tier API System │ │
│ │ ├───────────────┬───────────────┬───────────────────────┤ │
│ │ │ PluginAPI │ WidgetAPI │ ExternalAPI │ │
│ │ │ (Services) │ (Overlays) │ (REST/Webhooks) │ │
│ │ └───────┬───────┴───────┬───────┴───────────┬───────────┘ │
│ │ │ │ │ │
│ │ ┌───────┴───────┐ ┌─────┴─────┐ ┌───────────┴──────────┐ │
│ │ │ Core Services │ │ Event │ │ Data Layer │ │
│ │ │ │ │ Bus │ │ │ │
│ │ │ • Window Mgr │ │ (Pub/Sub) │ │ • SQLite Store │ │
│ │ │ • OCR Service │ │ │ │ • Settings │ │
│ │ │ • Screenshot │ │ │ │ • Plugin States │ │
│ │ │ • Log Reader │ │ │ │ • Activity Log │ │
│ │ │ • Nexus API │ │ │ │ │ │
│ │ │ • HTTP Client │ │ │ │ │ │
│ │ │ • Audio │ │ │ │ │ │
│ │ └───────────────┘ └───────────┘ └──────────────────────┘ │
│ │ │
│ │ ┌──────────────────────────────────────────────────────┐ │
│ │ │ Plugin Manager │ │
│ │ │ (Discovery, Loading, Lifecycle, Dependencies) │ │
│ │ └──────────────────────────────────────────────────────┘ │
│ │ │
│ └────────────────────────────────────────────────────────────────┘
└────────────────────────────────────────────────────────────────────┘
```
---
## Core Layer
### Three-Tier API System
The Core provides a unified API organized into three tiers:
#### 1. PluginAPI
Primary interface for plugin developers to access core services.
```python
from core.api import get_api
api = get_api()
# Window Management
window = api.get_eu_window()
is_focused = api.is_eu_focused()
# OCR
if api.ocr_available():
text = api.recognize_text(region=(100, 100, 200, 50))
# Data Storage
api.set_data("key", value)
value = api.get_data("key", default)
```
**Available Services:**
- `LogReader` - Read and monitor Entropia Universe chat logs
- `WindowManager` - Detect and interact with EU window
- `OCRService` - Screen text recognition (EasyOCR/Tesseract/PaddleOCR)
- `Screenshot` - Screen capture with multiple backends
- `NexusAPI` - Entropia Nexus item database integration
- `HTTPClient` - Cached web requests with rate limiting
- `Audio` - Sound playback and volume control
- `Clipboard` - Cross-platform copy/paste
- `Notifications` - Desktop toast notifications
- `EventBus` - Pub/sub event system
- `DataStore` - Persistent key-value storage
- `TaskManager` - Background task execution
#### 2. WidgetAPI
Manages overlay widgets - floating UI components.
```python
from core.api import get_widget_api
widget_api = get_widget_api()
# Create widget
widget = widget_api.create_widget(
name="loot_tracker",
title="Loot Tracker",
size=(400, 300)
)
widget.show()
```
**Features:**
- Draggable overlay widgets
- Size and position persistence
- Opacity control
- Lock/unlock positioning
- Layout helpers (grid, cascade)
#### 3. ExternalAPI
Provides REST endpoints and webhook support for third-party integrations.
```python
from core.api import get_external_api
ext = get_external_api()
ext.start_server(port=8080)
# Register endpoint
@ext.endpoint("stats", methods=["GET"])
def get_stats():
return {"kills": 100, "loot": "50 PED"}
```
**Features:**
- REST API server with CORS
- Incoming/outgoing webhooks
- HMAC authentication
- IPC (Inter-Process Communication)
- Server-Sent Events (SSE)
---
## Plugin Layer
### Plugin Architecture
All plugins inherit from `BasePlugin` and implement a standard interface:
```
┌─────────────────────────────────────────┐
│ BasePlugin (Abstract) │
├─────────────────────────────────────────┤
│ Metadata: name, version, author, etc. │
├─────────────────────────────────────────┤
│ initialize() → Setup plugin │
│ get_ui() → Return QWidget │
│ on_show() → Overlay visible │
│ on_hide() → Overlay hidden │
│ on_hotkey() → Hotkey pressed │
│ shutdown() → Cleanup resources │
├─────────────────────────────────────────┤
│ Helper Methods: │
│ • OCR capture │
│ • Screenshot │
│ • Log reading │
│ • Data storage │
│ • Event publishing/subscribing │
│ • Nexus API access │
│ • Background tasks │
│ • Notifications │
└─────────────────────────────────────────┘
┌───────────┼───────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Search │ │ Tracker │ │Utility │
│ Plugins │ │ Plugins │ │ Plugins │
└─────────┘ └─────────┘ └─────────┘
```
### Plugin Categories
| Category | Purpose | Examples |
|----------|---------|----------|
| **Search** | Data lookup | Universal Search, Nexus Search, TP Runner |
| **Trackers** | Progress monitoring | Loot, Skills, Codex, Missions, Globals |
| **Calculators** | Game math | DPP, Crafting, Enhancer, Markup |
| **Scanners** | OCR-based tools | Game Reader, Skill Scanner |
| **Integration** | External services | Spotify Controller, Chat Logger |
| **System** | Core functionality | Dashboard, Settings, Plugin Store |
### Plugin Lifecycle
```
Discovery
┌──────────┐
│ Import │
└────┬─────┘
┌──────────┐ No ┌──────────┐
│ Enabled? │───────────▶│ Skip │
└────┬─────┘ └──────────┘
│ Yes
┌──────────┐
│ Load │
│ Module │
└────┬─────┘
┌──────────┐ Error ┌──────────┐
│Initialize│───────────▶│ Disable │
└────┬─────┘ └──────────┘
│ Success
┌──────────┐
│ Running │◀───────┐
└────┬─────┘ │
│ │
▼ │
┌──────────┐ │
│ Hotkey │ │
│ Pressed │────────┘
└──────────┘
┌──────────┐
│ Shutdown │
└──────────┘
```
---
## Event System
### Event Bus Architecture
The Event Bus provides typed, filterable pub/sub communication:
```
┌─────────────────────────────────────────────────┐
│ Event Bus │
├─────────────────────────────────────────────────┤
│ │
│ Publisher ─────┐ │
│ │ │
│ ▼ │
│ ┌─────────────────────────┐ │
│ │ Event Router │ │
│ │ (Type + Filter Match) │ │
│ └────────────┬────────────┘ │
│ │ │
│ ┌───────────┼───────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ Sub │ │ Sub │ │ Sub │ │
│ │ #1 │ │ #2 │ │ #3 │ │
│ └──────┘ └──────┘ └──────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ Plugin A Plugin B Plugin C │
│ │
│ ┌────────────────────────────────────────────┐ │
│ │ Event Types: │ │
│ │ • SkillGainEvent │ │
│ │ • LootEvent │ │
│ │ • DamageEvent │ │
│ │ • GlobalEvent │ │
│ │ • ChatEvent │ │
│ │ • EconomyEvent │ │
│ │ • SystemEvent │ │
│ └────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
```
### Event Flow Example
```python
# Plugin A publishes loot event
from core.event_bus import LootEvent
self.publish_typed(LootEvent(
mob_name="Daikiba",
items=[{"name": "Animal Oil", "value": 0.05}],
total_tt_value=0.05
))
# Plugin B subscribes with filter
self.subscribe_typed(
LootEvent,
on_loot,
mob_types=["Daikiba", "Atrox"] # Filter
)
```
---
## Data Flow
### Data Layer Architecture
```
┌─────────────────────────────────────────────────────────┐
│ Data Layer │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ SQLite Data Store │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │user_prefs │ │plugin_states│ │ │
│ │ ├─────────────┤ ├─────────────┤ │ │
│ │ │• settings │ │• enabled │ │ │
│ │ │• hotkeys │ │• version │ │ │
│ │ │• theme │ │• settings │ │ │
│ │ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │sessions │ │activity_log │ │ │
│ │ ├─────────────┤ ├─────────────┤ │ │
│ │ │• start_time │ │• timestamp │ │ │
│ │ │• end_time │ │• category │ │ │
│ │ │• stats │ │• action │ │ │
│ │ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │dashboard │ │hotkeys │ │ │
│ │ │_widgets │ │ │ │ │
│ │ ├─────────────┤ ├─────────────┤ │ │
│ │ │• position │ │• key_combo │ │ │
│ │ │• size │ │• action │ │ │
│ │ │• config │ │• plugin_id │ │ │
│ │ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Data Access Pattern │ │
│ │ │ │
│ │ Plugin ──▶ API ──▶ SQLiteStore ──▶ SQLite DB │ │
│ │ │ │
│ │ All data is JSON-serialized for flexibility │ │
│ └─────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
```
---
## UI Architecture
### Overlay System
```
┌─────────────────────────────────────────────────────────────┐
│ Desktop │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Main Overlay Window │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ Plugin Tab Bar │ │ │
│ │ │ [Dash][Search][Calc][Track][...] │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ ┌─────────┬──────────────────────────────────┐ │ │
│ │ │ Plugin │ │ │ │
│ │ │ List │ Active Plugin Content │ │ │
│ │ │ │ │ │ │
│ │ │ • Search│ ┌──────────────────────┐ │ │ │
│ │ │ • Calc │ │ │ │ │ │
│ │ │ • Track │ │ Plugin UI Here │ │ │ │
│ │ │ • ... │ │ │ │ │ │
│ │ │ │ └──────────────────────┘ │ │ │
│ │ └─────────┴──────────────────────────────────┘ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ Quick Actions Bar │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────┼─────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Floating │ │ Widget │ │ Activity │ │
│ │ Icon │ │ (Loot) │ │ Bar │ │
│ │ (Draggable)│ │ (Draggable)│ │(Bottom/Top) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
```
### Component Hierarchy
```
QApplication
└── EUUtilityApp
├── MainOverlayWindow
│ ├── PluginTabBar
│ ├── PluginSidebar
│ ├── PluginContentArea
│ └── QuickActionsBar
├── FloatingIcon (always on top)
├── ActivityBar (optional, bottom/top)
│ ├── StartButton (opens AppDrawer)
│ ├── PinnedPlugins
│ ├── SearchBox
│ └── Clock/Settings
├── WidgetOverlay
│ └── Individual Widgets
└── TrayIcon
└── ContextMenu
```
---
## Security Architecture
### Data Protection
```
┌─────────────────────────────────────────┐
│ Security Layer │
├─────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────┐ │
│ │ Input Sanitization │ │
│ │ • Path traversal protection │ │
│ │ • SQL injection prevention │ │
│ │ • XSS protection │ │
│ └─────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────┐ │
│ │ Data Encryption │ │
│ │ • AES-256 for sensitive data │ │
│ │ • Secure key storage │ │
│ │ • Encrypted settings │ │
│ └─────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────┐ │
│ │ File Operations │ │
│ │ • Atomic writes (temp files) │ │
│ │ • Proper file permissions │ │
│ │ • Safe temp file handling │ │
│ └─────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────┐ │
│ │ Plugin Isolation │ │
│ │ • Try/except around plugin ops │ │
│ │ • Separate error handling │ │
│ │ • Resource cleanup on crash │ │
│ └─────────────────────────────────┘ │
│ │
└─────────────────────────────────────────┘
```
---
## Performance Optimizations
### Caching Strategy
| Layer | Cache Type | TTL | Purpose |
|-------|------------|-----|---------|
| HTTP Client | Response cache | Configurable | API responses |
| Nexus API | Item data | 5 minutes | Item/market data |
| Icon Manager | Loaded icons | Session | UI performance |
| Plugin Manager | Loaded plugins | Session | Startup time |
| Settings | Config values | Session | Fast access |
### Resource Management
```python
# Lazy initialization pattern
class ExpensiveService:
def __init__(self):
self._initialized = False
self._resource = None
@property
def resource(self):
if not self._initialized:
self._resource = self._create_expensive_resource()
self._initialized = True
return self._resource
```
---
## Technology Stack
| Component | Technology |
|-----------|------------|
| **Language** | Python 3.11+ |
| **UI Framework** | PyQt6 |
| **Database** | SQLite |
| **HTTP Client** | `requests` with caching |
| **OCR** | EasyOCR / Tesseract / PaddleOCR |
| **Screenshot** | PIL / MSS / Win32 (Windows) |
| **Audio** | pygame.mixer / simpleaudio |
| **Task Queue** | ThreadPoolExecutor |
---
## See Also
- [API Reference](./API.md) - Complete API documentation
- [Plugin Development](./docs/PLUGIN_DEVELOPMENT.md) - Creating plugins
- [Contributing](./CONTRIBUTING.md) - Contribution guidelines

120
MANIFEST.in Normal file
View File

@ -0,0 +1,120 @@
# EU-Utility - MANIFEST.in
# Controls what files are included in the source distribution (sdist)
# https://packaging.python.org/en/latest/guides/using-manifest-in/
# =============================================================================
# INCLUDE PATTERNS
# =============================================================================
# Core package files
recursive-include core *.py
recursive-include core *.json *.yaml *.yml
recursive-include core *.css *.qss *.ui
recursive-include core *.png *.jpg *.jpeg *.gif *.ico *.svg
# Plugin files
recursive-include plugins *.py
recursive-include plugins *.json *.yaml *.yml
recursive-include plugins *.css *.qss *.ui
recursive-include plugins/assets *.png *.jpg *.jpeg *.gif *.ico *.svg *.ttf *.woff *.woff2
recursive-include plugins/templates *.html *.txt *.md
# Documentation
recursive-include docs *.md *.rst *.txt
recursive-include docs *.png *.jpg *.jpeg *.gif *.svg
include README.md
include CONTRIBUTING.md
include CHANGELOG.md
include SECURITY_AUDIT_REPORT.md
include LICENSE
# Configuration files
include requirements.txt
include requirements-dev.txt
include pytest.ini
# Build and packaging
include setup.py
include pyproject.toml
include MANIFEST.in
include Makefile
# GitHub templates and workflows
recursive-include .github *.md *.yml *.yaml
# Assets
recursive-include assets *.png *.jpg *.jpeg *.gif *.ico *.svg
recursive-include benchmarks *.py *.md
# =============================================================================
# EXCLUDE PATTERNS
# =============================================================================
# Test files (excluded from distribution)
recursive-exclude tests *
recursive-exclude * test_*.py *_test.py
recursive-exclude * __pycache__
recursive-exclude * *.py[co]
recursive-exclude * *.so
recursive-exclude * .pytest_cache
recursive-exclude * .coverage
recursive-exclude * coverage.xml
recursive-exclude * htmlcov
# Development environment
recursive-exclude * .venv
recursive-exclude * venv
recursive-exclude * env
recursive-exclude * .env
recursive-exclude * .env.*
# Version control
recursive-exclude * .git
recursive-exclude * .gitignore
recursive-exclude * .gitattributes
# IDE and editor files
recursive-exclude * .vscode
recursive-exclude * .idea
recursive-exclude * *.swp
recursive-exclude * *.swo
recursive-exclude * *~
recursive-exclude * .DS_Store
recursive-exclude * Thumbs.db
# Build artifacts
recursive-exclude * build
recursive-exclude * dist
recursive-exclude * *.egg-info
recursive-exclude * .eggs
# CI/CD (excluded - these are for development only)
recursive-exclude .github/workflows *
# Temporary and cache files
recursive-exclude * .tox
recursive-exclude * .mypy_cache
recursive-exclude * .hypothesis
recursive-exclude * .ruff_cache
recursive-exclude * *.log
recursive-exclude * logs/*.log
recursive-exclude * *.db
recursive-exclude * *.sqlite
recursive-exclude * *.sqlite3
# Security and sensitive files (never include these)
exclude .env
exclude .env.local
exclude .env.production
exclude secrets.json
exclude credentials.json
exclude *secret*
exclude *password*
exclude *credential*
exclude *_key*
exclude private_*
# Debug and vulnerable files (exclude from distribution)
recursive-exclude * *_vulnerable.py
recursive-exclude * *_insecure.py
recursive-exclude * *_debug.py

328
pyproject.toml Normal file
View File

@ -0,0 +1,328 @@
# EU-Utility - Modern Python Packaging Configuration
# https://github.com/ImpulsiveFPS/EU-Utility
[build-system]
requires = [
"setuptools>=65.0",
"wheel>=0.41.0",
"setuptools-scm>=7.0",
]
build-backend = "setuptools.build_meta"
[project]
name = "eu-utility"
version = "2.1.0"
description = "A versatile Entropia Universe utility suite with a modular plugin system"
readme = "README.md"
license = {text = "MIT"}
authors = [
{name = "ImpulsiveFPS", email = "dev@impulsivefps.com"},
]
maintainers = [
{name = "ImpulsiveFPS", email = "dev@impulsivefps.com"},
]
keywords = [
"entropia universe",
"game utility",
"overlay",
"plugin system",
"ocr",
"tracker",
"calculator",
"gaming",
"mmorpg",
]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: End Users/Desktop",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX :: Linux",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Games/Entertainment",
"Topic :: Utilities",
"Topic :: Desktop Environment",
"Environment :: X11 Applications :: Qt",
"Environment :: Win32 (MS Windows)",
"Natural Language :: English",
]
requires-python = ">=3.11"
dependencies = [
"PyQt6>=6.4.0,<7.0.0",
"keyboard>=0.13.5,<1.0.0",
"psutil>=5.9.0,<6.0.0",
"pyperclip>=1.8.2,<2.0.0",
"easyocr>=1.7.0,<2.0.0",
"pytesseract>=0.3.10,<1.0.0",
"pyautogui>=0.9.54,<1.0.0",
"pillow>=10.0.0,<11.0.0",
"requests>=2.28.0,<3.0.0",
"urllib3>=1.26.0,<3.0.0",
"numpy>=1.21.0,<2.0.0",
'portalocker>=2.7.0; platform_system=="Windows"',
'pywin32>=306; platform_system=="Windows"',
]
[project.optional-dependencies]
spotify = [
"spotipy>=2.23.0,<3.0.0",
'pycaw>=20230407; platform_system=="Windows"',
]
discord = [
"pypresence>=4.3.0,<5.0.0",
]
all = [
"spotipy>=2.23.0,<3.0.0",
'pycaw>=20230407; platform_system=="Windows"',
"pypresence>=4.3.0,<5.0.0",
]
dev = [
"pytest>=7.4.0,<8.0.0",
"pytest-cov>=4.1.0,<5.0.0",
"pytest-mock>=3.11.0,<4.0.0",
"pytest-benchmark>=4.0.0,<5.0.0",
"pytest-qt>=4.2.0,<5.0.0",
"pytest-xvfb>=2.0.0,<3.0.0",
"black>=23.0.0,<24.0.0",
"flake8>=6.0.0,<7.0.0",
"mypy>=1.5.0,<2.0.0",
"isort>=5.12.0,<6.0.0",
"pydocstyle>=6.3.0,<7.0.0",
"bandit>=1.7.5,<2.0.0",
"safety>=2.3.0,<3.0.0",
"sphinx>=7.0.0,<8.0.0",
"sphinx-rtd-theme>=1.3.0,<2.0.0",
"myst-parser>=2.0.0,<3.0.0",
"build>=0.10.0,<1.0.0",
"twine>=4.0.0,<5.0.0",
"wheel>=0.41.0,<1.0.0",
"pre-commit>=3.4.0,<4.0.0",
]
[project.scripts]
eu-utility = "core.main:main"
eu-utility-secure = "core.main_optimized:main"
[project.gui-scripts]
eu-utility-gui = "core.main:main"
[project.urls]
Homepage = "https://github.com/ImpulsiveFPS/EU-Utility"
Documentation = "https://github.com/ImpulsiveFPS/EU-Utility/tree/main/docs"
Repository = "https://github.com/ImpulsiveFPS/EU-Utility.git"
"Bug Tracker" = "https://github.com/ImpulsiveFPS/EU-Utility/issues"
Changelog = "https://github.com/ImpulsiveFPS/EU-Utility/blob/main/CHANGELOG.md"
# =============================================================================
# TOOL CONFIGURATIONS
# =============================================================================
# Black - Code Formatter
[tool.black]
line-length = 100
target-version = ["py311", "py312"]
include = '\.pyi?$'
extend-exclude = '''
/(
\.git
| \.venv
| venv
| env
| build
| dist
| __pycache__
| \.pytest_cache
| htmlcov
| \.tox
| migrations
)/
'''
skip-string-normalization = false
preview = false
# isort - Import Sorting
[tool.isort]
profile = "black"
line_length = 100
multi_line_output = 3
include_trailing_comma = true
force_grid_wrap = 0
use_parentheses = true
ensure_newline_before_comments = true
skip = [".git", "__pycache__", "venv", ".venv", "build", "dist"]
known_first_party = ["core", "plugins"]
known_third_party = ["PyQt6", "pytest"]
# flake8 - Linting
[tool.flake8]
max-line-length = 100
extend-ignore = [
"E203", # Whitespace before ':' (conflicts with black)
"E501", # Line too long (handled by black)
"W503", # Line break before binary operator (black style)
]
exclude = [
".git",
"__pycache__",
".venv",
"venv",
"build",
"dist",
".pytest_cache",
"htmlcov",
".tox",
"migrations",
]
per-file-ignores = [
"__init__.py:F401,F403",
"test_*.py:S101",
]
max-complexity = 10
# mypy - Type Checking
[tool.mypy]
python_version = "3.11"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
disallow_untyped_decorators = false
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
warn_unreachable = true
strict_equality = true
show_error_codes = true
show_column_numbers = true
show_error_context = true
pretty = true
# Module-specific settings
[[tool.mypy.overrides]]
module = [
"pytesseract.*",
"pyautogui.*",
"easyocr.*",
"keyboard.*",
"psutil.*",
"PIL.*",
"win32con.*",
"win32gui.*",
"win32api.*",
"portalocker.*",
]
ignore_missing_imports = true
# pytest - Testing
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = [
"-v",
"--tb=short",
"--strict-markers",
"--cov=core",
"--cov=plugins",
"--cov-report=term-missing",
"--cov-report=html:htmlcov",
"--cov-report=xml:coverage.xml",
"--cov-fail-under=80",
]
markers = [
"unit: Unit tests for individual components",
"integration: Integration tests for plugin interactions",
"ui: UI automation tests",
"performance: Performance benchmarks",
"slow: Slow tests that may be skipped in CI",
"requires_qt: Tests requiring PyQt6",
"requires_network: Tests requiring network access",
]
filterwarnings = [
"ignore::DeprecationWarning",
"ignore::PendingDeprecationWarning",
]
# Coverage - Code Coverage
[tool.coverage.run]
source = ["core", "plugins"]
branch = true
omit = [
"*/tests/*",
"*/test_*",
"*/venv/*",
"*/.venv/*",
"setup.py",
"run_tests.py",
"code_review_report.py",
"*/benchmarks/*",
"*_vulnerable.py",
]
[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"if self.debug:",
"if settings.DEBUG",
"raise AssertionError",
"raise NotImplementedError",
"if 0:",
"if __name__ == .__main__.:",
"class .*\\bProtocol\\):",
"@(abc\\.)?abstractmethod",
"pass",
]
fail_under = 80
show_missing = true
skip_covered = false
[tool.coverage.html]
directory = "htmlcov"
# Bandit - Security Linter
[tool.bandit]
exclude_dirs = [
"tests",
"test",
".venv",
"venv",
"build",
"dist",
]
skips = [
"B101", # assert_used (common in Python code)
"B311", # random (acceptable for non-cryptographic use)
]
# Pydocstyle - Docstring Conventions
[tool.pydocstyle]
convention = "google"
match = "(?!test_).*\\.py"
match_dir = "^(?!tests|\\.venv|venv|build|dist).*"
add_ignore = [
"D100", # Missing docstring in public module
"D104", # Missing docstring in public package
"D107", # Missing docstring in __init__
]
# setuptools - Package Discovery
[tool.setuptools]
packages = ["core", "core.*", "plugins", "plugins.*"]
include-package-data = true
zip-safe = false
[tool.setuptools.package-data]
core = ["*.json", "*.yaml", "*.yml", "*.css", "*.qss"]
plugins = ["*/assets/*", "*/templates/*"]
[tool.setuptools.exclude-package-data]
core = ["tests/*", "*_test.py", "test_*.py"]
plugins = ["tests/*", "*_test.py", "test_*.py"]

View File

@ -7,12 +7,6 @@ addopts =
-v -v
--tb=short --tb=short
--strict-markers --strict-markers
--cov=core
--cov=plugins
--cov-report=term-missing
--cov-report=html:htmlcov
--cov-report=xml:coverage.xml
--cov-fail-under=80
markers = markers =
unit: Unit tests for individual components unit: Unit tests for individual components
integration: Integration tests for plugin interactions integration: Integration tests for plugin interactions

249
setup.py Normal file
View File

@ -0,0 +1,249 @@
#!/usr/bin/env python3
"""
EU-Utility - Setup Script
A versatile Entropia Universe utility suite with a modular plugin system.
For more information, visit: https://github.com/ImpulsiveFPS/EU-Utility
"""
import os
import sys
from pathlib import Path
# Ensure setuptools is available
from setuptools import setup, find_packages
# Project root directory
PROJECT_ROOT = Path(__file__).parent.resolve()
# Read version from core/__init__.py
def get_version():
"""Extract version from core/__init__.py."""
init_file = PROJECT_ROOT / "core" / "__init__.py"
with open(init_file, "r", encoding="utf-8") as f:
for line in f:
if line.startswith("__version__"):
return line.split("=")[1].strip().strip('"\'')
raise RuntimeError("Version not found in core/__init__.py")
# Read long description from README
def get_long_description():
"""Read README.md for long description."""
readme_file = PROJECT_ROOT / "README.md"
if readme_file.exists():
with open(readme_file, "r", encoding="utf-8") as f:
return f.read()
return ""
# Runtime dependencies
INSTALL_REQUIRES = [
# Core GUI Framework
"PyQt6>=6.4.0,<7.0.0",
# System Integration
"keyboard>=0.13.5,<1.0.0",
"psutil>=5.9.0,<6.0.0",
"pyperclip>=1.8.2,<2.0.0",
# OCR and Image Processing
"easyocr>=1.7.0,<2.0.0",
"pytesseract>=0.3.10,<1.0.0",
"pyautogui>=0.9.54,<1.0.0",
"pillow>=10.0.0,<11.0.0",
# HTTP and Networking
"requests>=2.28.0,<3.0.0",
"urllib3>=1.26.0,<3.0.0",
# Data Processing
"numpy>=1.21.0,<2.0.0",
# Windows-specific dependencies (installed only on Windows)
'portalocker>=2.7.0; platform_system=="Windows"',
'pywin32>=306; platform_system=="Windows"',
]
# Development dependencies
DEV_REQUIRES = [
# Testing
"pytest>=7.4.0,<8.0.0",
"pytest-cov>=4.1.0,<5.0.0",
"pytest-mock>=3.11.0,<4.0.0",
"pytest-benchmark>=4.0.0,<5.0.0",
"pytest-qt>=4.2.0,<5.0.0",
"pytest-xvfb>=2.0.0,<3.0.0",
# Code Quality
"black>=23.0.0,<24.0.0",
"flake8>=6.0.0,<7.0.0",
"mypy>=1.5.0,<2.0.0",
"isort>=5.12.0,<6.0.0",
"pydocstyle>=6.3.0,<7.0.0",
# Security
"bandit>=1.7.5,<2.0.0",
"safety>=2.3.0,<3.0.0",
# Documentation
"sphinx>=7.0.0,<8.0.0",
"sphinx-rtd-theme>=1.3.0,<2.0.0",
"myst-parser>=2.0.0,<3.0.0",
# Build and Packaging
"build>=0.10.0,<1.0.0",
"twine>=4.0.0,<5.0.0",
"wheel>=0.41.0,<1.0.0",
# Pre-commit hooks
"pre-commit>=3.4.0,<4.0.0",
]
# Optional plugin dependencies
EXTRAS_REQUIRE = {
# Advanced media control features
"spotify": [
"spotipy>=2.23.0,<3.0.0",
'pycaw>=20230407; platform_system=="Windows"',
],
# Discord Rich Presence integration
"discord": [
"pypresence>=4.3.0,<5.0.0",
],
# All optional features
"all": [
"spotipy>=2.23.0,<3.0.0",
'pycaw>=20230407; platform_system=="Windows"',
"pypresence>=4.3.0,<5.0.0",
],
# Development extras (includes all dev dependencies)
"dev": DEV_REQUIRES,
}
# Package classifiers
CLASSIFIERS = [
# Development Status
"Development Status :: 4 - Beta",
# Intended Audience
"Intended Audience :: End Users/Desktop",
"Intended Audience :: Gamers",
# License
"License :: OSI Approved :: MIT License",
# Operating System
"Operating System :: OS Independent",
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX :: Linux",
# Programming Language
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3 :: Only",
# Topic
"Topic :: Games/Entertainment",
"Topic :: Utilities",
"Topic :: Desktop Environment",
# Environment
"Environment :: X11 Applications :: Qt",
"Environment :: Win32 (MS Windows)",
# Natural Language
"Natural Language :: English",
]
# Entry points for CLI usage
ENTRY_POINTS = {
"console_scripts": [
"eu-utility=core.main:main",
"eu-utility-secure=core.main_optimized:main",
],
"gui_scripts": [
"eu-utility-gui=core.main:main",
],
}
# Package data to include
PACKAGE_DATA = {
"core": ["*.json", "*.yaml", "*.yml", "*.css", "*.qss"],
"plugins": ["*/assets/*", "*/templates/*"],
}
def main():
"""Execute setup."""
setup(
# Basic metadata
name="eu-utility",
version=get_version(),
author="ImpulsiveFPS",
author_email="dev@impulsivefps.com",
maintainer="ImpulsiveFPS",
maintainer_email="dev@impulsivefps.com",
url="https://github.com/ImpulsiveFPS/EU-Utility",
project_urls={
"Bug Reports": "https://github.com/ImpulsiveFPS/EU-Utility/issues",
"Source": "https://github.com/ImpulsiveFPS/EU-Utility",
"Documentation": "https://github.com/ImpulsiveFPS/EU-Utility/tree/main/docs",
"Changelog": "https://github.com/ImpulsiveFPS/EU-Utility/blob/main/CHANGELOG.md",
},
# Descriptions
description="A versatile Entropia Universe utility suite with a modular plugin system",
long_description=get_long_description(),
long_description_content_type="text/markdown",
keywords=[
"entropia universe",
"game utility",
"overlay",
"plugin system",
"ocr",
"tracker",
"calculator",
"gaming",
"mmorpg",
],
# Classifiers
classifiers=CLASSIFIERS,
# License
license="MIT",
# Python version requirement
python_requires=">=3.11",
# Packages
packages=find_packages(
include=["core", "core.*", "plugins", "plugins.*"],
exclude=["tests", "tests.*", "benchmarks", "benchmarks.*", "docs", "docs.*"],
),
# Dependencies
install_requires=INSTALL_REQUIRES,
extras_require=EXTRAS_REQUIRE,
# Package data
include_package_data=True,
package_data=PACKAGE_DATA,
# Entry points
entry_points=ENTRY_POINTS,
# Zip safety
zip_safe=False,
# Platforms
platforms=["win32", "win64", "linux"],
)
if __name__ == "__main__":
main()