solarwindpy 0.0.1.dev0__py3-none-any.whl → 0.1.1__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.

Files changed (412) hide show
  1. plans/.velocity/metrics.json +96 -0
  2. plans/0-overview-template.md +268 -0
  3. plans/N-phase-template.md +106 -0
  4. plans/PLAN_AUDIT_SUMMARY.md +173 -0
  5. plans/TEMPLATE-USAGE-GUIDE.md +198 -0
  6. plans/__init__.py +1 -0
  7. plans/abandoned/compaction-agent-system/0-Overview.md +123 -0
  8. plans/abandoned/compaction-agent-system/agents-index-update-plan.md +109 -0
  9. plans/abandoned/compaction-agent-system/compacted_state.md +85 -0
  10. plans/abandoned/compaction-agent-system/implementation-plan.md +107 -0
  11. plans/abandoned/compaction-agent-system/system-validation-report.md +159 -0
  12. plans/abandoned/compaction-agent-system/usage-guide.md +210 -0
  13. plans/abandoned/hook-system-enhancement/0-Overview.md +214 -0
  14. plans/abandoned/hook-system-enhancement/1-Phase1-Core-Infrastructure.md +313 -0
  15. plans/abandoned/hook-system-enhancement/2-Phase2-Intelligent-Testing.md +385 -0
  16. plans/abandoned/hook-system-enhancement/3-Phase3-Physics-Validation.md +444 -0
  17. plans/abandoned/hook-system-enhancement/4-Phase4-Performance-Monitoring.md +458 -0
  18. plans/abandoned/hook-system-enhancement/5-Phase5-Developer-Experience.md +532 -0
  19. plans/abandoned/hook-system-enhancement/6-Implementation-Timeline.md +274 -0
  20. plans/abandoned/hook-system-enhancement/7-Risk-Management.md +376 -0
  21. plans/abandoned/hook-system-enhancement/8-Testing-Strategy.md +579 -0
  22. plans/abandoned/readthedocs-automation/0-Overview.md +247 -0
  23. plans/abandoned/readthedocs-automation/1-Emergency-Documentation-Fixes.md +270 -0
  24. plans/abandoned/readthedocs-automation/2-Template-System-Enhancement.md +811 -0
  25. plans/abandoned/readthedocs-automation/3-Quality-Audit-ReadTheDocs-Integration.md +844 -0
  26. plans/abandoned/readthedocs-automation/4-Plan-Consolidation-Cleanup.md +632 -0
  27. plans/abandoned/readthedocs-automation/9-Closeout.md +207 -0
  28. plans/abandoned/readthedocs-automation/ABANDONMENT_REASON.md +72 -0
  29. plans/cicd-architecture-redesign/0-Overview.md +193 -0
  30. plans/cicd-architecture-redesign/1-Workflow-Creation.md +103 -0
  31. plans/cicd-architecture-redesign/2-Version-Detection.md +123 -0
  32. plans/cicd-architecture-redesign/3-Deployment-Gates.md +169 -0
  33. plans/cicd-architecture-redesign/4-RC-Testing.md +194 -0
  34. plans/cicd-architecture-redesign/5-TestPyPI-Validation.md +264 -0
  35. plans/cicd-architecture-redesign/6-Production-Release.md +263 -0
  36. plans/cicd-architecture-redesign/7-Cleanup.md +243 -0
  37. plans/cicd-architecture-redesign/8-Documentation.md +285 -0
  38. plans/cicd-architecture-redesign/Closeout.md +225 -0
  39. plans/closeout-template.md +259 -0
  40. plans/completed/circular-import-audit/0-Overview.md +152 -0
  41. plans/completed/circular-import-audit/1-Static-Dependency-Analysis.md +62 -0
  42. plans/completed/circular-import-audit/2-Dynamic-Import-Testing.md +56 -0
  43. plans/completed/circular-import-audit/3-Performance-Impact-Assessment.md +56 -0
  44. plans/completed/circular-import-audit/4-Issue-Remediation.md +78 -0
  45. plans/completed/circular-import-audit/5-Preventive-Infrastructure.md +89 -0
  46. plans/completed/claude-settings-ecosystem-alignment/0-Overview.md +162 -0
  47. plans/completed/claude-settings-ecosystem-alignment/1-Security-Foundation.md +148 -0
  48. plans/completed/claude-settings-ecosystem-alignment/2-Hook-Integration.md +158 -0
  49. plans/completed/claude-settings-ecosystem-alignment/3-Agent-System-Integration.md +177 -0
  50. plans/completed/claude-settings-ecosystem-alignment/4-Enhanced-Workflow-Automation.md +159 -0
  51. plans/completed/claude-settings-ecosystem-alignment/5-Validation-Monitoring.md +181 -0
  52. plans/completed/claude-settings-ecosystem-alignment/compacted_session_state.md +290 -0
  53. plans/completed/combined_plan_with_checklist_documentation/1-Overview-and-Goals.md +51 -0
  54. plans/completed/combined_plan_with_checklist_documentation/2-Toolchain-and-Hosting.md +69 -0
  55. plans/completed/combined_plan_with_checklist_documentation/3-Repository-Structure.md +61 -0
  56. plans/completed/combined_plan_with_checklist_documentation/4-Configuration-and-Standards.md +70 -0
  57. plans/completed/combined_plan_with_checklist_documentation/5-Documentation-Content.md +62 -0
  58. plans/completed/combined_plan_with_checklist_documentation/6-CI-CD-and-Validation.md +58 -0
  59. plans/completed/combined_plan_with_checklist_documentation/7-Maintenance.md +55 -0
  60. plans/completed/combined_test_plan_with_checklist_fitfunctions/0-Overview.md +135 -0
  61. plans/completed/combined_test_plan_with_checklist_fitfunctions/1-Common-fixtures.md +59 -0
  62. plans/completed/combined_test_plan_with_checklist_fitfunctions/10-power_laws.md +56 -0
  63. plans/completed/combined_test_plan_with_checklist_fitfunctions/2-core.py-FitFunction.md +118 -0
  64. plans/completed/combined_test_plan_with_checklist_fitfunctions/3-gaussians.py-Gaussian-GaussianNormalized-GaussianLn.md +69 -0
  65. plans/completed/combined_test_plan_with_checklist_fitfunctions/4-trend_fits.py-TrendFit.md +99 -0
  66. plans/completed/combined_test_plan_with_checklist_fitfunctions/5-plots.py-FFPlot.md +98 -0
  67. plans/completed/combined_test_plan_with_checklist_fitfunctions/6-tex_info.py-TeXinfo.md +79 -0
  68. plans/completed/combined_test_plan_with_checklist_fitfunctions/7-Justification.md +49 -0
  69. plans/completed/combined_test_plan_with_checklist_fitfunctions/8-exponentials.md +64 -0
  70. plans/completed/combined_test_plan_with_checklist_fitfunctions/9-lines.md +58 -0
  71. plans/completed/combined_test_plan_with_checklist_plotting/0-Overview.md +142 -0
  72. plans/completed/combined_test_plan_with_checklist_plotting/1-base.py.md +90 -0
  73. plans/completed/combined_test_plan_with_checklist_plotting/10-labels-special.py.md +102 -0
  74. plans/completed/combined_test_plan_with_checklist_plotting/11-labels-chemistry.py.md +212 -0
  75. plans/completed/combined_test_plan_with_checklist_plotting/12-labels-composition.py.md +242 -0
  76. plans/completed/combined_test_plan_with_checklist_plotting/13-labels-datetime.py.md +247 -0
  77. plans/completed/combined_test_plan_with_checklist_plotting/14-labels-elemental_abundance.py.md +274 -0
  78. plans/completed/combined_test_plan_with_checklist_plotting/15-visual-validation.md +256 -0
  79. plans/completed/combined_test_plan_with_checklist_plotting/16-integration-testing.md +266 -0
  80. plans/completed/combined_test_plan_with_checklist_plotting/17-performance-benchmarks.md +267 -0
  81. plans/completed/combined_test_plan_with_checklist_plotting/18-Fixtures-and-Utilities.md +86 -0
  82. plans/completed/combined_test_plan_with_checklist_plotting/2-agg_plot.py.md +90 -0
  83. plans/completed/combined_test_plan_with_checklist_plotting/3-histograms.py.md +201 -0
  84. plans/completed/combined_test_plan_with_checklist_plotting/4-scatter.py.md +167 -0
  85. plans/completed/combined_test_plan_with_checklist_plotting/5-spiral.py.md +216 -0
  86. plans/completed/combined_test_plan_with_checklist_plotting/6-orbits.py.md +108 -0
  87. plans/completed/combined_test_plan_with_checklist_plotting/7-tools.py.md +86 -0
  88. plans/completed/combined_test_plan_with_checklist_plotting/8-select_data_from_figure.py.md +97 -0
  89. plans/completed/combined_test_plan_with_checklist_plotting/9-labels-base.py.md +88 -0
  90. plans/completed/combined_test_plan_with_checklist_solar_activity/.gitkeep +0 -0
  91. plans/completed/combined_test_plan_with_checklist_solar_activity/0-Overview.md +170 -0
  92. plans/completed/combined_test_plan_with_checklist_solar_activity/1-Package-Entry-Point-__init__.py.md +121 -0
  93. plans/completed/combined_test_plan_with_checklist_solar_activity/2-Core-Base-Classes-base.py.md +142 -0
  94. plans/completed/combined_test_plan_with_checklist_solar_activity/3-Plotting-Helpers-plots.py.md +123 -0
  95. plans/completed/combined_test_plan_with_checklist_solar_activity/4-LISIRD-Sub-package.md +119 -0
  96. plans/completed/combined_test_plan_with_checklist_solar_activity/5-Extrema-Calculator.md +103 -0
  97. plans/completed/combined_test_plan_with_checklist_solar_activity/6-Sunspot-Number-Sub-package.md +163 -0
  98. plans/completed/combined_test_plan_with_checklist_solar_activity/7-Sunspot-Number-Init.py.md +217 -0
  99. plans/completed/combined_test_plan_with_checklist_solar_activity/compacted_state.md +52 -0
  100. plans/completed/compaction-agent-modernization/0-Overview.md +156 -0
  101. plans/completed/compaction-agent-modernization/1-Architecture-Audit-Gap-Analysis.md +132 -0
  102. plans/completed/compaction-agent-modernization/2-Token-Baseline-Recalibration.md +153 -0
  103. plans/completed/compaction-agent-modernization/3-Agent-Reference-Updates.md +184 -0
  104. plans/completed/compaction-agent-modernization/4-Compression-Algorithm-Modernization.md +238 -0
  105. plans/completed/compaction-agent-modernization/5-Workflow-Integration-Streamlining.md +252 -0
  106. plans/completed/compaction-agent-modernization/6-Template-Structure-Optimization.md +240 -0
  107. plans/completed/compaction-agent-modernization/7-Integration-Testing-Validation.md +292 -0
  108. plans/completed/compaction-hook-enhancement/0-Overview.md +150 -0
  109. plans/completed/compaction-hook-enhancement/1-Token-Estimation-Enhancement.md +179 -0
  110. plans/completed/compaction-hook-enhancement/2-Compression-Intelligence.md +294 -0
  111. plans/completed/compaction-hook-enhancement/3-Git-Integration-Metadata.md +310 -0
  112. plans/completed/compaction-hook-enhancement/4-Session-Continuity-Features.md +358 -0
  113. plans/completed/compaction-hook-enhancement/5-Testing-Strategy.md +404 -0
  114. plans/completed/compaction-hook-enhancement/6-Integration-Roadmap.md +319 -0
  115. plans/completed/compaction-hook-enhancement/compacted_state.md +142 -0
  116. plans/completed/docstring-audit-enhancement/0-Overview.md +274 -0
  117. plans/completed/docstring-audit-enhancement/1-Infrastructure-Setup-and-Validation-Tools.md +206 -0
  118. plans/completed/docstring-audit-enhancement/2-Core-Physics-Modules-Enhancement.md +237 -0
  119. plans/completed/docstring-audit-enhancement/3-Fitfunctions-Mathematical-Modules-Enhancement.md +188 -0
  120. plans/completed/docstring-audit-enhancement/4-Plotting-Visualization-Modules-Enhancement.md +243 -0
  121. plans/completed/docstring-audit-enhancement/5-Specialized-Modules-Enhancement.md +216 -0
  122. plans/completed/docstring-audit-enhancement/6-Validation-and-Integration.md +216 -0
  123. plans/completed/fitfunctions-testing-implementation/0-Overview.md +130 -0
  124. plans/completed/fitfunctions-testing-implementation/1-Test-Infrastructure-Setup.md +79 -0
  125. plans/completed/fitfunctions-testing-implementation/2-Common-Fixtures-Test-Utilities.md +104 -0
  126. plans/completed/fitfunctions-testing-implementation/3-Core-FitFunction-Testing.md +168 -0
  127. plans/completed/fitfunctions-testing-implementation/4-Specialized-Function-Classes.md +210 -0
  128. plans/completed/fitfunctions-testing-implementation/5-Advanced-Classes-Testing.md +214 -0
  129. plans/completed/fitfunctions-testing-implementation/6-Plotting-Integration-Testing.md +231 -0
  130. plans/completed/fitfunctions-testing-implementation/7-Extended-Coverage-BONUS.md +184 -0
  131. plans/completed/numpy-docstring-conversion-plan/numpy-docstring-conversion-plan.md +118 -0
  132. plans/completed/pr-review-remediation/0-Overview.md +138 -0
  133. plans/completed/pr-review-remediation/1-Critical-Safety-Improvements.md +179 -0
  134. plans/completed/pr-review-remediation/2-Smart-Timeouts-Validation.md +399 -0
  135. plans/completed/pr-review-remediation/3-Enhanced-GitHub-Integration.md +258 -0
  136. plans/completed/pr-review-remediation/compacted_state.md +66 -0
  137. plans/completed/python-310-migration/0-Overview.md +390 -0
  138. plans/completed/python-310-migration/1-Planning-Setup.md +164 -0
  139. plans/completed/python-310-migration/2-Implementation.md +256 -0
  140. plans/completed/python-310-migration/3-Testing-Validation.md +335 -0
  141. plans/completed/python-310-migration/4-Documentation-Release.md +274 -0
  142. plans/completed/python-310-migration/5-Closeout.md +252 -0
  143. plans/completed/requirements-management-consolidation/0-Overview.md +118 -0
  144. plans/completed/requirements-management-consolidation/1-Documentation-Validation-Environment-Setup.md +116 -0
  145. plans/completed/requirements-management-consolidation/2-Requirements-Consolidation.md +161 -0
  146. plans/completed/requirements-management-consolidation/3-Workflow-Automation-Final-Integration.md +196 -0
  147. plans/completed/single-ecosystem-plan-implementation/0-Overview.md +83 -0
  148. plans/completed/single-ecosystem-plan-implementation/1-Plan-Preservation-Session-Management.md +38 -0
  149. plans/completed/single-ecosystem-plan-implementation/2-File-Structure-Optimization.md +43 -0
  150. plans/completed/single-ecosystem-plan-implementation/3-Plan-Migration-Archive-Setup.md +82 -0
  151. plans/completed/single-ecosystem-plan-implementation/4-Agent-System-Transformation.md +108 -0
  152. plans/completed/single-ecosystem-plan-implementation/5-Template-System-Enhancement.md +131 -0
  153. plans/completed/single-ecosystem-plan-implementation/6-Final-Validation-Testing.md +120 -0
  154. plans/completed/test-directory-consolidation/0-Overview.md +51 -0
  155. plans/completed/test-directory-consolidation/1-Structure-Preparation.md +82 -0
  156. plans/completed/test-directory-consolidation/2-File-Migration.md +100 -0
  157. plans/completed/test-directory-consolidation/3-Import-Transformation.md +117 -0
  158. plans/completed/test-directory-consolidation/4-Configuration-Consolidation.md +140 -0
  159. plans/completed/test-directory-consolidation/5-Validation.md +152 -0
  160. plans/completed/test-directory-consolidation/6-Cleanup.md +156 -0
  161. plans/completed/test-planning-agents-architecture/0-Overview.md +79 -0
  162. plans/completed/test-planning-agents-architecture/1-Branch-Isolation-Testing.md +49 -0
  163. plans/completed/test-planning-agents-architecture/2-Cross-Branch-Coordination.md +51 -0
  164. plans/completed/test-planning-agents-architecture/3-Merge-Workflow-Testing.md +48 -0
  165. plans/deployment-semver-pypi-rtd/0-Overview.md +463 -0
  166. plans/deployment-semver-pypi-rtd/1-Semantic-Versioning-Foundation.md +136 -0
  167. plans/deployment-semver-pypi-rtd/2-PyPI-Deployment-Infrastructure.md +168 -0
  168. plans/deployment-semver-pypi-rtd/3-Release-Automation.md +214 -0
  169. plans/deployment-semver-pypi-rtd/4-Plan-Closeout.md +543 -0
  170. plans/deployment-semver-pypi-rtd/compacted_session_state.md +172 -0
  171. plans/deployment-semver-pypi-rtd/compacted_state.md +131 -0
  172. plans/documentation-code-audit/0-Overview.md +393 -0
  173. plans/documentation-code-audit/1-Discovery-Inventory.md +183 -0
  174. plans/documentation-code-audit/2-Execution-Environment-Setup.md +263 -0
  175. plans/documentation-code-audit/3-Systematic-Validation.md +322 -0
  176. plans/documentation-code-audit/4-Code-Example-Remediation.md +358 -0
  177. plans/documentation-code-audit/5-Physics-MultiIndex-Compliance.md +464 -0
  178. plans/documentation-code-audit/6-Doctest-Integration.md +523 -0
  179. plans/documentation-code-audit/7-Reporting-Documentation.md +498 -0
  180. plans/documentation-code-audit/8-Closeout.md +456 -0
  181. plans/documentation-rebuild-session/compacted_state.md +109 -0
  182. plans/documentation-rendering-fixes/0-Overview.md +104 -0
  183. plans/documentation-rendering-fixes/1-Sphinx-Build-Diagnostics-Warning-Audit.md +101 -0
  184. plans/documentation-rendering-fixes/2-Configuration-Infrastructure-Fixes.md +113 -0
  185. plans/documentation-rendering-fixes/3-Docstring-Syntax-Audit-Repair.md +131 -0
  186. plans/documentation-rendering-fixes/4-HTML-Page-Rendering-Verification.md +113 -0
  187. plans/documentation-rendering-fixes/5-Advanced-Documentation-Quality-Assurance.md +119 -0
  188. plans/documentation-rendering-fixes/6-Documentation-Build-Optimization-Testing.md +129 -0
  189. plans/documentation-rendering-fixes/compacted_state.md +132 -0
  190. plans/documentation-template-fix/0-Overview.md +197 -0
  191. plans/documentation-template-fix/1-Template-System-Analysis.md +269 -0
  192. plans/documentation-template-fix/2-Template-Modification.md +609 -0
  193. plans/documentation-template-fix/3-Build-System-Integration.md +766 -0
  194. plans/documentation-template-fix/4-Testing-Validation.md +1399 -0
  195. plans/documentation-template-fix/5-Documentation-Training.md +602 -0
  196. plans/documentation-workflow-fix/0-Overview.md +222 -0
  197. plans/documentation-workflow-fix/1-Immediate-Fixes.md +238 -0
  198. plans/documentation-workflow-fix/2-Configuration-Setup.md +298 -0
  199. plans/documentation-workflow-fix/3-Pre-commit-Integration.md +382 -0
  200. plans/documentation-workflow-fix/4-Workflow-Improvements.md +446 -0
  201. plans/documentation-workflow-fix/5-Documentation-and-Training.md +527 -0
  202. plans/duplicate-object-warnings-fix-plan.md +130 -0
  203. plans/github-issues-migration/0-Overview.md +510 -0
  204. plans/github-issues-migration/1-Foundation-Label-System.md +180 -0
  205. plans/github-issues-migration/2-Migration-Tool-Rewrite.md +235 -0
  206. plans/github-issues-migration/3-CLI-Integration-Automation.md +169 -0
  207. plans/github-issues-migration/4-Validated-Migration.md +252 -0
  208. plans/github-issues-migration/5-Documentation-Training.md +171 -0
  209. plans/github-issues-migration/6-Closeout.md +179 -0
  210. plans/github-workflows-repair/repair-plan.md +299 -0
  211. plans/issues_from_plans.py +342 -0
  212. plans/pr-270-doc-validation-fixes/0-Overview.md +354 -0
  213. plans/pr-270-doc-validation-fixes/1-Critical-PR-Fixes.md +117 -0
  214. plans/pr-270-doc-validation-fixes/2-Framework-Right-Sizing.md +129 -0
  215. plans/pr-270-doc-validation-fixes/3-Sustainable-Documentation.md +126 -0
  216. plans/pr-270-doc-validation-fixes/4-Closeout-Migration.md +143 -0
  217. plans/pr-270-doc-validation-fixes/PLAN_COMPLETED.md +149 -0
  218. plans/python-310-migration/0-Overview.md +390 -0
  219. plans/python-310-migration/1-Planning-Setup.md +164 -0
  220. plans/python-310-migration/2-Implementation.md +256 -0
  221. plans/python-310-migration/3-Testing-Validation.md +335 -0
  222. plans/python-310-migration/4-Documentation-Release.md +274 -0
  223. plans/python-310-migration/5-Closeout.md +252 -0
  224. plans/readthedocs-simplified/0-Overview.md +243 -0
  225. plans/readthedocs-simplified/1-Immediate-Fixes.md +216 -0
  226. plans/readthedocs-simplified/2-Template-Simplification.md +278 -0
  227. plans/readthedocs-simplified/3-ReadTheDocs-Setup.md +298 -0
  228. plans/readthedocs-simplified/4-Testing-Validation.md +328 -0
  229. plans/readthedocs-simplified/5-Closeout.md +231 -0
  230. plans/readthedocs-simplified/compacted_state.md +127 -0
  231. plans/session-compaction-2025-08-12/compacted_state.md +114 -0
  232. plans/session-compaction-2025-08-13/compacted_state.md +145 -0
  233. plans/session-continuity-protocol/0-Overview.md +35 -0
  234. plans/session-continuity-protocol/1-Core-Principles-Framework.md +40 -0
  235. plans/session-continuity-protocol/2-Pre-Session-Validation-System.md +79 -0
  236. plans/session-continuity-protocol/3-Context-Switching-Prevention.md +87 -0
  237. plans/session-continuity-protocol/4-Progress-Tracking-Recovery.md +100 -0
  238. plans/sphinx-warnings-analysis.md +222 -0
  239. plans/systemprompt-optimization/0-Overview.md +447 -0
  240. plans/systemprompt-optimization/1-Deploy-SystemPrompt.md +114 -0
  241. plans/systemprompt-optimization/2-Documentation-Alignment.md +198 -0
  242. plans/systemprompt-optimization/3-Monitoring-Infrastructure.md +396 -0
  243. plans/systemprompt-optimization/4-Implementation-Script.md +450 -0
  244. plans/systemprompt-optimization/9-Closeout.md +165 -0
  245. plans/systemprompt-optimization/compacted_state.md +143 -0
  246. plans/template-value-propositions/0-Overview.md +357 -0
  247. plans/template-value-propositions/1-Value-Proposition-Framework-Design.md +144 -0
  248. plans/template-value-propositions/2-Plan-Template-Enhancement.md +178 -0
  249. plans/template-value-propositions/3-Value-Generator-Hook-Implementation.md +291 -0
  250. plans/template-value-propositions/4-Value-Validator-Hook-Implementation.md +274 -0
  251. plans/template-value-propositions/5-Documentation-Agent-Updates.md +219 -0
  252. plans/template-value-propositions/6-Integration-Testing-Validation.md +247 -0
  253. plans/tests-audit/0-Overview.md +410 -0
  254. plans/tests-audit/1-Discovery-Inventory.md +170 -0
  255. plans/tests-audit/2-Physics-Validation-Audit.md +195 -0
  256. plans/tests-audit/3-Architecture-Compliance.md +195 -0
  257. plans/tests-audit/4-Numerical-Stability-Analysis.md +203 -0
  258. plans/tests-audit/5-Documentation-Enhancement.md +220 -0
  259. plans/tests-audit/6-Audit-Deliverables.md +220 -0
  260. plans/tests-audit/7-Closeout.md +252 -0
  261. plans/tests-audit/artifacts/ARCHITECTURE_COMPLIANCE_REPORT.md +315 -0
  262. plans/tests-audit/artifacts/ARCHITECTURE_RECOMMENDATIONS.md +943 -0
  263. plans/tests-audit/artifacts/COMPREHENSIVE_AUDIT_REPORT.md +356 -0
  264. plans/tests-audit/artifacts/CONTRIBUTING_ENHANCED_TEMPLATE.md +419 -0
  265. plans/tests-audit/artifacts/COVERAGE_GAP_ANALYSIS.md +152 -0
  266. plans/tests-audit/artifacts/DOCUMENTATION_ENHANCEMENT_REPORT.md +502 -0
  267. plans/tests-audit/artifacts/EXECUTIVE_AUDIT_SUMMARY.md +129 -0
  268. plans/tests-audit/artifacts/IMPLEMENTATION_ROADMAP.md +647 -0
  269. plans/tests-audit/artifacts/NUMERICAL_RECOMMENDATIONS.md +739 -0
  270. plans/tests-audit/artifacts/NUMERICAL_STABILITY_GUIDE_TEMPLATE.rst +451 -0
  271. plans/tests-audit/artifacts/NUMERICAL_STABILITY_REPORT.md +301 -0
  272. plans/tests-audit/artifacts/PHASE_3_SUMMARY.md +280 -0
  273. plans/tests-audit/artifacts/PHASE_4_SUMMARY.md +229 -0
  274. plans/tests-audit/artifacts/PHASE_5_SUMMARY.md +292 -0
  275. plans/tests-audit/artifacts/PHASE_6_CLOSEOUT.md +278 -0
  276. plans/tests-audit/artifacts/PHYSICS_GUIDE_TEMPLATE.rst +268 -0
  277. plans/tests-audit/artifacts/PHYSICS_VALIDATION_REPORT.md +235 -0
  278. plans/tests-audit/artifacts/TECHNICAL_DELIVERABLES_PACKAGE.md +2502 -0
  279. plans/tests-audit/artifacts/TEST_INVENTORY.csv +1204 -0
  280. plans/tests-audit/artifacts/TEST_INVENTORY.md +135 -0
  281. plans/tests-audit/artifacts/test_discovery_analysis.py +231 -0
  282. plans/tests-audit/artifacts/test_parser.py +395 -0
  283. solarwindpy/README.md +3 -0
  284. solarwindpy/Untitled.ipynb +54 -0
  285. solarwindpy/__init__.py +74 -0
  286. solarwindpy/core/__init__.py +23 -0
  287. solarwindpy/core/alfvenic_turbulence.py +804 -0
  288. solarwindpy/core/base.py +267 -0
  289. solarwindpy/core/ions.py +309 -0
  290. solarwindpy/core/plasma.py +2133 -0
  291. solarwindpy/core/spacecraft.py +256 -0
  292. solarwindpy/core/tensor.py +90 -0
  293. solarwindpy/core/units_constants.py +199 -0
  294. solarwindpy/core/vector.py +328 -0
  295. solarwindpy/fitfunctions/__init__.py +20 -0
  296. solarwindpy/fitfunctions/core.py +734 -0
  297. solarwindpy/fitfunctions/exponentials.py +188 -0
  298. solarwindpy/fitfunctions/gaussians.py +264 -0
  299. solarwindpy/fitfunctions/lines.py +116 -0
  300. solarwindpy/fitfunctions/moyal.py +71 -0
  301. solarwindpy/fitfunctions/plots.py +751 -0
  302. solarwindpy/fitfunctions/power_laws.py +209 -0
  303. solarwindpy/fitfunctions/tex_info.py +568 -0
  304. solarwindpy/fitfunctions/trend_fits.py +482 -0
  305. solarwindpy/instabilities/__init__.py +16 -0
  306. solarwindpy/instabilities/beta_ani.py +82 -0
  307. solarwindpy/instabilities/verscharen2016.py +631 -0
  308. solarwindpy/plotting/__init__.py +33 -0
  309. solarwindpy/plotting/agg_plot.py +489 -0
  310. solarwindpy/plotting/base.py +465 -0
  311. solarwindpy/plotting/hist1d.py +405 -0
  312. solarwindpy/plotting/hist2d.py +1035 -0
  313. solarwindpy/plotting/histograms.py +1845 -0
  314. solarwindpy/plotting/labels/__init__.py +104 -0
  315. solarwindpy/plotting/labels/base.py +686 -0
  316. solarwindpy/plotting/labels/chemistry.py +19 -0
  317. solarwindpy/plotting/labels/composition.py +100 -0
  318. solarwindpy/plotting/labels/datetime.py +235 -0
  319. solarwindpy/plotting/labels/elemental_abundance.py +73 -0
  320. solarwindpy/plotting/labels/special.py +794 -0
  321. solarwindpy/plotting/orbits.py +515 -0
  322. solarwindpy/plotting/scatter.py +99 -0
  323. solarwindpy/plotting/select_data_from_figure.py +329 -0
  324. solarwindpy/plotting/spiral.py +980 -0
  325. solarwindpy/plotting/tools.py +434 -0
  326. solarwindpy/scripts/__init__.py +1 -0
  327. solarwindpy/scripts/logs/.gitignore +1 -0
  328. solarwindpy/solar_activity/__init__.py +53 -0
  329. solarwindpy/solar_activity/base.py +605 -0
  330. solarwindpy/solar_activity/lisird/__init__.py +3 -0
  331. solarwindpy/solar_activity/lisird/extrema_calculator.py +394 -0
  332. solarwindpy/solar_activity/lisird/lisird.py +319 -0
  333. solarwindpy/solar_activity/plots.py +116 -0
  334. solarwindpy/solar_activity/sunspot_number/.DS_Store +0 -0
  335. solarwindpy/solar_activity/sunspot_number/__init__.py +3 -0
  336. solarwindpy/solar_activity/sunspot_number/sidc.py +556 -0
  337. solarwindpy/solar_activity/sunspot_number/ssn_extrema.csv +72 -0
  338. solarwindpy/solar_activity/sunspot_number/ssn_extrema.csv.silso +72 -0
  339. solarwindpy/tools/__init__.py +162 -0
  340. solarwindpy-0.1.1.dist-info/METADATA +181 -0
  341. solarwindpy-0.1.1.dist-info/RECORD +409 -0
  342. {solarwindpy-0.0.1.dev0.dist-info → solarwindpy-0.1.1.dist-info}/WHEEL +1 -1
  343. solarwindpy-0.1.1.dist-info/licenses/LICENSE.rst +32 -0
  344. solarwindpy-0.1.1.dist-info/top_level.txt +3 -0
  345. tests/__init__.py +1 -0
  346. tests/conftest.py +10 -0
  347. tests/core/__init__.py +1 -0
  348. tests/core/test_alfvenic_turbulence.py +544 -0
  349. tests/core/test_base.py +112 -0
  350. tests/core/test_base_head_tail.py +29 -0
  351. tests/core/test_base_mi_tuples.py +11 -0
  352. tests/core/test_core_verify_datetimeindex.py +32 -0
  353. tests/core/test_ions.py +325 -0
  354. tests/core/test_plasma.py +2581 -0
  355. tests/core/test_plasma_io.py +12 -0
  356. tests/core/test_quantities.py +507 -0
  357. tests/core/test_spacecraft.py +210 -0
  358. tests/core/test_units_constants.py +22 -0
  359. tests/data/epoch.csv +4 -0
  360. tests/data/plasma.csv +4 -0
  361. tests/data/spacecraft.csv +4 -0
  362. tests/fitfunctions/conftest.py +60 -0
  363. tests/fitfunctions/test_core.py +193 -0
  364. tests/fitfunctions/test_exponentials.py +342 -0
  365. tests/fitfunctions/test_gaussians.py +142 -0
  366. tests/fitfunctions/test_lines.py +349 -0
  367. tests/fitfunctions/test_moyal.py +258 -0
  368. tests/fitfunctions/test_plots.py +258 -0
  369. tests/fitfunctions/test_power_laws.py +365 -0
  370. tests/fitfunctions/test_tex_info.py +183 -0
  371. tests/fitfunctions/test_trend_fit_properties.py +31 -0
  372. tests/fitfunctions/test_trend_fits.py +244 -0
  373. tests/plotting/__init__.py +1 -0
  374. tests/plotting/labels/__init__.py +1 -0
  375. tests/plotting/labels/test_chemistry.py +243 -0
  376. tests/plotting/labels/test_composition.py +345 -0
  377. tests/plotting/labels/test_datetime.py +445 -0
  378. tests/plotting/labels/test_elemental_abundance.py +366 -0
  379. tests/plotting/labels/test_init.py +66 -0
  380. tests/plotting/labels/test_labels_base.py +347 -0
  381. tests/plotting/labels/test_special.py +550 -0
  382. tests/plotting/test_agg_plot.py +602 -0
  383. tests/plotting/test_base.py +752 -0
  384. tests/plotting/test_fixtures_utilities.py +775 -0
  385. tests/plotting/test_histograms.py +546 -0
  386. tests/plotting/test_integration.py +675 -0
  387. tests/plotting/test_orbits.py +435 -0
  388. tests/plotting/test_performance.py +708 -0
  389. tests/plotting/test_scatter.py +752 -0
  390. tests/plotting/test_select_data_from_figure.py +1209 -0
  391. tests/plotting/test_spiral.py +573 -0
  392. tests/plotting/test_tools.py +607 -0
  393. tests/plotting/test_visual_validation.py +465 -0
  394. tests/solar_activity/__init__.py +1 -0
  395. tests/solar_activity/lisird/__init__.py +1 -0
  396. tests/solar_activity/lisird/test_extrema_calculator.py +593 -0
  397. tests/solar_activity/lisird/test_lisird_id.py +187 -0
  398. tests/solar_activity/sunspot_number/__init__.py +1 -0
  399. tests/solar_activity/sunspot_number/test_init.py +399 -0
  400. tests/solar_activity/sunspot_number/test_sidc.py +465 -0
  401. tests/solar_activity/sunspot_number/test_sidc_id.py +223 -0
  402. tests/solar_activity/sunspot_number/test_sidc_loader.py +275 -0
  403. tests/solar_activity/sunspot_number/test_ssn_extrema.py +406 -0
  404. tests/solar_activity/test_base.py +656 -0
  405. tests/solar_activity/test_init.py +396 -0
  406. tests/solar_activity/test_plots.py +371 -0
  407. tests/test_circular_imports.py +408 -0
  408. tests/test_issue_titles.py +25 -0
  409. tests/test_statusline.py +298 -0
  410. solarwindpy-0.0.1.dev0.dist-info/METADATA +0 -14
  411. solarwindpy-0.0.1.dev0.dist-info/RECORD +0 -4
  412. solarwindpy-0.0.1.dev0.dist-info/top_level.txt +0 -1
@@ -0,0 +1,607 @@
1
+ #!/usr/bin/env python
2
+ """Tests for solarwindpy.plotting.tools module.
3
+
4
+ This module provides comprehensive test coverage for matplotlib utility functions
5
+ including subplot creation, figure saving, legends, and colorbar management.
6
+ """
7
+
8
+ import pytest
9
+ import logging
10
+ import numpy as np
11
+ from pathlib import Path
12
+ from unittest.mock import patch, MagicMock, call
13
+ from datetime import datetime
14
+ import tempfile
15
+ import os
16
+
17
+ import matplotlib
18
+
19
+ matplotlib.use("Agg") # Use non-interactive backend
20
+ from matplotlib import pyplot as plt
21
+ from matplotlib.figure import Figure
22
+ from matplotlib.axes import Axes
23
+ from matplotlib.legend import Legend
24
+ import matplotlib.gridspec
25
+
26
+ import solarwindpy.plotting.tools as tools_module
27
+
28
+
29
+ class TestToolsModuleStructure:
30
+ """Test tools module structure and imports."""
31
+
32
+ def test_module_imports(self):
33
+ """Test that all required imports are accessible."""
34
+ assert hasattr(tools_module, "np")
35
+ assert hasattr(tools_module, "mpl")
36
+ assert hasattr(tools_module, "plt")
37
+ assert hasattr(tools_module, "logging")
38
+ assert hasattr(tools_module, "Path")
39
+ assert hasattr(tools_module, "datetime")
40
+
41
+ def test_functions_available(self):
42
+ """Test that all utility functions are accessible."""
43
+ expected_functions = [
44
+ "subplots",
45
+ "save",
46
+ "joint_legend",
47
+ "multipanel_figure_shared_cbar",
48
+ "build_ax_array_with_common_colorbar",
49
+ "calculate_nrows_ncols",
50
+ ]
51
+
52
+ for func_name in expected_functions:
53
+ assert hasattr(tools_module, func_name)
54
+ assert callable(getattr(tools_module, func_name))
55
+
56
+ def test_module_docstring(self):
57
+ """Test that module has comprehensive docstring."""
58
+ assert tools_module.__doc__ is not None
59
+ assert len(tools_module.__doc__.strip()) > 0
60
+ assert "matplotlib" in tools_module.__doc__
61
+
62
+
63
+ class TestSubplotsFunction:
64
+ """Test subplots utility function."""
65
+
66
+ def test_subplots_default_parameters(self):
67
+ """Test subplots with default parameters."""
68
+ fig, ax = tools_module.subplots()
69
+
70
+ assert isinstance(fig, Figure)
71
+ assert isinstance(ax, Axes)
72
+
73
+ # Clean up
74
+ plt.close(fig)
75
+
76
+ def test_subplots_multiple_rows_cols(self):
77
+ """Test subplots with multiple rows and columns."""
78
+ fig, axes = tools_module.subplots(nrows=2, ncols=3)
79
+
80
+ assert isinstance(fig, Figure)
81
+ assert isinstance(axes, np.ndarray)
82
+ assert axes.shape == (2, 3)
83
+
84
+ # All elements should be Axes
85
+ for ax in axes.flat:
86
+ assert isinstance(ax, Axes)
87
+
88
+ plt.close(fig)
89
+
90
+ def test_subplots_scaling(self):
91
+ """Test figure size scaling."""
92
+ fig1, ax1 = tools_module.subplots(scale_width=1.0, scale_height=1.0)
93
+ fig2, ax2 = tools_module.subplots(scale_width=2.0, scale_height=1.5)
94
+
95
+ # Scaled figure should be larger
96
+ assert fig2.get_figwidth() > fig1.get_figwidth()
97
+ assert fig2.get_figheight() > fig1.get_figheight()
98
+
99
+ plt.close(fig1)
100
+ plt.close(fig2)
101
+
102
+ def test_subplots_with_kwargs(self):
103
+ """Test subplots with additional kwargs."""
104
+ fig, axes = tools_module.subplots(nrows=1, ncols=2, figsize=(10, 5))
105
+
106
+ assert isinstance(fig, Figure)
107
+ # Note: figsize may be scaled by the function
108
+ assert fig.get_figwidth() >= 10 # May be scaled up
109
+ assert fig.get_figheight() >= 5 # May be scaled up
110
+
111
+ plt.close(fig)
112
+
113
+ def test_subplots_single_row_col(self):
114
+ """Test subplots with single row/column returns array."""
115
+ fig, axes = tools_module.subplots(nrows=1, ncols=3)
116
+
117
+ assert isinstance(axes, np.ndarray)
118
+ assert axes.shape == (3,)
119
+
120
+ plt.close(fig)
121
+
122
+
123
+ class TestSaveFunction:
124
+ """Test save utility function."""
125
+
126
+ def setup_method(self):
127
+ """Set up temporary directory for save tests."""
128
+ self.temp_dir = Path(tempfile.mkdtemp())
129
+ self.test_path = self.temp_dir / "test_figure"
130
+
131
+ def teardown_method(self):
132
+ """Clean up temporary files."""
133
+ import shutil
134
+
135
+ if self.temp_dir.exists():
136
+ shutil.rmtree(self.temp_dir)
137
+
138
+ def test_save_figure_basic(self):
139
+ """Test basic figure saving."""
140
+ fig, ax = plt.subplots()
141
+ ax.plot([1, 2, 3], [1, 4, 2])
142
+
143
+ tools_module.save(fig, self.test_path, log=False)
144
+
145
+ # Check that files were created
146
+ assert (self.test_path.with_suffix(".pdf")).exists()
147
+ assert (self.test_path.with_suffix(".png")).exists()
148
+
149
+ plt.close(fig)
150
+
151
+ def test_save_axes_input(self):
152
+ """Test saving with Axes input instead of Figure."""
153
+ fig, ax = plt.subplots()
154
+ ax.plot([1, 2, 3], [1, 4, 2])
155
+
156
+ tools_module.save(ax, self.test_path, log=False)
157
+
158
+ # Should work the same as passing the figure
159
+ assert (self.test_path.with_suffix(".pdf")).exists()
160
+ assert (self.test_path.with_suffix(".png")).exists()
161
+
162
+ plt.close(fig)
163
+
164
+ def test_save_pdf_only(self):
165
+ """Test saving PDF only."""
166
+ fig, ax = plt.subplots()
167
+ ax.plot([1, 2, 3], [1, 4, 2])
168
+
169
+ tools_module.save(fig, self.test_path, pdf=True, png=False, log=False)
170
+
171
+ assert (self.test_path.with_suffix(".pdf")).exists()
172
+ assert not (self.test_path.with_suffix(".png")).exists()
173
+
174
+ plt.close(fig)
175
+
176
+ def test_save_png_only(self):
177
+ """Test saving PNG only."""
178
+ fig, ax = plt.subplots()
179
+ ax.plot([1, 2, 3], [1, 4, 2])
180
+
181
+ tools_module.save(fig, self.test_path, pdf=False, png=True, log=False)
182
+
183
+ assert not (self.test_path.with_suffix(".pdf")).exists()
184
+ assert (self.test_path.with_suffix(".png")).exists()
185
+
186
+ plt.close(fig)
187
+
188
+ def test_save_with_info(self):
189
+ """Test saving with attribution info."""
190
+ fig, ax = plt.subplots()
191
+ ax.plot([1, 2, 3], [1, 4, 2])
192
+
193
+ tools_module.save(fig, self.test_path, add_info=True, log=False)
194
+
195
+ # Files should exist (info is added to PNG)
196
+ assert (self.test_path.with_suffix(".pdf")).exists()
197
+ assert (self.test_path.with_suffix(".png")).exists()
198
+
199
+ plt.close(fig)
200
+
201
+ @patch("logging.getLogger")
202
+ def test_save_with_logging(self, mock_get_logger):
203
+ """Test save function with logging enabled."""
204
+ mock_logger = MagicMock()
205
+ mock_get_logger.return_value = mock_logger
206
+
207
+ fig, ax = plt.subplots()
208
+ ax.plot([1, 2, 3], [1, 4, 2])
209
+
210
+ tools_module.save(fig, self.test_path, log=True)
211
+
212
+ # Should have logged save information
213
+ mock_logger.info.assert_called()
214
+
215
+ plt.close(fig)
216
+
217
+ def test_save_input_validation(self):
218
+ """Test save function input validation."""
219
+ fig, ax = plt.subplots()
220
+
221
+ # Should work with Figure
222
+ tools_module.save(fig, self.test_path, log=False)
223
+
224
+ # Should work with Axes
225
+ tools_module.save(ax, self.test_path, log=False)
226
+
227
+ # Path should be a Path object (assertion in function)
228
+ with pytest.raises(AssertionError):
229
+ tools_module.save(fig, "string_path", log=False)
230
+
231
+ plt.close(fig)
232
+
233
+
234
+ class TestJointLegendFunction:
235
+ """Test joint_legend utility function."""
236
+
237
+ def test_joint_legend_basic(self):
238
+ """Test basic joint legend functionality."""
239
+ fig, axes = plt.subplots(1, 2)
240
+
241
+ axes[0].plot([1, 2, 3], [1, 4, 2], label="Line A")
242
+ axes[1].plot([1, 2, 3], [2, 3, 1], label="Line B")
243
+
244
+ legend = tools_module.joint_legend(axes[0], axes[1])
245
+
246
+ assert isinstance(legend, Legend)
247
+
248
+ # Check that legend contains both labels
249
+ legend_labels = [text.get_text() for text in legend.get_texts()]
250
+ assert "Line A" in legend_labels
251
+ assert "Line B" in legend_labels
252
+
253
+ plt.close(fig)
254
+
255
+ def test_joint_legend_duplicate_labels(self):
256
+ """Test joint legend with duplicate labels."""
257
+ fig, axes = plt.subplots(1, 2)
258
+
259
+ axes[0].plot([1, 2, 3], [1, 4, 2], label="Same Label")
260
+ axes[1].plot([1, 2, 3], [2, 3, 1], label="Same Label")
261
+
262
+ legend = tools_module.joint_legend(axes[0], axes[1])
263
+
264
+ # Should only have one entry for duplicate labels
265
+ legend_labels = [text.get_text() for text in legend.get_texts()]
266
+ assert legend_labels.count("Same Label") == 1
267
+
268
+ plt.close(fig)
269
+
270
+ def test_joint_legend_custom_idx(self):
271
+ """Test joint legend with custom axis index."""
272
+ fig, axes = plt.subplots(1, 3)
273
+
274
+ for i, ax in enumerate(axes):
275
+ ax.plot([1, 2, 3], [i, i + 1, i + 2], label=f"Line {i}")
276
+
277
+ legend = tools_module.joint_legend(*axes, idx_for_legend=1)
278
+
279
+ assert isinstance(legend, Legend)
280
+
281
+ plt.close(fig)
282
+
283
+ def test_joint_legend_with_kwargs(self):
284
+ """Test joint legend with additional kwargs."""
285
+ fig, axes = plt.subplots(1, 2)
286
+
287
+ axes[0].plot([1, 2, 3], [1, 4, 2], label="Line A")
288
+ axes[1].plot([1, 2, 3], [2, 3, 1], label="Line B")
289
+
290
+ legend = tools_module.joint_legend(
291
+ axes[0], axes[1], loc="upper right", frameon=True, ncol=2
292
+ )
293
+
294
+ assert isinstance(legend, Legend)
295
+
296
+ plt.close(fig)
297
+
298
+ def test_joint_legend_errorbar_handling(self):
299
+ """Test joint legend with errorbar containers."""
300
+ fig, axes = plt.subplots(1, 2)
301
+
302
+ x = [1, 2, 3]
303
+ y = [1, 4, 2]
304
+ yerr = [0.1, 0.2, 0.1]
305
+
306
+ axes[0].errorbar(x, y, yerr=yerr, label="Error Line")
307
+ axes[1].plot(x, [2, 3, 1], label="Regular Line")
308
+
309
+ legend = tools_module.joint_legend(axes[0], axes[1])
310
+
311
+ assert isinstance(legend, Legend)
312
+
313
+ plt.close(fig)
314
+
315
+ def test_joint_legend_sorting(self):
316
+ """Test that legend labels are sorted alphabetically."""
317
+ fig, axes = plt.subplots(1, 2)
318
+
319
+ axes[0].plot([1, 2, 3], [1, 4, 2], label="Z Line")
320
+ axes[1].plot([1, 2, 3], [2, 3, 1], label="A Line")
321
+
322
+ legend = tools_module.joint_legend(axes[0], axes[1])
323
+
324
+ legend_labels = [text.get_text() for text in legend.get_texts()]
325
+ assert legend_labels == ["A Line", "Z Line"]
326
+
327
+ plt.close(fig)
328
+
329
+
330
+ class TestMultipanelFigureSharedCbar:
331
+ """Test multipanel_figure_shared_cbar function."""
332
+
333
+ def test_multipanel_function_exists(self):
334
+ """Test that multipanel function exists and is callable."""
335
+ assert hasattr(tools_module, "multipanel_figure_shared_cbar")
336
+ assert callable(tools_module.multipanel_figure_shared_cbar)
337
+
338
+ def test_multipanel_basic_structure(self):
339
+ """Test basic multipanel figure structure."""
340
+ try:
341
+ fig, axes, cax = tools_module.multipanel_figure_shared_cbar(1, 1)
342
+
343
+ assert isinstance(fig, Figure)
344
+ assert isinstance(cax, Axes)
345
+ # axes might be ndarray or single Axes depending on input
346
+
347
+ plt.close(fig)
348
+ except AttributeError:
349
+ # Skip if matplotlib version incompatibility
350
+ pytest.skip("Matplotlib version incompatibility with axis sharing")
351
+
352
+ def test_multipanel_parameters(self):
353
+ """Test multipanel parameter handling."""
354
+ # Test that function accepts the expected parameters
355
+ try:
356
+ fig, axes, cax = tools_module.multipanel_figure_shared_cbar(
357
+ 1, 1, vertical_cbar=True, sharex=False, sharey=False
358
+ )
359
+ plt.close(fig)
360
+ except AttributeError:
361
+ pytest.skip("Matplotlib version incompatibility")
362
+
363
+
364
+ class TestBuildAxArrayWithCommonColorbar:
365
+ """Test build_ax_array_with_common_colorbar function."""
366
+
367
+ def test_build_ax_array_function_exists(self):
368
+ """Test that build_ax_array function exists and is callable."""
369
+ assert hasattr(tools_module, "build_ax_array_with_common_colorbar")
370
+ assert callable(tools_module.build_ax_array_with_common_colorbar)
371
+
372
+ def test_build_ax_array_basic_interface(self):
373
+ """Test basic interface without axis sharing."""
374
+ try:
375
+ fig, axes, cax = tools_module.build_ax_array_with_common_colorbar(
376
+ 1, 1, gs_kwargs={"sharex": False, "sharey": False}
377
+ )
378
+
379
+ assert isinstance(fig, Figure)
380
+ assert isinstance(cax, Axes)
381
+
382
+ plt.close(fig)
383
+ except AttributeError:
384
+ pytest.skip("Matplotlib version incompatibility with axis sharing")
385
+
386
+ def test_build_ax_array_invalid_location(self):
387
+ """Test invalid colorbar location raises error."""
388
+ with pytest.raises(ValueError):
389
+ tools_module.build_ax_array_with_common_colorbar(2, 2, cbar_loc="invalid")
390
+
391
+ def test_build_ax_array_location_validation(self):
392
+ """Test colorbar location validation."""
393
+ valid_locations = ["top", "bottom", "left", "right"]
394
+
395
+ for loc in valid_locations:
396
+ try:
397
+ fig, axes, cax = tools_module.build_ax_array_with_common_colorbar(
398
+ 1, 1, cbar_loc=loc, gs_kwargs={"sharex": False, "sharey": False}
399
+ )
400
+ plt.close(fig)
401
+ except AttributeError:
402
+ # Skip if matplotlib incompatibility
403
+ continue
404
+
405
+
406
+ class TestCalculateNrowsNcols:
407
+ """Test calculate_nrows_ncols utility function."""
408
+
409
+ def test_calculate_perfect_squares(self):
410
+ """Test calculation for perfect squares."""
411
+ # Perfect squares should give nearly square layouts
412
+ nrows, ncols = tools_module.calculate_nrows_ncols(4)
413
+ assert nrows * ncols >= 4
414
+ assert abs(nrows - ncols) <= 1
415
+
416
+ nrows, ncols = tools_module.calculate_nrows_ncols(9)
417
+ assert nrows * ncols >= 9
418
+
419
+ nrows, ncols = tools_module.calculate_nrows_ncols(16)
420
+ assert nrows * ncols >= 16
421
+
422
+ def test_calculate_prime_numbers(self):
423
+ """Test calculation for prime numbers."""
424
+ # Prime numbers should get bumped up to next composite
425
+ nrows, ncols = tools_module.calculate_nrows_ncols(7)
426
+ assert nrows * ncols >= 7
427
+
428
+ nrows, ncols = tools_module.calculate_nrows_ncols(11)
429
+ assert nrows * ncols >= 11
430
+
431
+ def test_calculate_small_numbers(self):
432
+ """Test calculation for small numbers."""
433
+ test_cases = [1, 2, 3, 4, 5, 6]
434
+
435
+ for n in test_cases:
436
+ nrows, ncols = tools_module.calculate_nrows_ncols(n)
437
+ assert nrows * ncols >= n
438
+ assert nrows > 0
439
+ assert ncols > 0
440
+
441
+ def test_calculate_larger_numbers(self):
442
+ """Test calculation for larger numbers."""
443
+ test_cases = [15, 20, 24, 30, 36]
444
+
445
+ for n in test_cases:
446
+ nrows, ncols = tools_module.calculate_nrows_ncols(n)
447
+ assert nrows * ncols >= n
448
+ assert nrows > 0
449
+ assert ncols > 0
450
+
451
+ def test_calculate_aspect_ratio_preference(self):
452
+ """Test that function prefers wider layouts."""
453
+ nrows, ncols = tools_module.calculate_nrows_ncols(6)
454
+ # Should prefer wider layout (fewer rows, more columns)
455
+ assert ncols >= nrows
456
+
457
+ def test_calculate_edge_cases(self):
458
+ """Test edge cases."""
459
+ # Test very small numbers
460
+ nrows, ncols = tools_module.calculate_nrows_ncols(1)
461
+ assert nrows * ncols >= 1
462
+
463
+ # Test numbers that require adjustment
464
+ nrows, ncols = tools_module.calculate_nrows_ncols(5)
465
+ assert nrows * ncols >= 5
466
+
467
+
468
+ class TestToolsIntegration:
469
+ """Test integration between different tools functions."""
470
+
471
+ def test_subplots_save_integration(self):
472
+ """Test integration between subplots and save."""
473
+ with tempfile.TemporaryDirectory() as temp_dir:
474
+ temp_path = Path(temp_dir) / "integration_test"
475
+
476
+ fig, axes = tools_module.subplots(2, 2, scale_width=1.5)
477
+
478
+ for i, ax in enumerate(axes.flat):
479
+ ax.plot([1, 2, 3], [i, i + 1, i + 2], label=f"Line {i}")
480
+
481
+ tools_module.save(fig, temp_path, log=False)
482
+
483
+ assert temp_path.with_suffix(".pdf").exists()
484
+ assert temp_path.with_suffix(".png").exists()
485
+
486
+ plt.close(fig)
487
+
488
+ def test_multipanel_joint_legend_integration(self):
489
+ """Test integration between multipanel and joint legend."""
490
+ try:
491
+ fig, axes, cax = tools_module.multipanel_figure_shared_cbar(
492
+ 1, 3, sharex=False, sharey=False
493
+ )
494
+
495
+ # Handle case where axes might be 1D array or single Axes
496
+ if isinstance(axes, np.ndarray):
497
+ for i, ax in enumerate(axes.flat):
498
+ ax.plot([1, 2, 3], [i, i + 1, i + 2], label=f"Series {i}")
499
+ legend = tools_module.joint_legend(*axes.flat)
500
+ else:
501
+ axes.plot([1, 2, 3], [1, 2, 3], label="Series")
502
+ legend = tools_module.joint_legend(axes)
503
+
504
+ assert isinstance(legend, Legend)
505
+
506
+ plt.close(fig)
507
+ except AttributeError:
508
+ pytest.skip("Matplotlib version incompatibility")
509
+
510
+ def test_calculate_nrows_ncols_with_basic_plotting(self):
511
+ """Test using calculate_nrows_ncols with basic plotting."""
512
+ n_plots = 6
513
+ nrows, ncols = tools_module.calculate_nrows_ncols(n_plots)
514
+
515
+ # Test with basic subplots instead of multipanel
516
+ fig, axes = tools_module.subplots(nrows, ncols)
517
+
518
+ assert nrows * ncols >= n_plots
519
+
520
+ plt.close(fig)
521
+
522
+
523
+ class TestToolsErrorHandling:
524
+ """Test error handling in tools functions."""
525
+
526
+ def test_save_invalid_inputs(self):
527
+ """Test save function with invalid inputs."""
528
+ fig, ax = plt.subplots()
529
+
530
+ # Invalid figure type
531
+ with pytest.raises(AssertionError):
532
+ tools_module.save("not_a_figure", Path("test"), log=False)
533
+
534
+ # Invalid path type
535
+ with pytest.raises(AssertionError):
536
+ tools_module.save(fig, "not_a_path_object", log=False)
537
+
538
+ plt.close(fig)
539
+
540
+ def test_multipanel_invalid_parameters(self):
541
+ """Test multipanel with edge case parameters."""
542
+ try:
543
+ # Test with minimal parameters
544
+ fig, axes, cax = tools_module.multipanel_figure_shared_cbar(
545
+ 1, 1, sharex=False, sharey=False
546
+ )
547
+ plt.close(fig)
548
+ except AttributeError:
549
+ pytest.skip("Matplotlib version incompatibility")
550
+
551
+ def test_build_ax_array_basic_validation(self):
552
+ """Test build_ax_array basic validation."""
553
+ try:
554
+ fig, axes, cax = tools_module.build_ax_array_with_common_colorbar(
555
+ 1, 1, gs_kwargs={"sharex": False, "sharey": False}
556
+ )
557
+
558
+ # Should return valid matplotlib objects
559
+ assert isinstance(fig, Figure)
560
+ assert isinstance(cax, Axes)
561
+
562
+ plt.close(fig)
563
+ except AttributeError:
564
+ pytest.skip("Matplotlib version incompatibility")
565
+
566
+
567
+ class TestToolsDocumentation:
568
+ """Test documentation and examples in tools functions."""
569
+
570
+ def test_function_docstrings(self):
571
+ """Test that all functions have comprehensive docstrings."""
572
+ functions = [
573
+ tools_module.subplots,
574
+ tools_module.save,
575
+ tools_module.joint_legend,
576
+ tools_module.multipanel_figure_shared_cbar,
577
+ tools_module.build_ax_array_with_common_colorbar,
578
+ tools_module.calculate_nrows_ncols,
579
+ ]
580
+
581
+ for func in functions:
582
+ assert func.__doc__ is not None
583
+ assert len(func.__doc__.strip()) > 0
584
+ # Should have Parameters section
585
+ assert "Parameters" in func.__doc__
586
+ # Should have Returns section (for most functions)
587
+ if func != tools_module.save: # save returns None
588
+ assert "Returns" in func.__doc__
589
+
590
+ def test_docstring_examples(self):
591
+ """Test that functions have usage examples in docstrings."""
592
+ functions_with_examples = [
593
+ tools_module.subplots,
594
+ tools_module.save,
595
+ tools_module.joint_legend,
596
+ tools_module.multipanel_figure_shared_cbar,
597
+ tools_module.build_ax_array_with_common_colorbar,
598
+ tools_module.calculate_nrows_ncols,
599
+ ]
600
+
601
+ for func in functions_with_examples:
602
+ assert "Examples" in func.__doc__
603
+ assert ">>>" in func.__doc__
604
+
605
+
606
+ if __name__ == "__main__":
607
+ pytest.main([__file__])