bakefile 0.0.9__py3-none-any.whl → 0.0.10__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.
@@ -9,6 +9,8 @@ from bake.utils.exceptions import PythonNotFoundError
9
9
 
10
10
  logger = logging.getLogger(__name__)
11
11
 
12
+ _NO_PROJECT_PYTHON_MSG = "No project Python found"
13
+
12
14
 
13
15
  def is_standalone_bakefile(bakefile_path: Path) -> bool:
14
16
  inline_metadata = read_inline(bakefile_path)
@@ -101,18 +103,33 @@ def _find_project_python(bakefile_path: Path) -> Path | None:
101
103
  # Check if stderr contains "Found `...` at `...` (...)"
102
104
  # where source is "active virtual environment" or "virtual environment"
103
105
  stderr = result.stderr.strip()
104
- pattern = r"Found `[^`]+` at `[^`]+` \(([^)]+)\)"
106
+ pattern = r"Found `[^`]+` at `([^`]+)` \(([^)]+)\)"
105
107
  match = re.search(pattern, stderr)
106
108
 
107
- if result.returncode == 0 and match:
108
- source = match.group(1)
109
- if source in {"active virtual environment", "virtual environment"}:
110
- python_path = Path(result.stdout.strip())
111
- logger.debug(f"Found project Python at {python_path} (source: {source})")
112
- return python_path
109
+ if not (result.returncode == 0 and match):
110
+ logger.debug(_NO_PROJECT_PYTHON_MSG)
111
+ return None
113
112
 
114
- logger.debug("No project Python found")
115
- return None
113
+ source = match.group(2)
114
+ if source not in {"active virtual environment", "virtual environment"}:
115
+ logger.debug(_NO_PROJECT_PYTHON_MSG)
116
+ return None
117
+
118
+ python_path_from_log = Path(match.group(1))
119
+ python_path_from_stdout = Path(result.stdout.strip())
120
+ if python_path_from_log != python_path_from_stdout:
121
+ logger.debug(
122
+ "Python path mismatch between log and stdout",
123
+ extra={
124
+ "python_path_from_log": python_path_from_log,
125
+ "python_path_from_stdout": python_path_from_stdout,
126
+ },
127
+ )
128
+ logger.debug(_NO_PROJECT_PYTHON_MSG)
129
+ return None
130
+
131
+ logger.debug(f"Found project Python at {python_path_from_stdout} (source: {source})")
132
+ return python_path_from_stdout
116
133
 
117
134
 
118
135
  def _create_bakefile_venv(bakefile_path: Path) -> Path | None:
bake/ui/run/splitter.py CHANGED
@@ -47,44 +47,55 @@ class OutputSplitter:
47
47
  output_list.append(data)
48
48
  return True
49
49
 
50
- def _read_pty(self, pty_fd: int, target, output_list, proc: subprocess.Popen):
51
- """Read from PTY file descriptor in chunks and stream to output."""
50
+ def _read_pty_eio_safe(self, pty_fd: int) -> bytes | None:
51
+ """Read from PTY, treating EIO as EOF (returns None)."""
52
+ try:
53
+ return os.read(pty_fd, 4096)
54
+ except OSError as e:
55
+ if e.errno == errno.EIO:
56
+ return None
57
+ raise
58
+
59
+ def _try_immediate_read(self, pty_fd: int, target, output_list) -> bool:
60
+ """Try immediate non-blocking read. Returns True if should continue."""
61
+ import fcntl
62
+
63
+ flags = fcntl.fcntl(pty_fd, fcntl.F_GETFL)
64
+ fcntl.fcntl(pty_fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
65
+
66
+ data = self._read_pty_eio_safe(pty_fd)
67
+ if data is None or not self._handle_data(data, target, output_list):
68
+ fcntl.fcntl(pty_fd, fcntl.F_SETFL, flags)
69
+ return False
70
+
71
+ fcntl.fcntl(pty_fd, fcntl.F_SETFL, flags)
72
+ return True
73
+
74
+ def _blocking_pty_read(self, pty_fd: int, target, output_list) -> bool:
75
+ """Try select-based blocking read. Returns True if should continue."""
52
76
  import fcntl
53
77
 
78
+ flags = fcntl.fcntl(pty_fd, fcntl.F_GETFL)
79
+ fcntl.fcntl(pty_fd, fcntl.F_SETFL, flags)
80
+
81
+ ready, _, _ = select.select([pty_fd], [], [], 0.1)
82
+ if ready:
83
+ data = self._read_pty_eio_safe(pty_fd)
84
+ if data is None or not self._handle_data(data, target, output_list):
85
+ return False
86
+ return True
87
+
88
+ def _read_pty(self, pty_fd: int, target, output_list, proc: subprocess.Popen):
89
+ """Read from PTY file descriptor in chunks and stream to output."""
54
90
  try:
55
91
  while True:
56
- # Try immediate non-blocking read first (catches fast-exiting processes)
57
92
  try:
58
- # Set non-blocking mode
59
- flags = fcntl.fcntl(pty_fd, fcntl.F_GETFL)
60
- fcntl.fcntl(pty_fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
61
-
62
- data = os.read(pty_fd, 4096)
63
- if not self._handle_data(data, target, output_list):
93
+ if not self._try_immediate_read(pty_fd, target, output_list):
64
94
  break
65
-
66
- # Restore blocking mode
67
- fcntl.fcntl(pty_fd, fcntl.F_SETFL, flags)
68
95
  except BlockingIOError:
69
- # No data available yet, restore blocking mode and wait with select
70
- fcntl.fcntl(pty_fd, fcntl.F_SETFL, flags)
71
-
72
- # Wait for data to be available
73
- ready, _, _ = select.select([pty_fd], [], [], 0.1)
74
-
75
- if ready:
76
- try:
77
- data = os.read(pty_fd, 4096)
78
- except OSError as e:
79
- # EIO (errno 5) means PTY slave closed - treat as EOF
80
- # This can happen in CI environments when process exits
81
- if e.errno == errno.EIO:
82
- break
83
- raise
84
- if not self._handle_data(data, target, output_list):
85
- break
86
-
87
- # Check if process exited after reading data
96
+ if not self._blocking_pty_read(pty_fd, target, output_list):
97
+ break
98
+
88
99
  if proc.poll() is not None:
89
100
  self._drain_pty(pty_fd, target, output_list)
90
101
  break
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bakefile
3
- Version: 0.0.9
3
+ Version: 0.0.10
4
4
  Summary: Add your description here
5
5
  Author: Wisaroot Lertthaweedech
6
6
  Author-email: Wisaroot Lertthaweedech <l.wisaroot@gmail.com>
@@ -28,7 +28,7 @@ bake/cli/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
28
  bake/cli/utils/version.py,sha256=aiweLD0vDezBlJAcCC99oMms71WGD9CWSJuZ4i3VLHA,390
29
29
  bake/manage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
30
  bake/manage/add_inline.py,sha256=yefHmF33ghCB8NZ-v61ybeVsaeE8iDFvfRGeTAKg4I8,2245
31
- bake/manage/find_python.py,sha256=oVmd8KaSsgDQWHuGZpYiQx-DHn50P9EkRi6-YIad99E,7165
31
+ bake/manage/find_python.py,sha256=67PAFPDA3fdSsDGjYfPcXOVUcgC63wg5mipjVIt1VUQ,7730
32
32
  bake/manage/lint.py,sha256=OqwYFF8GGvzHGVPuJcWMRAv5esXEIX4nQXdGcChnkqA,2394
33
33
  bake/manage/run_uv.py,sha256=QzlKeVpr20dXNDcwUgyJqnXT4MofRqK-6XkWpzBbUhE,3234
34
34
  bake/manage/write_bakefile.py,sha256=efGViLk7sh-QX9Mox7yQw_A1Tp7EOuc_vmSTbFmXUm0,736
@@ -45,7 +45,7 @@ bake/ui/params.py,sha256=yNDChJQkbeZSxQzXTSBrAPCbwsJ5zOK4s4sFHQPSnHs,140
45
45
  bake/ui/run/__init__.py,sha256=A671l5YVTRAtS47ewvaMCNwPRim_Wkof1am0WibxA2I,205
46
46
  bake/ui/run/run.py,sha256=qfDgy-YqcexJyHhSjnQ5IXipBDoK-umwKq-wAn8ZITU,17504
47
47
  bake/ui/run/script.py,sha256=fk7KiDklYDYpFGkH3wu-hZGI4OnvgcB8z5jtNt41Hg0,2263
48
- bake/ui/run/splitter.py,sha256=uS9v822aGkeA0mLu_OmVA2I0rgoLSvkoITMfCM75tVs,9025
48
+ bake/ui/run/splitter.py,sha256=L6uCU3bzpoMgj891Q1BZnOtiWF07QFDcCOx9RyUqHKk,9198
49
49
  bake/ui/run/uv.py,sha256=3NpnjgAwQNijJiUT_H6U-3mTHQgBZPlJbNWEeYCZY1g,2077
50
50
  bake/ui/style.py,sha256=v9dferzV317Acb0GHpVK_niCj_s2HtL-yiToBZtXky4,70
51
51
  bake/utils/__init__.py,sha256=GUu_xlJy3RAHo6UcZXu2x4khxGqLHMA9Zos4hDiQIY8,326
@@ -59,10 +59,10 @@ bakelib/environ/base.py,sha256=azPUdc9C5zVU8iyXJrEm3uDfe39nG48DRAZiF9rTdHI,3753
59
59
  bakelib/environ/get_bakebook.py,sha256=LihxB3VDcVq81KJy1HT-N-beyt2C7ReWm2kMPrd7VlA,1563
60
60
  bakelib/environ/presets.py,sha256=IwHGeDeQe4e57k9_u_vBQ61bjMS5Z2Jj9zkXw6YJHAE,1943
61
61
  bakelib/space/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
62
- bakelib/space/base.py,sha256=bJlpPkP85xBu8X5fJoVaHrMzX27rQrYTEPSObwBANJ8,6008
62
+ bakelib/space/base.py,sha256=4afkB2Cmq3kP-xBeL45lvmmOhARsA-m5F1-rEPLAgEc,5871
63
63
  bakelib/space/python.py,sha256=0qxjIQ1SYIvDkaeQjkykE2t8doBUTl1MONK8cuG5juo,2793
64
64
  bakelib/space/utils.py,sha256=xx4X_txhDH_p97CKJ-KuvFpgfNBC0y_din1IBlUVusU,2983
65
- bakefile-0.0.9.dist-info/WHEEL,sha256=XV0cjMrO7zXhVAIyyc8aFf1VjZ33Fen4IiJk5zFlC3g,80
66
- bakefile-0.0.9.dist-info/entry_points.txt,sha256=Ecvvh7BYHCPJ0UdntrDc3Od6AZdRPXN5Z7o_7ok_0Qw,107
67
- bakefile-0.0.9.dist-info/METADATA,sha256=ed15p6Yb_Bx_nnsu2rxVCsL7_AfSbu3Plr2-XHiKIIU,2367
68
- bakefile-0.0.9.dist-info/RECORD,,
65
+ bakefile-0.0.10.dist-info/WHEEL,sha256=XV0cjMrO7zXhVAIyyc8aFf1VjZ33Fen4IiJk5zFlC3g,80
66
+ bakefile-0.0.10.dist-info/entry_points.txt,sha256=Ecvvh7BYHCPJ0UdntrDc3Od6AZdRPXN5Z7o_7ok_0Qw,107
67
+ bakefile-0.0.10.dist-info/METADATA,sha256=sb-rcoJxanUjkn2dA-9ZfOg0aaXdlVF4ys-ATVVjuuk,2368
68
+ bakefile-0.0.10.dist-info/RECORD,,
bakelib/space/base.py CHANGED
@@ -57,20 +57,16 @@ class BaseSpace(Bakebook):
57
57
  help="Patterns to exclude",
58
58
  ),
59
59
  ] = None,
60
- use_default_excludes: Annotated[
60
+ default_excludes: Annotated[
61
61
  bool,
62
- typer.Option(
63
- "--no-default-excludes",
64
- help="Do not apply default exclude patterns",
65
- is_flag=True,
66
- ),
67
- ] = False,
62
+ typer.Option(help="Apply default exclude patterns (.env, .cache)"),
63
+ ] = True,
68
64
  ) -> None:
69
65
  results = ctx.run("git clean -fdX -n", stream=False, dry_run=False, echo=True)
70
66
 
71
67
  exclude_patterns: set[str] = set(exclude_patterns if exclude_patterns else [])
72
68
 
73
- if not use_default_excludes:
69
+ if default_excludes:
74
70
  exclude_patterns |= {".env", ".cache"}
75
71
 
76
72
  console.err.print(f"Exclude pattens: {exclude_patterns}")
@@ -175,7 +171,6 @@ class BaseSpace(Bakebook):
175
171
  "--skip-test",
176
172
  "-s",
177
173
  help="Skip running tests",
178
- is_flag=True,
179
174
  ),
180
175
  ] = False,
181
176
  ) -> None: