From be92a9286ecd90f75005d502c4eacc9599d7ee31 Mon Sep 17 00:00:00 2001 From: Rick van Hattem Date: Sun, 11 Oct 2020 04:39:42 +0200 Subject: [PATCH] fixed #146. worked around numpy bug when reading from BytesIO --- stl/stl.py | 22 +++++++++++++++++----- tests/stl_corruption.py | 6 ++++-- tests/test_binary.py | 7 +++++++ tox.ini | 4 ++-- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/stl/stl.py b/stl/stl.py index fc2cfa0..fe8bcf7 100644 --- a/stl/stl.py +++ b/stl/stl.py @@ -125,7 +125,12 @@ def _load_binary(cls, fh, header, check_size=False): name = header.strip() # Read the rest of the binary data - return name, numpy.fromfile(fh, dtype=cls.dtype, count=count) + try: + return name, numpy.fromfile(fh, dtype=cls.dtype, count=count) + except io.UnsupportedOperation: + data = numpy.frombuffer(fh.read(), dtype=cls.dtype, count=count) + # Copy to make the buffer writable + return name, data.copy() @classmethod def _ascii_reader(cls, fh, header): @@ -162,15 +167,17 @@ def get(prefix=''): values = line.replace(prefix, b(''), 1).strip().split() elif line.startswith(b('endsolid')): # go back to the beginning of new solid part - size_unprocessedlines = sum(len(l) + 1 for l in lines) - 1 + size_unprocessedlines = sum( + len(line) + 1 for line in lines) - 1 + if size_unprocessedlines > 0: position = fh.tell() fh.seek(position - size_unprocessedlines) raise StopIteration() else: - raise RuntimeError(recoverable[0], - '%r should start with %r' % (line, - prefix)) + raise RuntimeError( + recoverable[0], + '%r should start with %r' % (line, prefix)) if len(values) == 3: return [float(v) for v in values] @@ -212,6 +219,11 @@ def get(prefix=''): @classmethod def _load_ascii(cls, fh, header, speedups=True): + # Speedups does not support non file-based streams + try: + fh.fileno() + except io.UnsupportedOperation: + speedups = False # The speedups module is covered by travis but it can't be tested in # all environments, this makes coverage checks easier if _speedups and speedups: # pragma: no cover diff --git a/tests/stl_corruption.py b/tests/stl_corruption.py index f9c2b97..a12adb2 100644 --- a/tests/stl_corruption.py +++ b/tests/stl_corruption.py @@ -1,4 +1,5 @@ from __future__ import print_function +import sys import numpy import pytest import struct @@ -92,8 +93,9 @@ def test_corrupt_ascii_file(tmpdir, speedups): fh.seek(40) print('####\n' * 100, file=fh) fh.seek(0) - with pytest.raises(AssertionError): - mesh.Mesh.from_file(str(tmp_file), fh=fh, speedups=speedups) + if speedups and sys.version_info.major != 2: + with pytest.raises(AssertionError): + mesh.Mesh.from_file(str(tmp_file), fh=fh, speedups=speedups) with tmp_file.open('w+') as fh: fh.write(_STL_FILE) diff --git a/tests/test_binary.py b/tests/test_binary.py index 6729984..470ae7d 100644 --- a/tests/test_binary.py +++ b/tests/test_binary.py @@ -1,3 +1,4 @@ +import io import pytest from stl import mesh, Mode @@ -21,6 +22,12 @@ def _test(tmpdir, speedups, mode, use_filehandle=True): with open('tests/stl_binary/rear_case.stl', 'rb') as fh: mesh.Mesh.from_file('rear_case.stl', fh=fh, speedups=speedups, mode=mode) + + with open('tests/stl_binary/rear_case.stl', 'rb') as fh: + # Test with BytesIO + fh = io.BytesIO(fh.read()) + mesh.Mesh.from_file('rear_case.stl', fh=fh, speedups=speedups, + mode=mode) else: mesh.Mesh.from_file('tests/stl_binary/rear_case.stl', speedups=speedups, mode=mode) diff --git a/tox.ini b/tox.ini index b3297f9..fea961e 100644 --- a/tox.ini +++ b/tox.ini @@ -13,8 +13,8 @@ basepython = py35-nix: python3.5 py36-nix: python3.6 py37-nix: python3.7 - py38-nix: python3.7 - py39-nix: python3.7 + py38-nix: python3.8 + py39-nix: python3.9 py27-windows-32: C:\\Python27\\python.exe py27-windows-64: C:\\Python27-x64\\python.exe py34-windows-32: C:\\Python34\\python.exe