solarwindpy 0.0.1.dev0__py3-none-any.whl → 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of solarwindpy might be problematic. Click here for more details.
- plans/.velocity/metrics.json +96 -0
- plans/0-overview-template.md +268 -0
- plans/N-phase-template.md +106 -0
- plans/PLAN_AUDIT_SUMMARY.md +173 -0
- plans/TEMPLATE-USAGE-GUIDE.md +198 -0
- plans/__init__.py +1 -0
- plans/abandoned/compaction-agent-system/0-Overview.md +123 -0
- plans/abandoned/compaction-agent-system/agents-index-update-plan.md +109 -0
- plans/abandoned/compaction-agent-system/compacted_state.md +85 -0
- plans/abandoned/compaction-agent-system/implementation-plan.md +107 -0
- plans/abandoned/compaction-agent-system/system-validation-report.md +159 -0
- plans/abandoned/compaction-agent-system/usage-guide.md +210 -0
- plans/abandoned/hook-system-enhancement/0-Overview.md +214 -0
- plans/abandoned/hook-system-enhancement/1-Phase1-Core-Infrastructure.md +313 -0
- plans/abandoned/hook-system-enhancement/2-Phase2-Intelligent-Testing.md +385 -0
- plans/abandoned/hook-system-enhancement/3-Phase3-Physics-Validation.md +444 -0
- plans/abandoned/hook-system-enhancement/4-Phase4-Performance-Monitoring.md +458 -0
- plans/abandoned/hook-system-enhancement/5-Phase5-Developer-Experience.md +532 -0
- plans/abandoned/hook-system-enhancement/6-Implementation-Timeline.md +274 -0
- plans/abandoned/hook-system-enhancement/7-Risk-Management.md +376 -0
- plans/abandoned/hook-system-enhancement/8-Testing-Strategy.md +579 -0
- plans/abandoned/readthedocs-automation/0-Overview.md +247 -0
- plans/abandoned/readthedocs-automation/1-Emergency-Documentation-Fixes.md +270 -0
- plans/abandoned/readthedocs-automation/2-Template-System-Enhancement.md +811 -0
- plans/abandoned/readthedocs-automation/3-Quality-Audit-ReadTheDocs-Integration.md +844 -0
- plans/abandoned/readthedocs-automation/4-Plan-Consolidation-Cleanup.md +632 -0
- plans/abandoned/readthedocs-automation/9-Closeout.md +207 -0
- plans/abandoned/readthedocs-automation/ABANDONMENT_REASON.md +72 -0
- plans/cicd-architecture-redesign/0-Overview.md +193 -0
- plans/cicd-architecture-redesign/1-Workflow-Creation.md +103 -0
- plans/cicd-architecture-redesign/2-Version-Detection.md +123 -0
- plans/cicd-architecture-redesign/3-Deployment-Gates.md +169 -0
- plans/cicd-architecture-redesign/4-RC-Testing.md +194 -0
- plans/cicd-architecture-redesign/5-TestPyPI-Validation.md +264 -0
- plans/cicd-architecture-redesign/6-Production-Release.md +263 -0
- plans/cicd-architecture-redesign/7-Cleanup.md +243 -0
- plans/cicd-architecture-redesign/8-Documentation.md +285 -0
- plans/cicd-architecture-redesign/Closeout.md +225 -0
- plans/closeout-template.md +259 -0
- plans/completed/circular-import-audit/0-Overview.md +152 -0
- plans/completed/circular-import-audit/1-Static-Dependency-Analysis.md +62 -0
- plans/completed/circular-import-audit/2-Dynamic-Import-Testing.md +56 -0
- plans/completed/circular-import-audit/3-Performance-Impact-Assessment.md +56 -0
- plans/completed/circular-import-audit/4-Issue-Remediation.md +78 -0
- plans/completed/circular-import-audit/5-Preventive-Infrastructure.md +89 -0
- plans/completed/claude-settings-ecosystem-alignment/0-Overview.md +162 -0
- plans/completed/claude-settings-ecosystem-alignment/1-Security-Foundation.md +148 -0
- plans/completed/claude-settings-ecosystem-alignment/2-Hook-Integration.md +158 -0
- plans/completed/claude-settings-ecosystem-alignment/3-Agent-System-Integration.md +177 -0
- plans/completed/claude-settings-ecosystem-alignment/4-Enhanced-Workflow-Automation.md +159 -0
- plans/completed/claude-settings-ecosystem-alignment/5-Validation-Monitoring.md +181 -0
- plans/completed/claude-settings-ecosystem-alignment/compacted_session_state.md +290 -0
- plans/completed/combined_plan_with_checklist_documentation/1-Overview-and-Goals.md +51 -0
- plans/completed/combined_plan_with_checklist_documentation/2-Toolchain-and-Hosting.md +69 -0
- plans/completed/combined_plan_with_checklist_documentation/3-Repository-Structure.md +61 -0
- plans/completed/combined_plan_with_checklist_documentation/4-Configuration-and-Standards.md +70 -0
- plans/completed/combined_plan_with_checklist_documentation/5-Documentation-Content.md +62 -0
- plans/completed/combined_plan_with_checklist_documentation/6-CI-CD-and-Validation.md +58 -0
- plans/completed/combined_plan_with_checklist_documentation/7-Maintenance.md +55 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/0-Overview.md +135 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/1-Common-fixtures.md +59 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/10-power_laws.md +56 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/2-core.py-FitFunction.md +118 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/3-gaussians.py-Gaussian-GaussianNormalized-GaussianLn.md +69 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/4-trend_fits.py-TrendFit.md +99 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/5-plots.py-FFPlot.md +98 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/6-tex_info.py-TeXinfo.md +79 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/7-Justification.md +49 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/8-exponentials.md +64 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/9-lines.md +58 -0
- plans/completed/combined_test_plan_with_checklist_plotting/0-Overview.md +142 -0
- plans/completed/combined_test_plan_with_checklist_plotting/1-base.py.md +90 -0
- plans/completed/combined_test_plan_with_checklist_plotting/10-labels-special.py.md +102 -0
- plans/completed/combined_test_plan_with_checklist_plotting/11-labels-chemistry.py.md +212 -0
- plans/completed/combined_test_plan_with_checklist_plotting/12-labels-composition.py.md +242 -0
- plans/completed/combined_test_plan_with_checklist_plotting/13-labels-datetime.py.md +247 -0
- plans/completed/combined_test_plan_with_checklist_plotting/14-labels-elemental_abundance.py.md +274 -0
- plans/completed/combined_test_plan_with_checklist_plotting/15-visual-validation.md +256 -0
- plans/completed/combined_test_plan_with_checklist_plotting/16-integration-testing.md +266 -0
- plans/completed/combined_test_plan_with_checklist_plotting/17-performance-benchmarks.md +267 -0
- plans/completed/combined_test_plan_with_checklist_plotting/18-Fixtures-and-Utilities.md +86 -0
- plans/completed/combined_test_plan_with_checklist_plotting/2-agg_plot.py.md +90 -0
- plans/completed/combined_test_plan_with_checklist_plotting/3-histograms.py.md +201 -0
- plans/completed/combined_test_plan_with_checklist_plotting/4-scatter.py.md +167 -0
- plans/completed/combined_test_plan_with_checklist_plotting/5-spiral.py.md +216 -0
- plans/completed/combined_test_plan_with_checklist_plotting/6-orbits.py.md +108 -0
- plans/completed/combined_test_plan_with_checklist_plotting/7-tools.py.md +86 -0
- plans/completed/combined_test_plan_with_checklist_plotting/8-select_data_from_figure.py.md +97 -0
- plans/completed/combined_test_plan_with_checklist_plotting/9-labels-base.py.md +88 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/.gitkeep +0 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/0-Overview.md +170 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/1-Package-Entry-Point-__init__.py.md +121 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/2-Core-Base-Classes-base.py.md +142 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/3-Plotting-Helpers-plots.py.md +123 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/4-LISIRD-Sub-package.md +119 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/5-Extrema-Calculator.md +103 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/6-Sunspot-Number-Sub-package.md +163 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/7-Sunspot-Number-Init.py.md +217 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/compacted_state.md +52 -0
- plans/completed/compaction-agent-modernization/0-Overview.md +156 -0
- plans/completed/compaction-agent-modernization/1-Architecture-Audit-Gap-Analysis.md +132 -0
- plans/completed/compaction-agent-modernization/2-Token-Baseline-Recalibration.md +153 -0
- plans/completed/compaction-agent-modernization/3-Agent-Reference-Updates.md +184 -0
- plans/completed/compaction-agent-modernization/4-Compression-Algorithm-Modernization.md +238 -0
- plans/completed/compaction-agent-modernization/5-Workflow-Integration-Streamlining.md +252 -0
- plans/completed/compaction-agent-modernization/6-Template-Structure-Optimization.md +240 -0
- plans/completed/compaction-agent-modernization/7-Integration-Testing-Validation.md +292 -0
- plans/completed/compaction-hook-enhancement/0-Overview.md +150 -0
- plans/completed/compaction-hook-enhancement/1-Token-Estimation-Enhancement.md +179 -0
- plans/completed/compaction-hook-enhancement/2-Compression-Intelligence.md +294 -0
- plans/completed/compaction-hook-enhancement/3-Git-Integration-Metadata.md +310 -0
- plans/completed/compaction-hook-enhancement/4-Session-Continuity-Features.md +358 -0
- plans/completed/compaction-hook-enhancement/5-Testing-Strategy.md +404 -0
- plans/completed/compaction-hook-enhancement/6-Integration-Roadmap.md +319 -0
- plans/completed/compaction-hook-enhancement/compacted_state.md +142 -0
- plans/completed/docstring-audit-enhancement/0-Overview.md +274 -0
- plans/completed/docstring-audit-enhancement/1-Infrastructure-Setup-and-Validation-Tools.md +206 -0
- plans/completed/docstring-audit-enhancement/2-Core-Physics-Modules-Enhancement.md +237 -0
- plans/completed/docstring-audit-enhancement/3-Fitfunctions-Mathematical-Modules-Enhancement.md +188 -0
- plans/completed/docstring-audit-enhancement/4-Plotting-Visualization-Modules-Enhancement.md +243 -0
- plans/completed/docstring-audit-enhancement/5-Specialized-Modules-Enhancement.md +216 -0
- plans/completed/docstring-audit-enhancement/6-Validation-and-Integration.md +216 -0
- plans/completed/fitfunctions-testing-implementation/0-Overview.md +130 -0
- plans/completed/fitfunctions-testing-implementation/1-Test-Infrastructure-Setup.md +79 -0
- plans/completed/fitfunctions-testing-implementation/2-Common-Fixtures-Test-Utilities.md +104 -0
- plans/completed/fitfunctions-testing-implementation/3-Core-FitFunction-Testing.md +168 -0
- plans/completed/fitfunctions-testing-implementation/4-Specialized-Function-Classes.md +210 -0
- plans/completed/fitfunctions-testing-implementation/5-Advanced-Classes-Testing.md +214 -0
- plans/completed/fitfunctions-testing-implementation/6-Plotting-Integration-Testing.md +231 -0
- plans/completed/fitfunctions-testing-implementation/7-Extended-Coverage-BONUS.md +184 -0
- plans/completed/numpy-docstring-conversion-plan/numpy-docstring-conversion-plan.md +118 -0
- plans/completed/pr-review-remediation/0-Overview.md +138 -0
- plans/completed/pr-review-remediation/1-Critical-Safety-Improvements.md +179 -0
- plans/completed/pr-review-remediation/2-Smart-Timeouts-Validation.md +399 -0
- plans/completed/pr-review-remediation/3-Enhanced-GitHub-Integration.md +258 -0
- plans/completed/pr-review-remediation/compacted_state.md +66 -0
- plans/completed/python-310-migration/0-Overview.md +390 -0
- plans/completed/python-310-migration/1-Planning-Setup.md +164 -0
- plans/completed/python-310-migration/2-Implementation.md +256 -0
- plans/completed/python-310-migration/3-Testing-Validation.md +335 -0
- plans/completed/python-310-migration/4-Documentation-Release.md +274 -0
- plans/completed/python-310-migration/5-Closeout.md +252 -0
- plans/completed/requirements-management-consolidation/0-Overview.md +118 -0
- plans/completed/requirements-management-consolidation/1-Documentation-Validation-Environment-Setup.md +116 -0
- plans/completed/requirements-management-consolidation/2-Requirements-Consolidation.md +161 -0
- plans/completed/requirements-management-consolidation/3-Workflow-Automation-Final-Integration.md +196 -0
- plans/completed/single-ecosystem-plan-implementation/0-Overview.md +83 -0
- plans/completed/single-ecosystem-plan-implementation/1-Plan-Preservation-Session-Management.md +38 -0
- plans/completed/single-ecosystem-plan-implementation/2-File-Structure-Optimization.md +43 -0
- plans/completed/single-ecosystem-plan-implementation/3-Plan-Migration-Archive-Setup.md +82 -0
- plans/completed/single-ecosystem-plan-implementation/4-Agent-System-Transformation.md +108 -0
- plans/completed/single-ecosystem-plan-implementation/5-Template-System-Enhancement.md +131 -0
- plans/completed/single-ecosystem-plan-implementation/6-Final-Validation-Testing.md +120 -0
- plans/completed/test-directory-consolidation/0-Overview.md +51 -0
- plans/completed/test-directory-consolidation/1-Structure-Preparation.md +82 -0
- plans/completed/test-directory-consolidation/2-File-Migration.md +100 -0
- plans/completed/test-directory-consolidation/3-Import-Transformation.md +117 -0
- plans/completed/test-directory-consolidation/4-Configuration-Consolidation.md +140 -0
- plans/completed/test-directory-consolidation/5-Validation.md +152 -0
- plans/completed/test-directory-consolidation/6-Cleanup.md +156 -0
- plans/completed/test-planning-agents-architecture/0-Overview.md +79 -0
- plans/completed/test-planning-agents-architecture/1-Branch-Isolation-Testing.md +49 -0
- plans/completed/test-planning-agents-architecture/2-Cross-Branch-Coordination.md +51 -0
- plans/completed/test-planning-agents-architecture/3-Merge-Workflow-Testing.md +48 -0
- plans/deployment-semver-pypi-rtd/0-Overview.md +463 -0
- plans/deployment-semver-pypi-rtd/1-Semantic-Versioning-Foundation.md +136 -0
- plans/deployment-semver-pypi-rtd/2-PyPI-Deployment-Infrastructure.md +168 -0
- plans/deployment-semver-pypi-rtd/3-Release-Automation.md +214 -0
- plans/deployment-semver-pypi-rtd/4-Plan-Closeout.md +543 -0
- plans/deployment-semver-pypi-rtd/compacted_session_state.md +172 -0
- plans/deployment-semver-pypi-rtd/compacted_state.md +131 -0
- plans/documentation-code-audit/0-Overview.md +393 -0
- plans/documentation-code-audit/1-Discovery-Inventory.md +183 -0
- plans/documentation-code-audit/2-Execution-Environment-Setup.md +263 -0
- plans/documentation-code-audit/3-Systematic-Validation.md +322 -0
- plans/documentation-code-audit/4-Code-Example-Remediation.md +358 -0
- plans/documentation-code-audit/5-Physics-MultiIndex-Compliance.md +464 -0
- plans/documentation-code-audit/6-Doctest-Integration.md +523 -0
- plans/documentation-code-audit/7-Reporting-Documentation.md +498 -0
- plans/documentation-code-audit/8-Closeout.md +456 -0
- plans/documentation-rebuild-session/compacted_state.md +109 -0
- plans/documentation-rendering-fixes/0-Overview.md +104 -0
- plans/documentation-rendering-fixes/1-Sphinx-Build-Diagnostics-Warning-Audit.md +101 -0
- plans/documentation-rendering-fixes/2-Configuration-Infrastructure-Fixes.md +113 -0
- plans/documentation-rendering-fixes/3-Docstring-Syntax-Audit-Repair.md +131 -0
- plans/documentation-rendering-fixes/4-HTML-Page-Rendering-Verification.md +113 -0
- plans/documentation-rendering-fixes/5-Advanced-Documentation-Quality-Assurance.md +119 -0
- plans/documentation-rendering-fixes/6-Documentation-Build-Optimization-Testing.md +129 -0
- plans/documentation-rendering-fixes/compacted_state.md +132 -0
- plans/documentation-template-fix/0-Overview.md +197 -0
- plans/documentation-template-fix/1-Template-System-Analysis.md +269 -0
- plans/documentation-template-fix/2-Template-Modification.md +609 -0
- plans/documentation-template-fix/3-Build-System-Integration.md +766 -0
- plans/documentation-template-fix/4-Testing-Validation.md +1399 -0
- plans/documentation-template-fix/5-Documentation-Training.md +602 -0
- plans/documentation-workflow-fix/0-Overview.md +222 -0
- plans/documentation-workflow-fix/1-Immediate-Fixes.md +238 -0
- plans/documentation-workflow-fix/2-Configuration-Setup.md +298 -0
- plans/documentation-workflow-fix/3-Pre-commit-Integration.md +382 -0
- plans/documentation-workflow-fix/4-Workflow-Improvements.md +446 -0
- plans/documentation-workflow-fix/5-Documentation-and-Training.md +527 -0
- plans/duplicate-object-warnings-fix-plan.md +130 -0
- plans/github-issues-migration/0-Overview.md +510 -0
- plans/github-issues-migration/1-Foundation-Label-System.md +180 -0
- plans/github-issues-migration/2-Migration-Tool-Rewrite.md +235 -0
- plans/github-issues-migration/3-CLI-Integration-Automation.md +169 -0
- plans/github-issues-migration/4-Validated-Migration.md +252 -0
- plans/github-issues-migration/5-Documentation-Training.md +171 -0
- plans/github-issues-migration/6-Closeout.md +179 -0
- plans/github-workflows-repair/repair-plan.md +299 -0
- plans/issues_from_plans.py +342 -0
- plans/pr-270-doc-validation-fixes/0-Overview.md +354 -0
- plans/pr-270-doc-validation-fixes/1-Critical-PR-Fixes.md +117 -0
- plans/pr-270-doc-validation-fixes/2-Framework-Right-Sizing.md +129 -0
- plans/pr-270-doc-validation-fixes/3-Sustainable-Documentation.md +126 -0
- plans/pr-270-doc-validation-fixes/4-Closeout-Migration.md +143 -0
- plans/pr-270-doc-validation-fixes/PLAN_COMPLETED.md +149 -0
- plans/python-310-migration/0-Overview.md +390 -0
- plans/python-310-migration/1-Planning-Setup.md +164 -0
- plans/python-310-migration/2-Implementation.md +256 -0
- plans/python-310-migration/3-Testing-Validation.md +335 -0
- plans/python-310-migration/4-Documentation-Release.md +274 -0
- plans/python-310-migration/5-Closeout.md +252 -0
- plans/readthedocs-simplified/0-Overview.md +243 -0
- plans/readthedocs-simplified/1-Immediate-Fixes.md +216 -0
- plans/readthedocs-simplified/2-Template-Simplification.md +278 -0
- plans/readthedocs-simplified/3-ReadTheDocs-Setup.md +298 -0
- plans/readthedocs-simplified/4-Testing-Validation.md +328 -0
- plans/readthedocs-simplified/5-Closeout.md +231 -0
- plans/readthedocs-simplified/compacted_state.md +127 -0
- plans/session-compaction-2025-08-12/compacted_state.md +114 -0
- plans/session-compaction-2025-08-13/compacted_state.md +145 -0
- plans/session-continuity-protocol/0-Overview.md +35 -0
- plans/session-continuity-protocol/1-Core-Principles-Framework.md +40 -0
- plans/session-continuity-protocol/2-Pre-Session-Validation-System.md +79 -0
- plans/session-continuity-protocol/3-Context-Switching-Prevention.md +87 -0
- plans/session-continuity-protocol/4-Progress-Tracking-Recovery.md +100 -0
- plans/sphinx-warnings-analysis.md +222 -0
- plans/systemprompt-optimization/0-Overview.md +447 -0
- plans/systemprompt-optimization/1-Deploy-SystemPrompt.md +114 -0
- plans/systemprompt-optimization/2-Documentation-Alignment.md +198 -0
- plans/systemprompt-optimization/3-Monitoring-Infrastructure.md +396 -0
- plans/systemprompt-optimization/4-Implementation-Script.md +450 -0
- plans/systemprompt-optimization/9-Closeout.md +165 -0
- plans/systemprompt-optimization/compacted_state.md +143 -0
- plans/template-value-propositions/0-Overview.md +357 -0
- plans/template-value-propositions/1-Value-Proposition-Framework-Design.md +144 -0
- plans/template-value-propositions/2-Plan-Template-Enhancement.md +178 -0
- plans/template-value-propositions/3-Value-Generator-Hook-Implementation.md +291 -0
- plans/template-value-propositions/4-Value-Validator-Hook-Implementation.md +274 -0
- plans/template-value-propositions/5-Documentation-Agent-Updates.md +219 -0
- plans/template-value-propositions/6-Integration-Testing-Validation.md +247 -0
- plans/tests-audit/0-Overview.md +410 -0
- plans/tests-audit/1-Discovery-Inventory.md +170 -0
- plans/tests-audit/2-Physics-Validation-Audit.md +195 -0
- plans/tests-audit/3-Architecture-Compliance.md +195 -0
- plans/tests-audit/4-Numerical-Stability-Analysis.md +203 -0
- plans/tests-audit/5-Documentation-Enhancement.md +220 -0
- plans/tests-audit/6-Audit-Deliverables.md +220 -0
- plans/tests-audit/7-Closeout.md +252 -0
- plans/tests-audit/artifacts/ARCHITECTURE_COMPLIANCE_REPORT.md +315 -0
- plans/tests-audit/artifacts/ARCHITECTURE_RECOMMENDATIONS.md +943 -0
- plans/tests-audit/artifacts/COMPREHENSIVE_AUDIT_REPORT.md +356 -0
- plans/tests-audit/artifacts/CONTRIBUTING_ENHANCED_TEMPLATE.md +419 -0
- plans/tests-audit/artifacts/COVERAGE_GAP_ANALYSIS.md +152 -0
- plans/tests-audit/artifacts/DOCUMENTATION_ENHANCEMENT_REPORT.md +502 -0
- plans/tests-audit/artifacts/EXECUTIVE_AUDIT_SUMMARY.md +129 -0
- plans/tests-audit/artifacts/IMPLEMENTATION_ROADMAP.md +647 -0
- plans/tests-audit/artifacts/NUMERICAL_RECOMMENDATIONS.md +739 -0
- plans/tests-audit/artifacts/NUMERICAL_STABILITY_GUIDE_TEMPLATE.rst +451 -0
- plans/tests-audit/artifacts/NUMERICAL_STABILITY_REPORT.md +301 -0
- plans/tests-audit/artifacts/PHASE_3_SUMMARY.md +280 -0
- plans/tests-audit/artifacts/PHASE_4_SUMMARY.md +229 -0
- plans/tests-audit/artifacts/PHASE_5_SUMMARY.md +292 -0
- plans/tests-audit/artifacts/PHASE_6_CLOSEOUT.md +278 -0
- plans/tests-audit/artifacts/PHYSICS_GUIDE_TEMPLATE.rst +268 -0
- plans/tests-audit/artifacts/PHYSICS_VALIDATION_REPORT.md +235 -0
- plans/tests-audit/artifacts/TECHNICAL_DELIVERABLES_PACKAGE.md +2502 -0
- plans/tests-audit/artifacts/TEST_INVENTORY.csv +1204 -0
- plans/tests-audit/artifacts/TEST_INVENTORY.md +135 -0
- plans/tests-audit/artifacts/test_discovery_analysis.py +231 -0
- plans/tests-audit/artifacts/test_parser.py +395 -0
- solarwindpy/README.md +3 -0
- solarwindpy/Untitled.ipynb +54 -0
- solarwindpy/__init__.py +74 -0
- solarwindpy/core/__init__.py +23 -0
- solarwindpy/core/alfvenic_turbulence.py +804 -0
- solarwindpy/core/base.py +267 -0
- solarwindpy/core/ions.py +309 -0
- solarwindpy/core/plasma.py +2133 -0
- solarwindpy/core/spacecraft.py +256 -0
- solarwindpy/core/tensor.py +90 -0
- solarwindpy/core/units_constants.py +199 -0
- solarwindpy/core/vector.py +328 -0
- solarwindpy/fitfunctions/__init__.py +20 -0
- solarwindpy/fitfunctions/core.py +734 -0
- solarwindpy/fitfunctions/exponentials.py +188 -0
- solarwindpy/fitfunctions/gaussians.py +264 -0
- solarwindpy/fitfunctions/lines.py +116 -0
- solarwindpy/fitfunctions/moyal.py +71 -0
- solarwindpy/fitfunctions/plots.py +751 -0
- solarwindpy/fitfunctions/power_laws.py +209 -0
- solarwindpy/fitfunctions/tex_info.py +568 -0
- solarwindpy/fitfunctions/trend_fits.py +482 -0
- solarwindpy/instabilities/__init__.py +16 -0
- solarwindpy/instabilities/beta_ani.py +82 -0
- solarwindpy/instabilities/verscharen2016.py +631 -0
- solarwindpy/plotting/__init__.py +33 -0
- solarwindpy/plotting/agg_plot.py +489 -0
- solarwindpy/plotting/base.py +465 -0
- solarwindpy/plotting/hist1d.py +405 -0
- solarwindpy/plotting/hist2d.py +1035 -0
- solarwindpy/plotting/histograms.py +1845 -0
- solarwindpy/plotting/labels/__init__.py +104 -0
- solarwindpy/plotting/labels/base.py +686 -0
- solarwindpy/plotting/labels/chemistry.py +19 -0
- solarwindpy/plotting/labels/composition.py +100 -0
- solarwindpy/plotting/labels/datetime.py +235 -0
- solarwindpy/plotting/labels/elemental_abundance.py +73 -0
- solarwindpy/plotting/labels/special.py +794 -0
- solarwindpy/plotting/orbits.py +515 -0
- solarwindpy/plotting/scatter.py +99 -0
- solarwindpy/plotting/select_data_from_figure.py +329 -0
- solarwindpy/plotting/spiral.py +980 -0
- solarwindpy/plotting/tools.py +434 -0
- solarwindpy/scripts/__init__.py +1 -0
- solarwindpy/scripts/logs/.gitignore +1 -0
- solarwindpy/solar_activity/__init__.py +53 -0
- solarwindpy/solar_activity/base.py +605 -0
- solarwindpy/solar_activity/lisird/__init__.py +3 -0
- solarwindpy/solar_activity/lisird/extrema_calculator.py +394 -0
- solarwindpy/solar_activity/lisird/lisird.py +319 -0
- solarwindpy/solar_activity/plots.py +116 -0
- solarwindpy/solar_activity/sunspot_number/.DS_Store +0 -0
- solarwindpy/solar_activity/sunspot_number/__init__.py +3 -0
- solarwindpy/solar_activity/sunspot_number/sidc.py +556 -0
- solarwindpy/solar_activity/sunspot_number/ssn_extrema.csv +72 -0
- solarwindpy/solar_activity/sunspot_number/ssn_extrema.csv.silso +72 -0
- solarwindpy/tools/__init__.py +162 -0
- solarwindpy-0.1.0.dist-info/METADATA +181 -0
- solarwindpy-0.1.0.dist-info/RECORD +409 -0
- {solarwindpy-0.0.1.dev0.dist-info → solarwindpy-0.1.0.dist-info}/WHEEL +1 -1
- solarwindpy-0.1.0.dist-info/licenses/LICENSE.rst +32 -0
- solarwindpy-0.1.0.dist-info/top_level.txt +3 -0
- tests/__init__.py +1 -0
- tests/conftest.py +10 -0
- tests/core/__init__.py +1 -0
- tests/core/test_alfvenic_turbulence.py +544 -0
- tests/core/test_base.py +112 -0
- tests/core/test_base_head_tail.py +29 -0
- tests/core/test_base_mi_tuples.py +11 -0
- tests/core/test_core_verify_datetimeindex.py +32 -0
- tests/core/test_ions.py +325 -0
- tests/core/test_plasma.py +2581 -0
- tests/core/test_plasma_io.py +12 -0
- tests/core/test_quantities.py +507 -0
- tests/core/test_spacecraft.py +210 -0
- tests/core/test_units_constants.py +22 -0
- tests/data/epoch.csv +4 -0
- tests/data/plasma.csv +4 -0
- tests/data/spacecraft.csv +4 -0
- tests/fitfunctions/conftest.py +60 -0
- tests/fitfunctions/test_core.py +193 -0
- tests/fitfunctions/test_exponentials.py +342 -0
- tests/fitfunctions/test_gaussians.py +142 -0
- tests/fitfunctions/test_lines.py +349 -0
- tests/fitfunctions/test_moyal.py +258 -0
- tests/fitfunctions/test_plots.py +258 -0
- tests/fitfunctions/test_power_laws.py +365 -0
- tests/fitfunctions/test_tex_info.py +183 -0
- tests/fitfunctions/test_trend_fit_properties.py +31 -0
- tests/fitfunctions/test_trend_fits.py +244 -0
- tests/plotting/__init__.py +1 -0
- tests/plotting/labels/__init__.py +1 -0
- tests/plotting/labels/test_chemistry.py +243 -0
- tests/plotting/labels/test_composition.py +345 -0
- tests/plotting/labels/test_datetime.py +445 -0
- tests/plotting/labels/test_elemental_abundance.py +366 -0
- tests/plotting/labels/test_init.py +66 -0
- tests/plotting/labels/test_labels_base.py +347 -0
- tests/plotting/labels/test_special.py +550 -0
- tests/plotting/test_agg_plot.py +602 -0
- tests/plotting/test_base.py +752 -0
- tests/plotting/test_fixtures_utilities.py +775 -0
- tests/plotting/test_histograms.py +546 -0
- tests/plotting/test_integration.py +675 -0
- tests/plotting/test_orbits.py +435 -0
- tests/plotting/test_performance.py +708 -0
- tests/plotting/test_scatter.py +752 -0
- tests/plotting/test_select_data_from_figure.py +1209 -0
- tests/plotting/test_spiral.py +573 -0
- tests/plotting/test_tools.py +607 -0
- tests/plotting/test_visual_validation.py +465 -0
- tests/solar_activity/__init__.py +1 -0
- tests/solar_activity/lisird/__init__.py +1 -0
- tests/solar_activity/lisird/test_extrema_calculator.py +593 -0
- tests/solar_activity/lisird/test_lisird_id.py +187 -0
- tests/solar_activity/sunspot_number/__init__.py +1 -0
- tests/solar_activity/sunspot_number/test_init.py +399 -0
- tests/solar_activity/sunspot_number/test_sidc.py +465 -0
- tests/solar_activity/sunspot_number/test_sidc_id.py +223 -0
- tests/solar_activity/sunspot_number/test_sidc_loader.py +275 -0
- tests/solar_activity/sunspot_number/test_ssn_extrema.py +406 -0
- tests/solar_activity/test_base.py +656 -0
- tests/solar_activity/test_init.py +396 -0
- tests/solar_activity/test_plots.py +371 -0
- tests/test_circular_imports.py +408 -0
- tests/test_issue_titles.py +25 -0
- tests/test_statusline.py +298 -0
- solarwindpy-0.0.1.dev0.dist-info/METADATA +0 -14
- solarwindpy-0.0.1.dev0.dist-info/RECORD +0 -4
- solarwindpy-0.0.1.dev0.dist-info/top_level.txt +0 -1
|
@@ -0,0 +1,752 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Tests for solarwindpy.plotting.base module.
|
|
3
|
+
|
|
4
|
+
This module provides comprehensive test coverage for the abstract base classes and
|
|
5
|
+
helper classes used throughout the plotting package.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
import logging
|
|
10
|
+
import pandas as pd
|
|
11
|
+
import numpy as np
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from unittest.mock import patch, MagicMock
|
|
14
|
+
|
|
15
|
+
from solarwindpy.plotting.base import (
|
|
16
|
+
Base,
|
|
17
|
+
LogAxes,
|
|
18
|
+
AxesLabels,
|
|
19
|
+
RangeLimits,
|
|
20
|
+
DataLimFormatter,
|
|
21
|
+
CbarMaker,
|
|
22
|
+
PlotWithZdata,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ConcreteBase(Base):
|
|
27
|
+
"""Concrete implementation of Base for testing abstract functionality."""
|
|
28
|
+
|
|
29
|
+
def __init__(self):
|
|
30
|
+
super().__init__()
|
|
31
|
+
self._data = None
|
|
32
|
+
self._clip = False
|
|
33
|
+
|
|
34
|
+
def set_data(self, data=None):
|
|
35
|
+
"""Minimal implementation for testing."""
|
|
36
|
+
if data is None:
|
|
37
|
+
self._data = pd.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
|
|
38
|
+
else:
|
|
39
|
+
self._data = data
|
|
40
|
+
|
|
41
|
+
def make_plot(self):
|
|
42
|
+
"""Minimal implementation for testing."""
|
|
43
|
+
return "plot_created"
|
|
44
|
+
|
|
45
|
+
def set_path(self, new, add_scale=False):
|
|
46
|
+
"""Concrete implementation of set_path for testing."""
|
|
47
|
+
path, x, y, z, scale_info = super().set_path(new, add_scale)
|
|
48
|
+
self._path = path
|
|
49
|
+
return path, x, y, z, scale_info
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class ConcretePlotWithZdata(PlotWithZdata):
|
|
53
|
+
"""Concrete implementation of PlotWithZdata for testing."""
|
|
54
|
+
|
|
55
|
+
def __init__(self):
|
|
56
|
+
super().__init__()
|
|
57
|
+
|
|
58
|
+
def make_plot(self):
|
|
59
|
+
"""Minimal implementation for testing."""
|
|
60
|
+
return "plot_with_z_created"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class TestNamedTuples:
|
|
64
|
+
"""Test the named tuple definitions."""
|
|
65
|
+
|
|
66
|
+
def test_log_axes_creation(self):
|
|
67
|
+
"""Test LogAxes namedtuple with defaults."""
|
|
68
|
+
# LogAxes defaults=(False,) only provides default for y, x is required
|
|
69
|
+
log_axes = LogAxes(x=True)
|
|
70
|
+
assert log_axes.x is True
|
|
71
|
+
assert log_axes.y is False # default
|
|
72
|
+
|
|
73
|
+
log_axes = LogAxes(True, True)
|
|
74
|
+
assert log_axes.x is True
|
|
75
|
+
assert log_axes.y is True
|
|
76
|
+
|
|
77
|
+
def test_axes_labels_creation(self):
|
|
78
|
+
"""Test AxesLabels namedtuple with defaults."""
|
|
79
|
+
# AxesLabels defaults=(None,) only provides default for z, x and y are required
|
|
80
|
+
labels = AxesLabels("X-axis", "Y-axis")
|
|
81
|
+
assert labels.x == "X-axis"
|
|
82
|
+
assert labels.y == "Y-axis"
|
|
83
|
+
assert labels.z is None # default
|
|
84
|
+
|
|
85
|
+
labels = AxesLabels("X-axis", "Y-axis", "Z-axis")
|
|
86
|
+
assert labels.x == "X-axis"
|
|
87
|
+
assert labels.y == "Y-axis"
|
|
88
|
+
assert labels.z == "Z-axis"
|
|
89
|
+
|
|
90
|
+
def test_range_limits_creation(self):
|
|
91
|
+
"""Test RangeLimits namedtuple with defaults."""
|
|
92
|
+
# RangeLimits requires at least the 'lower' parameter
|
|
93
|
+
limits = RangeLimits(None)
|
|
94
|
+
assert limits.lower is None
|
|
95
|
+
assert limits.upper is None
|
|
96
|
+
|
|
97
|
+
limits = RangeLimits(0, 100)
|
|
98
|
+
assert limits.lower == 0
|
|
99
|
+
assert limits.upper == 100
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class TestBaseAbstractClass:
|
|
103
|
+
"""Test the Base abstract class functionality."""
|
|
104
|
+
|
|
105
|
+
def test_base_instantiation_via_subclass(self):
|
|
106
|
+
"""Test that Base can be instantiated via subclass with proper
|
|
107
|
+
initialization."""
|
|
108
|
+
concrete = ConcreteBase()
|
|
109
|
+
|
|
110
|
+
# Verify initialization occurred
|
|
111
|
+
assert hasattr(concrete, "_logger")
|
|
112
|
+
assert hasattr(concrete, "_labels")
|
|
113
|
+
assert hasattr(concrete, "_log")
|
|
114
|
+
assert hasattr(concrete, "_path")
|
|
115
|
+
|
|
116
|
+
# Verify types and defaults
|
|
117
|
+
assert isinstance(concrete._labels, tuple) # AxesLabels is a namedtuple
|
|
118
|
+
assert isinstance(concrete._log, tuple) # LogAxes is a namedtuple
|
|
119
|
+
assert concrete._labels.x == "x"
|
|
120
|
+
assert concrete._labels.y == "y"
|
|
121
|
+
assert concrete._log.x is False
|
|
122
|
+
assert concrete._log.y is False
|
|
123
|
+
|
|
124
|
+
def test_base_cannot_be_instantiated_directly(self):
|
|
125
|
+
"""Test that Base cannot be instantiated directly."""
|
|
126
|
+
with pytest.raises(TypeError):
|
|
127
|
+
Base()
|
|
128
|
+
|
|
129
|
+
def test_str_returns_class_name(self):
|
|
130
|
+
"""Test that __str__ returns the class name."""
|
|
131
|
+
concrete = ConcreteBase()
|
|
132
|
+
assert str(concrete) == "ConcreteBase"
|
|
133
|
+
|
|
134
|
+
def test_logger_initialization(self):
|
|
135
|
+
"""Test that logger is properly initialized."""
|
|
136
|
+
concrete = ConcreteBase()
|
|
137
|
+
logger = concrete.logger
|
|
138
|
+
assert isinstance(logger, logging.Logger)
|
|
139
|
+
assert logger.name.endswith("ConcreteBase")
|
|
140
|
+
|
|
141
|
+
def test_data_property(self):
|
|
142
|
+
"""Test that data property returns internal _data."""
|
|
143
|
+
concrete = ConcreteBase()
|
|
144
|
+
test_data = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
|
|
145
|
+
concrete._data = test_data
|
|
146
|
+
assert concrete.data is test_data
|
|
147
|
+
|
|
148
|
+
def test_clip_property(self):
|
|
149
|
+
"""Test that clip property returns internal _clip."""
|
|
150
|
+
concrete = ConcreteBase()
|
|
151
|
+
concrete._clip = True
|
|
152
|
+
assert concrete.clip is True
|
|
153
|
+
|
|
154
|
+
concrete._clip = False
|
|
155
|
+
assert concrete.clip is False
|
|
156
|
+
|
|
157
|
+
def test_log_property(self):
|
|
158
|
+
"""Test that log property returns internal _log."""
|
|
159
|
+
concrete = ConcreteBase()
|
|
160
|
+
assert concrete.log == concrete._log
|
|
161
|
+
assert concrete.log.x is False
|
|
162
|
+
assert concrete.log.y is False
|
|
163
|
+
|
|
164
|
+
def test_labels_property(self):
|
|
165
|
+
"""Test that labels property returns internal _labels."""
|
|
166
|
+
concrete = ConcreteBase()
|
|
167
|
+
assert concrete.labels == concrete._labels
|
|
168
|
+
assert concrete.labels.x == "x"
|
|
169
|
+
assert concrete.labels.y == "y"
|
|
170
|
+
|
|
171
|
+
def test_path_property(self):
|
|
172
|
+
"""Test that path property returns internal _path."""
|
|
173
|
+
concrete = ConcreteBase()
|
|
174
|
+
# Path should be set during initialization
|
|
175
|
+
assert hasattr(concrete, "_path")
|
|
176
|
+
assert concrete.path == concrete._path
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class TestBaseLogMethods:
|
|
180
|
+
"""Test log scaling functionality in Base class."""
|
|
181
|
+
|
|
182
|
+
def test_set_log_defaults(self):
|
|
183
|
+
"""Test set_log() with defaults toggles log.x and log.y appropriately."""
|
|
184
|
+
concrete = ConcreteBase()
|
|
185
|
+
|
|
186
|
+
# Initial state
|
|
187
|
+
assert concrete.log.x is False
|
|
188
|
+
assert concrete.log.y is False
|
|
189
|
+
|
|
190
|
+
# Call with no arguments should use current values
|
|
191
|
+
concrete.set_log()
|
|
192
|
+
assert concrete.log.x is False
|
|
193
|
+
assert concrete.log.y is False
|
|
194
|
+
|
|
195
|
+
def test_set_log_explicit_values(self):
|
|
196
|
+
"""Test set_log(x=True, y=False) correctly updates log axes."""
|
|
197
|
+
concrete = ConcreteBase()
|
|
198
|
+
|
|
199
|
+
concrete.set_log(x=True, y=False)
|
|
200
|
+
assert concrete.log.x is True
|
|
201
|
+
assert concrete.log.y is False
|
|
202
|
+
|
|
203
|
+
concrete.set_log(x=False, y=True)
|
|
204
|
+
assert concrete.log.x is False
|
|
205
|
+
assert concrete.log.y is True
|
|
206
|
+
|
|
207
|
+
concrete.set_log(x=True, y=True)
|
|
208
|
+
assert concrete.log.x is True
|
|
209
|
+
assert concrete.log.y is True
|
|
210
|
+
|
|
211
|
+
def test_set_log_partial_specification(self):
|
|
212
|
+
"""Test set_log with only x or y specified."""
|
|
213
|
+
concrete = ConcreteBase()
|
|
214
|
+
|
|
215
|
+
# Set initial state
|
|
216
|
+
concrete.set_log(x=True, y=True)
|
|
217
|
+
|
|
218
|
+
# Change only x
|
|
219
|
+
concrete.set_log(x=False)
|
|
220
|
+
assert concrete.log.x is False
|
|
221
|
+
assert concrete.log.y is True # Should remain unchanged
|
|
222
|
+
|
|
223
|
+
# Change only y
|
|
224
|
+
concrete.set_log(y=False)
|
|
225
|
+
assert concrete.log.x is False # Should remain unchanged
|
|
226
|
+
assert concrete.log.y is False
|
|
227
|
+
|
|
228
|
+
def test_set_log_type_coercion(self):
|
|
229
|
+
"""Test that set_log converts values to bool."""
|
|
230
|
+
concrete = ConcreteBase()
|
|
231
|
+
|
|
232
|
+
# Test truthy/falsy values
|
|
233
|
+
concrete.set_log(x=1, y=0)
|
|
234
|
+
assert concrete.log.x is True
|
|
235
|
+
assert concrete.log.y is False
|
|
236
|
+
|
|
237
|
+
concrete.set_log(x="true", y="")
|
|
238
|
+
assert concrete.log.x is True
|
|
239
|
+
assert concrete.log.y is False
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class TestBaseLabelMethods:
|
|
243
|
+
"""Test label management functionality in Base class."""
|
|
244
|
+
|
|
245
|
+
def test_set_labels_updates_labels_and_regenerates_path(self):
|
|
246
|
+
"""Test set_labels() updates labels and regenerates path."""
|
|
247
|
+
concrete = ConcreteBase()
|
|
248
|
+
original_path = concrete.path
|
|
249
|
+
|
|
250
|
+
concrete.set_labels(x="New X", y="New Y")
|
|
251
|
+
|
|
252
|
+
assert concrete.labels.x == "New X"
|
|
253
|
+
assert concrete.labels.y == "New Y"
|
|
254
|
+
# Path should have been regenerated (different from original)
|
|
255
|
+
# Note: exact path comparison depends on implementation details
|
|
256
|
+
assert hasattr(concrete, "_path")
|
|
257
|
+
|
|
258
|
+
def test_set_labels_partial_update(self):
|
|
259
|
+
"""Test setting only some labels preserves others."""
|
|
260
|
+
concrete = ConcreteBase()
|
|
261
|
+
|
|
262
|
+
# Set initial labels
|
|
263
|
+
concrete.set_labels(x="X1", y="Y1", z="Z1")
|
|
264
|
+
|
|
265
|
+
# Update only x
|
|
266
|
+
concrete.set_labels(x="X2")
|
|
267
|
+
assert concrete.labels.x == "X2"
|
|
268
|
+
assert concrete.labels.y == "Y1" # Should remain unchanged
|
|
269
|
+
assert concrete.labels.z == "Z1" # Should remain unchanged
|
|
270
|
+
|
|
271
|
+
def test_set_labels_auto_update_path_false(self):
|
|
272
|
+
"""Test set_labels with auto_update_path=False."""
|
|
273
|
+
concrete = ConcreteBase()
|
|
274
|
+
original_path = concrete.path
|
|
275
|
+
|
|
276
|
+
# This should not trigger path update
|
|
277
|
+
concrete.set_labels(x="New X", auto_update_path=False)
|
|
278
|
+
|
|
279
|
+
assert concrete.labels.x == "New X"
|
|
280
|
+
# Path should remain the same (though this is implementation dependent)
|
|
281
|
+
# The main point is that set_path("auto") was not called
|
|
282
|
+
|
|
283
|
+
def test_set_labels_unexpected_kwarg_raises_keyerror(self):
|
|
284
|
+
"""Test that set_labels(unexpected=...) raises KeyError."""
|
|
285
|
+
concrete = ConcreteBase()
|
|
286
|
+
|
|
287
|
+
with pytest.raises(KeyError, match="Unexpected kwarg"):
|
|
288
|
+
concrete.set_labels(unexpected="value")
|
|
289
|
+
|
|
290
|
+
with pytest.raises(KeyError, match="Unexpected kwarg"):
|
|
291
|
+
concrete.set_labels(x="valid", invalid="invalid")
|
|
292
|
+
|
|
293
|
+
def test_set_labels_multiple_unexpected_kwargs(self):
|
|
294
|
+
"""Test error message with multiple unexpected kwargs."""
|
|
295
|
+
concrete = ConcreteBase()
|
|
296
|
+
|
|
297
|
+
with pytest.raises(KeyError) as exc_info:
|
|
298
|
+
concrete.set_labels(bad1="value1", bad2="value2")
|
|
299
|
+
|
|
300
|
+
# Should mention both unexpected kwargs
|
|
301
|
+
error_message = str(exc_info.value)
|
|
302
|
+
assert "bad1" in error_message
|
|
303
|
+
assert "bad2" in error_message
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
class TestBasePathMethods:
|
|
307
|
+
"""Test path management functionality in Base class."""
|
|
308
|
+
|
|
309
|
+
def test_set_path_auto_mode(self):
|
|
310
|
+
"""Test set_path with 'auto' mode."""
|
|
311
|
+
concrete = ConcreteBase()
|
|
312
|
+
|
|
313
|
+
# Set some labels first
|
|
314
|
+
concrete.set_labels(x="density", y="velocity", z="temperature")
|
|
315
|
+
|
|
316
|
+
# Test auto path generation
|
|
317
|
+
path, x, y, z, scale_info = concrete.set_path("auto")
|
|
318
|
+
|
|
319
|
+
assert isinstance(path, Path)
|
|
320
|
+
assert path.name == "ConcreteBase" # Should use class name
|
|
321
|
+
assert x == "density"
|
|
322
|
+
assert y == "velocity"
|
|
323
|
+
assert z == "temperature"
|
|
324
|
+
assert scale_info is None # add_scale defaults to False
|
|
325
|
+
|
|
326
|
+
def test_set_path_auto_mode_with_scale(self):
|
|
327
|
+
"""Test set_path with 'auto' mode and add_scale=True."""
|
|
328
|
+
concrete = ConcreteBase()
|
|
329
|
+
concrete.set_log(x=True, y=False)
|
|
330
|
+
|
|
331
|
+
path, x, y, z, scale_info = concrete.set_path("auto", add_scale=True)
|
|
332
|
+
|
|
333
|
+
assert scale_info == ["logX", "linY"]
|
|
334
|
+
|
|
335
|
+
def test_set_path_explicit_path(self):
|
|
336
|
+
"""Test set_path with explicit path."""
|
|
337
|
+
concrete = ConcreteBase()
|
|
338
|
+
|
|
339
|
+
path, x, y, z, scale_info = concrete.set_path("/custom/path")
|
|
340
|
+
|
|
341
|
+
assert path == Path("/custom/path")
|
|
342
|
+
assert x is None
|
|
343
|
+
assert y is None
|
|
344
|
+
assert z is None
|
|
345
|
+
assert scale_info is None
|
|
346
|
+
|
|
347
|
+
def test_set_path_none(self):
|
|
348
|
+
"""Test set_path with None."""
|
|
349
|
+
concrete = ConcreteBase()
|
|
350
|
+
|
|
351
|
+
path, x, y, z, scale_info = concrete.set_path(None)
|
|
352
|
+
|
|
353
|
+
assert path == Path("")
|
|
354
|
+
assert x is None
|
|
355
|
+
assert y is None
|
|
356
|
+
assert z is None
|
|
357
|
+
assert scale_info is None
|
|
358
|
+
|
|
359
|
+
def test_set_path_label_attribute_handling(self):
|
|
360
|
+
"""Test set_path handles labels with .path attributes."""
|
|
361
|
+
concrete = ConcreteBase()
|
|
362
|
+
|
|
363
|
+
# Mock labels with .path attributes
|
|
364
|
+
mock_label = MagicMock()
|
|
365
|
+
mock_label.path = "custom-path"
|
|
366
|
+
concrete._labels = AxesLabels(x=mock_label, y="normal-label", z=None)
|
|
367
|
+
|
|
368
|
+
path, x, y, z, scale_info = concrete.set_path("auto")
|
|
369
|
+
|
|
370
|
+
assert x == "custom-path"
|
|
371
|
+
assert y == "normal-label"
|
|
372
|
+
assert z == "z" # Default when None
|
|
373
|
+
|
|
374
|
+
def test_set_path_string_sanitization(self):
|
|
375
|
+
"""Test that set_path sanitizes string labels."""
|
|
376
|
+
concrete = ConcreteBase()
|
|
377
|
+
concrete._labels = AxesLabels(x="Label With Spaces", y="normal", z="None")
|
|
378
|
+
|
|
379
|
+
path, x, y, z, scale_info = concrete.set_path("auto")
|
|
380
|
+
|
|
381
|
+
assert x == "Label-With-Spaces" # Spaces replaced with hyphens
|
|
382
|
+
assert y == "normal"
|
|
383
|
+
assert z == "z" # "None" string converted to default
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
class TestBaseAxisFormatting:
|
|
387
|
+
"""Test axis formatting methods in Base class."""
|
|
388
|
+
|
|
389
|
+
@patch("matplotlib.pyplot")
|
|
390
|
+
def test_add_axis_labels(self, mock_plt):
|
|
391
|
+
"""Test _add_axis_labels method."""
|
|
392
|
+
concrete = ConcreteBase()
|
|
393
|
+
concrete.set_labels(x="X Label", y="Y Label")
|
|
394
|
+
|
|
395
|
+
mock_ax = MagicMock()
|
|
396
|
+
concrete._add_axis_labels(mock_ax)
|
|
397
|
+
|
|
398
|
+
mock_ax.set_xlabel.assert_called_once_with("X Label")
|
|
399
|
+
mock_ax.set_ylabel.assert_called_once_with("Y Label")
|
|
400
|
+
|
|
401
|
+
@patch("matplotlib.pyplot")
|
|
402
|
+
def test_add_axis_labels_transpose(self, mock_plt):
|
|
403
|
+
"""Test _add_axis_labels with transpose_axes=True."""
|
|
404
|
+
concrete = ConcreteBase()
|
|
405
|
+
concrete.set_labels(x="X Label", y="Y Label")
|
|
406
|
+
|
|
407
|
+
mock_ax = MagicMock()
|
|
408
|
+
concrete._add_axis_labels(mock_ax, transpose_axes=True)
|
|
409
|
+
|
|
410
|
+
# Labels should be swapped
|
|
411
|
+
mock_ax.set_xlabel.assert_called_once_with("Y Label")
|
|
412
|
+
mock_ax.set_ylabel.assert_called_once_with("X Label")
|
|
413
|
+
|
|
414
|
+
@patch("matplotlib.pyplot")
|
|
415
|
+
def test_add_axis_labels_none_handling(self, mock_plt):
|
|
416
|
+
"""Test _add_axis_labels with None labels."""
|
|
417
|
+
concrete = ConcreteBase()
|
|
418
|
+
concrete.set_labels(x=None, y="Y Label")
|
|
419
|
+
|
|
420
|
+
mock_ax = MagicMock()
|
|
421
|
+
concrete._add_axis_labels(mock_ax)
|
|
422
|
+
|
|
423
|
+
mock_ax.set_xlabel.assert_not_called()
|
|
424
|
+
mock_ax.set_ylabel.assert_called_once_with("Y Label")
|
|
425
|
+
|
|
426
|
+
@patch("matplotlib.pyplot")
|
|
427
|
+
def test_set_axis_scale(self, mock_plt):
|
|
428
|
+
"""Test _set_axis_scale method."""
|
|
429
|
+
concrete = ConcreteBase()
|
|
430
|
+
concrete.set_log(x=True, y=False)
|
|
431
|
+
|
|
432
|
+
mock_ax = MagicMock()
|
|
433
|
+
concrete._set_axis_scale(mock_ax)
|
|
434
|
+
|
|
435
|
+
mock_ax.set_xscale.assert_called_once_with("log")
|
|
436
|
+
mock_ax.set_yscale.assert_not_called()
|
|
437
|
+
|
|
438
|
+
@patch("matplotlib.pyplot")
|
|
439
|
+
def test_set_axis_scale_transpose(self, mock_plt):
|
|
440
|
+
"""Test _set_axis_scale with transpose_axes=True."""
|
|
441
|
+
concrete = ConcreteBase()
|
|
442
|
+
concrete.set_log(x=True, y=False)
|
|
443
|
+
|
|
444
|
+
mock_ax = MagicMock()
|
|
445
|
+
concrete._set_axis_scale(mock_ax, transpose_axes=True)
|
|
446
|
+
|
|
447
|
+
# Scales should be swapped
|
|
448
|
+
mock_ax.set_xscale.assert_not_called()
|
|
449
|
+
mock_ax.set_yscale.assert_called_once_with("log")
|
|
450
|
+
|
|
451
|
+
@patch("matplotlib.pyplot")
|
|
452
|
+
def test_format_axis_complete(self, mock_plt):
|
|
453
|
+
"""Test _format_axis method calls all formatting functions."""
|
|
454
|
+
concrete = ConcreteBase()
|
|
455
|
+
concrete.set_labels(x="X", y="Y")
|
|
456
|
+
concrete.set_log(x=True, y=True)
|
|
457
|
+
|
|
458
|
+
mock_ax = MagicMock()
|
|
459
|
+
concrete._format_axis(mock_ax)
|
|
460
|
+
|
|
461
|
+
# Check that all formatting was applied
|
|
462
|
+
mock_ax.set_xlabel.assert_called_once_with("X")
|
|
463
|
+
mock_ax.set_ylabel.assert_called_once_with("Y")
|
|
464
|
+
mock_ax.set_xscale.assert_called_once_with("log")
|
|
465
|
+
mock_ax.set_yscale.assert_called_once_with("log")
|
|
466
|
+
mock_ax.grid.assert_called_once_with(True, which="major", axis="both")
|
|
467
|
+
mock_ax.tick_params.assert_called_once_with(
|
|
468
|
+
axis="both", which="both", direction="inout"
|
|
469
|
+
)
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
class TestPlotWithZdata:
|
|
473
|
+
"""Test the PlotWithZdata class functionality."""
|
|
474
|
+
|
|
475
|
+
def test_set_data_basic(self):
|
|
476
|
+
"""Test basic set_data functionality."""
|
|
477
|
+
plot = ConcretePlotWithZdata()
|
|
478
|
+
|
|
479
|
+
x = np.array([1, 2, 3])
|
|
480
|
+
y = np.array([4, 5, 6])
|
|
481
|
+
z = np.array([7, 8, 9])
|
|
482
|
+
|
|
483
|
+
plot.set_data(x, y, z)
|
|
484
|
+
|
|
485
|
+
assert isinstance(plot.data, pd.DataFrame)
|
|
486
|
+
assert list(plot.data.columns) == ["x", "y", "z"]
|
|
487
|
+
assert len(plot.data) == 3
|
|
488
|
+
assert plot.clip is False
|
|
489
|
+
|
|
490
|
+
def test_set_data_without_z(self):
|
|
491
|
+
"""Test set_data without z parameter creates default z=1."""
|
|
492
|
+
plot = ConcretePlotWithZdata()
|
|
493
|
+
|
|
494
|
+
x = np.array([1, 2, 3])
|
|
495
|
+
y = np.array([4, 5, 6])
|
|
496
|
+
|
|
497
|
+
plot.set_data(x, y)
|
|
498
|
+
|
|
499
|
+
assert "z" in plot.data.columns
|
|
500
|
+
assert all(plot.data["z"] == 1)
|
|
501
|
+
|
|
502
|
+
def test_set_data_with_clip(self):
|
|
503
|
+
"""Test set_data with clip_data=True."""
|
|
504
|
+
plot = ConcretePlotWithZdata()
|
|
505
|
+
|
|
506
|
+
x = np.array([1, 2, 3])
|
|
507
|
+
y = np.array([4, 5, 6])
|
|
508
|
+
|
|
509
|
+
plot.set_data(x, y, clip_data=True)
|
|
510
|
+
|
|
511
|
+
assert plot.clip is True
|
|
512
|
+
|
|
513
|
+
def test_set_data_drops_nan(self):
|
|
514
|
+
"""Test that set_data drops NaN values."""
|
|
515
|
+
plot = ConcretePlotWithZdata()
|
|
516
|
+
|
|
517
|
+
x = np.array([1, np.nan, 3])
|
|
518
|
+
y = np.array([4, 5, np.nan])
|
|
519
|
+
z = np.array([7, 8, 9])
|
|
520
|
+
|
|
521
|
+
plot.set_data(x, y, z)
|
|
522
|
+
|
|
523
|
+
# Should have dropped rows with NaN
|
|
524
|
+
assert len(plot.data) == 1 # Only first row is complete
|
|
525
|
+
assert plot.data.iloc[0]["x"] == 1
|
|
526
|
+
assert plot.data.iloc[0]["y"] == 4
|
|
527
|
+
assert plot.data.iloc[0]["z"] == 7
|
|
528
|
+
|
|
529
|
+
def test_set_data_all_nan_raises_error(self):
|
|
530
|
+
"""Test that set_data raises ValueError when all data is NaN."""
|
|
531
|
+
plot = ConcretePlotWithZdata()
|
|
532
|
+
|
|
533
|
+
x = np.array([np.nan, np.nan])
|
|
534
|
+
y = np.array([np.nan, np.nan])
|
|
535
|
+
|
|
536
|
+
with pytest.raises(ValueError, match="exclusively NaNs"):
|
|
537
|
+
plot.set_data(x, y)
|
|
538
|
+
|
|
539
|
+
def test_set_path_auto_with_scale(self):
|
|
540
|
+
"""Test set_path auto mode with add_scale=True (default)."""
|
|
541
|
+
plot = ConcretePlotWithZdata()
|
|
542
|
+
plot.set_labels(x="X", y="Y", z="Z")
|
|
543
|
+
plot.set_log(x=True, y=False)
|
|
544
|
+
|
|
545
|
+
plot.set_path("auto")
|
|
546
|
+
|
|
547
|
+
# Check that path was constructed properly
|
|
548
|
+
assert isinstance(plot.path, Path)
|
|
549
|
+
# Should include scale information by default
|
|
550
|
+
|
|
551
|
+
def test_set_path_explicit(self):
|
|
552
|
+
"""Test set_path with explicit path."""
|
|
553
|
+
plot = ConcretePlotWithZdata()
|
|
554
|
+
|
|
555
|
+
plot.set_path("/custom/path", add_scale=False)
|
|
556
|
+
|
|
557
|
+
assert plot.path == Path("/custom/path")
|
|
558
|
+
|
|
559
|
+
def test_set_labels_preserves_z(self):
|
|
560
|
+
"""Test that set_labels properly handles z label."""
|
|
561
|
+
plot = ConcretePlotWithZdata()
|
|
562
|
+
plot.set_labels(x="X", y="Y", z="Z")
|
|
563
|
+
|
|
564
|
+
# Update only x and y
|
|
565
|
+
plot.set_labels(x="New X", y="New Y")
|
|
566
|
+
|
|
567
|
+
assert plot.labels.x == "New X"
|
|
568
|
+
assert plot.labels.y == "New Y"
|
|
569
|
+
assert plot.labels.z == "Z" # Should be preserved
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
class TestDataLimFormatter:
|
|
573
|
+
"""Test the DataLimFormatter mixin class."""
|
|
574
|
+
|
|
575
|
+
def test_format_axis_calls_super_and_sets_limits(self):
|
|
576
|
+
"""Test that _format_axis calls super and sets data limits."""
|
|
577
|
+
# This is a mixin, so we need to test it with a concrete class
|
|
578
|
+
# that also inherits from Base
|
|
579
|
+
|
|
580
|
+
class ConcreteDataLimFormatter(DataLimFormatter, ConcreteBase):
|
|
581
|
+
def __init__(self):
|
|
582
|
+
super().__init__()
|
|
583
|
+
self.set_data(pd.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]}))
|
|
584
|
+
|
|
585
|
+
formatter = ConcreteDataLimFormatter()
|
|
586
|
+
|
|
587
|
+
mock_ax = MagicMock()
|
|
588
|
+
mock_collection = MagicMock()
|
|
589
|
+
mock_collection.sticky_edges.x = []
|
|
590
|
+
mock_collection.sticky_edges.y = []
|
|
591
|
+
|
|
592
|
+
formatter._format_axis(mock_ax, mock_collection)
|
|
593
|
+
|
|
594
|
+
# Should have called grid and tick_params from super()
|
|
595
|
+
mock_ax.grid.assert_called_once()
|
|
596
|
+
mock_ax.tick_params.assert_called_once()
|
|
597
|
+
|
|
598
|
+
# Should have set sticky edges
|
|
599
|
+
assert mock_collection.sticky_edges.x == [1, 3] # min, max of x
|
|
600
|
+
assert mock_collection.sticky_edges.y == [4, 6] # min, max of y
|
|
601
|
+
|
|
602
|
+
# Should have updated data limits
|
|
603
|
+
mock_ax.update_datalim.assert_called_once()
|
|
604
|
+
mock_ax.autoscale_view.assert_called_once()
|
|
605
|
+
|
|
606
|
+
|
|
607
|
+
class TestCbarMaker:
|
|
608
|
+
"""Test the CbarMaker mixin class."""
|
|
609
|
+
|
|
610
|
+
@patch("matplotlib.pyplot")
|
|
611
|
+
def test_make_cbar_with_ax(self, mock_plt):
|
|
612
|
+
"""Test _make_cbar with ax parameter."""
|
|
613
|
+
|
|
614
|
+
class ConcreteCbarMaker(CbarMaker, ConcreteBase):
|
|
615
|
+
pass
|
|
616
|
+
|
|
617
|
+
maker = ConcreteCbarMaker()
|
|
618
|
+
maker.set_labels(z="Z Label")
|
|
619
|
+
|
|
620
|
+
mock_ax = MagicMock()
|
|
621
|
+
mock_fig = MagicMock()
|
|
622
|
+
mock_ax.figure = mock_fig
|
|
623
|
+
mock_mappable = MagicMock()
|
|
624
|
+
|
|
625
|
+
result = maker._make_cbar(mock_mappable, ax=mock_ax)
|
|
626
|
+
|
|
627
|
+
mock_fig.colorbar.assert_called_once_with(
|
|
628
|
+
mock_mappable, label="Z Label", ax=mock_ax, cax=None
|
|
629
|
+
)
|
|
630
|
+
assert result == mock_fig.colorbar.return_value
|
|
631
|
+
|
|
632
|
+
@patch("matplotlib.pyplot")
|
|
633
|
+
def test_make_cbar_with_cax(self, mock_plt):
|
|
634
|
+
"""Test _make_cbar with cax parameter."""
|
|
635
|
+
|
|
636
|
+
class ConcreteCbarMaker(CbarMaker, ConcreteBase):
|
|
637
|
+
pass
|
|
638
|
+
|
|
639
|
+
maker = ConcreteCbarMaker()
|
|
640
|
+
maker.set_labels(z="Z Label")
|
|
641
|
+
|
|
642
|
+
mock_cax = MagicMock()
|
|
643
|
+
mock_fig = MagicMock()
|
|
644
|
+
mock_cax.figure = mock_fig
|
|
645
|
+
mock_mappable = MagicMock()
|
|
646
|
+
|
|
647
|
+
result = maker._make_cbar(mock_mappable, cax=mock_cax)
|
|
648
|
+
|
|
649
|
+
mock_fig.colorbar.assert_called_once_with(
|
|
650
|
+
mock_mappable, label="Z Label", ax=None, cax=mock_cax
|
|
651
|
+
)
|
|
652
|
+
|
|
653
|
+
def test_make_cbar_ax_and_cax_error(self):
|
|
654
|
+
"""Test that passing both ax and cax raises ValueError."""
|
|
655
|
+
|
|
656
|
+
class ConcreteCbarMaker(CbarMaker, ConcreteBase):
|
|
657
|
+
pass
|
|
658
|
+
|
|
659
|
+
maker = ConcreteCbarMaker()
|
|
660
|
+
mock_ax = MagicMock()
|
|
661
|
+
mock_cax = MagicMock()
|
|
662
|
+
mock_mappable = MagicMock()
|
|
663
|
+
|
|
664
|
+
with pytest.raises(ValueError, match="Can't pass ax and cax"):
|
|
665
|
+
maker._make_cbar(mock_mappable, ax=mock_ax, cax=mock_cax)
|
|
666
|
+
|
|
667
|
+
def test_make_cbar_no_ax_or_cax_error(self):
|
|
668
|
+
"""Test that not passing ax or cax raises ValueError."""
|
|
669
|
+
|
|
670
|
+
class ConcreteCbarMaker(CbarMaker, ConcreteBase):
|
|
671
|
+
pass
|
|
672
|
+
|
|
673
|
+
maker = ConcreteCbarMaker()
|
|
674
|
+
mock_mappable = MagicMock()
|
|
675
|
+
|
|
676
|
+
with pytest.raises(ValueError, match="You must pass `ax` or `cax`"):
|
|
677
|
+
maker._make_cbar(mock_mappable)
|
|
678
|
+
|
|
679
|
+
@patch("matplotlib.pyplot")
|
|
680
|
+
def test_make_cbar_custom_label(self, mock_plt):
|
|
681
|
+
"""Test _make_cbar with custom label parameter."""
|
|
682
|
+
|
|
683
|
+
class ConcreteCbarMaker(CbarMaker, ConcreteBase):
|
|
684
|
+
pass
|
|
685
|
+
|
|
686
|
+
maker = ConcreteCbarMaker()
|
|
687
|
+
|
|
688
|
+
mock_ax = MagicMock()
|
|
689
|
+
mock_fig = MagicMock()
|
|
690
|
+
mock_ax.figure = mock_fig
|
|
691
|
+
mock_mappable = MagicMock()
|
|
692
|
+
|
|
693
|
+
maker._make_cbar(mock_mappable, ax=mock_ax, label="Custom Label")
|
|
694
|
+
|
|
695
|
+
mock_fig.colorbar.assert_called_once_with(
|
|
696
|
+
mock_mappable, label="Custom Label", ax=mock_ax, cax=None
|
|
697
|
+
)
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
class TestBaseEdgeCases:
|
|
701
|
+
"""Test edge cases and error conditions."""
|
|
702
|
+
|
|
703
|
+
def test_abstract_methods_not_implemented(self):
|
|
704
|
+
"""Test that abstract methods raise NotImplementedError if not implemented."""
|
|
705
|
+
|
|
706
|
+
class IncompleteBase(Base):
|
|
707
|
+
def __init__(self):
|
|
708
|
+
super().__init__()
|
|
709
|
+
|
|
710
|
+
# Missing set_data and make_plot implementations
|
|
711
|
+
|
|
712
|
+
with pytest.raises(TypeError):
|
|
713
|
+
IncompleteBase()
|
|
714
|
+
|
|
715
|
+
def test_logger_name_format(self):
|
|
716
|
+
"""Test that logger name includes module and class name."""
|
|
717
|
+
concrete = ConcreteBase()
|
|
718
|
+
logger_name = concrete.logger.name
|
|
719
|
+
|
|
720
|
+
assert "base" in logger_name # module name
|
|
721
|
+
assert "ConcreteBase" in logger_name # class name
|
|
722
|
+
|
|
723
|
+
def test_multiple_label_updates(self):
|
|
724
|
+
"""Test multiple sequential label updates."""
|
|
725
|
+
concrete = ConcreteBase()
|
|
726
|
+
|
|
727
|
+
concrete.set_labels(x="X1", y="Y1")
|
|
728
|
+
assert concrete.labels.x == "X1"
|
|
729
|
+
|
|
730
|
+
concrete.set_labels(x="X2")
|
|
731
|
+
assert concrete.labels.x == "X2"
|
|
732
|
+
assert concrete.labels.y == "Y1" # Should be preserved
|
|
733
|
+
|
|
734
|
+
concrete.set_labels(y="Y2", z="Z2")
|
|
735
|
+
assert concrete.labels.x == "X2" # Should be preserved
|
|
736
|
+
assert concrete.labels.y == "Y2"
|
|
737
|
+
assert concrete.labels.z == "Z2"
|
|
738
|
+
|
|
739
|
+
def test_log_scale_persistence(self):
|
|
740
|
+
"""Test that log scale settings persist across operations."""
|
|
741
|
+
concrete = ConcreteBase()
|
|
742
|
+
|
|
743
|
+
concrete.set_log(x=True, y=True)
|
|
744
|
+
concrete.set_labels(x="New X") # This might trigger path update
|
|
745
|
+
|
|
746
|
+
# Log settings should remain unchanged
|
|
747
|
+
assert concrete.log.x is True
|
|
748
|
+
assert concrete.log.y is True
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
if __name__ == "__main__":
|
|
752
|
+
pytest.main([__file__])
|