Skip to content

Commit ab10826

Browse files
committed
stream output to command stdout/stderr
1 parent b308523 commit ab10826

File tree

4 files changed

+52
-4
lines changed

4 files changed

+52
-4
lines changed

django_routines/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,19 @@ class _RoutineCommand(ABC):
7474
or for all invocations of the routine if no switches are configured.
7575
"""
7676

77+
# pre_hook: t.Optional[t.Callable[[Command], t.Optional[bool]]] = None
78+
"""
79+
A function to run before the command is run. The function should take the command instance and
80+
may return True to skip the command.
81+
"""
82+
83+
# post_hook: t.Optional[t.Callable[[Command, t.Any], t.Any]] = None
84+
"""
85+
A function to run after the command has been run. The function should take the command instance
86+
and the result of the function which will be whatever call_command returns if run in the same
87+
process, or the result object returned by subprocess.run() if run in a subprocess.
88+
"""
89+
7790
@property
7891
@abstractmethod
7992
def kind(self) -> str:

django_routines/management/commands/routine.py

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -217,10 +217,38 @@ def _subprocess(self, command: RCommand):
217217
if self.verbosity > 0:
218218
self.secho(" ".join(args), fg="cyan")
219219

220-
result = subprocess.run(args, env=os.environ.copy(), capture_output=True)
221-
self.stdout.write(result.stdout.decode())
222-
self.stderr.write(result.stderr.decode())
223-
return result.returncode
220+
# result = subprocess.run(args, env=os.environ.copy(), capture_output=True)
221+
# self.stdout.write(result.stdout.decode())
222+
# self.stderr.write(result.stderr.decode())
223+
224+
with subprocess.Popen(
225+
args,
226+
env=os.environ.copy(),
227+
stdout=subprocess.PIPE,
228+
stderr=subprocess.PIPE,
229+
text=True,
230+
) as proc:
231+
assert proc.stdout
232+
assert proc.stderr
233+
while True:
234+
output = proc.stdout.readline()
235+
if output:
236+
self.stdout.write(output)
237+
self.stdout.flush()
238+
error = proc.stderr.readline()
239+
if error:
240+
self.stderr.write(error)
241+
self.stderr.flush()
242+
243+
if output == "" and error == "" and proc.poll() is not None:
244+
break
245+
246+
if proc.returncode != 0:
247+
for line in proc.stderr:
248+
self.stderr.write(line)
249+
self.stderr.flush()
250+
251+
return proc.returncode
224252

225253
def _list(self) -> None:
226254
"""

doc/source/changelog.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Change Log
55
v1.1.0
66
======
77

8+
* `Support function pre and post hooks to be run prior to and after given commands. <https://github.com/bckohan/django-routines/issues/9>`_
89
* `Command type for system commands (i.e. non-management commands) to be run as subprocesses <https://github.com/bckohan/django-routines/issues/7>`_
910
* `Option to run management commands as subprocesses instead of in the same process space. <https://github.com/bckohan/django-routines/issues/6>`_
1011

tests/pytest_routine.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from .settings import *
2+
from django_routines import system
3+
4+
DJANGO_ROUTINES = {}
5+
6+
system('test', 'pytest')

0 commit comments

Comments
 (0)