@@ -104,11 +104,30 @@ def _construct_pypath(mrctx, *, entries):
104104 ])
105105 return pypath
106106
107- def _execute_checked (mrctx , * , srcs , ** kwargs ):
107+ def _execute_prep (mrctx , * , python , srcs , ** kwargs ):
108+ for src in srcs :
109+ # This will ensure that we will re-evaluate the bzlmod extension or
110+ # refetch the repository_rule when the srcs change. This should work on
111+ # Bazel versions without `mrctx.watch` as well.
112+ repo_utils .watch (mrctx , mrctx .path (src ))
113+
114+ environment = kwargs .pop ("environment" , {})
115+ pythonpath = environment .get ("PYTHONPATH" , "" )
116+ if pythonpath and not types .is_string (pythonpath ):
117+ environment ["PYTHONPATH" ] = _construct_pypath (mrctx , entries = pythonpath )
118+ kwargs ["environment" ] = environment
119+
120+ # -B is added to prevent the repo-phase invocation from creating timestamp
121+ # based pyc files, which contributes to race conditions and non-determinism
122+ kwargs ["arguments" ] = [python , "-B" ] + kwargs .get ("arguments" , [])
123+ return kwargs
124+
125+ def _execute_checked (mrctx , * , python , srcs , ** kwargs ):
108126 """Helper function to run a python script and modify the PYTHONPATH to include external deps.
109127
110128 Args:
111129 mrctx: Handle to the module_ctx or repository_ctx.
130+ python: The python interpreter to use.
112131 srcs: The src files that the script depends on. This is important to
113132 ensure that the Bazel repository cache or the bzlmod lock file gets
114133 invalidated when any one file changes. It is advisable to use
@@ -118,26 +137,34 @@ def _execute_checked(mrctx, *, srcs, **kwargs):
118137 the `environment` has a value `PYTHONPATH` and it is a list, then
119138 it will be passed to `construct_pythonpath` function.
120139 """
140+ return repo_utils .execute_checked (
141+ mrctx ,
142+ ** _execute_prep (mrctx , python = python , srcs = srcs , ** kwargs )
143+ )
121144
122- for src in srcs :
123- # This will ensure that we will re-evaluate the bzlmod extension or
124- # refetch the repository_rule when the srcs change. This should work on
125- # Bazel versions without `mrctx.watch` as well.
126- repo_utils .watch (mrctx , mrctx .path (src ))
127-
128- env = kwargs .pop ("environment" , {})
129- pythonpath = env .get ("PYTHONPATH" , "" )
130- if pythonpath and not types .is_string (pythonpath ):
131- env ["PYTHONPATH" ] = _construct_pypath (mrctx , entries = pythonpath )
145+ def _execute_checked_stdout (mrctx , * , python , srcs , ** kwargs ):
146+ """Helper function to run a python script and modify the PYTHONPATH to include external deps.
132147
133- return repo_utils .execute_checked (
148+ Args:
149+ mrctx: Handle to the module_ctx or repository_ctx.
150+ python: The python interpreter to use.
151+ srcs: The src files that the script depends on. This is important to
152+ ensure that the Bazel repository cache or the bzlmod lock file gets
153+ invalidated when any one file changes. It is advisable to use
154+ `RECORD` files for external deps and the list of srcs from the
155+ rules_python repo for any scripts.
156+ **kwargs: Arguments forwarded to `repo_utils.execute_checked`. If
157+ the `environment` has a value `PYTHONPATH` and it is a list, then
158+ it will be passed to `construct_pythonpath` function.
159+ """
160+ return repo_utils .execute_checked_stdout (
134161 mrctx ,
135- environment = env ,
136- ** kwargs
162+ ** _execute_prep (mrctx , python = python , srcs = srcs , ** kwargs )
137163 )
138164
139165pypi_repo_utils = struct (
140166 construct_pythonpath = _construct_pypath ,
141167 execute_checked = _execute_checked ,
168+ execute_checked_stdout = _execute_checked_stdout ,
142169 resolve_python_interpreter = _resolve_python_interpreter ,
143170)
0 commit comments