Skip to content

Commit

Permalink
Cope with https://bugs.python.org/issue14156 being fixed
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanor authored and mr-c committed Aug 22, 2022
1 parent 7023029 commit 39bf7b6
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 12 deletions.
6 changes: 6 additions & 0 deletions khmer/kfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,12 @@ def is_block(fthing):
"""Take in a file object and checks to see if it's a block or fifo."""
if fthing is sys.stdout or fthing is sys.stdin:
return True
if hasattr(fthing, "iastty") and fthing.isatty():
return True
elif not hasattr(fthing, 'name'):
return True
if fthing.name == "<stdout>":
return True
else:
mode = os.stat(fthing.name).st_mode
return S_ISBLK(mode) or S_ISCHR(mode)
Expand Down
6 changes: 4 additions & 2 deletions khmer/khmer_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,14 +156,16 @@ def parse_args(self, args=None, namespace=None):

# Temporary fix to argparse FileType which ignores the
# binary mode flag. Upstream bug tracked in https://bugs.python.org/issue14156
# Fixed in 3.9.12 and 3.10.3.
# pylint: disable=too-few-public-methods,missing-docstring
class FileType(argparse.FileType):
def __call__(self, fname):
# detect if stdout is being faked (StringIO during unit tests) in
# which case we do not have to do anything
if (fname == '-' and
sys.version_info.major == 3 and
not isinstance(sys.stdout, StringIO)):
not isinstance(sys.stdout, StringIO) and
(sys.version_info < (3, 9, 12) or
(3, 10) < sys.version_info < (3, 10, 3))):
if 'r' in self._mode:
fname = sys.stdin.fileno()
elif 'w' in self._mode:
Expand Down
2 changes: 1 addition & 1 deletion scripts/trim-low-abund.py
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ def main():

if args.output is None:
log_info('output in *.abundtrim')
elif args.output.name == 1:
elif not hasattr(args.output, 'name') or args.output.name == 1:
log_info('output streamed to stdout')
elif args.output.name:
log_info('output in {}'.format(args.output.name))
Expand Down
31 changes: 22 additions & 9 deletions tests/khmer_tst_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,13 @@
import sys
import traceback
import subprocess
from io import open # pylint: disable=redefined-builtin
from io import BufferedWriter, BytesIO, StringIO, TextIOWrapper
from hashlib import md5

from khmer import reverse_complement as revcomp

import pytest

try:
from StringIO import StringIO
except ImportError:
from io import StringIO


def _equals_rc(query, match):
return (query == match) or (revcomp(query) == match)
Expand Down Expand Up @@ -150,6 +145,25 @@ def _runscript(scriptname, sandbox=False):
return -1


class StdIOBuffer(TextIOWrapper):
'''Replacement for writable io.StringIO that behaves more like real file
Unlike StringIO, provides a buffer attribute that holds the underlying
binary data, allowing it to replace sys.stdout/sys.stderr in more
contexts.
'''

name = 'StdIOBuffer'

def __init__(self, initial_value='', newline='\n'):
initial_value = initial_value.encode('utf-8')
super().__init__(BufferedWriter(BytesIO(initial_value)),
'utf-8', newline=newline)

def getvalue(self):
self.flush()
return self.buffer.raw.getvalue().decode('utf-8')


def runscript(scriptname, args, in_directory=None,
fail_ok=False, sandbox=False):
"""Run a Python script using exec().
Expand All @@ -171,9 +185,8 @@ def runscript(scriptname, args, in_directory=None,
sys.argv = sysargs

oldout, olderr = sys.stdout, sys.stderr
sys.stdout = StringIO()
sys.stdout.name = "StringIO"
sys.stderr = StringIO()
sys.stdout = StdIOBuffer()
sys.stderr = StdIOBuffer()

if in_directory:
os.chdir(in_directory)
Expand Down

0 comments on commit 39bf7b6

Please sign in to comment.