Skip to main content

Python client library for SunSolve p90 analysis service

Project description

SunSolve P90 Analysis Client

A Python client library for connecting to the SunSolve P90 analysis service via gRPC. This client enables photovoltaic system P90 analysis with comprehensive error handling and type safety.

For more details please consult our documentation

Features

  • gRPC Client: Direct connection to SunSolve P90 analysis service
  • Multi-Year Analysis: Support for both TMY (Typical Mean Year) and actual multi-year datasets
  • Comprehensive Error Handling: Custom exception classes for different error scenarios
  • Type Safety: Full type annotations and MyPy compatibility
  • Protocol Buffer Support: Automatic generation and management of protobuf files
  • Development Tools: Integrated linting, formatting, and code quality checks
  • Example Implementation: Complete working example with weather data processing

Quick Start

Instructions here apply to users who wish to import the sunsolve_p90_client library within their own solution. Installation of the package would not be required when using this code base directly.

Prerequisites

  • Python 3.12+ installed
  • SunSolve account with Uncertainty Analysis subscription (Getting started with P90)
  • API access permissions enabled on your account
  • Basic familiarity with Python virtual environments

Install the Package

๐Ÿ“ฆ Package Availability: The wheel package is automatically created by the build pipeline and available on pypi. For local development, you can build the package yourself using the instructions in the Building the Package section.

# Install the wheel package
pip install sunsolve-p90-client

Basic Usage Example

The P90 analysis service processes weather data and applies uncertainty distributions to calculate P-values over multiple simulations. This example shows the minimal setup required to perform an analysis.

from pvl_p90_client.client.p90_client import P90Client
from pvl_p90_client.helpers import pvl_login
from pvl_p90_client.helpers.request_helpers import (
    build_request,
    build_distribution,
    build_gaussian_distribution,
    load_weather_data_from_pvw_file,
)
from pvl_p90_client.grpcclient.uncertaintyMessages_pb2 import DistributionInput

# Connect to the P90 analysis service
with P90Client() as client:
    # Authenticate with your SunSolve credentials (prompts for username/password)
    credentials = pvl_login.login()
    
    # Load weather data from a PVW file (Typical Mean Year format)
    weather_data = load_weather_data_from_pvw_file("data/sydney.pvw")
    
    # Add uncertainty distribution for Global Horizontal Irradiance (GHI)
    # This adds ยฑ5% variation to solar irradiance values
    distributions = [
        build_distribution(
            input=DistributionInput.GHI,
            sim_to_sim_distribution=build_gaussian_distribution(1.0, 0.05)
        )
    ]
    
    # Create a minimal request with weather data and basic uncertainty
    # This uses default system parameters and simulation settings
    request = build_request(
        time_step_data=weather_data,
        distributions=distributions
    )
    
    # Send the analysis request and receive results
    summary, used_inputs = client.send_request(request, credentials, timeout=60.0)
    
    # Display results
    if summary:
        print(f"Analysis complete! Generated {len(summary.YearlyPValue)} yearly P-values")
        for pvalue in summary.YearlyPValue[:3]:  # Show first 3 years
            print(f"  Year {pvalue.Year}: P{pvalue.P} = {pvalue.P50Deviation:.4f}")
    else:
        print("No analysis results received")

What this example does:

  • Connects to the P90 service using the client context manager for automatic cleanup
  • Authenticates using your SunSolve account credentials
  • Loads weather data from a PVW file (Typical Mean Year format)
  • Creates a minimal request using only weather data and basic simulation settings
  • Sends the analysis and receives both summary results and details of inputs used
  • Displays P-values showing the probability of exceedance for different confidence levels

๐Ÿ”ง Customization Available: This minimal example uses default system parameters. For detailed system configuration including module specifications, electrical settings, and uncertainty distributions, see the Request Building Guide section below.

๐Ÿ“– For a complete working example with detailed request building, error handling, and result processing, see src/example.py.


API Documentation

P90Client

The main client class for interacting with the SunSolve uncertainty service. In most cases defaults do not need to be changed. In rare cases, the version may need to be set specifically if the version of the library is no longer compatible with the latest server version and if an updated version of the library is not yet available.

from pvl_p90_client.client.p90_client import P90Client

# Initialize client
client = P90Client(
    api_base_uri="middleware.pvlighthouse.com.au",  # Default
    version="latest-prod"                         # Default
)

# Use as context manager (recommended)
with P90Client() as client:
    # Client automatically handles connection cleanup
    summary, used_inputs = client.send_request(request, credentials, timeout=30.0)

Methods:

  • send_request(request, call_credentials, timeout=30.0): Send analysis request, returns (summary, used_inputs) tuple
  • close(): Manually close connection
  • Context manager support for automatic cleanup

Custom Exceptions:

  • P90ClientError: Base exception class
  • AuthenticationError: Authentication failures and permission denied errors
  • P90ConnectionError: Connection issues
  • ServiceError: Service-level errors

Note: AuthenticationError is raised for both invalid credentials and insufficient permissions (e.g., no Uncertainty Analysis subscription).

Helper Functions

Authentication (pvl_p90_client.helpers.pvl_login)

from pvl_p90_client.helpers import pvl_login

# Login with credentials (prompts for username/password if not provided)
credentials = pvl_login.login()

# Or provide credentials programmatically
credentials = pvl_login.login(username="your_username", password="your_password")

Features:

  • Interactive credential prompting when parameters not provided
  • Secure password input (hidden from console)
  • Automatic token validation and error handling
  • Raises AuthenticationError on authentication failure

Weather Data Loading (pvl_p90_client.helpers.request_helpers)

from pvl_p90_client.helpers.request_helpers import (
    load_weather_data_from_pvw_file,
    load_time_step_data_from_csv
)

# Load weather data from PVW file (binary format)
weather_data = load_weather_data_from_pvw_file("data/sydney.pvw")

# Load weather data from CSV file (text format)  
weather_data = load_time_step_data_from_csv("data/sydney.csv")

What these functions do:

  • PVW files: Load binary weather data in SunSolve's native format. This format does not include time step based tilt angle which would need to be added manually
  • CSV files: Load text-based time step data with automatic validation and conversion
  • Both return lists of TimeStepData protobuf messages ready for analysis
  • Raise TimeStepDataError on file format or validation errors

Request Building Guide

The build_request helper function provides a streamlined way to create analysis requests with optional detailed configuration. This section shows how to customize your analysis beyond the basic example.

Using the build_request Helper

Minimal usage (uses defaults for all system parameters):

from pvl_p90_client.helpers.request_helpers import (
    build_request, build_distribution, build_gaussian_distribution
)
from pvl_p90_client.grpcclient.uncertaintyMessages_pb2 import DistributionInput

# Add basic uncertainty to solar irradiance
distributions = [
    build_distribution(
        input=DistributionInput.GHI,
        sim_to_sim_distribution=build_gaussian_distribution(1.0, 0.05)  # ยฑ5% GHI uncertainty
    )
]

# Create request with weather data and basic uncertainty - all system parameters use defaults
request = build_request(
    time_step_data=weather_data,
    distributions=distributions
)

Full customization with detailed system configuration:

from pvl_p90_client.helpers.request_helpers import (
    build_request, build_module_info, build_system_info, 
    build_electrical_settings, build_optical_settings, 
    build_thermal_settings, build_operational_settings,
    build_simulation_options, build_result_options,
    build_distribution, build_gaussian_distribution,
    build_weibull_distribution, build_skewed_gaussian_distribution
)
from pvl_p90_client.grpcclient.uncertaintyMessages_pb2 import TrackingType 

# Define module physical properties
module = build_module_info(
    length=2.0,                                    # Module length in meters
    width=1.0,                                     # Module width in meters  
    cell_to_cell_mismatch=0.02,                   # Cell-to-cell variation
    power_temperature_coefficient=-0.004,         # Temperature coefficient
    power_at_stc=460,                             # Rated power at STC (Watts)
    bifaciality=0.75                              # Bifaciality factor (rear/front efficiency ratio)
)

# Configure system layout and basic parameters  
system = build_system_info(
    number_of_inverters=1,                        # Number of inverters
    strings_per_inverter=10,                      # Strings per inverter
    modules_per_string=20,                        # Modules per string
    row_pitch=5.6,                               # Distance between rows
    module_azimuth=180.0,                        # System azimuth (180ยฐ = north)
    module_tilt=25.0,                            # Default tilt when not specified per timestep
    module_tracking=TrackingType.SAT,            # Tracking type (NotSet or SAT)
    module_tilt_limit=60.0,                      # Maximum tilt angle for tracking systems
    module_height=1.0                            # Module height above ground
)

# Define electrical characteristics and losses
electrical = build_electrical_settings(
    inverter_efficiency=0.98,                    # Inverter efficiency
    module_to_module_mismatch=0.02,              # Module manufacturing variation
    string_wiring_loss=0.01,                    # DC wiring losses
    max_power_tracking_loss=0.995,              # MPPT tracking efficiency
    inverter_wiring_loss=0.01,                  # AC wiring losses
    string_to_string_mismatch=0.02,             # String-to-string variation
    inverter_to_inverter_mismatch=0.01          # Inverter-to-inverter variation
)

# Configure optical settings for irradiance processing
optical = build_optical_settings(
    beam_multiplier_front=1.0,                   # Beam irradiance adjustment (front)
    beam_multiplier_rear=1.0,                    # Beam irradiance adjustment (rear)
    isotropic_multiplier_front=1.0,              # Diffuse irradiance adjustment (front)
    isotropic_multiplier_rear=1.0,               # Diffuse irradiance adjustment (rear)
    albedo=0.2,                                  # Ground reflectance default
    soiling_front=0.0,                          # Soiling loss default (front)
    soiling_rear=0.0,                           # Soiling loss default (rear)
    spectral_correction=1.0,                    # Spectral correction default
    rear_transmission_factor=0.8,               # Rear surface transmission factor default
    rear_structural_shading_factor=0.9          # Rear structural shading factor default
)

# Set thermal modeling parameters
thermal = build_thermal_settings(
    uc=29.0,                                     # Heat loss coefficient (W/mยฒK)
    uv=0.0,                                      # Wind speed coefficient
    alpha=0.9                                    # Solar absorptance
)

# Configure operational parameters
operational = build_operational_settings(
    annual_degradation_rate=0.005,               # Annual power degradation (0.5%/year)
    curtailment=0.0,                             # Grid curtailment losses
    availability=0.98,                           # System availability
    dc_health=1.0,                               # DC system health factor
    undulating_ground=False,                     # Terrain type
    yield_modifier=1.0                           # Overall yield adjustment
)

# Define comprehensive uncertainty distributions
distributions = [
    # GHI uncertainty with simulation-to-simulation and year-to-year variations
    build_distribution(
        input=DistributionInput.GHI,
        sim_to_sim_distribution=build_gaussian_distribution(1.0, 0.05),      # ยฑ5% per simulation
        yr_to_yr_distribution=build_gaussian_distribution(1.0, 0.02)         # ยฑ2% per year
    ),
    
    # Soiling uncertainty with all three distribution types
    build_distribution(
        input=DistributionInput.SoilingFront,
        sim_to_sim_distribution=build_gaussian_distribution(0.98, 0.02),     # 2% baseline soiling ยฑ2%
        yr_to_yr_distribution=build_weibull_distribution(1.0, 0.05, 2.0),    # Weibull year variation  
        step_to_step_distribution=build_gaussian_distribution(1.0, 0.01)     # 1% timestep noise
    ),
    
    # Module degradation with skewed distribution
    build_distribution(
        input=DistributionInput.AnnualDegradationRate,
        sim_to_sim_distribution=build_skewed_gaussian_distribution(          # Skewed degradation
            alpha=2.0,      # Skewness parameter
            zeta=0.005,     # Location (0.5%/year baseline)
            omega=0.002     # Scale parameter
        )
    )
    # Add more distributions for other inputs: Temperature, WindSpeed, Availability, etc.
]

# Set analysis parameters
simulation_options = build_simulation_options(number_of_years=25, number_of_simulations=10000)
result_options = build_result_options(bin_min=0.5, bin_delta=0.01, p_values=[5, 10, 50, 90, 95])

# Build complete request with all customizations
request = build_request(
    time_step_data=weather_data,
    module=module,
    system=system, 
    electrical=electrical,
    optical=optical,
    thermal=thermal,
    operational=operational,
    distributions=distributions,
    simulation_options=simulation_options,
    result_options=result_options
)

What each configuration does:

  • Module settings define the physical properties and electrical characteristics of individual PV modules
  • System settings specify the overall layout, orientation, and basic system architecture
  • Electrical settings configure efficiency parameters and loss factors throughout the DC and AC systems
  • Optical settings control how irradiance data is processed and applied to front/rear surfaces
  • Thermal settings define the heat transfer model used for temperature-dependent performance
  • Operational settings include long-term factors like degradation, availability, and maintenance
  • Distributions apply uncertainty variations to specific input parameters across simulations
  • Simulation options control the number of years and Monte Carlo simulations to run
  • Result options specify which percentile values to calculate and report

Legacy Request Building

If you need more control or prefer the traditional approach, you can build requests manually:

from pvl_p90_client.grpcclient.uncertaintyMessages_pb2 import UncertaintyRequest

# Build system components individually
request = UncertaintyRequest()
request.Module.CopyFrom(build_module_info())
request.System.CopyFrom(build_system_info()) 
request.SimulationOptions.CopyFrom(build_simulation_options(5, 1000))
request.ResultOptions.CopyFrom(build_result_options(0.75, 0.01, [5, 10, 50, 90, 95]))

# Add distributions and weather data
request.Distributions.extend(distributions)
request.TMYDataSet.TimeStepDataPoints.extend(weather_data)

Understanding Uncertainty Distributions

Distributions are the core mechanism for introducing uncertainty into P90 analysis. They apply multiplicative factors to targeted input parameters across different time scales.

How Distribution Factors Are Applied

For each targeted input parameter, the final factor is calculated as:

factor = baseline_value ร— sim_to_sim_factor ร— yr_to_yr_factor ร— step_to_step_factor

Distribution Types by Time Scale:

  • Sim-to-sim: Same factor applied across all years in a single simulation (systematic uncertainty)
  • Year-to-year: Same factor applied across all timesteps in a specific year (annual variation)
  • Step-to-step: Different factor for each individual timestep (short-term variability)

Available Distribution Inputs

You can target any of these input parameters with uncertainty distributions:

Solar Resource:

  • GHI - Global Horizontal Irradiance
  • DiffuseFraction - Fraction of diffuse vs direct radiation
  • CircumsolarFraction - Circumsolar radiation component
  • WindSpeed - Wind speed affecting module temperature
  • Temperature - Ambient temperature
  • Albedo - Ground reflectance

Module Performance:

  • ModulePower - Module power rating uncertainty
  • SpectralCorrection - Spectral response corrections
  • ModulePowerTemperatureCoefficient - Temperature coefficient variation
  • CellToCellMismatch - Individual cell performance variation

System Losses:

  • SoilingFront / SoilingRear - Soiling losses on module surfaces
  • InverterEfficiency - Inverter conversion efficiency
  • InverterToInverterMismatch - Inverter-to-inverter variations
  • StringToStringMismatch - String-to-string performance differences
  • ModuleToModuleMismatch - Module manufacturing tolerances

Environmental & Operational:

  • Uc / Uv / Alpha - Thermal model parameters
  • AnnualDegradationRate - Long-term power degradation
  • Availability - System uptime and maintenance losses
  • Curtailment - Grid curtailment requirements
  • DCHealth - DC system health factor
  • YieldModifier - Overall system yield adjustment
  • UndulatingGround - Terrain effects on irradiance
  • ExtraIrradiance - Additional irradiance adjustments
  • RearTransmissionFactor - Bifacial rear surface transmission factor
  • RearStructuralShadingFactor - Rear surface structural shading

Example Distribution Targeting Multiple Inputs:

distributions = [
    # Solar resource uncertainty
    build_distribution(input=DistributionInput.GHI, sim_to_sim_distribution=build_gaussian_distribution(1.0, 0.05)),
    build_distribution(input=DistributionInput.Temperature, yr_to_yr_distribution=build_gaussian_distribution(1.0, 0.03)),
    
    # System performance uncertainty  
    build_distribution(input=DistributionInput.ModuleToModuleMismatch, sim_to_sim_distribution=build_weibull_distribution(1.0, 0.02, 2.0)),
    build_distribution(input=DistributionInput.SoilingFront, step_to_step_distribution=build_gaussian_distribution(0.98, 0.01)),
    
    # Long-term operational uncertainty
    build_distribution(input=DistributionInput.AnnualDegradationRate, sim_to_sim_distribution=build_skewed_gaussian_distribution(2.0, 0.005, 0.002))
]

Example Usage

The src/example.py file demonstrates a complete p90 analysis workflow:

Running the Example

Using VS Code Launch Configuration (recommended):

# Method 1: Using Run and Debug view
# - Open Run and Debug view (Ctrl+Shift+D)
# - Select "Run Example Script" from dropdown
# - Click the green play button

# Method 2: Using Command Palette
# - Press Ctrl+Shift+P
# - Type "Debug: Start Debugging"
# - Select "Run Example Script"

# Method 3: Using keyboard shortcut
# - Press F5 (if "Run Example Script" is active configuration)

Manual execution:

cd src
python example.py

Example Workflow

The example demonstrates:

  1. Authentication: Login to SunSolve service
  2. Data Loading: Load weather data from included Sydney dataset
  3. Request Building: Create uncertainty distributions and analysis parameters
  4. Analysis Execution: Send request and process streaming results
  5. Error Handling: Comprehensive error handling for all failure scenarios
def main():
    with P90Client() as client:
        # Step 1: Authenticate
        if not (call_credentials := pvl_login.login()):
            print("โŒ Authentication failed")
            return
            
        # Step 2: Load weather data
        if not (weather_data := load_weather_data_from_pvw_file("../data/sydney.pvw")):
            print("โŒ Failed to load weather data")
            return
            
        # Step 3: Build request with distributions
        distributions = create_distributions()  # GHI, soiling, availability distributions
        request = build_request(time_step_data=weather_data, distributions=distributions)
        
        # Step 4: Execute analysis
        perform_analysis(client, request, call_credentials)

Expected Output

Connecting to SunSolve...
Authenticating...
Enter username: your_username
Password: ********
Authentication successful!
Loading weather data...
Loaded 8760 weather data points
Creating uncertainty distributions...
Built request with 3 distributions
Starting P90 analysis...
Progress: 5.0%
...
๐ŸŽ‰ Analysis complete!

Results: 5 yearly P-values calculated
  Year 1: P5 = 1.05 of P50
  Year 1: P10 = 1.04 of P50
  Year 1: P50 = 1.00 of P50
...

Yearly P50 Deviations to first year P50 value:
  Year 1: 1.00
  Year 2: 0.98
...

Histogram data showing distribution of simulations across uncertainty ranges:
  Year 1: 0 0 0 0 1 15 45 65 75 120 85 77 59 39 21 5 1 0 0 0
  Year 2: 0 0 0 0 2 18 42 68 71 115 89 73 61 35 18 8 0 0 0 0
...

Development Setup Instructions

Option 1: Development Container (Recommended)

The easiest way to get started with development from this codebase is by using the provided development container:

  1. Prerequisites:

    • Docker Desktop
    • VS Code with Dev Containers extension
  2. Setup:

    • Open VS Code
    • Open Command Palette (Ctrl+Shift+P / Cmd+Shift+P)
    • Type "Dev Containers: Clone Repository in Container Volume..."
    • Enter the repository URL when prompted
    • VS Code will automatically clone and open the project in the dev container
  3. Verify Setup:

    • Press Ctrl+Shift+B (or Cmd+Shift+B on Mac) to open the build menu
    • Select "Full Build" task
    • This will run protocol buffer generation, linting, tests, and package building
    • All steps should complete successfully, confirming your environment is ready
  4. Run the Example:

    • Press Ctrl+F5 (or Cmd+F5 on Mac) to run the example script
    • You'll be prompted to enter your SunSolve credentials
    • The example will demonstrate a complete P90 analysis workflow

Option 2: Manual Setup

If you prefer a manual installation:

  1. Prerequisites:

    • Python 3.12+
    • pip and pip-tools
  2. Environment Setup:

    git clone <repository-url>
    cd pvl_p90_client
    
    # Create virtual environment
    python -m venv .venv
    source .venv/bin/activate  # On Windows: .venv\Scripts\activate
    
    # Install pip-tools
    pip install pip-tools
    
    # Compile and install dependencies
    pip-compile requirements-dev.in  # This also compiles requirements.in as a dependency
    pip-sync requirements-dev.txt
    
  3. Build Protocol Buffers:

    chmod +x scripts/build-proto.sh
    ./scripts/build-proto.sh
    
  4. Verify Installation:

    # Run linting checks
    ./scripts/lint.sh
    
    # Run example (requires SunSolve credentials)
    python src/example.py
    

Building the Package

Building for Distribution

To build the Python package for distribution:

# Build both wheel and source distribution
./scripts/build-package.sh

This script will:

  1. Validate the version and set up build environment
  2. Clean previous builds
  3. Build protocol buffers if needed
  4. Create both wheel (.whl) and source (.tar.gz) distributions
  5. Place output files in build/dist/

Build Output

After building, you'll find the distribution files in:

build/dist/
โ”œโ”€โ”€ sunsolve_p90_client-<version>-py3-none-any.whl  # Wheel package
โ””โ”€โ”€ sunsolve_p90_client-<version>.tar.gz           # Source distribution

Installing the Built Package

# Install the wheel package locally
pip install build/dist/sunsolve_p90_client-*.whl

# Or install in development mode (editable install)
pip install -e .

Version Management

The package version is automatically determined from:

  • VERSION file for the base version
  • Build number from BITBUCKET_BUILD_NUMBER environment variable (CI/CD)
  • Branch information for development builds

For local development builds, the version will be <base_version>+local format.


Development Tools

Code Quality

The project uses modern, fast linting tools:

# Run all linting checks
./scripts/lint.sh

# Auto-fix formatting and linting issues
./scripts/lint.sh -fix

Tools Used:

  • Ruff: Ultra-fast Python linter and formatter (replaces Black, isort, Flake8, Bandit, Pylint)
  • MyPy: Static type checking
  • Custom Test Naming Validator: Enforces GIVEN_WHEN_THEN test method naming convention

Pre-commit Hooks:

# Install pre-commit hooks (runs linting before commits)
pre-commit install

# Test a commit message format
echo "SUN-4189 Add new feature" | python scripts/check-commit-message.py /dev/stdin

VS Code Tasks

Available tasks in VS Code (Ctrl+Shift+P โ†’ Tasks: Run Task):

  • Run Linter (Check Only): Check code quality without making changes
  • Fix Linting Issues: Auto-fix formatting and import issues
  • Validate Test Naming: Check test method naming conventions
  • Build Protocol Buffers: Regenerate protobuf files
  • Run Tests: Execute all tests with coverage
  • Run Tests with Coverage: Execute tests with detailed coverage reports
  • Clean DevEnv: Remove all ignored files (caches, build artifacts, compiled requirements) - follow with container rebuild

VS Code Launch Configurations

Available launch configurations for running and debugging (Ctrl+Shift+D or F5):

  • Run Example Script: Execute the example P90 analysis with interactive authentication
  • Run Example (Debug): Debug the example script with breakpoints and step-through debugging
  • Python Debugger: Current File: Debug the currently open Python file
  • Debug pytest Tests: Debug all tests with breakpoints
  • Debug Current Test File: Debug the currently open test file

Testing

The project includes comprehensive test coverage using pytest:

VS Code Test Explorer

The devcontainer is configured to automatically discover tests in VS Code:

  1. Test Discovery: Tests appear in the VS Code Test Explorer sidebar
  2. Run Individual Tests: Click the play button next to any test
  3. Debug Tests: Right-click and select "Debug Test"
  4. Run All Tests: Use the play button at the top of the Test Explorer

Command Line Testing

# Run all tests
python -m pytest tests/ -v

# Run tests with coverage
python -m pytest tests/ --cov=src --cov-report=term-missing

# Run specific test file
python -m pytest tests/test_helpers/test_request_helpers.py -v

# Run specific test class
python -m pytest tests/test_helpers/test_request_helpers.py::TestBuildWeibullErrorFunction -v

# Run specific test
python -m pytest tests/test_helpers/test_request_helpers.py::TestBuildWeibullErrorFunction::test_basic_weibull_creation -v

VS Code Testing Tasks

Use VS Code tasks for common testing workflows:

  • Run Tests: Execute all tests with verbose output
  • Run Tests with Coverage: Generate HTML coverage reports in htmlcov/
  • Run Specific Test File: Run the currently open test file

Test Structure

tests/
โ”œโ”€โ”€ conftest.py                    # Shared fixtures and configuration
โ”œโ”€โ”€ test_helpers/
โ”‚   โ””โ”€โ”€ test_request_helpers.py    # Tests for helper functions
โ””โ”€โ”€ __init__.py

Current Coverage: 27 tests covering:
- Weibull error function creation and validation
- Gaussian error function creation
- Module and system info builders
- Utility functions (temperature, angle conversions)
- Weather data loading and error handling
- Integration tests with protobuf message validation

Protocol Buffer Management

# Rebuild protobuf files (automatic import fixing included)
./scripts/build-proto.sh

# Manual protobuf compilation
python -m grpc_tools.protoc --proto_path=protos \
    --python_out=src/pvl_p90_client/grpcclient \
    --grpc_python_out=src/pvl_p90_client/grpcclient \
    protos/*.proto

Project Structure

pvl_p90_client/
โ”œโ”€โ”€ .devcontainer/                     # VS Code dev container configuration
โ”œโ”€โ”€ .vscode/                           # VS Code workspace settings
โ”œโ”€โ”€ data/
โ”‚   โ””โ”€โ”€ sydney.pvw                     # Sample weather data
โ”œโ”€โ”€ protos/                            # Protocol buffer definitions
โ”œโ”€โ”€ scripts/                           # Build and utility scripts
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ pvl_p90_client/
โ”‚   โ”‚   โ”œโ”€โ”€ client/                    # Main client class
โ”‚   โ”‚   โ”œโ”€โ”€ grpcclient/                # Auto-generated protobuf files
โ”‚   โ”‚   โ””โ”€โ”€ helpers/                   # Authentication and request utilities
โ”‚   โ””โ”€โ”€ example.py                     # Complete usage example
โ”œโ”€โ”€ tests/                             # Test suite
โ”‚   โ”œโ”€โ”€ test_client/
โ”‚   โ”œโ”€โ”€ test_helpers/
โ”‚   โ””โ”€โ”€ conftest.py                    # Shared test fixtures
โ”œโ”€โ”€ .pre-commit-config.yaml            # Pre-commit hooks configuration
โ”œโ”€โ”€ bitbucket-pipelines.yml            # CI/CD pipeline configuration
โ”œโ”€โ”€ pyproject.toml                     # Project configuration
โ”œโ”€โ”€ requirements-dev.in                # Development dependencies (source)
โ”œโ”€โ”€ requirements.in                    # Core dependencies (source)
โ””โ”€โ”€ VERSION                            # Version file

Dependencies

Core Dependencies:

  • grpcio & grpcio-tools: gRPC communication
  • protobuf: Protocol buffer serialization
  • requests: HTTP authentication
  • PyJWT: Token handling

Development Dependencies:

  • ruff: Ultra-fast Python linter and formatter
  • mypy: Type checking
  • pre-commit: Git commit quality enforcement
  • pip-tools: Dependency management

Troubleshooting

Common Issues

Import Errors:

# Rebuild protocol buffers
./scripts/build-proto.sh

Authentication Failures:

  • Verify SunSolve credentials
  • Check network connectivity
  • Remove .pvlToken file to force re-authentication

Permission Denied Errors:

If you encounter a "Permission denied" or HTTP 403 error during analysis:

  • Verify your account has an active Uncertainty Analysis subscription
  • Ensure your account has API access permissions enabled
  • Contact SunSolve support to confirm subscription status
  • Check that your subscription includes P90/uncertainty analysis features

Linting Errors:

# Auto-fix most issues
./scripts/lint.sh -fix

Getting Help

For issues specific to this client library, check:

  1. Error messages and stack traces
  2. Linting output for code quality issues
  3. VS Code Problems panel for real-time feedback

For SunSolve service issues:

  • Verify account access and permissions
  • Check service status and availability

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sunsolve_p90_client-0.1.1.199.tar.gz (56.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sunsolve_p90_client-0.1.1.199-py3-none-any.whl (42.3 kB view details)

Uploaded Python 3

File details

Details for the file sunsolve_p90_client-0.1.1.199.tar.gz.

File metadata

  • Download URL: sunsolve_p90_client-0.1.1.199.tar.gz
  • Upload date:
  • Size: 56.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for sunsolve_p90_client-0.1.1.199.tar.gz
Algorithm Hash digest
SHA256 9f41fc95e34a824ca14fd59cdbaba19e2f78d9693531e50620d95eeec2b6fbff
MD5 70a1964ce8b49600c92b42b63810ee28
BLAKE2b-256 a94a71bc7329d8cbef453cf5a41189d9b1ef02958655841424833e91f4479783

See more details on using hashes here.

File details

Details for the file sunsolve_p90_client-0.1.1.199-py3-none-any.whl.

File metadata

File hashes

Hashes for sunsolve_p90_client-0.1.1.199-py3-none-any.whl
Algorithm Hash digest
SHA256 2862929daabd065b51cba188a86f739a85b634cb7b1787053af215788fe69df5
MD5 cbdb6fc5dccbf3a397008297ca268da4
BLAKE2b-256 d15e06a0127a8e940e2385e7d6652b64a2b57cb5c86eff0674ac79adedb2856e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page