jazzoo 0.1.0__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 (222) hide show
  1. jazzoo-0.1.0/LICENSE +21 -0
  2. jazzoo-0.1.0/MANIFEST.in +2 -0
  3. jazzoo-0.1.0/PKG-INFO +18 -0
  4. jazzoo-0.1.0/README.short.md +5 -0
  5. jazzoo-0.1.0/pyproject.toml +42 -0
  6. jazzoo-0.1.0/setup.cfg +11 -0
  7. jazzoo-0.1.0/setup.py +18 -0
  8. jazzoo-0.1.0/src/jazzoo/__init__.py +57 -0
  9. jazzoo-0.1.0/src/jazzoo/aliases/__init__.py +0 -0
  10. jazzoo-0.1.0/src/jazzoo/aliases/errors.py +5 -0
  11. jazzoo-0.1.0/src/jazzoo/aliases/rules/__init__.py +0 -0
  12. jazzoo-0.1.0/src/jazzoo/aliases/rules/expand_alias.py +38 -0
  13. jazzoo-0.1.0/src/jazzoo/aliases/rules/get_alias_config_file.py +7 -0
  14. jazzoo-0.1.0/src/jazzoo/aliases/rules/read_aliases.py +36 -0
  15. jazzoo-0.1.0/src/jazzoo/blocks/__init__.py +0 -0
  16. jazzoo-0.1.0/src/jazzoo/blocks/actions/__init__.py +0 -0
  17. jazzoo-0.1.0/src/jazzoo/blocks/actions/run_block.py +80 -0
  18. jazzoo-0.1.0/src/jazzoo/blocks/models/__init__.py +0 -0
  19. jazzoo-0.1.0/src/jazzoo/blocks/models/block.py +21 -0
  20. jazzoo-0.1.0/src/jazzoo/blocks/rules/__init__.py +0 -0
  21. jazzoo-0.1.0/src/jazzoo/commands/__init__.py +19 -0
  22. jazzoo-0.1.0/src/jazzoo/commands/__main__.py +5 -0
  23. jazzoo-0.1.0/src/jazzoo/commands/actions/__init__.py +0 -0
  24. jazzoo-0.1.0/src/jazzoo/commands/actions/confirm_command.py +36 -0
  25. jazzoo-0.1.0/src/jazzoo/commands/actions/run.py +100 -0
  26. jazzoo-0.1.0/src/jazzoo/commands/actions/run_docker.py +67 -0
  27. jazzoo-0.1.0/src/jazzoo/commands/entrypoints/__init__.py +0 -0
  28. jazzoo-0.1.0/src/jazzoo/commands/entrypoints/jaz_run.py +76 -0
  29. jazzoo-0.1.0/src/jazzoo/commands/errors.py +26 -0
  30. jazzoo-0.1.0/src/jazzoo/commands/models/__init__.py +0 -0
  31. jazzoo-0.1.0/src/jazzoo/commands/models/command_result.py +15 -0
  32. jazzoo-0.1.0/src/jazzoo/commands/rules/__init__.py +0 -0
  33. jazzoo-0.1.0/src/jazzoo/commands/rules/find_executable.py +18 -0
  34. jazzoo-0.1.0/src/jazzoo/commands/rules/has_terminal.py +9 -0
  35. jazzoo-0.1.0/src/jazzoo/commands/rules/is_confirm_on.py +7 -0
  36. jazzoo-0.1.0/src/jazzoo/commands/rules/needs_tty.py +9 -0
  37. jazzoo-0.1.0/src/jazzoo/commands/settings.py +7 -0
  38. jazzoo-0.1.0/src/jazzoo/commands/utils/__init__.py +0 -0
  39. jazzoo-0.1.0/src/jazzoo/commands/utils/dataclass.py +34 -0
  40. jazzoo-0.1.0/src/jazzoo/commands/utils/format_command.py +9 -0
  41. jazzoo-0.1.0/src/jazzoo/commands/utils/ignoring_sigint.py +18 -0
  42. jazzoo-0.1.0/src/jazzoo/config/__init__.py +17 -0
  43. jazzoo-0.1.0/src/jazzoo/config/_vendor/__init__.py +0 -0
  44. jazzoo-0.1.0/src/jazzoo/config/_vendor/vendor.txt +1 -0
  45. jazzoo-0.1.0/src/jazzoo/config/_vendor/yaml/LICENSE +20 -0
  46. jazzoo-0.1.0/src/jazzoo/config/_vendor/yaml/__init__.py +390 -0
  47. jazzoo-0.1.0/src/jazzoo/config/_vendor/yaml/composer.py +139 -0
  48. jazzoo-0.1.0/src/jazzoo/config/_vendor/yaml/constructor.py +748 -0
  49. jazzoo-0.1.0/src/jazzoo/config/_vendor/yaml/dumper.py +62 -0
  50. jazzoo-0.1.0/src/jazzoo/config/_vendor/yaml/emitter.py +1137 -0
  51. jazzoo-0.1.0/src/jazzoo/config/_vendor/yaml/error.py +75 -0
  52. jazzoo-0.1.0/src/jazzoo/config/_vendor/yaml/events.py +86 -0
  53. jazzoo-0.1.0/src/jazzoo/config/_vendor/yaml/loader.py +63 -0
  54. jazzoo-0.1.0/src/jazzoo/config/_vendor/yaml/nodes.py +49 -0
  55. jazzoo-0.1.0/src/jazzoo/config/_vendor/yaml/parser.py +589 -0
  56. jazzoo-0.1.0/src/jazzoo/config/_vendor/yaml/reader.py +185 -0
  57. jazzoo-0.1.0/src/jazzoo/config/_vendor/yaml/representer.py +389 -0
  58. jazzoo-0.1.0/src/jazzoo/config/_vendor/yaml/resolver.py +227 -0
  59. jazzoo-0.1.0/src/jazzoo/config/_vendor/yaml/scanner.py +1435 -0
  60. jazzoo-0.1.0/src/jazzoo/config/_vendor/yaml/serializer.py +111 -0
  61. jazzoo-0.1.0/src/jazzoo/config/_vendor/yaml/tokens.py +104 -0
  62. jazzoo-0.1.0/src/jazzoo/config/errors.py +14 -0
  63. jazzoo-0.1.0/src/jazzoo/config/models/__init__.py +0 -0
  64. jazzoo-0.1.0/src/jazzoo/config/models/loaded_config.py +17 -0
  65. jazzoo-0.1.0/src/jazzoo/config/rules/__init__.py +0 -0
  66. jazzoo-0.1.0/src/jazzoo/config/rules/expand_include_path.py +73 -0
  67. jazzoo-0.1.0/src/jazzoo/config/rules/get_config.py +26 -0
  68. jazzoo-0.1.0/src/jazzoo/config/rules/get_loaded_config.py +63 -0
  69. jazzoo-0.1.0/src/jazzoo/config/rules/get_value.py +199 -0
  70. jazzoo-0.1.0/src/jazzoo/config/rules/prepare_config.py +5 -0
  71. jazzoo-0.1.0/src/jazzoo/config/rules/read_config_file.py +30 -0
  72. jazzoo-0.1.0/src/jazzoo/config/rules/read_config_layers.py +58 -0
  73. jazzoo-0.1.0/src/jazzoo/config/rules/split_config_path.py +7 -0
  74. jazzoo-0.1.0/src/jazzoo/config/settings.py +6 -0
  75. jazzoo-0.1.0/src/jazzoo/config/utils/__init__.py +0 -0
  76. jazzoo-0.1.0/src/jazzoo/config/utils/dataclass.py +34 -0
  77. jazzoo-0.1.0/src/jazzoo/config/utils/format_config_path.py +5 -0
  78. jazzoo-0.1.0/src/jazzoo/config/utils/merge_config.py +11 -0
  79. jazzoo-0.1.0/src/jazzoo/config/utils/render_scalar.py +17 -0
  80. jazzoo-0.1.0/src/jazzoo/config/utils/split_expressions.py +59 -0
  81. jazzoo-0.1.0/src/jazzoo/enums.py +15 -0
  82. jazzoo-0.1.0/src/jazzoo/environment/__init__.py +0 -0
  83. jazzoo-0.1.0/src/jazzoo/environment/actions/__init__.py +0 -0
  84. jazzoo-0.1.0/src/jazzoo/environment/actions/load_config.py +26 -0
  85. jazzoo-0.1.0/src/jazzoo/environment/actions/load_env.py +30 -0
  86. jazzoo-0.1.0/src/jazzoo/environment/utils/__init__.py +0 -0
  87. jazzoo-0.1.0/src/jazzoo/environment/utils/parse_dotenv.py +17 -0
  88. jazzoo-0.1.0/src/jazzoo/errors.py +43 -0
  89. jazzoo-0.1.0/src/jazzoo/expressions/__init__.py +0 -0
  90. jazzoo-0.1.0/src/jazzoo/expressions/actions/__init__.py +0 -0
  91. jazzoo-0.1.0/src/jazzoo/expressions/actions/evaluate.py +17 -0
  92. jazzoo-0.1.0/src/jazzoo/expressions/actions/evaluate_expression.py +344 -0
  93. jazzoo-0.1.0/src/jazzoo/expressions/models/__init__.py +0 -0
  94. jazzoo-0.1.0/src/jazzoo/expressions/models/boolean.py +25 -0
  95. jazzoo-0.1.0/src/jazzoo/expressions/models/literal.py +11 -0
  96. jazzoo-0.1.0/src/jazzoo/expressions/models/path_join.py +12 -0
  97. jazzoo-0.1.0/src/jazzoo/expressions/models/pipe.py +13 -0
  98. jazzoo-0.1.0/src/jazzoo/expressions/models/reference.py +21 -0
  99. jazzoo-0.1.0/src/jazzoo/expressions/models/ternary.py +20 -0
  100. jazzoo-0.1.0/src/jazzoo/expressions/rules/__init__.py +0 -0
  101. jazzoo-0.1.0/src/jazzoo/expressions/rules/apply_builtin_pipe.py +55 -0
  102. jazzoo-0.1.0/src/jazzoo/expressions/rules/get_by_path.py +47 -0
  103. jazzoo-0.1.0/src/jazzoo/expressions/rules/is_truthy.py +22 -0
  104. jazzoo-0.1.0/src/jazzoo/expressions/rules/parse_expression.py +201 -0
  105. jazzoo-0.1.0/src/jazzoo/expressions/rules/parse_references.py +318 -0
  106. jazzoo-0.1.0/src/jazzoo/expressions/rules/resolve_reference.py +71 -0
  107. jazzoo-0.1.0/src/jazzoo/expressions/rules/split_reference_path.py +25 -0
  108. jazzoo-0.1.0/src/jazzoo/expressions/rules/substitute_references.py +51 -0
  109. jazzoo-0.1.0/src/jazzoo/expressions/rules/tokenize_expression.py +207 -0
  110. jazzoo-0.1.0/src/jazzoo/expressions/utils/__init__.py +0 -0
  111. jazzoo-0.1.0/src/jazzoo/expressions/utils/join_path.py +13 -0
  112. jazzoo-0.1.0/src/jazzoo/expressions/utils/render_value.py +22 -0
  113. jazzoo-0.1.0/src/jazzoo/expressions/utils/shell_quote.py +6 -0
  114. jazzoo-0.1.0/src/jazzoo/expressions/utils/strip_one_newline.py +5 -0
  115. jazzoo-0.1.0/src/jazzoo/functions/__init__.py +0 -0
  116. jazzoo-0.1.0/src/jazzoo/functions/actions/__init__.py +0 -0
  117. jazzoo-0.1.0/src/jazzoo/functions/actions/call_builtin_function.py +62 -0
  118. jazzoo-0.1.0/src/jazzoo/functions/actions/call_function.py +262 -0
  119. jazzoo-0.1.0/src/jazzoo/functions/models/__init__.py +0 -0
  120. jazzoo-0.1.0/src/jazzoo/functions/models/call_site.py +25 -0
  121. jazzoo-0.1.0/src/jazzoo/functions/models/curried_function.py +18 -0
  122. jazzoo-0.1.0/src/jazzoo/functions/models/function.py +32 -0
  123. jazzoo-0.1.0/src/jazzoo/functions/models/parameter.py +11 -0
  124. jazzoo-0.1.0/src/jazzoo/functions/rules/__init__.py +0 -0
  125. jazzoo-0.1.0/src/jazzoo/functions/rules/format_signature.py +18 -0
  126. jazzoo-0.1.0/src/jazzoo/functions/rules/get_function_by_path.py +25 -0
  127. jazzoo-0.1.0/src/jazzoo/functions/rules/get_target_by_path.py +41 -0
  128. jazzoo-0.1.0/src/jazzoo/functions/rules/get_targets.py +13 -0
  129. jazzoo-0.1.0/src/jazzoo/functions/rules/parse_curry.py +81 -0
  130. jazzoo-0.1.0/src/jazzoo/modules/__init__.py +0 -0
  131. jazzoo-0.1.0/src/jazzoo/modules/actions/__init__.py +0 -0
  132. jazzoo-0.1.0/src/jazzoo/modules/actions/parse_module.py +248 -0
  133. jazzoo-0.1.0/src/jazzoo/modules/actions/resolve_import.py +261 -0
  134. jazzoo-0.1.0/src/jazzoo/modules/models/__init__.py +0 -0
  135. jazzoo-0.1.0/src/jazzoo/modules/models/absent.py +14 -0
  136. jazzoo-0.1.0/src/jazzoo/modules/models/assignment.py +13 -0
  137. jazzoo-0.1.0/src/jazzoo/modules/models/builtin_call.py +14 -0
  138. jazzoo-0.1.0/src/jazzoo/modules/models/frame.py +86 -0
  139. jazzoo-0.1.0/src/jazzoo/modules/models/import_statement.py +26 -0
  140. jazzoo-0.1.0/src/jazzoo/modules/models/module.py +28 -0
  141. jazzoo-0.1.0/src/jazzoo/modules/models/parsed_source.py +15 -0
  142. jazzoo-0.1.0/src/jazzoo/modules/models/scope.py +13 -0
  143. jazzoo-0.1.0/src/jazzoo/modules/models/variable.py +13 -0
  144. jazzoo-0.1.0/src/jazzoo/modules/rules/__init__.py +0 -0
  145. jazzoo-0.1.0/src/jazzoo/modules/rules/get_module_by_path.py +22 -0
  146. jazzoo-0.1.0/src/jazzoo/modules/rules/list_targets.py +46 -0
  147. jazzoo-0.1.0/src/jazzoo/modules/rules/parse_attribute_line.py +31 -0
  148. jazzoo-0.1.0/src/jazzoo/modules/rules/parse_body.py +136 -0
  149. jazzoo-0.1.0/src/jazzoo/modules/rules/parse_call_arguments.py +19 -0
  150. jazzoo-0.1.0/src/jazzoo/modules/rules/parse_dependencies.py +20 -0
  151. jazzoo-0.1.0/src/jazzoo/modules/rules/parse_import_statement.py +101 -0
  152. jazzoo-0.1.0/src/jazzoo/modules/rules/parse_parameters.py +18 -0
  153. jazzoo-0.1.0/src/jazzoo/modules/rules/parse_source.py +154 -0
  154. jazzoo-0.1.0/src/jazzoo/modules/rules/validate_module.py +489 -0
  155. jazzoo-0.1.0/src/jazzoo/runtime/__init__.py +0 -0
  156. jazzoo-0.1.0/src/jazzoo/runtime/entrypoints/__init__.py +0 -0
  157. jazzoo-0.1.0/src/jazzoo/runtime/entrypoints/jazzoo.py +214 -0
  158. jazzoo-0.1.0/src/jazzoo/runtime/entrypoints/zoo.py +150 -0
  159. jazzoo-0.1.0/src/jazzoo/runtime/utils/__init__.py +0 -0
  160. jazzoo-0.1.0/src/jazzoo/runtime/utils/format_error.py +13 -0
  161. jazzoo-0.1.0/src/jazzoo/runtime/utils/test_utils.py +103 -0
  162. jazzoo-0.1.0/src/jazzoo/settings.py +40 -0
  163. jazzoo-0.1.0/src/jazzoo/utils/__init__.py +0 -0
  164. jazzoo-0.1.0/src/jazzoo/utils/dataclass.py +34 -0
  165. jazzoo-0.1.0/src/jazzoo/utils/indent_of.py +2 -0
  166. jazzoo-0.1.0/src/jazzoo/utils/join_continuations.py +25 -0
  167. jazzoo-0.1.0/src/jazzoo/utils/split_top_level.py +31 -0
  168. jazzoo-0.1.0/src/jazzoo/zoo/__init__.py +0 -0
  169. jazzoo-0.1.0/src/jazzoo/zoo/actions/__init__.py +0 -0
  170. jazzoo-0.1.0/src/jazzoo/zoo/actions/activate_zoo_env.py +16 -0
  171. jazzoo-0.1.0/src/jazzoo/zoo/actions/create_venv.py +148 -0
  172. jazzoo-0.1.0/src/jazzoo/zoo/actions/forget_zoo_env.py +31 -0
  173. jazzoo-0.1.0/src/jazzoo/zoo/actions/init_zoo_env.py +129 -0
  174. jazzoo-0.1.0/src/jazzoo/zoo/actions/install_fish_files.py +84 -0
  175. jazzoo-0.1.0/src/jazzoo/zoo/actions/run_in_zoo_env.py +29 -0
  176. jazzoo-0.1.0/src/jazzoo/zoo/actions/write_latest_zoo_env_scripts.py +21 -0
  177. jazzoo-0.1.0/src/jazzoo/zoo/actions/write_recent_zoo_envs.py +19 -0
  178. jazzoo-0.1.0/src/jazzoo/zoo/errors.py +61 -0
  179. jazzoo-0.1.0/src/jazzoo/zoo/models/__init__.py +0 -0
  180. jazzoo-0.1.0/src/jazzoo/zoo/models/zoo_env.py +9 -0
  181. jazzoo-0.1.0/src/jazzoo/zoo/rules/__init__.py +0 -0
  182. jazzoo-0.1.0/src/jazzoo/zoo/rules/find_zoo_env_of_venv.py +14 -0
  183. jazzoo-0.1.0/src/jazzoo/zoo/rules/format_zoo_env_list.py +18 -0
  184. jazzoo-0.1.0/src/jazzoo/zoo/rules/get_activate_filename.py +8 -0
  185. jazzoo-0.1.0/src/jazzoo/zoo/rules/get_fish_config_dir.py +8 -0
  186. jazzoo-0.1.0/src/jazzoo/zoo/rules/get_jazzoo_version.py +30 -0
  187. jazzoo-0.1.0/src/jazzoo/zoo/rules/get_recent_zoo_env.py +10 -0
  188. jazzoo-0.1.0/src/jazzoo/zoo/rules/get_shell_name.py +8 -0
  189. jazzoo-0.1.0/src/jazzoo/zoo/rules/get_zoo_env.py +17 -0
  190. jazzoo-0.1.0/src/jazzoo/zoo/rules/get_zoo_env_dir.py +7 -0
  191. jazzoo-0.1.0/src/jazzoo/zoo/rules/get_zoo_link.py +7 -0
  192. jazzoo-0.1.0/src/jazzoo/zoo/rules/get_zoo_venv_dir.py +6 -0
  193. jazzoo-0.1.0/src/jazzoo/zoo/rules/list_zoo_envs.py +17 -0
  194. jazzoo-0.1.0/src/jazzoo/zoo/rules/read_recent_zoo_envs.py +17 -0
  195. jazzoo-0.1.0/src/jazzoo/zoo/rules/validate_zoo_env_name.py +13 -0
  196. jazzoo-0.1.0/src/jazzoo.egg-info/PKG-INFO +18 -0
  197. jazzoo-0.1.0/src/jazzoo.egg-info/SOURCES.txt +221 -0
  198. jazzoo-0.1.0/src/jazzoo.egg-info/dependency_links.txt +1 -0
  199. jazzoo-0.1.0/src/jazzoo.egg-info/entry_points.txt +5 -0
  200. jazzoo-0.1.0/src/jazzoo.egg-info/requires.txt +3 -0
  201. jazzoo-0.1.0/src/jazzoo.egg-info/top_level.txt +1 -0
  202. jazzoo-0.1.0/tests/test_boolean_operators.py +614 -0
  203. jazzoo-0.1.0/tests/test_cli.py +404 -0
  204. jazzoo-0.1.0/tests/test_comments.py +224 -0
  205. jazzoo-0.1.0/tests/test_console_output.py +265 -0
  206. jazzoo-0.1.0/tests/test_dataclass.py +165 -0
  207. jazzoo-0.1.0/tests/test_errors.py +302 -0
  208. jazzoo-0.1.0/tests/test_export_layers.py +523 -0
  209. jazzoo-0.1.0/tests/test_exports.py +264 -0
  210. jazzoo-0.1.0/tests/test_expressions.py +371 -0
  211. jazzoo-0.1.0/tests/test_functions.py +810 -0
  212. jazzoo-0.1.0/tests/test_imports.py +363 -0
  213. jazzoo-0.1.0/tests/test_inline_calls.py +145 -0
  214. jazzoo-0.1.0/tests/test_load_env.py +124 -0
  215. jazzoo-0.1.0/tests/test_local_functions.py +411 -0
  216. jazzoo-0.1.0/tests/test_module_state_across_imports.py +199 -0
  217. jazzoo-0.1.0/tests/test_package_structure.py +70 -0
  218. jazzoo-0.1.0/tests/test_pipes_and_currying.py +521 -0
  219. jazzoo-0.1.0/tests/test_shebang_blocks.py +345 -0
  220. jazzoo-0.1.0/tests/test_structured_values.py +1025 -0
  221. jazzoo-0.1.0/tests/test_substitutions.py +739 -0
  222. jazzoo-0.1.0/tests/test_system_variables.py +338 -0
jazzoo-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Maarten Nieber
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,2 @@
1
+ # Keep the full README out of the sdist until the launch (see readme in pyproject.toml)
2
+ exclude README.md
jazzoo-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,18 @@
1
+ Metadata-Version: 2.4
2
+ Name: jazzoo
3
+ Version: 0.1.0
4
+ Summary: A beast of a task-runner
5
+ Author: Maarten Nieber
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Provides-Extra: dev
11
+ Requires-Dist: pytest; extra == "dev"
12
+ Dynamic: license-file
13
+
14
+ # jazzoo
15
+
16
+ A beast of a task-runner.
17
+
18
+ Docs coming soon.
@@ -0,0 +1,5 @@
1
+ # jazzoo
2
+
3
+ A beast of a task-runner.
4
+
5
+ Docs coming soon.
@@ -0,0 +1,42 @@
1
+ [project]
2
+ name = "jazzoo"
3
+ version = "0.1.0"
4
+ description = "A beast of a task-runner"
5
+ readme = "README.short.md"
6
+ authors = [{ name = "Maarten Nieber" }]
7
+ license = "MIT"
8
+ license-files = ["LICENSE"]
9
+ requires-python = ">=3.10"
10
+ dependencies = []
11
+
12
+ # Uncomment at launch, when the GitHub repo is public
13
+ # [project.urls]
14
+ # Homepage = "https://github.com/mnieber/jazzoo"
15
+ # Issues = "https://github.com/mnieber/jazzoo/issues"
16
+
17
+ [project.optional-dependencies]
18
+ dev = ["pytest"]
19
+
20
+ [project.scripts]
21
+ jazzoo = "jazzoo.runtime.entrypoints.jazzoo:main"
22
+ jaz = "jazzoo.runtime.entrypoints.jazzoo:main"
23
+ jaz-run = "jazzoo.commands.entrypoints.jaz_run:main"
24
+ zoo = "jazzoo.runtime.entrypoints.zoo:main"
25
+
26
+ [tool.setuptools.package-dir]
27
+ "" = "src"
28
+
29
+ [tool.setuptools.packages.find]
30
+ where = ["src"]
31
+
32
+ [tool.setuptools.package-data]
33
+ "jazzoo.config._vendor" = ["vendor.txt"]
34
+ "jazzoo.config._vendor.yaml" = ["LICENSE"]
35
+
36
+ [tool.pytest.ini_options]
37
+ testpaths = ["tests"]
38
+
39
+ [build-system]
40
+ # setuptools 77 is the first that understands license = "MIT"
41
+ requires = ["setuptools>=77", "wheel"]
42
+ build-backend = "setuptools.build_meta"
jazzoo-0.1.0/setup.cfg ADDED
@@ -0,0 +1,11 @@
1
+ [isort]
2
+ multi_line_output = 3
3
+ include_trailing_comma = True
4
+ force_grid_wrap = 0
5
+ use_parentheses = True
6
+ line_length = 88
7
+
8
+ [egg_info]
9
+ tag_build =
10
+ tag_date = 0
11
+
jazzoo-0.1.0/setup.py ADDED
@@ -0,0 +1,18 @@
1
+ from pathlib import Path
2
+
3
+ from setuptools import setup
4
+
5
+
6
+ def create_placeholder():
7
+ this_directory = Path(__file__).parent
8
+ pkg_directory = this_directory / "src" / "jazzoo"
9
+
10
+ if not pkg_directory.exists():
11
+ pkg_directory.mkdir(parents=True)
12
+ with open(pkg_directory / "__init__.py", "w") as f:
13
+ f.write("# Placeholder for package")
14
+
15
+
16
+ if __name__ == "__main__":
17
+ create_placeholder()
18
+ setup()
@@ -0,0 +1,57 @@
1
+ from jazzoo.commands import (
2
+ CommandAbortedError,
3
+ CommandError,
4
+ CommandFailedError,
5
+ CommandNotFoundError,
6
+ CommandResult,
7
+ run,
8
+ run_docker,
9
+ )
10
+ from jazzoo.config import (
11
+ ConfigError,
12
+ ConfigExpansionError,
13
+ ConfigFileError,
14
+ ConfigKeyError,
15
+ get_config,
16
+ prepare_config,
17
+ )
18
+ from jazzoo.errors import (
19
+ ArgumentError,
20
+ ExecutionError,
21
+ JazzooError,
22
+ ModuleImportError,
23
+ ParseError,
24
+ ResolutionError,
25
+ )
26
+ from jazzoo.expressions.actions.evaluate import evaluate
27
+ from jazzoo.functions.rules.get_function_by_path import get_function_by_path
28
+ from jazzoo.functions.rules.get_targets import get_targets
29
+ from jazzoo.modules.actions.parse_module import parse_module
30
+ from jazzoo.modules.rules.get_module_by_path import get_module_by_path
31
+
32
+ __all__ = [
33
+ "ArgumentError",
34
+ "CommandAbortedError",
35
+ "CommandError",
36
+ "CommandFailedError",
37
+ "CommandNotFoundError",
38
+ "CommandResult",
39
+ "ConfigError",
40
+ "ConfigExpansionError",
41
+ "ConfigFileError",
42
+ "ConfigKeyError",
43
+ "ExecutionError",
44
+ "JazzooError",
45
+ "ModuleImportError",
46
+ "ParseError",
47
+ "ResolutionError",
48
+ "evaluate",
49
+ "get_config",
50
+ "get_function_by_path",
51
+ "get_module_by_path",
52
+ "get_targets",
53
+ "parse_module",
54
+ "prepare_config",
55
+ "run",
56
+ "run_docker",
57
+ ]
File without changes
@@ -0,0 +1,5 @@
1
+ from jazzoo.errors import JazzooError
2
+
3
+
4
+ class AliasError(JazzooError):
5
+ pass
File without changes
@@ -0,0 +1,38 @@
1
+ import shlex
2
+ import typing as T
3
+
4
+ from jazzoo.aliases.errors import AliasError
5
+ from jazzoo.aliases.rules.get_alias_config_file import get_alias_config_file
6
+ from jazzoo.aliases.rules.read_aliases import read_aliases
7
+
8
+ # The options of jaz that an expansion may contain
9
+ _ALLOWED_OPTIONS = ("--confirm", "--trace")
10
+
11
+
12
+ def expand_alias(name: str) -> T.Optional[T.List[str]]:
13
+ config_file = get_alias_config_file()
14
+ expansion = read_aliases(config_file).get(name)
15
+ if expansion is None:
16
+ return None
17
+
18
+ try:
19
+ tokens = shlex.split(expansion)
20
+ except ValueError as error:
21
+ raise AliasError(
22
+ f'alias "{name}" has an invalid expansion: {error}', filename=config_file
23
+ )
24
+ if not tokens:
25
+ raise AliasError(f'alias "{name}" has an empty expansion', filename=config_file)
26
+
27
+ # Only the options that change how the target runs are allowed
28
+ for token in tokens:
29
+ option = token.partition("=")[0]
30
+ if option.startswith("-") and option not in _ALLOWED_OPTIONS:
31
+ raise AliasError(
32
+ f'alias "{name}" may not use the option {option}',
33
+ filename=config_file,
34
+ )
35
+ if all(token in _ALLOWED_OPTIONS for token in tokens):
36
+ raise AliasError(f'alias "{name}" names no target', filename=config_file)
37
+
38
+ return tokens
@@ -0,0 +1,7 @@
1
+ import os
2
+
3
+ from jazzoo.settings import get_zoo_config_dir
4
+
5
+
6
+ def get_alias_config_file() -> str:
7
+ return os.path.join(get_zoo_config_dir(), "config")
@@ -0,0 +1,36 @@
1
+ import configparser
2
+ import os
3
+ import re
4
+ import typing as T
5
+
6
+ from jazzoo.aliases.errors import AliasError
7
+
8
+ # A target path: names separated by dots
9
+ _ALIAS_NAME_RE = re.compile(r"^[A-Za-z_][A-Za-z0-9_-]*(\.[A-Za-z_][A-Za-z0-9_-]*)*$")
10
+
11
+
12
+ def read_aliases(config_file: str) -> T.Dict[str, str]:
13
+ if not os.path.exists(config_file):
14
+ return {}
15
+
16
+ # No section is special: a section header cannot contain a newline, so the
17
+ # default section of configparser never occurs
18
+ parser = configparser.ConfigParser(
19
+ interpolation=None, strict=True, default_section="\n"
20
+ )
21
+ # Alias names are case-sensitive
22
+ parser.optionxform = str # type: ignore[assignment]
23
+ try:
24
+ with open(config_file, encoding="utf-8") as f:
25
+ parser.read_file(f, source=config_file)
26
+ except (OSError, UnicodeDecodeError, configparser.Error) as error:
27
+ raise AliasError(f"invalid config file: {error}", filename=config_file)
28
+
29
+ if not parser.has_section("alias"):
30
+ return {}
31
+
32
+ aliases = dict(parser.items("alias"))
33
+ for name in aliases:
34
+ if not _ALIAS_NAME_RE.match(name):
35
+ raise AliasError(f'invalid alias name "{name}"', filename=config_file)
36
+ return aliases
File without changes
File without changes
@@ -0,0 +1,80 @@
1
+ import os
2
+ import stat
3
+ import subprocess
4
+ import sys
5
+ import tempfile
6
+ import typing as T
7
+
8
+ from jazzoo.errors import ExecutionError
9
+ from jazzoo.settings import DEFAULT_SHEBANG
10
+
11
+
12
+ def run_block(
13
+ shebang: T.Optional[str],
14
+ body: str,
15
+ filename: T.Optional[str] = None,
16
+ line: T.Optional[int] = None,
17
+ is_quiet: bool = False,
18
+ is_interactive: bool = False,
19
+ ) -> str:
20
+ """Run one block as a single subprocess and return its raw stdout.
21
+
22
+ The block is written to a temporary executable file so the shebang selects the
23
+ interpreter, exactly as it would for a script on disk.
24
+ """
25
+ shebang = shebang or DEFAULT_SHEBANG
26
+ script = shebang + "\n" + body
27
+ if not script.endswith("\n"):
28
+ script += "\n"
29
+
30
+ handle = tempfile.NamedTemporaryFile(
31
+ mode="w", suffix=".jaz-block", delete=False, encoding="utf-8"
32
+ )
33
+ try:
34
+ handle.write(script)
35
+ handle.close()
36
+ os.chmod(handle.name, os.stat(handle.name).st_mode | stat.S_IEXEC)
37
+
38
+ if is_interactive:
39
+ # Whatever was echoed must reach the console before the block's output
40
+ sys.stdout.flush()
41
+ sys.stderr.flush()
42
+ completed = subprocess.run([handle.name])
43
+ else:
44
+ completed = subprocess.run(
45
+ [handle.name],
46
+ capture_output=True,
47
+ text=True,
48
+ )
49
+ finally:
50
+ os.unlink(handle.name)
51
+
52
+ # An interactive block writes to the console itself, and Jazzoo never sees its
53
+ # output, not even in a quiet call.
54
+ if is_interactive:
55
+ if completed.returncode != 0:
56
+ raise ExecutionError(
57
+ f"recipe failed with exit code {completed.returncode}: "
58
+ f"command failed: {body.strip()}",
59
+ filename=filename,
60
+ line=line,
61
+ )
62
+ return ""
63
+
64
+ # The block's own output goes to the console as well as being captured for
65
+ # ⚙️.stdout, so a target behaves like the commands it runs. A quiet block keeps
66
+ # its stdout for the caller, but its stderr is always shown.
67
+ if completed.stdout and not is_quiet:
68
+ print(completed.stdout, end="")
69
+ if completed.stderr:
70
+ print(completed.stderr, end="", file=sys.stderr)
71
+
72
+ if completed.returncode != 0:
73
+ message = completed.stderr.strip() or f"command failed: {body.strip()}"
74
+ raise ExecutionError(
75
+ f"recipe failed with exit code {completed.returncode}: {message}",
76
+ filename=filename,
77
+ line=line,
78
+ )
79
+
80
+ return completed.stdout
File without changes
@@ -0,0 +1,21 @@
1
+ import typing as T
2
+
3
+ from jazzoo.enums import BlockMode
4
+ from jazzoo.utils.dataclass import dataclass
5
+
6
+
7
+ @dataclass
8
+ class BlockLine:
9
+ text: str
10
+ line: int
11
+ # Set by a leading `@`, which hides the echoed command but not its output.
12
+ is_quiet: bool = False
13
+
14
+
15
+ @dataclass
16
+ class Block:
17
+ mode: BlockMode
18
+ # The interpreter line, e.g. "#!/usr/bin/env python3". None in jazzoo mode.
19
+ shebang: T.Optional[str] = None
20
+ lines: T.List[BlockLine] = []
21
+ filename: T.Optional[str] = None
File without changes
@@ -0,0 +1,19 @@
1
+ from .actions.run import run
2
+ from .actions.run_docker import run_docker
3
+ from .errors import (
4
+ CommandAbortedError,
5
+ CommandError,
6
+ CommandFailedError,
7
+ CommandNotFoundError,
8
+ )
9
+ from .models.command_result import CommandResult
10
+
11
+ __all__ = [
12
+ "CommandAbortedError",
13
+ "CommandError",
14
+ "CommandFailedError",
15
+ "CommandNotFoundError",
16
+ "CommandResult",
17
+ "run",
18
+ "run_docker",
19
+ ]
@@ -0,0 +1,5 @@
1
+ import sys
2
+
3
+ from .entrypoints.jaz_run import main
4
+
5
+ sys.exit(main())
File without changes
@@ -0,0 +1,36 @@
1
+ import os
2
+ import typing as T
3
+
4
+ from ..errors import CommandAbortedError, CommandError
5
+ from ..settings import CONFIRM_PROMPT, TERMINAL
6
+ from ..utils.format_command import format_command
7
+
8
+
9
+ def confirm_command(
10
+ command: T.Union[str, T.List[str]], cwd: T.Optional[str] = None
11
+ ) -> bool:
12
+ try:
13
+ reader = open(TERMINAL, "r", encoding="utf-8")
14
+ writer = open(TERMINAL, "w", encoding="utf-8")
15
+ except OSError:
16
+ raise CommandError("--confirm needs a terminal")
17
+
18
+ with reader, writer:
19
+ # Asks again until the answer is y, n, q or Enter
20
+ while True:
21
+ writer.write(format_command(command, cwd or os.getcwd()) + "\n")
22
+ writer.write(CONFIRM_PROMPT)
23
+ writer.flush()
24
+
25
+ line = reader.readline()
26
+ # An empty line has a newline; no newline means the end of input
27
+ if not line:
28
+ raise CommandAbortedError("aborted by the user")
29
+
30
+ answer = line.strip().lower()
31
+ if answer in ("", "y"):
32
+ return True
33
+ if answer == "n":
34
+ return False
35
+ if answer == "q":
36
+ raise CommandAbortedError("aborted by the user")
@@ -0,0 +1,100 @@
1
+ import os
2
+ import shutil
3
+ import signal
4
+ import subprocess
5
+ import sys
6
+ import typing as T
7
+
8
+ from ..errors import CommandFailedError
9
+ from ..models.command_result import CommandResult
10
+ from ..rules.find_executable import find_executable
11
+ from ..rules.is_confirm_on import is_confirm_on
12
+ from ..utils.format_command import format_command
13
+ from ..utils.ignoring_sigint import ignoring_sigint
14
+ from .confirm_command import confirm_command
15
+
16
+
17
+ def run(
18
+ command: T.Union[str, T.List[str]],
19
+ cwd: T.Optional[str] = None,
20
+ env: T.Optional[T.Dict[str, str]] = None,
21
+ capture: bool = False,
22
+ check: bool = True,
23
+ echo: bool = False,
24
+ ) -> CommandResult:
25
+ # Check the arguments before anything runs
26
+ if isinstance(command, str):
27
+ if not command.strip():
28
+ raise ValueError("the command is empty")
29
+ elif not command:
30
+ raise ValueError("the command is empty")
31
+ if cwd is not None and not os.path.isdir(cwd):
32
+ raise ValueError(f"directory not found: {cwd}")
33
+
34
+ environ = {**os.environ, **(env or {})}
35
+
36
+ # A string runs in bash; a list runs directly
37
+ if isinstance(command, str):
38
+ args = ["bash", "-c", command]
39
+ executable = shutil.which("bash") or "/bin/bash"
40
+ else:
41
+ args = list(command)
42
+ executable = find_executable(args[0], environ)
43
+
44
+ # The prompt shows the command, so it replaces the echo
45
+ if is_confirm_on():
46
+ if not confirm_command(command, cwd):
47
+ skipped_output = "" if capture else None
48
+ return CommandResult(
49
+ command=command,
50
+ returncode=0,
51
+ stdout=skipped_output,
52
+ stderr=skipped_output,
53
+ skipped=True,
54
+ )
55
+ elif echo:
56
+ print(format_command(command, cwd))
57
+
58
+ # The command writes to the same file descriptors as the script, so what the
59
+ # script printed before must come first
60
+ sys.stdout.flush()
61
+ sys.stderr.flush()
62
+
63
+ output = subprocess.PIPE if capture else None
64
+ process = subprocess.Popen(
65
+ args,
66
+ executable=executable,
67
+ cwd=cwd,
68
+ env=environ,
69
+ stdout=output,
70
+ stderr=output,
71
+ text=True,
72
+ )
73
+
74
+ # SIGINT is ignored only after the command has started, because an ignored
75
+ # signal would be inherited by the command. A ctrl-c then reaches the command
76
+ # only.
77
+ with ignoring_sigint():
78
+ stdout, stderr = process.communicate()
79
+
80
+ if process.returncode == -signal.SIGINT:
81
+ raise KeyboardInterrupt
82
+
83
+ result = CommandResult(
84
+ command=command,
85
+ returncode=process.returncode,
86
+ stdout=stdout,
87
+ stderr=stderr,
88
+ )
89
+ if check and result.returncode != 0:
90
+ raise CommandFailedError(_failure_message(result, cwd), result)
91
+ return result
92
+
93
+
94
+ def _failure_message(result: CommandResult, cwd: T.Optional[str]) -> str:
95
+ message = f"command failed with exit code {result.returncode}: " + format_command(
96
+ result.command, cwd
97
+ )
98
+ if result.stderr and result.stderr.strip():
99
+ message += "\n" + result.stderr.strip()
100
+ return message
@@ -0,0 +1,67 @@
1
+ import typing as T
2
+
3
+ from ..models.command_result import CommandResult
4
+ from ..rules.needs_tty import needs_tty
5
+
6
+ Command = T.Union[str, T.List[str]]
7
+ RunFunction = T.Callable[..., CommandResult]
8
+
9
+
10
+ def run_docker(
11
+ container: str,
12
+ user: T.Optional[str] = None,
13
+ workdir: T.Optional[str] = None,
14
+ env: T.Optional[T.Dict[str, str]] = None,
15
+ shell: str = "bash",
16
+ ) -> T.Callable[[RunFunction], RunFunction]:
17
+ if not container or not container.strip():
18
+ raise ValueError("the container is empty")
19
+
20
+ container_env = dict(env or {})
21
+
22
+ def decorator(run: RunFunction) -> RunFunction:
23
+ def run_in_container(
24
+ command: Command,
25
+ cwd: T.Optional[str] = None,
26
+ env: T.Optional[T.Dict[str, str]] = None,
27
+ capture: bool = False,
28
+ check: bool = True,
29
+ echo: bool = False,
30
+ ) -> CommandResult:
31
+ # Check the command before the docker command hides it
32
+ if isinstance(command, str):
33
+ if not command.strip():
34
+ raise ValueError("the command is empty")
35
+ command_args = [shell, "-c", command]
36
+ elif not command:
37
+ raise ValueError("the command is empty")
38
+ else:
39
+ command_args = list(command)
40
+
41
+ # The options come in a fixed order
42
+ docker_command = ["docker", "exec", "--interactive"]
43
+ if needs_tty(capture):
44
+ docker_command.append("--tty")
45
+ if user:
46
+ docker_command += ["--user", user]
47
+ # A cwd only replaces the workdir for this call
48
+ call_workdir = cwd or workdir
49
+ if call_workdir:
50
+ docker_command += ["--workdir", call_workdir]
51
+ for name, value in {**container_env, **(env or {})}.items():
52
+ docker_command += ["--env", f"{name}={value}"]
53
+ docker_command += [container, *command_args]
54
+
55
+ # The cwd and env belong to the container, not to the docker client
56
+ return run(
57
+ docker_command,
58
+ cwd=None,
59
+ env=None,
60
+ capture=capture,
61
+ check=check,
62
+ echo=echo,
63
+ )
64
+
65
+ return run_in_container
66
+
67
+ return decorator