pyallel 0.3.4__tar.gz → 0.4.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyallel
3
- Version: 0.3.4
3
+ Version: 0.4.0
4
4
  Summary: Run and handle the output of multiple executables in pyallel (as in parallel)
5
5
  Home-page: https://github.com/Danthewaann/pyallel
6
6
  License: MIT
@@ -53,6 +53,7 @@ pyallel "black --color --check --diff ." "mypy ." "ruff check --no-fix ."
53
53
  - [ ] Allow a single main command output to be streamed to stdout, while all other
54
54
  commands will only get outputted after the main command has completed (such as running
55
55
  `pytest` as the main command, whilst running `mypy`, `ruff` etc. as other commands)
56
+ - [x] Provide a way to set environment variables for each command to run with
56
57
  - [ ] Allow list of files to be provided to supply as input arguments to each command
57
58
  - [ ] Allow input to be piped into `pyallel` via stdin to supply as standard input to each
58
59
  command
@@ -32,6 +32,7 @@ pyallel "black --color --check --diff ." "mypy ." "ruff check --no-fix ."
32
32
  - [ ] Allow a single main command output to be streamed to stdout, while all other
33
33
  commands will only get outputted after the main command has completed (such as running
34
34
  `pytest` as the main command, whilst running `mypy`, `ruff` etc. as other commands)
35
+ - [x] Provide a way to set environment variables for each command to run with
35
36
  - [ ] Allow list of files to be provided to supply as input arguments to each command
36
37
  - [ ] Allow input to be piped into `pyallel` via stdin to supply as standard input to each
37
38
  command
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "pyallel"
3
- version = "0.3.4"
3
+ version = "0.4.0"
4
4
  description = "Run and handle the output of multiple executables in pyallel (as in parallel)"
5
5
  authors = ["Daniel Black <danielcrblack@gmail.com>"]
6
6
  license = "MIT"
@@ -1,18 +1,12 @@
1
1
  from __future__ import annotations
2
- import io
3
2
 
4
- import os
5
3
  import sys
6
4
  import time
7
- import shutil
8
- from dataclasses import dataclass
9
- import shlex
10
5
  import importlib.metadata
11
- import subprocess
12
- from typing import IO
13
6
 
14
7
  from pyallel.errors import InvalidExecutableErrors, InvalidExecutableError
15
8
  from pyallel.parser import Arguments, create_parser
9
+ from pyallel.process import Process
16
10
 
17
11
  IN_TTY = sys.__stdin__.isatty()
18
12
 
@@ -42,57 +36,13 @@ TICK = "\u2713"
42
36
  X = "\u2717"
43
37
 
44
38
 
45
- @dataclass
46
- class Process:
47
- name: str
48
- args: list[str]
49
- start: float = 0.0
50
- process: subprocess.Popen[bytes] | None = None
51
-
52
- def run(self) -> None:
53
- env = os.environ.copy()
54
- # TODO: need to provide a way to supply environment variablesreturn
55
- # for each provided command
56
- env["MYPY_FORCE_COLOR"] = "1" if IN_TTY else "0"
57
- self.start = time.perf_counter()
58
- self.process = subprocess.Popen(
59
- [self.name, *self.args],
60
- stdout=subprocess.PIPE,
61
- stderr=subprocess.STDOUT,
62
- env=env,
63
- )
64
-
65
- def poll(self) -> int | None:
66
- if self.process:
67
- return self.process.poll()
68
- return None
69
-
70
- def stdout(self) -> IO[bytes]:
71
- if self.process and self.process.stdout:
72
- return self.process.stdout
73
- return io.BytesIO(b"")
74
-
75
- def return_code(self) -> int | None:
76
- if self.process:
77
- return self.process.returncode
78
- return None
79
-
80
-
81
- def parse_command(command: str) -> Process:
82
- executable, *args = command.split(maxsplit=1)
83
- if not shutil.which(executable):
84
- raise InvalidExecutableError(executable)
85
- args = shlex.split(" ".join(args))
86
- return Process(name=executable, args=args)
87
-
88
-
89
39
  def run_commands(commands: list[str]) -> list[Process]:
90
40
  processes: list[Process] = []
91
41
  errors: list[InvalidExecutableError] = []
92
42
 
93
43
  for command in commands:
94
44
  try:
95
- processes.append(parse_command(command))
45
+ processes.append(Process.from_command(command))
96
46
  except InvalidExecutableError as e:
97
47
  errors.append(e)
98
48
 
@@ -257,3 +207,7 @@ def run(*args: str) -> int:
257
207
 
258
208
  def entry_point() -> None:
259
209
  sys.exit(run(*sys.argv[1:]))
210
+
211
+
212
+ if __name__ == "__main__":
213
+ entry_point()
@@ -0,0 +1,63 @@
1
+ from __future__ import annotations
2
+
3
+ import time
4
+ import subprocess
5
+ import shlex
6
+ import io
7
+ import shutil
8
+ import os
9
+ from typing import IO
10
+
11
+ from dataclasses import dataclass, field
12
+ from pyallel.errors import InvalidExecutableError
13
+
14
+
15
+ @dataclass
16
+ class Process:
17
+ name: str
18
+ args: list[str]
19
+ env: dict[str, str] = field(default_factory=dict)
20
+ start: float = 0.0
21
+ process: subprocess.Popen[bytes] | None = None
22
+
23
+ def run(self) -> None:
24
+ self.start = time.perf_counter()
25
+ self.process = subprocess.Popen(
26
+ [self.name, *self.args],
27
+ stdout=subprocess.PIPE,
28
+ stderr=subprocess.STDOUT,
29
+ env=self.env,
30
+ )
31
+
32
+ def poll(self) -> int | None:
33
+ if self.process:
34
+ return self.process.poll()
35
+ return None
36
+
37
+ def stdout(self) -> IO[bytes]:
38
+ if self.process and self.process.stdout:
39
+ return self.process.stdout
40
+ return io.BytesIO(b"")
41
+
42
+ def return_code(self) -> int | None:
43
+ if self.process:
44
+ return self.process.returncode
45
+ return None
46
+
47
+ @classmethod
48
+ def from_command(cls, command: str) -> Process:
49
+ env = os.environ.copy()
50
+ args = command.split()
51
+ parsed_args: list[str] = []
52
+ for arg in args:
53
+ if "=" in arg:
54
+ name, value = arg.split("=")
55
+ env[name] = value
56
+ else:
57
+ parsed_args.append(arg)
58
+
59
+ if not shutil.which(parsed_args[0]):
60
+ raise InvalidExecutableError(parsed_args[0])
61
+
62
+ args = shlex.split(" ".join(parsed_args[1:]))
63
+ return Process(name=parsed_args[0], args=args, env=env)
File without changes
File without changes
File without changes
File without changes
File without changes