py-env-studio 2.1.0__tar.gz → 2.1.2__tar.gz

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.
Files changed (154) hide show
  1. {py_env_studio-2.1.0/py_env_studio.egg-info → py_env_studio-2.1.2}/PKG-INFO +3 -2
  2. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/PYPI_README.md +1 -1
  3. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/README.md +31 -7
  4. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/config.ini +1 -1
  5. py_env_studio-2.1.2/py_env_studio/core/app_updates.py +94 -0
  6. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/database.py +12 -0
  7. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/env_manager.py +25 -5
  8. py_env_studio-2.1.2/py_env_studio/core/environment_lock.py +704 -0
  9. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/mcp/tools/__init__.py +13 -0
  10. py_env_studio-2.1.2/py_env_studio/core/mcp/tools/analysis.py +87 -0
  11. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/package_manager.py +97 -8
  12. py_env_studio-2.1.2/py_env_studio/core/package_update_monitor.py +162 -0
  13. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/plugins/manager.py +110 -15
  14. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/runtime_cache.py +7 -1
  15. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/runtime_providers.py +95 -4
  16. py_env_studio-2.1.2/py_env_studio/core/schema/environment_locks.sql +37 -0
  17. py_env_studio-2.1.2/py_env_studio/core/schema/package_updates.sql +36 -0
  18. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/ui/main_window.py +1166 -110
  19. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/utils/app_logging.py +42 -2
  20. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/utils/vulneribility_scanner.py +1 -1
  21. {py_env_studio-2.1.0 → py_env_studio-2.1.2/py_env_studio.egg-info}/PKG-INFO +3 -2
  22. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio.egg-info/SOURCES.txt +40 -1
  23. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio.egg-info/requires.txt +1 -0
  24. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/pyproject.toml +3 -2
  25. py_env_studio-2.1.2/tests/test_all_features.py +568 -0
  26. py_env_studio-2.1.2/tests/test_app_logging.py +183 -0
  27. py_env_studio-2.1.2/tests/test_app_updates.py +106 -0
  28. py_env_studio-2.1.2/tests/test_cli_commands.py +126 -0
  29. py_env_studio-2.1.2/tests/test_cli_progress.py +134 -0
  30. py_env_studio-2.1.2/tests/test_community_templates.py +158 -0
  31. py_env_studio-2.1.2/tests/test_configuration_service.py +139 -0
  32. py_env_studio-2.1.2/tests/test_dependency_preview.py +288 -0
  33. py_env_studio-2.1.2/tests/test_environment_lock.py +364 -0
  34. py_env_studio-2.1.2/tests/test_github_template_import.py +81 -0
  35. py_env_studio-2.1.2/tests/test_mcp_consistency.py +438 -0
  36. py_env_studio-2.1.2/tests/test_mcp_server.py +350 -0
  37. py_env_studio-2.1.2/tests/test_package_update_monitor.py +579 -0
  38. py_env_studio-2.1.2/tests/test_plugin_events.py +45 -0
  39. py_env_studio-2.1.2/tests/test_plugin_import.py +21 -0
  40. py_env_studio-2.1.2/tests/test_plugin_load.py +28 -0
  41. py_env_studio-2.1.2/tests/test_plugin_manager.py +205 -0
  42. py_env_studio-2.1.2/tests/test_project_contract.py +494 -0
  43. py_env_studio-2.1.2/tests/test_project_intelligence.py +631 -0
  44. py_env_studio-2.1.2/tests/test_project_openers.py +85 -0
  45. py_env_studio-2.1.2/tests/test_project_runtime.py +89 -0
  46. py_env_studio-2.1.2/tests/test_runtime_cache.py +234 -0
  47. py_env_studio-2.1.2/tests/test_runtime_providers.py +400 -0
  48. py_env_studio-2.1.2/tests/test_schema_templates.py +141 -0
  49. py_env_studio-2.1.2/tests/test_status_progress.py +192 -0
  50. py_env_studio-2.1.2/tests/test_template_engine.py +178 -0
  51. py_env_studio-2.1.2/tests/test_template_registry.py +73 -0
  52. py_env_studio-2.1.2/tests/test_template_workflow.py +54 -0
  53. py_env_studio-2.1.2/tests/test_ui_backend.py +63 -0
  54. py_env_studio-2.1.2/tests/test_user_template_store.py +125 -0
  55. py_env_studio-2.1.2/tests/test_uv_packages.py +47 -0
  56. py_env_studio-2.1.2/tests/test_vulnerability_insights_charts.py +256 -0
  57. py_env_studio-2.1.2/tests/test_vulnerability_insights_update.py +387 -0
  58. py_env_studio-2.1.2/tests/test_window_icon.py +297 -0
  59. py_env_studio-2.1.0/py_env_studio/core/mcp/tools/analysis.py +0 -20
  60. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/LICENSE +0 -0
  61. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/__init__.py +0 -0
  62. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/__main__.py +0 -0
  63. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/commands.py +0 -0
  64. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/__init__.py +0 -0
  65. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/auto_resolve.py +0 -0
  66. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/bootstrap.py +0 -0
  67. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/configuration.py +0 -0
  68. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/dependency_preview.py +0 -0
  69. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/integration.py +0 -0
  70. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/mcp/__init__.py +0 -0
  71. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/mcp/config.py +0 -0
  72. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/mcp/context.py +0 -0
  73. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/mcp/errors.py +0 -0
  74. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/mcp/schemas/__init__.py +0 -0
  75. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/mcp/schemas/responses.py +0 -0
  76. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/mcp/server.py +0 -0
  77. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/mcp/tools/environments.py +0 -0
  78. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/mcp/tools/packages.py +0 -0
  79. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/mcp/tools/project.py +0 -0
  80. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/mcp/tools/security.py +0 -0
  81. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/pip_tools.py +0 -0
  82. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/plugins/__init__.py +0 -0
  83. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/plugins/base.py +0 -0
  84. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/plugins/exceptions.py +0 -0
  85. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/project_contract/__init__.py +0 -0
  86. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/project_contract/models.py +0 -0
  87. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/project_contract/repository.py +0 -0
  88. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/project_contract/service.py +0 -0
  89. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/project_intelligence/__init__.py +0 -0
  90. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/project_intelligence/models.py +0 -0
  91. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/project_intelligence/service.py +0 -0
  92. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/project_launcher.py +0 -0
  93. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/py_tonic.py +0 -0
  94. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/runtime.py +0 -0
  95. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/runtime_toggle.py +0 -0
  96. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/schema/__init__.py +0 -0
  97. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/schema/environments.sql +0 -0
  98. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/schema/migration.sql +0 -0
  99. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/schema/project_contract.sql +0 -0
  100. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/schema/runtime_cache.sql +0 -0
  101. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/schema/schema_core.sql +0 -0
  102. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/schema/schema_runtime_cache.sql +0 -0
  103. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/schema/vulnerability.sql +0 -0
  104. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/setup_state.py +0 -0
  105. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/strategies.py +0 -0
  106. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/templates/__init__.py +0 -0
  107. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/templates/builtin_templates.py +0 -0
  108. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/templates/community.py +0 -0
  109. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/templates/content_filters.py +0 -0
  110. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/templates/engine.py +0 -0
  111. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/templates/github_import.py +0 -0
  112. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/templates/models.py +0 -0
  113. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/templates/registry.py +0 -0
  114. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/templates/user_template_store.py +0 -0
  115. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/templates/validator.py +0 -0
  116. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/templates/workflow.py +0 -0
  117. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/tool_probe.py +0 -0
  118. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/tools.py +0 -0
  119. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/uv_tools.py +0 -0
  120. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/core/windows_apps.py +0 -0
  121. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/main.py +0 -0
  122. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/ui/__init__.py +0 -0
  123. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/ui/static/icons/__init__.py +0 -0
  124. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/ui/static/icons/about.png +0 -0
  125. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/ui/static/icons/activate-env.png +0 -0
  126. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/ui/static/icons/available-env.png +0 -0
  127. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/ui/static/icons/create-env.png +0 -0
  128. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/ui/static/icons/delete-env.png +0 -0
  129. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/ui/static/icons/export.png +0 -0
  130. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/ui/static/icons/install.png +0 -0
  131. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/ui/static/icons/list-env.png +0 -0
  132. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/ui/static/icons/logo.png +0 -0
  133. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/ui/static/icons/packages.png +0 -0
  134. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/ui/static/icons/pes-default-transparrent.png +0 -0
  135. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/ui/static/icons/pes-icon-default.ico +0 -0
  136. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/ui/static/icons/pes-icon-default.png +0 -0
  137. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/ui/static/icons/pes-transparrent-icon-default.ico +0 -0
  138. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/ui/static/icons/requirements.png +0 -0
  139. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/ui/static/icons/selected-env.png +0 -0
  140. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/ui/static/icons/uninstall.png +0 -0
  141. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/ui/static/icons/update.png +0 -0
  142. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/ui/status_bar.py +0 -0
  143. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/ui/ui_tasks.py +0 -0
  144. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/utils/__init__.py +0 -0
  145. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/utils/app_icon.py +0 -0
  146. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/utils/db_status.py +0 -0
  147. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/utils/handlers.py +0 -0
  148. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/utils/progress.py +0 -0
  149. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/utils/version_utils.py +0 -0
  150. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio/utils/vulneribility_insights.py +0 -0
  151. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio.egg-info/dependency_links.txt +0 -0
  152. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio.egg-info/entry_points.txt +0 -0
  153. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/py_env_studio.egg-info/top_level.txt +0 -0
  154. {py_env_studio-2.1.0 → py_env_studio-2.1.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: py-env-studio
3
- Version: 2.1.0
3
+ Version: 2.1.2
4
4
  Summary: A comprehensive cross-platform GUI and CLI tool for managing Python virtual environments and packages with advanced features including environment lifecycle management, package operations, vulnerability scanning, security insights, project templates, Py-Tonic interactive learning mode, an extensible plugin system for custom functionality, and a local read-only MCP control plane (beta) for AI coding agents.
5
5
  Author-email: Py Env Studio Team <contact.shaikh.wasim@gmail.com>
6
6
  License: MIT License
@@ -54,6 +54,7 @@ Requires-Dist: pip
54
54
  Requires-Dist: setuptools
55
55
  Requires-Dist: wheel
56
56
  Requires-Dist: platformdirs>=4.2.0
57
+ Requires-Dist: packaging>=24.2
57
58
  Provides-Extra: dev
58
59
  Requires-Dist: pytest; extra == "dev"
59
60
  Requires-Dist: black; extra == "dev"
@@ -160,7 +161,7 @@ Setup steps for VS Code and other clients:
160
161
 
161
162
  - Documentation home: [https://py-env-studio.readthedocs.io/](https://py-env-studio.readthedocs.io/)
162
163
  - Usage manual: [https://py-env-studio.readthedocs.io/en/latest/getting-started/usage.html](https://py-env-studio.readthedocs.io/en/latest/getting-started/usage.html)
163
- - Release notes: [https://py-env-studio.readthedocs.io/en/latest/releases/v2.1.0.html](https://py-env-studio.readthedocs.io/en/latest/releases/v2.1.0.html)
164
+ - Release notes: [https://py-env-studio.readthedocs.io/en/latest/releases/v2.1.2.html](https://py-env-studio.readthedocs.io/en/latest/releases/v2.1.2.html)
164
165
  - Source code: [https://github.com/pyenvstudio/py-env-studio](https://github.com/pyenvstudio/py-env-studio)
165
166
  - Issue tracker: [https://github.com/pyenvstudio/py-env-studio/issues](https://github.com/pyenvstudio/py-env-studio/issues)
166
167
 
@@ -96,7 +96,7 @@ Setup steps for VS Code and other clients:
96
96
 
97
97
  - Documentation home: [https://py-env-studio.readthedocs.io/](https://py-env-studio.readthedocs.io/)
98
98
  - Usage manual: [https://py-env-studio.readthedocs.io/en/latest/getting-started/usage.html](https://py-env-studio.readthedocs.io/en/latest/getting-started/usage.html)
99
- - Release notes: [https://py-env-studio.readthedocs.io/en/latest/releases/v2.1.0.html](https://py-env-studio.readthedocs.io/en/latest/releases/v2.1.0.html)
99
+ - Release notes: [https://py-env-studio.readthedocs.io/en/latest/releases/v2.1.2.html](https://py-env-studio.readthedocs.io/en/latest/releases/v2.1.2.html)
100
100
  - Source code: [https://github.com/pyenvstudio/py-env-studio](https://github.com/pyenvstudio/py-env-studio)
101
101
  - Issue tracker: [https://github.com/pyenvstudio/py-env-studio/issues](https://github.com/pyenvstudio/py-env-studio/issues)
102
102
 
@@ -29,7 +29,7 @@ Perfect for:
29
29
 
30
30
  ---
31
31
 
32
- ## 🆕 What's new in v2.1.0
32
+ ## 🆕 What's new in v2.1.2
33
33
 
34
34
  - 🧪 **MCP control plane (beta)** — a local, read-only MCP server lets AI coding
35
35
  agents (VS Code Copilot and other MCP clients) read authoritative
@@ -48,7 +48,7 @@ Perfect for:
48
48
  - 📊 **Native dashboard charts** (`tkinter-dash`, no matplotlib), 📶 a CLI
49
49
  progress gauge and GUI status gauge, and consistent application icons.
50
50
 
51
- → [Full v2.1.0 release notes](docs/releases/v2.1.0.md)
51
+ → [Full v2.1.2 release notes](docs/releases/v2.1.2.md)
52
52
 
53
53
  ---
54
54
 
@@ -105,7 +105,7 @@ PyEnvStudio now features a powerful plugin system that allows developers to exte
105
105
  - **Easy Development** - Simple plugin API with lifecycle management
106
106
  - **Examples Included** - Full working sample plugin with documentation
107
107
 
108
- See the [v2.1.0 release notes](docs/releases/v2.1.0.md) and the [plugin development guide](docs/plugins/development.md).
108
+ See the [v2.1.2 release notes](docs/releases/v2.1.2.md) and the [plugin development guide](docs/plugins/development.md).
109
109
 
110
110
  ### Additional implemented capabilities
111
111
 
@@ -160,6 +160,9 @@ If you find **Py Env Studio** helpful, consider supporting me:
160
160
  [![Ko-fi](https://img.shields.io/badge/Ko--fi-Support%20me-ff5e5b?logo=ko-fi&logoColor=white&style=for-the-badge)](https://ko-fi.com/contactshaikhwasim)
161
161
  [![PayPal](https://img.shields.io/badge/Donate-PayPal-blue?logo=paypal&style=for-the-badge)](https://www.paypal.me/paypalwasimshaikh)
162
162
 
163
+ <p align="center">
164
+ <img src="https://github.com/pyenvstudio/py-env-studio/blob/main/screenshots/bmc-qr-code.png?raw=true" alt="Buy Me a Coffee QR Code" width="200">
165
+ </p>
163
166
 
164
167
  ---
165
168
 
@@ -182,13 +185,21 @@ The same aliases apply to every CLI command shown in the documentation
182
185
 
183
186
  Refer usage documentation here: https://py-env-studio.readthedocs.io/en/latest/
184
187
 
188
+ ## 📸 Screenshots
189
+
185
190
  <p align="center">
186
191
  <img src="https://github.com/pyenvstudio/py-env-studio/blob/main/screenshots/1.environment-screen.PNG?raw=true" alt="Environment Screen" width="400">
187
-
188
- <img src="https://github.com/pyenvstudio/py-env-studio/blob/main/screenshots/plugin-screen.PNG?raw=true" alt="Plugin Screen" width="400">
192
+ <img src="https://github.com/pyenvstudio/py-env-studio/blob/main/screenshots/1.1.more_options.PNG?raw=true" alt="Environment More Options" width="400"><br>
193
+ <img src="https://github.com/pyenvstudio/py-env-studio/blob/main/screenshots/1.2.1_vulneribility_scan_report.PNG?raw=true" alt="Vulnerability Scan Report" width="400">
194
+ <img src="https://github.com/pyenvstudio/py-env-studio/blob/main/screenshots/1.2.2_vulneribility_scan_report.PNG?raw=true" alt="Vulnerability Scan Report Details" width="400"><br>
195
+ <img src="https://github.com/pyenvstudio/py-env-studio/blob/main/screenshots/1.2.3_vulneribility_scan_report.PNG?raw=true" alt="Vulnerability Scan Report Insights" width="400">
189
196
  <img src="https://github.com/pyenvstudio/py-env-studio/blob/main/screenshots/2.0.package-screen.PNG?raw=true" alt="Package Screen" width="400"><br>
190
- <img src="https://github.com/pyenvstudio/py-env-studio/blob/main/screenshots/1.2.1_vulneribility_scan_report.PNG?raw=true" alt="Package Screen" width="400">
191
- <img src="https://github.com/pyenvstudio/py-env-studio/blob/main/screenshots/1.2.2_vulneribility_scan_report.PNG?raw=true" alt="Package Screen" width="400">
197
+ <img src="https://github.com/pyenvstudio/py-env-studio/blob/main/screenshots/2.1.package-screen.PNG?raw=true" alt="Package Screen Details" width="400">
198
+ <img src="https://github.com/pyenvstudio/py-env-studio/blob/main/screenshots/plugin-screen.PNG?raw=true" alt="Plugin Screen" width="400"><br>
199
+ <img src="https://github.com/pyenvstudio/py-env-studio/blob/main/screenshots/templates.PNG?raw=true" alt="Templates Screen" width="400">
200
+ <img src="https://github.com/pyenvstudio/py-env-studio/blob/main/screenshots/python-manager.PNG?raw=true" alt="Python Manager Screen" width="400"><br>
201
+ <img src="https://github.com/pyenvstudio/py-env-studio/blob/main/screenshots/configuration.PNG?raw=true" alt="Configuration Screen" width="400">
202
+ <img src="https://github.com/pyenvstudio/py-env-studio/blob/main/screenshots/3.about-sceeen.PNG?raw=true" alt="About Screen" width="400">
192
203
  </p>
193
204
 
194
205
  **📁 Project Structure**
@@ -249,6 +260,7 @@ This project uses public APIs for core features:
249
260
  | PyPI | Package metadata | [pypi.org](https://pypi.org) |
250
261
  | deps.dev | Dependency data | [deps.dev](https://deps.dev) |
251
262
  | OSV.dev | Vulnerability info | [osv.dev](https://osv.dev) |
263
+ | Github | Community templates | [github.com](https://github.com) |
252
264
 
253
265
  Ensure HTTPS access to these domains.
254
266
  APIs are public, read-only, no auth required.
@@ -260,6 +272,18 @@ APIs are public, read-only, no auth required.
260
272
  We welcome contributions!
261
273
  Feel free to fork the repository, raise issues, or submit pull requests.
262
274
 
275
+ ## Acknowledgements
276
+
277
+ Py Env Studio is built on the work of the Python community and the broader open-source ecosystem.
278
+
279
+ **Built with:** [Python](https://www.python.org/), [CustomTkinter](https://github.com/TomSchimansky/CustomTkinter), which provides the desktop UI foundation, and [Pillow](https://python-pillow.org/) for image and icon handling.
280
+
281
+ **Integrates with:** the [Python Install Manager](https://docs.python.org/3/using/windows.html#python-install-manager) for Python runtime management; [PyPI](https://pypi.org/) and the [Python Packaging community](https://packaging.python.org/) for package distribution and metadata; and [pip](https://pip.pypa.io/) and [uv](https://docs.astral.sh/uv/) for package management.
282
+
283
+ Thanks to the maintainers and contributors behind these projects and to everyone building Python and open-source software. These acknowledgements do not imply endorsement, affiliation, or official partnership.
284
+
285
+ *Built with Python. Powered by open source.*
286
+
263
287
  **⚖️ License**
264
288
  This project is licensed under the MIT License.
265
289
 
@@ -1,5 +1,5 @@
1
1
  [project]
2
- version = 2.1.0
2
+ version = 2.1.2
3
3
 
4
4
  [settings]
5
5
  venv_dir = ~/.py_env_studio/venvs
@@ -0,0 +1,94 @@
1
+ """Check and apply Py Env Studio package updates."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ import os
7
+ import subprocess
8
+ import sys
9
+ from dataclasses import dataclass
10
+ from importlib.metadata import PackageNotFoundError, version
11
+
12
+ import requests
13
+ from packaging.version import InvalidVersion, Version
14
+
15
+ from .runtime import get_runtime_config
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+ PACKAGE_NAME = "py-env-studio"
20
+ PYPI_JSON_URL = "https://pypi.org/pypi/py-env-studio/json"
21
+ RELEASES_URL = "https://github.com/pyenvstudio/py-env-studio/releases/latest"
22
+
23
+
24
+ @dataclass(frozen=True)
25
+ class AppUpdateStatus:
26
+ current_version: str
27
+ latest_version: str
28
+ update_available: bool
29
+
30
+
31
+ def get_installed_app_version() -> str:
32
+ """Return the installed distribution version, falling back to package config."""
33
+ try:
34
+ return version(PACKAGE_NAME)
35
+ except PackageNotFoundError:
36
+ configured_version = get_runtime_config().app_version
37
+ return configured_version if configured_version != "stable" else "Unknown"
38
+
39
+
40
+ def check_for_app_update(current_version: str | None = None) -> AppUpdateStatus:
41
+ """Fetch PyPI's latest release metadata and compare it with this install."""
42
+ current = current_version or get_installed_app_version()
43
+ response = requests.get(
44
+ PYPI_JSON_URL,
45
+ headers={"Accept": "application/json"},
46
+ timeout=10,
47
+ )
48
+ response.raise_for_status()
49
+ try:
50
+ latest = str(response.json()["info"]["version"])
51
+ update_available = Version(latest) > Version(current)
52
+ except (KeyError, TypeError, InvalidVersion) as exc:
53
+ raise RuntimeError("PyPI returned invalid Py Env Studio version metadata") from exc
54
+ return AppUpdateStatus(current, latest, update_available)
55
+
56
+
57
+ def is_frozen_build() -> bool:
58
+ """Whether this process is running from a bundled executable."""
59
+ return bool(getattr(sys, "frozen", False))
60
+
61
+
62
+ def install_app_update(target_version: str) -> None:
63
+ """Upgrade this interpreter's Py Env Studio distribution through pip."""
64
+ try:
65
+ Version(target_version)
66
+ except InvalidVersion as exc:
67
+ raise ValueError(f"Invalid Py Env Studio version: {target_version}") from exc
68
+ if is_frozen_build():
69
+ raise RuntimeError("Bundled builds must be updated from the release download page")
70
+
71
+ command = [
72
+ sys.executable,
73
+ "-m",
74
+ "pip",
75
+ "install",
76
+ "--upgrade",
77
+ f"{PACKAGE_NAME}=={target_version}",
78
+ ]
79
+ result = subprocess.run(command, capture_output=True, text=True, timeout=600)
80
+ if result.returncode != 0:
81
+ details = (result.stderr or result.stdout or "pip exited with an error").strip()
82
+ raise RuntimeError(f"pip could not install Py Env Studio {target_version}: {details}")
83
+ logger.info("Installed Py Env Studio %s", target_version)
84
+
85
+
86
+ def restart_app() -> subprocess.Popen:
87
+ """Start a fresh GUI process using the same Python interpreter."""
88
+ command = [sys.executable, "-m", "py_env_studio"]
89
+ options = {"close_fds": True}
90
+ if os.name == "nt":
91
+ options["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP | subprocess.DETACHED_PROCESS
92
+ else:
93
+ options["start_new_session"] = True
94
+ return subprocess.Popen(command, **options)
@@ -42,6 +42,18 @@ class DatabaseManager:
42
42
  cur.execute(sql.get("schema_core", name))
43
43
  for statement in sql.statements("schema_runtime_cache"):
44
44
  cur.execute(statement)
45
+ for name in sql.available("package_updates"):
46
+ if name.startswith("create_"):
47
+ cur.execute(sql.get("package_updates", name))
48
+ for name in sql.available("environment_locks"):
49
+ if name.startswith("create_"):
50
+ cur.execute(sql.get("environment_locks", name))
51
+ package_update_columns = {
52
+ row[1]
53
+ for row in cur.execute("PRAGMA table_info(package_update_cache)").fetchall()
54
+ }
55
+ if "outdated_packages" not in package_update_columns:
56
+ cur.execute(sql.get("package_updates", "add_outdated_packages_column"))
45
57
  # project_contract.sql mixes DDL with DML templates: only the
46
58
  # create_* statements are schema, the rest are fetched by name
47
59
  # at the call site (see ProjectContractRepository).
@@ -183,7 +183,7 @@ def _save_env_data(data):
183
183
  LOGGER.error("Failed to save env data: %s", exc)
184
184
 
185
185
 
186
- def set_env_data(env_name, recent_location=None, size=None, last_scanned=None, python_version=None, package_manager=None):
186
+ def set_env_data(env_name, recent_location=None, size=None, last_scanned=None, python_version=None, package_manager=None, package_update_check_enabled=None):
187
187
  data = _load_env_data()
188
188
  entry = data.get(env_name, {})
189
189
 
@@ -197,6 +197,8 @@ def set_env_data(env_name, recent_location=None, size=None, last_scanned=None, p
197
197
  entry["python_version"] = python_version
198
198
  if package_manager is not None:
199
199
  entry["package_manager"] = package_manager
200
+ if package_update_check_enabled is not None:
201
+ entry["package_update_check_enabled"] = package_update_check_enabled is True
200
202
 
201
203
  data[env_name] = entry
202
204
  _save_env_data(data)
@@ -204,7 +206,10 @@ def set_env_data(env_name, recent_location=None, size=None, last_scanned=None, p
204
206
 
205
207
  def get_env_data(env_name):
206
208
  data = _load_env_data()
207
- return data.get(env_name, {})
209
+ entry = data.get(env_name, {})
210
+ if "package_update_check_enabled" not in entry:
211
+ entry["package_update_check_enabled"] = False
212
+ return entry
208
213
 
209
214
 
210
215
  def calculate_env_size_mb(env_path):
@@ -327,7 +332,7 @@ def _is_valid_env_name(name: str) -> bool:
327
332
  return True
328
333
 
329
334
 
330
- def create_env(name, python_path=None, upgrade_pip=False, log_callback=None):
335
+ def create_env(name, python_path=None, upgrade_pip=False, log_callback=None, package_update_check_enabled=False):
331
336
  env_path = os.path.join(VENV_DIR, name)
332
337
  python_path = python_path or PYTHON_PATH or "python"
333
338
  python_version = _extract_python_version(python_path) or "default"
@@ -444,7 +449,14 @@ def create_env(name, python_path=None, upgrade_pip=False, log_callback=None):
444
449
  size_mb = calculate_env_size_mb(env_path)
445
450
  detected_version = _extract_python_version(venv_python)
446
451
  # Store which package manager was actually used to create this environment
447
- set_env_data(name, recent_location=env_path, size=size_mb, python_version=detected_version, package_manager=package_manager)
452
+ set_env_data(
453
+ name,
454
+ recent_location=env_path,
455
+ size=size_mb,
456
+ python_version=detected_version,
457
+ package_manager=package_manager,
458
+ package_update_check_enabled=package_update_check_enabled,
459
+ )
448
460
 
449
461
  LOGGER.info(
450
462
  "Created environment at: %s with Python: %s using %s (%.1fs)",
@@ -570,6 +582,13 @@ def delete_env(name, log_callback=None):
570
582
  shutil.rmtree(env_path)
571
583
  LOGGER.info("Deleted environment: %s", name)
572
584
 
585
+ try:
586
+ from .package_update_monitor import PackageUpdateMonitor
587
+
588
+ PackageUpdateMonitor().invalidate_cache(name)
589
+ except Exception as exc:
590
+ LOGGER.warning("Could not invalidate package-update cache for '%s': %s", name, exc)
591
+
573
592
  data = _load_env_data()
574
593
  if name in data:
575
594
  del data[name]
@@ -586,7 +605,8 @@ def delete_env(name, log_callback=None):
586
605
 
587
606
 
588
607
  def get_env_python(env_name):
589
- return os.path.join(VENV_DIR, env_name, "Scripts" if os.name == "nt" else "bin", "python")
608
+ executable = "python.exe" if os.name == "nt" else "python"
609
+ return os.path.join(VENV_DIR, env_name, "Scripts" if os.name == "nt" else "bin", executable)
590
610
 
591
611
 
592
612
  def activate_env(env_name, directory=None, open_with="vscode", open_in_venv_cwd=False, log_callback=None):