diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..41d626a --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,8 @@ +include LICENSE +include README.md +include pyproject.toml +recursive-exclude tests * +recursive-exclude docs * +recursive-exclude scripts * +recursive-exclude * __pycache__ +recursive-exclude * *.py[co] diff --git a/README.md b/README.md index 7f7200d..581776f 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ A comprehensive Python client library for the [ESO Logs API v2](https://www.esol | Metric | Status | |--------|--------| -| **Current Version** | 0.2.0-alpha | +| **Current Version** | 0.2.0a2 | | **API Coverage** | ~83% (comprehensive analysis shows 6/8 API sections fully implemented) | | **Development Stage** | Active development | | **Documentation** | [Read the Docs](https://esologs-python.readthedocs.io/) | @@ -44,25 +44,20 @@ A comprehensive Python client library for the [ESO Logs API v2](https://www.esol ## Installation -**Note**: This package is currently in development and not yet published to PyPI. - -### Current Installation Method - ```bash -# Clone the repository -git clone https://github.com/knowlen/esologs-python.git -cd esologs-python +# Install from PyPI (recommended) +pip install esologs-python -# Basic installation -pip install --upgrade pip -pip install -e . +# For development or latest features +pip install git+https://github.com/knowlen/esologs-python.git@main ``` ### Development Installation -For development with testing, linting, and pre-commit hooks: ```bash -# Development installation +# Clone for development +git clone https://github.com/knowlen/esologs-python.git +cd esologs-python pip install -e ".[dev]" ``` @@ -95,7 +90,7 @@ For comprehensive documentation, visit [esologs-python.readthedocs.io](https://e ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def main(): # Get authentication token @@ -128,7 +123,7 @@ asyncio.run(main()) ### Authentication Only ```python -from access_token import get_access_token +from esologs.auth import get_access_token # Using environment variables token = get_access_token() @@ -146,7 +141,7 @@ token = get_access_token( import asyncio from esologs.client import Client from esologs.enums import CharacterRankingMetricType, RoleType -from access_token import get_access_token +from esologs.auth import get_access_token async def main(): token = get_access_token() @@ -186,7 +181,7 @@ asyncio.run(main()) ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def main(): token = get_access_token() @@ -315,6 +310,7 @@ esologs-python/ ├── esologs/ # Main package │ ├── client.py # Main client implementation │ ├── async_base_client.py # Base async GraphQL client +│ ├── auth.py # OAuth2 authentication module │ ├── exceptions.py # Custom exceptions │ ├── validators.py # Parameter validation utilities │ └── get_*.py # Generated GraphQL query modules @@ -324,7 +320,6 @@ esologs-python/ │ ├── docs/ # Documentation tests (98 tests) │ └── sanity/ # Sanity tests (19 tests) ├── docs/ # Documentation source -├── access_token.py # OAuth2 authentication ├── schema.graphql # GraphQL schema ├── queries.graphql # GraphQL queries ├── pyproject.toml # Project configuration diff --git a/docs/api-reference/character-data.md b/docs/api-reference/character-data.md index 4844407..0b68011 100644 --- a/docs/api-reference/character-data.md +++ b/docs/api-reference/character-data.md @@ -35,7 +35,7 @@ Enables the retrieval of single characters or filtered collections of characters ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def get_character_profile(): token = get_access_token() @@ -99,7 +99,7 @@ Guild Rank: 0 ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def get_character_recent_reports(): token = get_access_token() @@ -151,7 +151,7 @@ Showing 5 reports: ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def get_character_encounter_ranking(): token = get_access_token() @@ -213,7 +213,7 @@ Available data: ['bestAmount', 'medianPerformance', 'averagePerformance', 'total ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def get_character_encounter_rankings(): token = get_access_token() @@ -285,7 +285,7 @@ Rank percentile: 68.0% ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def get_character_zone_rankings(): token = get_access_token() @@ -324,7 +324,7 @@ Available metrics: ['bestPerformanceAverage', 'medianPerformanceAverage', 'diffi ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def analyze_character(character_id: int): """Complete character analysis including profile and recent activity.""" @@ -365,7 +365,7 @@ Recent activity: 286 reports ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def track_character_performance(character_id: int, encounter_id: int): """Track character performance for a specific encounter.""" diff --git a/docs/api-reference/game-data.md b/docs/api-reference/game-data.md index 6d9e0f9..72ffe60 100644 --- a/docs/api-reference/game-data.md +++ b/docs/api-reference/game-data.md @@ -33,7 +33,7 @@ Access collections of data such as NPCs, classes, abilities, items, maps, etc. G ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def get_all_abilities(): token = get_access_token() @@ -98,7 +98,7 @@ except GraphQLClientHttpError as e: ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def get_ability_details(): token = get_access_token() @@ -145,7 +145,7 @@ ID: 2 ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def list_character_classes(): token = get_access_token() @@ -196,7 +196,7 @@ Available character classes: ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def get_class_details(): token = get_access_token() @@ -240,7 +240,7 @@ Class: Dragonknight ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def browse_items(): token = get_access_token() @@ -290,7 +290,7 @@ Found 3 items ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def get_item_details(): token = get_access_token() @@ -342,7 +342,7 @@ ID: 3 ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def list_npcs(): token = get_access_token() @@ -392,7 +392,7 @@ Found 5 NPCs ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def get_npc_details(): token = get_access_token() @@ -440,7 +440,7 @@ ID: 1 ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def list_maps(): token = get_access_token() @@ -490,7 +490,7 @@ Found 100 maps (first page) ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def get_map_details(): token = get_access_token() @@ -536,7 +536,7 @@ ID: 1 ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def list_factions(): token = get_access_token() @@ -572,7 +572,7 @@ Efficiently collect and store item information for analysis: ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def build_item_database(): token = get_access_token() @@ -646,7 +646,7 @@ async def respectful_bulk_operation(): ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def monitor_usage(): token = get_access_token() diff --git a/docs/api-reference/guild-data.md b/docs/api-reference/guild-data.md index 0c75015..fbe640f 100644 --- a/docs/api-reference/guild-data.md +++ b/docs/api-reference/guild-data.md @@ -34,7 +34,7 @@ Enables the retrieval of single guilds or filtered collections of guilds. Guild ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def get_guild_info(): token = get_access_token() @@ -88,7 +88,7 @@ Region: North America ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def get_guild_reports(): token = get_access_token() @@ -139,7 +139,7 @@ Guild-related filtering is also available in the main search methods: ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def search_guild_reports(): token = get_access_token() @@ -178,7 +178,7 @@ Track guild performance over time: import asyncio from datetime import datetime, timedelta from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def analyze_guild_performance(): token = get_access_token() @@ -236,7 +236,7 @@ Monitor guild member participation using report rankings data: ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def track_member_activity(): token = get_access_token() @@ -340,7 +340,7 @@ Unlike some APIs that throw exceptions for missing data, guild methods return `N ```python from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def handle_missing_guild(): token = get_access_token() diff --git a/docs/api-reference/report-analysis.md b/docs/api-reference/report-analysis.md index 7c0bdbc..f302352 100644 --- a/docs/api-reference/report-analysis.md +++ b/docs/api-reference/report-analysis.md @@ -60,7 +60,7 @@ Access detailed (behavioral) combat log data including events, performance graph import asyncio from esologs.client import Client from esologs.enums import EventDataType -from access_token import get_access_token +from esologs.auth import get_access_token async def analyze_report_events(): token = get_access_token() @@ -147,7 +147,7 @@ More data available after: 264591.0 import asyncio from esologs.client import Client from esologs.enums import GraphDataType -from access_token import get_access_token +from esologs.auth import get_access_token async def get_damage_graph(): token = get_access_token() @@ -230,7 +230,7 @@ Data points: 240 import asyncio from esologs.client import Client from esologs.enums import TableDataType -from access_token import get_access_token +from esologs.auth import get_access_token async def get_damage_table(): token = get_access_token() @@ -292,7 +292,7 @@ Number of players: 10 import asyncio from esologs.client import Client from esologs.enums import ReportRankingMetricType -from access_token import get_access_token +from esologs.auth import get_access_token async def get_dps_rankings(): token = get_access_token() @@ -360,7 +360,7 @@ Top DPS Players: ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def get_player_performance(): token = get_access_token() @@ -433,7 +433,7 @@ Combine different analysis methods for comprehensive performance review: import asyncio from esologs.client import Client from esologs.enums import GraphDataType, TableDataType, ReportRankingMetricType -from access_token import get_access_token +from esologs.auth import get_access_token async def comprehensive_analysis(): token = get_access_token() @@ -509,7 +509,7 @@ Analyze specific phases of boss encounters: import asyncio from esologs.client import Client from esologs.enums import EventDataType, GraphDataType -from access_token import get_access_token +from esologs.auth import get_access_token async def analyze_encounter_phase(): token = get_access_token() diff --git a/docs/api-reference/report-search.md b/docs/api-reference/report-search.md index fb6544b..9a1fb65 100644 --- a/docs/api-reference/report-search.md +++ b/docs/api-reference/report-search.md @@ -83,7 +83,7 @@ Search and filter combat reports with advanced criteria including guilds, encoun ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def search_recent_reports(): token = get_access_token() @@ -136,7 +136,7 @@ Has more pages: True import asyncio import time from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def search_with_filters(): token = get_access_token() @@ -214,7 +214,7 @@ except GraphQLClientHttpError as e: ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def get_guild_activity(): token = get_access_token() @@ -266,7 +266,7 @@ Guild has 10 recent reports ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def get_user_activity(): token = get_access_token() diff --git a/docs/api-reference/system.md b/docs/api-reference/system.md index 8b13e2c..b08a6ed 100644 --- a/docs/api-reference/system.md +++ b/docs/api-reference/system.md @@ -27,7 +27,7 @@ Monitor API usage, handle rate limits, and manage authentication. ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def check_rate_limits(): token = get_access_token() @@ -63,7 +63,7 @@ Handle authentication failures and token expiration: import asyncio from esologs.client import Client from esologs.exceptions import GraphQLClientHttpError -from access_token import get_access_token +from esologs.auth import get_access_token async def handle_auth_errors(): try: @@ -108,7 +108,7 @@ Handle rate limit exceeded scenarios: import asyncio from esologs.client import Client from esologs.exceptions import GraphQLClientHttpError -from access_token import get_access_token +from esologs.auth import get_access_token async def handle_rate_limits(): token = get_access_token() @@ -151,7 +151,7 @@ import asyncio from esologs.client import Client from esologs.exceptions import GraphQLClientGraphQLError, GraphQLClientGraphQLMultiError from pydantic import ValidationError -from access_token import get_access_token +from esologs.auth import get_access_token async def handle_graphql_errors(): token = get_access_token() @@ -188,7 +188,7 @@ import asyncio import httpx from esologs.client import Client from esologs.exceptions import GraphQLClientHttpError -from access_token import get_access_token +from esologs.auth import get_access_token async def handle_network_errors(): token = get_access_token() @@ -226,7 +226,7 @@ Monitor your usage throughout a session: ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token class RateLimitMonitor: def __init__(self, client): @@ -294,7 +294,7 @@ import asyncio import random from esologs.client import Client from esologs.exceptions import GraphQLClientHttpError -from access_token import get_access_token +from esologs.auth import get_access_token async def robust_api_call(client, operation, max_retries=3): """ @@ -366,7 +366,7 @@ Manage long-running sessions with periodic health checks: import asyncio from esologs.client import Client from esologs.exceptions import GraphQLClientHttpError -from access_token import get_access_token +from esologs.auth import get_access_token class APISession: def __init__(self): diff --git a/docs/api-reference/world-data.md b/docs/api-reference/world-data.md index 6e08696..e3e3f26 100644 --- a/docs/api-reference/world-data.md +++ b/docs/api-reference/world-data.md @@ -40,7 +40,7 @@ Access world information including encounters, zones, regions, and dungeon/trial ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def list_zones(): token = get_access_token() @@ -127,7 +127,7 @@ Arenas (ID: 30) ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def list_regions(): token = get_access_token() @@ -182,7 +182,7 @@ Europe (ID: 2) ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def get_dungeon_encounters(): token = get_access_token() @@ -238,7 +238,7 @@ Find all encounters across all zones: ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def discover_all_encounters(): token = get_access_token() @@ -291,7 +291,7 @@ Find all zones that offer Veteran Hard Mode difficulty: ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def analyze_veteran_hard_mode_zones(): token = get_access_token() diff --git a/docs/authentication.md b/docs/authentication.md index 9b848cf..67dec30 100644 --- a/docs/authentication.md +++ b/docs/authentication.md @@ -124,7 +124,7 @@ ESOLOGS_SECRET=your_client_secret_here For testing or specific use cases, you can pass credentials directly: ```python -from access_token import get_access_token +from esologs.auth import get_access_token # Direct parameter passing (not recommended for production) token = get_access_token( @@ -138,7 +138,7 @@ token = get_access_token( ### Basic Authentication ```python -from access_token import get_access_token +from esologs.auth import get_access_token # Get access token using environment variables token = get_access_token() @@ -151,7 +151,7 @@ print(f"Access token: {token[:20]}...") # Show first 20 chars ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def main(): # Get authentication token @@ -175,7 +175,7 @@ asyncio.run(main()) ```python import asyncio -from access_token import get_access_token +from esologs.auth import get_access_token from esologs.client import Client from esologs.exceptions import GraphQLClientHttpError @@ -241,7 +241,7 @@ Verify your token is working: ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def validate_token(): """Validate authentication token by making a simple API call.""" @@ -364,7 +364,7 @@ Enable debug logging to troubleshoot issues: ```python import logging -from access_token import get_access_token +from esologs.auth import get_access_token # Enable debug logging logging.basicConfig(level=logging.DEBUG) diff --git a/docs/changelog.md b/docs/changelog.md index 4b993e2..b8d2004 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -5,6 +5,20 @@ All notable changes to ESO Logs Python will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.2.0a2] - 2025-07-16 + +### Fixed + +- **CRITICAL**: Moved authentication module (`access_token.py`) into the package as `esologs.auth` so it's included in pip distributions +- Updated all imports to use `from esologs.auth import get_access_token` or `from esologs import get_access_token` +- Authentication is now properly packaged and accessible when installing from PyPI + +## [0.2.0a1] - 2025-07-15 + +### Added + +This is the first alpha release of version 0.2.0. See the [0.2.0] section below for full feature list. + ## [0.2.0] - 2024-01-XX (Upcoming Release) ### Added diff --git a/docs/development/architecture.md b/docs/development/architecture.md index 19f357c..fde1437 100644 --- a/docs/development/architecture.md +++ b/docs/development/architecture.md @@ -60,7 +60,7 @@ class Client(BaseClient): **Purpose**: OAuth2 client credentials flow for secure API access ```python -# access_token.py +# esologs/auth.py def get_access_token(client_id=None, client_secret=None): """Get OAuth2 access token using client credentials flow.""" @@ -316,7 +316,7 @@ TEST_DATA = { ```toml [project] name = "esologs-python" -version = "0.2.0-alpha" +version = "0.2.0a2" dependencies = [ "httpx>=0.24.0", "pydantic>=2.0.0", diff --git a/docs/development/setup.md b/docs/development/setup.md index a611981..50b4f2d 100644 --- a/docs/development/setup.md +++ b/docs/development/setup.md @@ -74,10 +74,11 @@ pytest # Run all tests ``` esologs-python/ -├── esologs/ # Generated GraphQL client +├── esologs/ # Main package +│ ├── auth.py # OAuth2 authentication +│ └── *.py # Client and generated modules ├── tests/ # Test suites (see Testing Guide) ├── docs/ # Documentation source -├── access_token.py # OAuth2 authentication ├── queries.graphql # GraphQL queries to generate ├── schema.graphql # ESO Logs API schema └── mini.toml # Code generation config diff --git a/docs/index.md b/docs/index.md index de3256b..cae3cda 100644 --- a/docs/index.md +++ b/docs/index.md @@ -23,11 +23,12 @@ === "Installation" ```bash - # Clone the repository + # Install from PyPI + pip install esologs-python + + # Or install latest development version git clone https://github.com/knowlen/esologs-python.git cd esologs-python - - # Install the package pip install -e . ``` @@ -44,7 +45,7 @@ ```python import asyncio from esologs.client import Client - from access_token import get_access_token + from esologs.auth import get_access_token async def main(): token = get_access_token() @@ -72,7 +73,7 @@

Current Version

-

v0.2.0-alpha
+

v0.2.0a2
83% API Coverage

Active development with comprehensive testing and documentation.

diff --git a/docs/installation.md b/docs/installation.md index 88804f1..ebd69ae 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -10,9 +10,23 @@ Get ESO Logs Python up and running in your environment. ## Installation Methods -!!! warning "Development Version" - ESO Logs Python is currently in development and not yet published to PyPI. - Use the development installation method below. +### PyPI Installation (Recommended) + +ESO Logs Python is available on PyPI: + +=== "Latest Alpha" + + ```bash + # Install the latest alpha release + pip install esologs-python + ``` + +=== "Any Version" + + ```bash + # Install any available version (including pre-releases) + pip install esologs-python + ``` ### Development Installation @@ -72,7 +86,7 @@ Verify your installation by running a simple test: ```python # test_installation.py import esologs -from access_token import get_access_token +from esologs.auth import get_access_token # Check version print(f"ESO Logs Python version: {esologs.__version__}") diff --git a/docs/quickstart.md b/docs/quickstart.md index 8d851fb..7b9dc76 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -20,8 +20,8 @@ Before starting, ensure you have: ``` Get your credentials from [esologs.com/v2-api-docs](https://www.esologs.com/v2-api-docs) - 2. **Access to `access_token.py`** - Examples assume this module is available in your project. - If running outside the project directory, replace `from access_token import get_access_token` + 2. **Access to the authentication module** - Examples assume this module is available in your project. + If running outside the project directory, replace `from esologs.auth import get_access_token` with your own authentication implementation. ## Your First API Call @@ -31,7 +31,7 @@ Let's start with a simple example to verify everything is working: ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def hello_esologs(): """Your first ESO Logs API call.""" @@ -70,7 +70,7 @@ ESO Logs Python is built for async programming: ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def main(): token = get_access_token() @@ -107,7 +107,7 @@ Use the client as a context manager for proper resource cleanup: ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def main(): token = get_access_token() @@ -138,7 +138,7 @@ ESO Logs Python provides detailed error information: import asyncio from esologs.client import Client from esologs.exceptions import GraphQLClientHttpError, GraphQLClientGraphQLError, ValidationError -from access_token import get_access_token +from esologs.auth import get_access_token async def safe_api_call(): token = get_access_token() @@ -183,7 +183,7 @@ asyncio.run(safe_api_call()) ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def explore_game_data(): """Explore ESO's game data.""" @@ -247,7 +247,7 @@ Zones (48 total): ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def analyze_character(): """Analyze a specific character.""" @@ -301,7 +301,7 @@ Recent Reports (3): ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def search_reports(): """Search for reports with filtering.""" @@ -350,7 +350,7 @@ All responses use Pydantic models for type safety: ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def type_safe_example(): """Demonstrate type safety with Pydantic models.""" @@ -400,7 +400,7 @@ ESO Logs Python validates all parameters: import asyncio from esologs.client import Client from esologs.exceptions import ValidationError -from access_token import get_access_token +from esologs.auth import get_access_token async def validation_example(): """Show parameter validation in action.""" @@ -439,7 +439,7 @@ Found 25 reports ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def character_dashboard(character_id: int): """Create a simple character dashboard.""" @@ -499,7 +499,7 @@ Race ID: 5 ```python import asyncio from esologs.client import Client -from access_token import get_access_token +from esologs.auth import get_access_token async def guild_monitor(guild_id: int): """Monitor recent guild activity.""" diff --git a/esologs/__init__.py b/esologs/__init__.py index cf2ba43..dce1d70 100644 --- a/esologs/__init__.py +++ b/esologs/__init__.py @@ -1,4 +1,7 @@ +__version__ = "0.2.0a2" + from .async_base_client import AsyncBaseClient +from .auth import get_access_token from .base_model import BaseModel, Upload from .client import Client from .enums import ( @@ -358,4 +361,5 @@ "TableDataType", "Upload", "ViewType", + "get_access_token", ] diff --git a/access_token.py b/esologs/auth.py similarity index 91% rename from access_token.py rename to esologs/auth.py index d4b5acd..a35ff3d 100644 --- a/access_token.py +++ b/esologs/auth.py @@ -1,3 +1,14 @@ +"""Authentication module for ESO Logs API. + +This module provides OAuth2 client credentials flow authentication for accessing +the ESO Logs GraphQL API. It handles credential management, token acquisition, +and includes utilities for schema downloading. + +The primary function `get_access_token` supports both environment variable +and parameter-based credential passing, making it suitable for both production +deployments and development/testing scenarios. +""" + import base64 import logging import os diff --git a/esologs/py.typed b/esologs/py.typed new file mode 100644 index 0000000..c37b2a1 --- /dev/null +++ b/esologs/py.typed @@ -0,0 +1,7 @@ +# PEP 561 marker file +# This file indicates that the esologs package includes inline type annotations. +# Type checkers like mypy will use these annotations when type checking code +# that imports this package. +# +# This file should remain empty except for comments. +# See: https://www.python.org/dev/peps/pep-0561/ diff --git a/pyproject.toml b/pyproject.toml index e1722da..dc9b254 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,13 +4,17 @@ build-backend = "setuptools.build_meta" [project] name = "esologs-python" -version = "0.2.0" +version = "0.2.0a2" description = "A Python client library for the ESO Logs API v2" readme = "README.md" license = {text = "MIT"} authors = [ {name = "Nick Knowles"}, ] +keywords = [ + "eso", "elder-scrolls-online", "esologs", "api", "graphql", + "combat-logs", "mmorpg", "gaming", "api-client", "python" +] classifiers = [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", @@ -67,7 +71,9 @@ all = [ Homepage = "https://github.com/knowlen/esologs-python" Repository = "https://github.com/knowlen/esologs-python" Issues = "https://github.com/knowlen/esologs-python/issues" -Documentation = "https://github.com/knowlen/esologs-python" +Documentation = "https://esologs-python.readthedocs.io/" +Changelog = "https://github.com/knowlen/esologs-python/wiki/Changelog" +Wiki = "https://github.com/knowlen/esologs-python/wiki" [tool.setuptools.packages.find] where = ["."] diff --git a/tests/docs/conftest.py b/tests/docs/conftest.py index 9e0eb6d..e2c5377 100644 --- a/tests/docs/conftest.py +++ b/tests/docs/conftest.py @@ -4,7 +4,7 @@ import pytest -from access_token import get_access_token +from esologs.auth import get_access_token @pytest.fixture(scope="session") diff --git a/tests/docs/test_authentication_examples.py b/tests/docs/test_authentication_examples.py index 7c830b8..19c3e97 100644 --- a/tests/docs/test_authentication_examples.py +++ b/tests/docs/test_authentication_examples.py @@ -7,7 +7,7 @@ import pytest -from access_token import get_access_token +from esologs.auth import get_access_token from esologs.client import Client from esologs.exceptions import GraphQLClientHttpError @@ -137,7 +137,7 @@ def test_access_token_direct_parameters(self): # We can't test with fake credentials, but we can test the interface import inspect - from access_token import get_access_token + from esologs.auth import get_access_token # Verify function signature supports client_id and client_secret parameters sig = inspect.signature(get_access_token) @@ -160,7 +160,7 @@ class TestAuthenticationDocumentationIntegrity: def test_authentication_imports(self): """Test that all modules used in auth docs are importable.""" # Test basic imports - from access_token import get_access_token + from esologs.auth import get_access_token from esologs.client import Client from esologs.exceptions import GraphQLClientHttpError @@ -189,7 +189,7 @@ def test_environment_variable_handling(self): def test_oauth_error_handling(self): """Test that OAuth errors are handled as documented.""" - from access_token import get_access_token + from esologs.auth import get_access_token # Test with invalid credentials to verify error handling try: diff --git a/tests/docs/test_quickstart_examples.py b/tests/docs/test_quickstart_examples.py index dfc1bb0..5b27d94 100644 --- a/tests/docs/test_quickstart_examples.py +++ b/tests/docs/test_quickstart_examples.py @@ -7,7 +7,7 @@ import pytest -from access_token import get_access_token +from esologs.auth import get_access_token from esologs.client import Client from esologs.exceptions import ( GraphQLClientGraphQLError, diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 37f474b..9e141cc 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -3,7 +3,7 @@ import pytest -from access_token import get_access_token +from esologs.auth import get_access_token from esologs.client import Client diff --git a/tests/integration/test_character_rankings.py b/tests/integration/test_character_rankings.py index 42f02a7..be60f7e 100644 --- a/tests/integration/test_character_rankings.py +++ b/tests/integration/test_character_rankings.py @@ -4,7 +4,7 @@ import pytest -from access_token import get_access_token +from esologs.auth import get_access_token from esologs.client import Client from esologs.enums import CharacterRankingMetricType diff --git a/tests/integration/test_core_api.py b/tests/integration/test_core_api.py index 1b8af50..3c3a33a 100644 --- a/tests/integration/test_core_api.py +++ b/tests/integration/test_core_api.py @@ -4,7 +4,7 @@ import pytest -from access_token import get_access_token +from esologs.auth import get_access_token from esologs.client import Client # Fixtures are now centralized in conftest.py diff --git a/tests/integration/test_error_handling.py b/tests/integration/test_error_handling.py index 13bf2d2..a2d108c 100644 --- a/tests/integration/test_error_handling.py +++ b/tests/integration/test_error_handling.py @@ -4,7 +4,7 @@ import pytest -from access_token import get_access_token +from esologs.auth import get_access_token from esologs.client import Client from esologs.enums import CharacterRankingMetricType, EventDataType diff --git a/tests/integration/test_report_analysis.py b/tests/integration/test_report_analysis.py index a64fa97..f9d6a3c 100644 --- a/tests/integration/test_report_analysis.py +++ b/tests/integration/test_report_analysis.py @@ -4,7 +4,7 @@ import pytest -from access_token import get_access_token +from esologs.auth import get_access_token from esologs.client import Client from esologs.enums import ( EventDataType, diff --git a/tests/sanity/conftest.py b/tests/sanity/conftest.py index 4f5cac2..0d805e6 100644 --- a/tests/sanity/conftest.py +++ b/tests/sanity/conftest.py @@ -3,7 +3,7 @@ import pytest -from access_token import get_access_token +from esologs.auth import get_access_token from esologs.client import Client diff --git a/tests/unit/README.md b/tests/unit/README.md index bce5335..f71de1d 100644 --- a/tests/unit/README.md +++ b/tests/unit/README.md @@ -16,7 +16,7 @@ The unit tests provide: ### Core Test Files - **`test_validators.py`**: Parameter validation functions (22 test classes) -- **`test_access_token.py`**: OAuth2 token handling and credential validation +- **`test_access_token.py`**: Tests for auth module - OAuth2 token handling and credential validation - **`test_character_rankings.py`**: Character ranking method logic and validation - **`test_report_analysis.py`**: Report analysis method signatures and validation - **`test_report_search.py`**: Report search validation, date parsing, and method logic @@ -32,7 +32,7 @@ The unit tests provide: - **Fight ID Validation**: Fight ID list validation - **Required String Validation**: Non-empty string validation -#### Authentication Tests (`test_access_token.py`) +#### Authentication Tests (`test_access_token.py` - tests `esologs.auth` module) - **Credential Handling**: Environment variable and parameter validation - **Error Scenarios**: Missing credentials and invalid responses - **OAuth Flow**: Mock testing of token request/response cycle diff --git a/tests/unit/test_access_token.py b/tests/unit/test_access_token.py index de3ce26..9f9b84e 100644 --- a/tests/unit/test_access_token.py +++ b/tests/unit/test_access_token.py @@ -6,7 +6,7 @@ import pytest from requests import Response -from access_token import get_access_token +from esologs.auth import get_access_token class TestGetAccessToken: @@ -14,7 +14,7 @@ class TestGetAccessToken: def test_get_access_token_with_parameters(self): """Test getting access token with explicit parameters.""" - with patch("access_token.requests.post") as mock_post: + with patch("esologs.auth.requests.post") as mock_post: mock_response = Mock(spec=Response) mock_response.status_code = 200 mock_response.json.return_value = {"access_token": "test_token"} @@ -30,7 +30,7 @@ def test_get_access_token_with_env_vars(self): with patch.dict( os.environ, {"ESOLOGS_ID": "env_id", "ESOLOGS_SECRET": "env_secret"} ): - with patch("access_token.requests.post") as mock_post: + with patch("esologs.auth.requests.post") as mock_post: mock_response = Mock(spec=Response) mock_response.status_code = 200 mock_response.json.return_value = {"access_token": "env_token"} @@ -54,7 +54,7 @@ def test_get_access_token_missing_client_secret(self): def test_get_access_token_http_error(self): """Test error handling for HTTP errors.""" - with patch("access_token.requests.post") as mock_post: + with patch("esologs.auth.requests.post") as mock_post: mock_response = Mock(spec=Response) mock_response.status_code = 401 mock_response.text = "Unauthorized" @@ -65,7 +65,7 @@ def test_get_access_token_http_error(self): def test_get_access_token_missing_token_in_response(self): """Test error when access token is missing from response.""" - with patch("access_token.requests.post") as mock_post: + with patch("esologs.auth.requests.post") as mock_post: mock_response = Mock(spec=Response) mock_response.status_code = 200 mock_response.json.return_value = {}