diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..3507e72 --- /dev/null +++ b/ARCHITECTURE.md @@ -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 diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..6e65bef --- /dev/null +++ b/MANIFEST.in @@ -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 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..99dfce7 --- /dev/null +++ b/pyproject.toml @@ -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"] diff --git a/pytest.ini b/pytest.ini index 546b099..e1cb795 100644 --- a/pytest.ini +++ b/pytest.ini @@ -7,12 +7,6 @@ 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 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..78b6f07 --- /dev/null +++ b/setup.py @@ -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()