bakefile 0.0.3__py3-none-any.whl → 0.0.5__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.
Files changed (67) hide show
  1. bake/__init__.py +9 -0
  2. bake/bakebook/bakebook.py +85 -0
  3. bake/bakebook/decorator.py +50 -0
  4. bake/bakebook/get.py +175 -0
  5. bake/cli/bake/__init__.py +3 -0
  6. bake/cli/bake/__main__.py +5 -0
  7. bake/cli/bake/main.py +74 -0
  8. bake/cli/bake/reinvocation.py +63 -0
  9. bake/cli/bakefile/__init__.py +3 -0
  10. bake/cli/bakefile/__main__.py +5 -0
  11. bake/cli/bakefile/add_inline.py +29 -0
  12. bake/cli/bakefile/find_python.py +18 -0
  13. bake/cli/bakefile/init.py +56 -0
  14. bake/cli/bakefile/lint.py +77 -0
  15. bake/cli/bakefile/main.py +41 -0
  16. bake/cli/bakefile/uv.py +146 -0
  17. bake/cli/common/app.py +54 -0
  18. bake/cli/common/callback.py +13 -0
  19. bake/cli/common/context.py +145 -0
  20. bake/cli/common/exception_handler.py +57 -0
  21. bake/cli/common/obj.py +214 -0
  22. bake/cli/common/params.py +72 -0
  23. bake/cli/utils/__init__.py +0 -0
  24. bake/cli/utils/version.py +18 -0
  25. bake/manage/__init__.py +0 -0
  26. bake/manage/add_inline.py +71 -0
  27. bake/manage/find_python.py +210 -0
  28. bake/manage/lint.py +101 -0
  29. bake/manage/run_uv.py +88 -0
  30. bake/manage/write_bakefile.py +20 -0
  31. bake/py.typed +0 -0
  32. bake/samples/__init__.py +0 -0
  33. bake/samples/simple.py +9 -0
  34. bake/ui/__init__.py +10 -0
  35. bake/ui/console.py +58 -0
  36. bake/ui/logger/__init__.py +33 -0
  37. bake/ui/logger/capsys.py +158 -0
  38. bake/ui/logger/setup.py +53 -0
  39. bake/ui/logger/utils.py +215 -0
  40. bake/ui/run/__init__.py +11 -0
  41. bake/ui/run/run.py +541 -0
  42. bake/ui/run/script.py +74 -0
  43. bake/ui/run/splitter.py +237 -0
  44. bake/ui/run/uv.py +83 -0
  45. bake/ui/style.py +2 -0
  46. bake/utils/__init__.py +11 -0
  47. bake/utils/constants.py +21 -0
  48. bake/utils/env.py +10 -0
  49. bake/utils/exceptions.py +17 -0
  50. {bakefile-0.0.3.dist-info → bakefile-0.0.5.dist-info}/METADATA +14 -2
  51. bakefile-0.0.5.dist-info/RECORD +61 -0
  52. {bakefile-0.0.3.dist-info → bakefile-0.0.5.dist-info}/WHEEL +1 -1
  53. bakefile-0.0.5.dist-info/entry_points.txt +5 -0
  54. bakelib/__init__.py +4 -0
  55. bakelib/space/__init__.py +0 -0
  56. bakelib/space/base.py +73 -0
  57. bakelib/space/python.py +42 -0
  58. bakelib/space/utils.py +55 -0
  59. bakefile/cli/bake/__init__.py +0 -3
  60. bakefile/cli/bake/main.py +0 -17
  61. bakefile/cli/bake/resolve_bakebook.py +0 -75
  62. bakefile/cli/bakefile.py +0 -8
  63. bakefile-0.0.3.dist-info/RECORD +0 -11
  64. bakefile-0.0.3.dist-info/entry_points.txt +0 -4
  65. {bakefile → bake/bakebook}/__init__.py +0 -0
  66. {bakefile → bake}/cli/__init__.py +0 -0
  67. /bakefile/py.typed → /bake/cli/common/__init__.py +0 -0
@@ -0,0 +1,41 @@
1
+ from bake.cli.common.app import (
2
+ BakefileApp,
3
+ add_completion,
4
+ bake_app_callback_with_obj,
5
+ rich_markup_mode,
6
+ )
7
+ from bake.cli.common.obj import get_bakefile_object
8
+
9
+ from . import uv
10
+ from .add_inline import add_inline
11
+ from .find_python import find_python
12
+ from .init import init
13
+ from .lint import lint
14
+
15
+
16
+ def main():
17
+ bakefile_obj = get_bakefile_object(rich_markup_mode=rich_markup_mode)
18
+ bakefile_obj.setup_logging()
19
+ bakefile_obj.resolve_bakefile_path()
20
+
21
+ bakefile_app = BakefileApp(
22
+ add_completion=add_completion,
23
+ rich_markup_mode=rich_markup_mode,
24
+ )
25
+
26
+ uv_commands_context_settings = {
27
+ "allow_extra_args": True,
28
+ "ignore_unknown_options": True,
29
+ }
30
+
31
+ bakefile_app.callback(invoke_without_command=True)(bake_app_callback_with_obj(obj=bakefile_obj))
32
+ bakefile_app.command()(init)
33
+ bakefile_app.command()(add_inline)
34
+ bakefile_app.command()(find_python)
35
+ bakefile_app.command()(lint)
36
+ bakefile_app.command(context_settings=uv_commands_context_settings)(uv.sync)
37
+ bakefile_app.command(context_settings=uv_commands_context_settings)(uv.lock)
38
+ bakefile_app.command(context_settings=uv_commands_context_settings)(uv.add)
39
+ bakefile_app.command(context_settings=uv_commands_context_settings)(uv.pip)
40
+ bakefile_app.bakefile_object = bakefile_obj
41
+ bakefile_app()
@@ -0,0 +1,146 @@
1
+ from typing import Annotated, Literal
2
+
3
+ import typer
4
+
5
+ from bake.cli.common.context import Context
6
+ from bake.manage.run_uv import run_uv_add, run_uv_lock, run_uv_pip, run_uv_sync
7
+ from bake.ui import console
8
+ from bake.utils.exceptions import BakebookError, PythonNotFoundError
9
+
10
+ PipCommand = Literal[
11
+ "compile",
12
+ "sync",
13
+ "install",
14
+ "uninstall",
15
+ "freeze",
16
+ "list",
17
+ "show",
18
+ "tree",
19
+ "check",
20
+ ]
21
+
22
+
23
+ def pip(
24
+ ctx: Context,
25
+ command: Annotated[
26
+ PipCommand,
27
+ typer.Argument(help="UV pip subcommand"),
28
+ ],
29
+ ) -> None:
30
+ """
31
+ This runs `[bold cyan]uv pip <command> <args> --python <bakefile-python-path>[/bold cyan]`
32
+
33
+ For complete docs: `[cyan]uv pip --help[/cyan]`
34
+ """
35
+ bakefile_path = ctx.obj.bakefile_path
36
+ try:
37
+ cmd = [command, *ctx.args]
38
+ result = run_uv_pip(bakefile_path=bakefile_path, cmd=cmd, dry_run=ctx.obj.dry_run)
39
+ raise typer.Exit(result.returncode)
40
+ except (PythonNotFoundError, BakebookError) as e:
41
+ console.error(str(e))
42
+ raise typer.Exit(code=1) from None
43
+
44
+
45
+ def add(ctx: Context) -> None:
46
+ """
47
+ This runs `[bold cyan]uv add --script bakefile.py <args>[/bold cyan]`
48
+
49
+ Requires PEP 723 inline metadata.
50
+
51
+ To add metadata: `[cyan]bakefile add-inline[/cyan]`
52
+ For project-level deps: `[cyan]uv add[/cyan]`
53
+ For complete docs: `[cyan]uv add --help[/cyan]`
54
+
55
+ Examples:
56
+ bakefile add requests typer
57
+ bakefile add "requests>=2.32.0" --dev
58
+ """
59
+ bakefile_path = ctx.obj.bakefile_path
60
+ args = ctx.args
61
+
62
+ try:
63
+ result = run_uv_add(bakefile_path=bakefile_path, cmd=args, dry_run=ctx.obj.dry_run)
64
+ raise typer.Exit(result.returncode)
65
+ except (PythonNotFoundError, BakebookError) as e:
66
+ console.error(str(e))
67
+ raise typer.Exit(code=1) from None
68
+
69
+
70
+ def lock(
71
+ ctx: Context,
72
+ upgrade: Annotated[
73
+ bool,
74
+ typer.Option("--upgrade", "-U", help="Upgrade package dependencies"),
75
+ ] = False,
76
+ ) -> None:
77
+ """
78
+ This runs `[bold cyan]uv lock --script bakefile.py <args>[/bold cyan]`
79
+
80
+ Requires PEP 723 inline metadata.
81
+
82
+ To add metadata: `[cyan]bakefile add-inline[/cyan]`
83
+ For project-level deps: `[cyan]uv lock[/cyan]`
84
+ For complete docs: `[cyan]uv lock --help[/cyan]`
85
+
86
+ Examples:
87
+ bakefile lock
88
+ bakefile lock --upgrade
89
+ bakefile lock --no-build
90
+ """
91
+ bakefile_path = ctx.obj.bakefile_path
92
+ args = list(ctx.args)
93
+
94
+ if upgrade:
95
+ args.append("--upgrade")
96
+
97
+ try:
98
+ result = run_uv_lock(bakefile_path=bakefile_path, cmd=args, dry_run=ctx.obj.dry_run)
99
+ raise typer.Exit(result.returncode)
100
+ except (PythonNotFoundError, BakebookError) as e:
101
+ console.error(str(e))
102
+ raise typer.Exit(code=1) from None
103
+
104
+
105
+ def sync(
106
+ ctx: Context,
107
+ upgrade: Annotated[
108
+ bool,
109
+ typer.Option("--upgrade", "-U", help="Upgrade package dependencies"),
110
+ ] = False,
111
+ reinstall: Annotated[
112
+ bool,
113
+ typer.Option("--reinstall", help="Reinstall all packages"),
114
+ ] = False,
115
+ ) -> None:
116
+ """
117
+ This runs `[bold cyan]uv sync --script bakefile.py <args>[/bold cyan]`
118
+
119
+ Requires PEP 723 inline metadata.
120
+
121
+ To add metadata: `[cyan]bakefile add-inline[/cyan]`
122
+ For project-level deps: `[cyan]uv sync[/cyan]`
123
+ For complete docs: `[cyan]uv sync --help[/cyan]`
124
+
125
+ Examples:
126
+ bakefile sync
127
+ bakefile sync --upgrade
128
+ bakefile sync --reinstall
129
+ bakefile sync --frozen
130
+ bakefile sync --no-dev
131
+ bakefile sync --no-build
132
+ """
133
+ bakefile_path = ctx.obj.bakefile_path
134
+ args = list(ctx.args)
135
+
136
+ if upgrade:
137
+ args.append("--upgrade")
138
+ if reinstall:
139
+ args.append("--reinstall")
140
+
141
+ try:
142
+ result = run_uv_sync(bakefile_path=bakefile_path, cmd=args, dry_run=ctx.obj.dry_run)
143
+ raise typer.Exit(result.returncode)
144
+ except (PythonNotFoundError, BakebookError) as e:
145
+ console.error(str(e))
146
+ raise typer.Exit(code=1) from None
bake/cli/common/app.py ADDED
@@ -0,0 +1,54 @@
1
+ from collections.abc import Callable
2
+
3
+ import typer
4
+ from typer.core import MarkupMode
5
+
6
+ from bake.cli.common.context import Context
7
+ from bake.cli.common.params import (
8
+ bakebook_name_option,
9
+ chdir_option,
10
+ dry_run_option,
11
+ file_name_option,
12
+ is_chain_commands_option,
13
+ verbosity_option,
14
+ version_option,
15
+ )
16
+ from bake.ui import console
17
+ from bake.utils.constants import (
18
+ DEFAULT_BAKEBOOK_NAME,
19
+ DEFAULT_CHDIR,
20
+ DEFAULT_FILE_NAME,
21
+ DEFAULT_IS_CHAIN_COMMAND,
22
+ )
23
+
24
+ from .obj import BakefileObject
25
+
26
+ rich_markup_mode: MarkupMode = "rich" if not console.out.no_color else None
27
+ add_completion = False
28
+
29
+
30
+ class BakefileApp(typer.Typer):
31
+ bakefile_object: BakefileObject
32
+
33
+
34
+ def show_help_if_no_command(ctx: Context) -> None:
35
+ if ctx.invoked_subcommand is None:
36
+ console.echo(ctx.get_help())
37
+ raise typer.Exit(1)
38
+
39
+
40
+ def bake_app_callback_with_obj(obj: BakefileObject) -> Callable:
41
+ def bake_app_callback(
42
+ ctx: Context,
43
+ _chdir: chdir_option = DEFAULT_CHDIR,
44
+ _file_name: file_name_option = DEFAULT_FILE_NAME,
45
+ _bakebook_name: bakebook_name_option = DEFAULT_BAKEBOOK_NAME,
46
+ _version: version_option = False,
47
+ _is_chain_commands: is_chain_commands_option = DEFAULT_IS_CHAIN_COMMAND,
48
+ _verbosity: verbosity_option = 0,
49
+ _dry_run: dry_run_option = False,
50
+ ):
51
+ ctx.obj = obj
52
+ show_help_if_no_command(ctx)
53
+
54
+ return bake_app_callback
@@ -0,0 +1,13 @@
1
+ import typer
2
+
3
+
4
+ def validate_file_name(file_name: str) -> str:
5
+ if "/" in file_name or "\\" in file_name:
6
+ raise typer.BadParameter(f"File name must not contain path separators: {file_name}")
7
+ if not file_name.endswith(".py"):
8
+ raise typer.BadParameter(f"File name must end with .py: {file_name}")
9
+ return file_name
10
+
11
+
12
+ def validate_file_name_callback(value: str) -> str:
13
+ return validate_file_name(file_name=value)
@@ -0,0 +1,145 @@
1
+ import subprocess
2
+ from pathlib import Path
3
+ from typing import TYPE_CHECKING, Literal, overload
4
+
5
+ import click
6
+ import typer
7
+ from typer.core import TyperCommand
8
+
9
+ from bake.ui.run import run as _run
10
+ from bake.ui.run.script import run_script as _run_script
11
+
12
+ from .obj import BakefileObject
13
+
14
+ if TYPE_CHECKING:
15
+ from bake.bakebook.bakebook import Bakebook
16
+
17
+
18
+ class Context(typer.Context):
19
+ obj: BakefileObject
20
+
21
+ @property
22
+ def dry_run(self) -> bool:
23
+ return self.obj.dry_run
24
+
25
+ @property
26
+ def verbosity(self) -> int:
27
+ return self.obj.verbosity
28
+
29
+ @property
30
+ def bakebook(self) -> "Bakebook | None":
31
+ return self.obj.bakebook
32
+
33
+ @overload
34
+ def run(
35
+ self,
36
+ cmd: str,
37
+ *,
38
+ capture_output: Literal[True] = True,
39
+ check: bool = True,
40
+ cwd: Path | str | None = None,
41
+ stream: bool = True,
42
+ shell: bool | None = None,
43
+ echo: bool = True,
44
+ dry_run: bool | None = None,
45
+ **kwargs,
46
+ ) -> subprocess.CompletedProcess[str]: ...
47
+
48
+ @overload
49
+ def run(
50
+ self,
51
+ cmd: str,
52
+ *,
53
+ capture_output: Literal[False],
54
+ check: bool = True,
55
+ cwd: Path | str | None = None,
56
+ stream: bool = True,
57
+ shell: bool | None = None,
58
+ echo: bool = True,
59
+ dry_run: bool | None = None,
60
+ **kwargs,
61
+ ) -> subprocess.CompletedProcess[None]: ...
62
+
63
+ @overload
64
+ def run(
65
+ self,
66
+ cmd: list[str] | tuple[str, ...],
67
+ *,
68
+ capture_output: Literal[True] = True,
69
+ check: bool = True,
70
+ cwd: Path | str | None = None,
71
+ stream: bool = True,
72
+ shell: bool | None = None,
73
+ echo: bool = True,
74
+ dry_run: bool | None = None,
75
+ **kwargs,
76
+ ) -> subprocess.CompletedProcess[str]: ...
77
+
78
+ @overload
79
+ def run(
80
+ self,
81
+ cmd: list[str] | tuple[str, ...],
82
+ *,
83
+ capture_output: Literal[False],
84
+ check: bool = True,
85
+ cwd: Path | str | None = None,
86
+ stream: bool = True,
87
+ shell: bool | None = None,
88
+ echo: bool = True,
89
+ dry_run: bool | None = None,
90
+ **kwargs,
91
+ ) -> subprocess.CompletedProcess[None]: ...
92
+
93
+ def run(
94
+ self,
95
+ cmd: str | list[str] | tuple[str, ...],
96
+ *,
97
+ capture_output: bool = True,
98
+ check: bool = True,
99
+ cwd: Path | str | None = None,
100
+ stream: bool = True,
101
+ shell: bool | None = None,
102
+ echo: bool = True,
103
+ dry_run: bool | None = None,
104
+ **kwargs,
105
+ ) -> subprocess.CompletedProcess[str] | subprocess.CompletedProcess[None]:
106
+ return _run(
107
+ cmd,
108
+ capture_output=capture_output,
109
+ check=check,
110
+ cwd=cwd,
111
+ stream=stream,
112
+ shell=shell,
113
+ echo=echo,
114
+ dry_run=self.obj.dry_run if dry_run is None else dry_run,
115
+ **kwargs,
116
+ )
117
+
118
+ def run_script(
119
+ self,
120
+ title: str,
121
+ script: str,
122
+ *,
123
+ capture_output: bool = True,
124
+ check: bool = True,
125
+ cwd: Path | str | None = None,
126
+ stream: bool = True,
127
+ echo: bool = True,
128
+ dry_run: bool | None = None,
129
+ **kwargs,
130
+ ) -> subprocess.CompletedProcess[str] | subprocess.CompletedProcess[None]:
131
+ return _run_script(
132
+ title,
133
+ script,
134
+ capture_output=capture_output,
135
+ check=check,
136
+ cwd=cwd,
137
+ stream=stream,
138
+ echo=echo,
139
+ dry_run=self.obj.dry_run if dry_run is None else dry_run,
140
+ **kwargs,
141
+ )
142
+
143
+
144
+ class BakeCommand(TyperCommand):
145
+ context_class: type[click.Context] = Context
@@ -0,0 +1,57 @@
1
+ import errno
2
+ import sys
3
+ from contextlib import contextmanager
4
+ from gettext import gettext
5
+ from typing import TextIO, cast
6
+
7
+ import click
8
+ from typer.core import HAS_RICH, MarkupMode
9
+
10
+
11
+ @contextmanager
12
+ def typer_exception_handler(
13
+ *,
14
+ standalone_mode: bool,
15
+ rich_markup_mode: MarkupMode,
16
+ ):
17
+ # Reference code: https://github.com/fastapi/typer/blob/da9c4c67f3d8e4acd5f76e8909503bb999f1b751/typer/core.py#L186-L248
18
+ try:
19
+ try:
20
+ yield
21
+ except EOFError as e:
22
+ click.echo(file=sys.stderr)
23
+ raise click.Abort() from e
24
+ except KeyboardInterrupt as e:
25
+ raise click.exceptions.Exit(130) from e
26
+ except click.ClickException as e:
27
+ if not standalone_mode:
28
+ raise
29
+ if HAS_RICH and rich_markup_mode is not None:
30
+ from typer import rich_utils
31
+
32
+ rich_utils.rich_format_error(e)
33
+ else:
34
+ e.show()
35
+ sys.exit(e.exit_code)
36
+ except OSError as e:
37
+ if e.errno == errno.EPIPE:
38
+ sys.stdout = cast(TextIO, click.utils.PacifyFlushWrapper(sys.stdout))
39
+ sys.stderr = cast(TextIO, click.utils.PacifyFlushWrapper(sys.stderr))
40
+ sys.exit(1)
41
+ raise
42
+ except click.exceptions.Exit as e:
43
+ if standalone_mode:
44
+ sys.exit(e.exit_code)
45
+ else:
46
+ # return exit code to caller
47
+ raise
48
+ except click.Abort:
49
+ if not standalone_mode:
50
+ raise
51
+ if HAS_RICH and rich_markup_mode is not None:
52
+ from typer import rich_utils
53
+
54
+ rich_utils.rich_abort_error()
55
+ else:
56
+ click.echo(gettext("Aborted!"), file=sys.stderr)
57
+ sys.exit(1)
bake/cli/common/obj.py ADDED
@@ -0,0 +1,214 @@
1
+ import contextlib
2
+ import logging
3
+ import os
4
+ import sys
5
+ from dataclasses import dataclass
6
+ from pathlib import Path
7
+ from typing import TYPE_CHECKING
8
+
9
+ import click
10
+ import typer
11
+ from pydantic import ValidationError
12
+ from rich.traceback import Traceback
13
+ from typer.core import MarkupMode
14
+ from typer.main import get_command_from_info
15
+
16
+ from bake.bakebook.get import (
17
+ get_bakebook_from_target_dir_path,
18
+ resolve_bakefile_path,
19
+ )
20
+ from bake.ui import console, setup_logging
21
+ from bake.utils.constants import (
22
+ DEFAULT_BAKEBOOK_NAME,
23
+ DEFAULT_CHDIR,
24
+ DEFAULT_FILE_NAME,
25
+ DEFAULT_IS_CHAIN_COMMAND,
26
+ GET_BAKEFILE_OBJECT,
27
+ )
28
+ from bake.utils.exceptions import BakebookError, BakefileNotFoundError
29
+
30
+ from .callback import validate_file_name
31
+ from .exception_handler import typer_exception_handler
32
+ from .params import (
33
+ bakebook_name_option,
34
+ chdir_option,
35
+ dry_run_option,
36
+ file_name_option,
37
+ is_chain_commands_option,
38
+ remaining_args_argument,
39
+ verbosity_option,
40
+ )
41
+
42
+ if TYPE_CHECKING:
43
+ from bake.bakebook.bakebook import Bakebook
44
+
45
+ logger = logging.Logger(__name__)
46
+
47
+
48
+ @dataclass
49
+ class BakefileObject:
50
+ chdir: Path
51
+ file_name: str
52
+ bakebook_name: str
53
+ bakefile_path: Path | None = None
54
+ bakebook: "Bakebook | None" = None
55
+ verbosity: int = 0
56
+ dry_run: bool = False
57
+ remaining_args: list[str] | None = None
58
+ is_chain_commands: bool = False
59
+
60
+ def __post_init__(self):
61
+ validate_file_name(self.file_name)
62
+
63
+ def resolve_bakefile_path(self) -> Path | None:
64
+ if self.bakefile_path is not None:
65
+ return self.bakefile_path
66
+
67
+ with contextlib.suppress(BakefileNotFoundError):
68
+ self.bakefile_path = resolve_bakefile_path(chdir=self.chdir, file_name=self.file_name)
69
+
70
+ return self.bakefile_path
71
+
72
+ def get_bakebook(self, allow_missing: bool):
73
+ if self.bakebook is not None:
74
+ return
75
+
76
+ try:
77
+ if self.bakefile_path is None:
78
+ self.bakefile_path = resolve_bakefile_path(
79
+ chdir=self.chdir, file_name=self.file_name
80
+ )
81
+ self.bakebook = get_bakebook_from_target_dir_path(
82
+ target_dir_path=self.bakefile_path, bakebook_name=self.bakebook_name
83
+ )
84
+ except BakefileNotFoundError:
85
+ if allow_missing:
86
+ return
87
+ except BakebookError as e:
88
+ if allow_missing:
89
+ return
90
+ exc_to_show = e.__cause__ if e.__cause__ else e
91
+
92
+ if exc_to_show.__class__ in {ValidationError, BakebookError}:
93
+ console.err.print(
94
+ f"[bold red]{exc_to_show.__class__.__name__}:[/bold red]", end=" "
95
+ )
96
+ console.err.print(exc_to_show)
97
+ console.err.print(f"Searched in: {self.chdir.resolve()}\n")
98
+ else:
99
+ console.err.print(
100
+ Traceback.from_exception(
101
+ type(exc_to_show), exc_to_show, exc_to_show.__traceback__
102
+ )
103
+ )
104
+ raise SystemExit(1) from e
105
+
106
+ def warn_if_no_bakebook(self, color_echo: bool):
107
+ if self.bakebook is None:
108
+ _ = color_echo # Color handled by console module
109
+ console.warning(f"Bakebook `{self.bakebook_name}` not found in `{self.file_name}`")
110
+ console.echo(f"Searched in: {self.chdir.resolve()}\n")
111
+
112
+ def setup_logging(self):
113
+ level_map = {0: logging.WARNING, 1: logging.INFO, 2: logging.DEBUG}
114
+ log_level = level_map.get(self.verbosity, logging.WARNING)
115
+ setup_logging(level_per_module={"": log_level}, is_pretty_log=True)
116
+
117
+
118
+ bakefile_obj_app = typer.Typer()
119
+
120
+
121
+ def get_args(args: list[str] | None = None, windows_expand_args: bool = True) -> list[str]:
122
+ if args is None:
123
+ args = sys.argv[1:]
124
+
125
+ # Covered in Click tests
126
+ if os.name == "nt" and windows_expand_args: # pragma: no cover
127
+ args = click.utils._expand_args(args)
128
+ else:
129
+ args = list(args)
130
+
131
+ return args
132
+
133
+
134
+ def bakefile_obj_app_args(
135
+ args: list[str] | None = None,
136
+ windows_expand_args: bool = True,
137
+ ) -> list[str]:
138
+ # source from https://github.com/fastapi/typer/blob/b7f39eaad60141988f5d9a58df72c44d6128cd53/typer/core.py#L175-L185
139
+
140
+ args = get_args(args=args, windows_expand_args=windows_expand_args)
141
+
142
+ prohibited_non_bakefile_obj_app_args: list[str] = ["--help", "--version"]
143
+
144
+ args = [arg for arg in args if arg not in prohibited_non_bakefile_obj_app_args]
145
+ return args
146
+
147
+
148
+ def is_bakebook_optional(remaining_args: list[str] | None) -> bool:
149
+ args = get_args()
150
+
151
+ some_args: list[str] = ["--help", "--version"]
152
+ is_some_args = len([arg for arg in args if arg in some_args]) > 0
153
+ return is_some_args or remaining_args is None or remaining_args == []
154
+
155
+
156
+ @bakefile_obj_app.command(
157
+ name=GET_BAKEFILE_OBJECT,
158
+ hidden=True,
159
+ context_settings={
160
+ "allow_extra_args": True,
161
+ "allow_interspersed_args": False,
162
+ "ignore_unknown_options": True,
163
+ },
164
+ )
165
+ def _get_bakefile_object(
166
+ ctx: typer.Context,
167
+ chdir: chdir_option = DEFAULT_CHDIR,
168
+ file_name: file_name_option = DEFAULT_FILE_NAME,
169
+ bakebook_name: bakebook_name_option = DEFAULT_BAKEBOOK_NAME,
170
+ is_chain_commands: is_chain_commands_option = DEFAULT_IS_CHAIN_COMMAND,
171
+ remaining_args: remaining_args_argument = None,
172
+ verbosity: verbosity_option = 0,
173
+ dry_run: dry_run_option = False,
174
+ ):
175
+ _ = ctx
176
+ return BakefileObject(
177
+ chdir=chdir,
178
+ file_name=file_name,
179
+ bakebook_name=bakebook_name,
180
+ verbosity=verbosity,
181
+ dry_run=dry_run,
182
+ remaining_args=remaining_args,
183
+ is_chain_commands=is_chain_commands,
184
+ )
185
+
186
+
187
+ def get_bakefile_object(rich_markup_mode: MarkupMode) -> BakefileObject:
188
+ with typer_exception_handler(standalone_mode=True, rich_markup_mode=rich_markup_mode):
189
+ args = bakefile_obj_app_args()
190
+
191
+ for registered_command in bakefile_obj_app.registered_commands:
192
+ if registered_command.name != GET_BAKEFILE_OBJECT:
193
+ continue
194
+
195
+ command = get_command_from_info(
196
+ registered_command,
197
+ pretty_exceptions_short=bakefile_obj_app.pretty_exceptions_short,
198
+ rich_markup_mode=bakefile_obj_app.rich_markup_mode,
199
+ )
200
+
201
+ with command.make_context(info_name=GET_BAKEFILE_OBJECT, args=args) as ctx:
202
+ bakefile_obj = command.invoke(ctx)
203
+ if not isinstance(bakefile_obj, BakefileObject):
204
+ msg = (
205
+ f"Expected `bakefile_obj` to be an instance of "
206
+ f"{BakefileObject.__name__}, got {type(bakefile_obj).__name__}"
207
+ )
208
+ raise TypeError(msg)
209
+ return bakefile_obj
210
+
211
+ raise RuntimeError(
212
+ f"Failed to find the `{GET_BAKEFILE_OBJECT}` command in registered commands. "
213
+ f"This should never happen - please report this bug."
214
+ )