Skip to content

Commit 9c8e8fc

Browse files
authored
Merge pull request #342 from ales-erjavec/fixes/subprocess-encoding-error
[FIX] Addons: Install encoding error
2 parents 9b12b1d + a4a5d7d commit 9c8e8fc

File tree

5 files changed

+42
-11
lines changed

5 files changed

+42
-11
lines changed

i18n/si/msgs.jaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,6 +1326,15 @@ application/utils/addons.py:
13261326
def `run_command`:
13271327
Running %s: false
13281328
' ': false
1329+
env: false
1330+
PYTHONIOENCODING: false
1331+
utf-8: false
1332+
PYTHONUTF8: false
1333+
1: false
1334+
encoding: false
1335+
errors: false
1336+
backslashreplace: false
1337+
universal_newlines: false
13291338
python: false
13301339
def `run_process`:
13311340
subprocess.Popen: false
@@ -3780,6 +3789,7 @@ utils/shtools.py:
37803789
nt: false
37813790
def `temp_named_file`:
37823791
utf-8: false
3792+
wb: false
37833793
wt: false
37843794
utils/localization/__init__.py:
37853795
import 'orangecanvas.localization', not 'orangecanvas.utils.localization': false

orangecanvas/application/tests/test_addons_utils.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import io
12
import os
23
import stat
34
import unittest
5+
from shutil import which
46
from tempfile import mkdtemp
57

68
from requests import Session
@@ -14,9 +16,10 @@
1416
installable_from_json_response,
1517
installable_items,
1618
is_updatable,
17-
prettify_name, _session,
19+
prettify_name, _session, run_command,
1820
)
1921
from orangecanvas.application.tests.test_addons import FakeDistribution
22+
from orangecanvas.utils.shtools import temp_named_file
2023

2124

2225
class TestUtils(unittest.TestCase):
@@ -112,6 +115,13 @@ def test_session(self):
112115
os.chmod(temp_dir, stat.S_IRUSR)
113116
self.assertIsInstance(_session(temp_dir), Session)
114117

118+
@unittest.skipIf(which("cat") is None, "'cat' not present")
119+
def test_run_command_decode_errors(self):
120+
f = io.StringIO()
121+
with temp_named_file(b'\x00' * 16, encoding=None) as fname:
122+
run_command(["cat", fname], file=f)
123+
self.assertEqual("\x00" * 16, f.getvalue())
124+
115125

116126
if __name__ == "__main__":
117127
unittest.main()

orangecanvas/application/utils/addons.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -639,20 +639,30 @@ def __bool__(self):
639639
return bool(self.conda)
640640

641641

642-
def run_command(command, raise_on_fail=True, **kwargs):
643-
# type: (List[str], bool, Any) -> Tuple[int, List[AnyStr]]
642+
def run_command(
643+
command: List[str], raise_on_fail: bool = True,/, file=None, **kwargs
644+
) -> Tuple[int, List[str]]:
644645
"""
645646
Run command in a subprocess.
646647
647648
Return `process` return code and output once it completes.
648649
"""
649650
log.info("Running %s", " ".join(command))
650651

652+
env = kwargs.pop("env", os.environ).copy()
653+
env["PYTHONIOENCODING"] = "utf-8"
654+
env["PYTHONUTF8"] = "1"
655+
kwargs["env"] = env
656+
657+
kwargs.setdefault("encoding", "utf-8")
658+
kwargs.setdefault("errors", "backslashreplace")
659+
kwargs.setdefault("universal_newlines", True)
660+
651661
if command[0] == "python":
652662
process = python_process(command[1:], **kwargs)
653663
else:
654664
process = create_process(command, **kwargs)
655-
rcode, output = run_process(process, file=sys.stdout)
665+
rcode, output = run_process(process, file=file)
656666
if rcode != 0 and raise_on_fail:
657667
raise CommandFailed(command, rcode, output)
658668
else:

orangecanvas/utils/shtools.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ def create_process(
8181
executable: Optional[str] = None,
8282
stderr=subprocess.STDOUT,
8383
stdout=subprocess.PIPE,
84-
universal_newlines=True,
8584
**kwargs
8685
) -> subprocess.Popen:
8786
"""
@@ -99,14 +98,13 @@ def create_process(
9998
executable=executable,
10099
stderr=stderr,
101100
stdout=stdout,
102-
universal_newlines=universal_newlines,
103101
**kwargs
104102
)
105103

106104

107105
@contextmanager
108106
def temp_named_file(
109-
content: str, encoding="utf-8",
107+
content: str | bytes, encoding: str | None = "utf-8",
110108
suffix: Optional[str] = None,
111109
prefix: Optional[str] = None,
112110
dir: Optional[str] = None,
@@ -118,7 +116,7 @@ def temp_named_file(
118116
119117
Parameters
120118
----------
121-
content: str
119+
content: str | bytes
122120
The contents to write into the temp file
123121
encoding: str
124122
Encoding
@@ -141,7 +139,8 @@ def temp_named_file(
141139
tempfile.mkstemp
142140
"""
143141
fd, name = tempfile.mkstemp(suffix, prefix, dir=dir, text=True)
144-
file = os.fdopen(fd, mode="wt", encoding=encoding,)
142+
mode = "wb" if encoding is None else "wt"
143+
file = os.fdopen(fd, mode=mode, encoding=encoding,)
145144
file.write(content)
146145
file.close()
147146
try:

orangecanvas/utils/tests/test_shtools.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
class Test(unittest.TestCase):
99
def test_python_process(self):
10-
p = python_process(["-c", "print('Hello')"])
10+
p = python_process(["-c", "print('Hello')"], encoding="utf-8")
1111
out, _ = p.communicate()
1212
self.assertEqual(out.strip(), "Hello")
1313
self.assertEqual(p.wait(), 0)
@@ -16,10 +16,12 @@ def test_temp_named_file(self):
1616
cases = [
1717
("Hello", "utf-8"),
1818
("Hello", "utf-16"),
19+
(b"Hello", None)
1920
]
2021
for content, encoding in cases:
2122
with temp_named_file(content, encoding=encoding) as fname:
22-
with open(fname, "r", encoding=encoding) as f:
23+
with open(fname, "rb" if encoding is None else "r",
24+
encoding=encoding) as f:
2325
c = f.read()
2426
self.assertEqual(c, content)
2527
self.assertFalse(os.path.exists(fname))

0 commit comments

Comments
 (0)