python-subunit
Advanced tools
+32
| sudo: false | ||
| addons: | ||
| apt: | ||
| packages: | ||
| - check | ||
| - libcppunit-dev | ||
| language: python | ||
| python: | ||
| - "2.7" | ||
| - "3.4" | ||
| - "3.5" | ||
| - "3.6" | ||
| - "3.7" | ||
| - "3.8" | ||
| - pypy | ||
| - pypy3.5 | ||
| matrix: | ||
| include: | ||
| # Travis nightly look to be 3.5.0a4, b3 is out and the error we see | ||
| # doesn't happen in trunk. | ||
| # - python: "nightly" | ||
| install: | ||
| - pip install -U pip | ||
| - pip install -U wheel setuptools | ||
| - pip install -U .[test,docs] | ||
| - pip list | ||
| - python --version | ||
| - autoreconf -fi && ./configure && make | ||
| script: | ||
| - make check | ||
| - make distcheck | ||
| - rst2html.py README.rst README.html |
+36
| # | ||
| # subunit: extensions to Python unittest to get test results from subprocesses. | ||
| # Copyright (C) 2013 Robert Collins <robertc@robertcollins.net> | ||
| # | ||
| # Licensed under either the Apache License, Version 2.0 or the BSD 3-clause | ||
| # license at the users choice. A copy of both licenses are available in the | ||
| # project source as Apache-2.0 and BSD. You may not use this file except in | ||
| # compliance with one of these two licences. | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT | ||
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
| # license you chose for the specific language governing permissions and | ||
| # limitations under that license. | ||
| # | ||
| import unittest | ||
| import subunit | ||
| class ShellTests(subunit.ExecTestCase): | ||
| def test_sourcing(self): | ||
| """./shell/tests/test_source_library.sh""" | ||
| def test_functions(self): | ||
| """./shell/tests/test_function_output.sh""" | ||
| def test_suite(): | ||
| result = unittest.TestSuite() | ||
| result.addTest(subunit.test_suite()) | ||
| result.addTest(ShellTests('test_sourcing')) | ||
| result.addTest(ShellTests('test_functions')) | ||
| return result |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
+36
| Subunit is licensed under two licenses, the Apache License, Version 2.0 or the | ||
| 3-clause BSD License. You may use this project under either of these licenses | ||
| - choose the one that works best for you. | ||
| We require contributions to be licensed under both licenses. The primary | ||
| difference between them is that the Apache license takes care of potential | ||
| issues with Patents and other intellectual property concerns. This is | ||
| important to Subunit as Subunit wants to be license compatible in a very | ||
| broad manner to allow reuse and incorporation into other projects. | ||
| Generally every source file in Subunit needs a license grant under both these | ||
| licenses. As the code is shipped as a single unit, a brief form is used: | ||
| ---- | ||
| Copyright (c) [yyyy][,yyyy]* [name or 'Subunit Contributors'] | ||
| Licensed under either the Apache License, Version 2.0 or the BSD 3-clause | ||
| license at the users choice. A copy of both licenses are available in the | ||
| project source as Apache-2.0 and BSD. You may not use this file except in | ||
| compliance with one of these two licences. | ||
| Unless required by applicable law or agreed to in writing, software | ||
| distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT | ||
| WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
| license you chose for the specific language governing permissions and | ||
| limitations under that license. | ||
| ---- | ||
| Code that has been incorporated into Subunit from other projects will | ||
| naturally be under its own license, and will retain that license. | ||
| A known list of such code is maintained here: | ||
| * The python/iso8601 module by Michael Twomey, distributed under an MIT style | ||
| licence - see python/iso8601/LICENSE for details. | ||
| * The runtests.py and python/subunit/tests/TestUtil.py module are GPL test | ||
| support modules. They are not installed by Subunit - they are only ever | ||
| used on the build machine. Copyright 2004 Canonical Limited. |
| Copyright (c) 2007 Michael Twomey | ||
| Permission is hereby granted, free of charge, to any person obtaining a | ||
| copy of this software and associated documentation files (the | ||
| "Software"), to deal in the Software without restriction, including | ||
| without limitation the rights to use, copy, modify, merge, publish, | ||
| distribute, sublicense, and/or sell copies of the Software, and to | ||
| permit persons to whom the Software is furnished to do so, subject to | ||
| the following conditions: | ||
| The above copyright notice and this permission notice shall be included | ||
| in all copies or substantial portions of the Software. | ||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
| OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
| IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
| CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
| TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
| SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| A simple package to deal with ISO 8601 date time formats. | ||
| ISO 8601 defines a neutral, unambiguous date string format, which also | ||
| has the property of sorting naturally. | ||
| e.g. YYYY-MM-DDTHH:MM:SSZ or 2007-01-25T12:00:00Z | ||
| Currently this covers only the most common date formats encountered, not | ||
| all of ISO 8601 is handled. | ||
| Currently the following formats are handled: | ||
| * 2006-01-01T00:00:00Z | ||
| * 2006-01-01T00:00:00[+-]00:00 | ||
| I'll add more as I encounter them in my day to day life. Patches with | ||
| new formats and tests will be gratefully accepted of course :) | ||
| References: | ||
| * http://www.cl.cam.ac.uk/~mgk25/iso-time.html - simple overview | ||
| * http://hydracen.com/dx/iso8601.htm - more detailed enumeration of | ||
| valid formats. | ||
| See the LICENSE file for the license this package is released under. |
Sorry, the diff of this file is not supported yet
| try: | ||
| from setuptools import setup | ||
| except ImportError: | ||
| from distutils import setup | ||
| long_description="""Simple module to parse ISO 8601 dates | ||
| This module parses the most common forms of ISO 8601 date strings (e.g. | ||
| 2007-01-14T20:34:22+00:00) into datetime objects. | ||
| >>> import iso8601 | ||
| >>> iso8601.parse_date("2007-01-25T12:00:00Z") | ||
| datetime.datetime(2007, 1, 25, 12, 0, tzinfo=<iso8601.iso8601.Utc ...>) | ||
| >>> | ||
| Changes | ||
| ======= | ||
| 0.1.4 | ||
| ----- | ||
| * The default_timezone argument wasn't being passed through correctly, | ||
| UTC was being used in every case. Fixes issue 10. | ||
| 0.1.3 | ||
| ----- | ||
| * Fixed the microsecond handling, the generated microsecond values were | ||
| way too small. Fixes issue 9. | ||
| 0.1.2 | ||
| ----- | ||
| * Adding ParseError to __all__ in iso8601 module, allows people to import it. | ||
| Addresses issue 7. | ||
| * Be a little more flexible when dealing with dates without leading zeroes. | ||
| This violates the spec a little, but handles more dates as seen in the | ||
| field. Addresses issue 6. | ||
| * Allow date/time separators other than T. | ||
| 0.1.1 | ||
| ----- | ||
| * When parsing dates without a timezone the specified default is used. If no | ||
| default is specified then UTC is used. Addresses issue 4. | ||
| """ | ||
| setup( | ||
| name="iso8601", | ||
| version="0.1.4", | ||
| description=long_description.split("\n")[0], | ||
| long_description=long_description, | ||
| author="Michael Twomey", | ||
| author_email="micktwomey+iso8601@gmail.com", | ||
| url="http://code.google.com/p/pyiso8601/", | ||
| packages=["iso8601"], | ||
| license="MIT", | ||
| ) |
| import iso8601 | ||
| def test_iso8601_regex(): | ||
| assert iso8601.ISO8601_REGEX.match("2006-10-11T00:14:33Z") | ||
| def test_timezone_regex(): | ||
| assert iso8601.TIMEZONE_REGEX.match("+01:00") | ||
| assert iso8601.TIMEZONE_REGEX.match("+00:00") | ||
| assert iso8601.TIMEZONE_REGEX.match("+01:20") | ||
| assert iso8601.TIMEZONE_REGEX.match("-01:00") | ||
| def test_parse_date(): | ||
| d = iso8601.parse_date("2006-10-20T15:34:56Z") | ||
| assert d.year == 2006 | ||
| assert d.month == 10 | ||
| assert d.day == 20 | ||
| assert d.hour == 15 | ||
| assert d.minute == 34 | ||
| assert d.second == 56 | ||
| assert d.tzinfo == iso8601.UTC | ||
| def test_parse_date_fraction(): | ||
| d = iso8601.parse_date("2006-10-20T15:34:56.123Z") | ||
| assert d.year == 2006 | ||
| assert d.month == 10 | ||
| assert d.day == 20 | ||
| assert d.hour == 15 | ||
| assert d.minute == 34 | ||
| assert d.second == 56 | ||
| assert d.microsecond == 123000 | ||
| assert d.tzinfo == iso8601.UTC | ||
| def test_parse_date_fraction_2(): | ||
| """From bug 6 | ||
| """ | ||
| d = iso8601.parse_date("2007-5-7T11:43:55.328Z'") | ||
| assert d.year == 2007 | ||
| assert d.month == 5 | ||
| assert d.day == 7 | ||
| assert d.hour == 11 | ||
| assert d.minute == 43 | ||
| assert d.second == 55 | ||
| assert d.microsecond == 328000 | ||
| assert d.tzinfo == iso8601.UTC | ||
| def test_parse_date_tz(): | ||
| d = iso8601.parse_date("2006-10-20T15:34:56.123+02:30") | ||
| assert d.year == 2006 | ||
| assert d.month == 10 | ||
| assert d.day == 20 | ||
| assert d.hour == 15 | ||
| assert d.minute == 34 | ||
| assert d.second == 56 | ||
| assert d.microsecond == 123000 | ||
| assert d.tzinfo.tzname(None) == "+02:30" | ||
| offset = d.tzinfo.utcoffset(None) | ||
| assert offset.days == 0 | ||
| assert offset.seconds == 60 * 60 * 2.5 | ||
| def test_parse_invalid_date(): | ||
| try: | ||
| iso8601.parse_date(None) | ||
| except iso8601.ParseError: | ||
| pass | ||
| else: | ||
| assert 1 == 2 | ||
| def test_parse_invalid_date2(): | ||
| try: | ||
| iso8601.parse_date("23") | ||
| except iso8601.ParseError: | ||
| pass | ||
| else: | ||
| assert 1 == 2 | ||
| def test_parse_no_timezone(): | ||
| """issue 4 - Handle datetime string without timezone | ||
| This tests what happens when you parse a date with no timezone. While not | ||
| strictly correct this is quite common. I'll assume UTC for the time zone | ||
| in this case. | ||
| """ | ||
| d = iso8601.parse_date("2007-01-01T08:00:00") | ||
| assert d.year == 2007 | ||
| assert d.month == 1 | ||
| assert d.day == 1 | ||
| assert d.hour == 8 | ||
| assert d.minute == 0 | ||
| assert d.second == 0 | ||
| assert d.microsecond == 0 | ||
| assert d.tzinfo == iso8601.UTC | ||
| def test_parse_no_timezone_different_default(): | ||
| tz = iso8601.FixedOffset(2, 0, "test offset") | ||
| d = iso8601.parse_date("2007-01-01T08:00:00", default_timezone=tz) | ||
| assert d.tzinfo == tz | ||
| def test_space_separator(): | ||
| """Handle a separator other than T | ||
| """ | ||
| d = iso8601.parse_date("2007-06-23 06:40:34.00Z") | ||
| assert d.year == 2007 | ||
| assert d.month == 6 | ||
| assert d.day == 23 | ||
| assert d.hour == 6 | ||
| assert d.minute == 40 | ||
| assert d.second == 34 | ||
| assert d.microsecond == 0 | ||
| assert d.tzinfo == iso8601.UTC |
+30
-0
@@ -8,2 +8,32 @@ --------------------- | ||
| 1.4.0 | ||
| ----- | ||
| IMPROVEMENTS | ||
| ~~~~~~~~~~~~ | ||
| * Drop Python 3.3 support, and test on 3.5 and 3.6. | ||
| (Jelmer Vernooij) | ||
| * Add support for Python 3.7 and 3.8. | ||
| (Matthew Treinish) | ||
| * Improve readability of SubUnit v2 spec. | ||
| (Sergey Bronnikov) | ||
| * Add license to setup.py. (Sergiu) | ||
| BUGFIXES | ||
| ~~~~~~~~ | ||
| * Migrate Gtk interface to GObject introspection. | ||
| (Haikel Guemar) | ||
| * Fix file open for python3. (Quique Llorente) | ||
| * Check written bytes are not None before summing them to offset. | ||
| (Federico Ressi, #1845631) | ||
| * Correctly handle py3 RawIOBase read(). (Stephen Finucane, partially #1813147) | ||
| 1.3.0 | ||
@@ -10,0 +40,0 @@ ----- |
+41
-21
| Metadata-Version: 2.1 | ||
| Name: python-subunit | ||
| Version: 1.3.0 | ||
| Version: 1.4.0 | ||
| Summary: Python implementation of subunit test streaming protocol | ||
@@ -8,3 +8,5 @@ Home-page: http://launchpad.net/subunit | ||
| Author-email: subunit-dev@lists.launchpad.net | ||
| License: UNKNOWN | ||
| License: Apache-2.0 or BSD | ||
| Project-URL: Bug Tracker, https://bugs.launchpad.net/subunit | ||
| Project-URL: Source Code, https://github.com/testing-cabal/subunit/ | ||
| Description: | ||
@@ -275,23 +277,35 @@ subunit: A streaming protocol for test results | ||
| Feature bits: | ||
| Bit 11 - mask 0x0800 - Test id present. | ||
| Bit 10 - mask 0x0400 - Routing code present. | ||
| Bit 9 - mask 0x0200 - Timestamp present. | ||
| Bit 8 - mask 0x0100 - Test is 'runnable'. | ||
| Bit 7 - mask 0x0080 - Tags are present. | ||
| Bit 6 - mask 0x0040 - File content is present. | ||
| Bit 5 - mask 0x0020 - File MIME type is present. | ||
| Bit 4 - mask 0x0010 - EOF marker. | ||
| Bit 3 - mask 0x0008 - Must be zero in version 2. | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 11 | mask 0x0800 | Test id present. | | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 10 | mask 0x0400 | Routing code present. | | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 9 | mask 0x0200 | Timestamp present. | | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 8 | mask 0x0100 | Test is 'runnable'. | | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 7 | mask 0x0080 | Tags are present. | | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 6 | mask 0x0040 | File content is present. | | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 5 | mask 0x0020 | File MIME type is present.| | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 4 | mask 0x0010 | EOF marker. | | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 3 | mask 0x0008 | Must be zero in version 2.| | ||
| +---------+-------------+---------------------------+ | ||
| Test status gets three bits: | ||
| Bit 2 | Bit 1 | Bit 0 - mask 0x0007 - A test status enum lookup: | ||
| 000 - undefined / no test | ||
| 001 - Enumeration / existence | ||
| 002 - In progress | ||
| 003 - Success | ||
| 004 - Unexpected Success | ||
| 005 - Skipped | ||
| 006 - Failed | ||
| 007 - Expected failure | ||
| * 000 - undefined / no test | ||
| * 001 - Enumeration / existence | ||
| * 002 - In progress | ||
| * 003 - Success | ||
| * 004 - Unexpected Success | ||
| * 005 - Skipped | ||
| * 006 - Failed | ||
| * 007 - Expected failure | ||
| After the flags field is a number field giving the length in bytes for the | ||
@@ -496,6 +510,12 @@ entire packet including the signature and the checksum. This length must | ||
| Classifier: Intended Audience :: Developers | ||
| Classifier: Operating System :: OS Independent | ||
| Classifier: Programming Language :: Python | ||
| Classifier: Programming Language :: Python :: 2.7 | ||
| Classifier: Programming Language :: Python :: 3 | ||
| Classifier: Programming Language :: Python | ||
| Classifier: Programming Language :: Python :: 3.5 | ||
| Classifier: Programming Language :: Python :: 3.6 | ||
| Classifier: Programming Language :: Python :: 3.7 | ||
| Classifier: Programming Language :: Python :: 3.8 | ||
| Classifier: Topic :: Software Development :: Testing | ||
| Provides-Extra: docs | ||
| Provides-Extra: test | ||
| Provides-Extra: docs |
| Metadata-Version: 2.1 | ||
| Name: python-subunit | ||
| Version: 1.3.0 | ||
| Version: 1.4.0 | ||
| Summary: Python implementation of subunit test streaming protocol | ||
@@ -8,3 +8,5 @@ Home-page: http://launchpad.net/subunit | ||
| Author-email: subunit-dev@lists.launchpad.net | ||
| License: UNKNOWN | ||
| License: Apache-2.0 or BSD | ||
| Project-URL: Bug Tracker, https://bugs.launchpad.net/subunit | ||
| Project-URL: Source Code, https://github.com/testing-cabal/subunit/ | ||
| Description: | ||
@@ -275,23 +277,35 @@ subunit: A streaming protocol for test results | ||
| Feature bits: | ||
| Bit 11 - mask 0x0800 - Test id present. | ||
| Bit 10 - mask 0x0400 - Routing code present. | ||
| Bit 9 - mask 0x0200 - Timestamp present. | ||
| Bit 8 - mask 0x0100 - Test is 'runnable'. | ||
| Bit 7 - mask 0x0080 - Tags are present. | ||
| Bit 6 - mask 0x0040 - File content is present. | ||
| Bit 5 - mask 0x0020 - File MIME type is present. | ||
| Bit 4 - mask 0x0010 - EOF marker. | ||
| Bit 3 - mask 0x0008 - Must be zero in version 2. | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 11 | mask 0x0800 | Test id present. | | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 10 | mask 0x0400 | Routing code present. | | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 9 | mask 0x0200 | Timestamp present. | | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 8 | mask 0x0100 | Test is 'runnable'. | | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 7 | mask 0x0080 | Tags are present. | | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 6 | mask 0x0040 | File content is present. | | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 5 | mask 0x0020 | File MIME type is present.| | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 4 | mask 0x0010 | EOF marker. | | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 3 | mask 0x0008 | Must be zero in version 2.| | ||
| +---------+-------------+---------------------------+ | ||
| Test status gets three bits: | ||
| Bit 2 | Bit 1 | Bit 0 - mask 0x0007 - A test status enum lookup: | ||
| 000 - undefined / no test | ||
| 001 - Enumeration / existence | ||
| 002 - In progress | ||
| 003 - Success | ||
| 004 - Unexpected Success | ||
| 005 - Skipped | ||
| 006 - Failed | ||
| 007 - Expected failure | ||
| * 000 - undefined / no test | ||
| * 001 - Enumeration / existence | ||
| * 002 - In progress | ||
| * 003 - Success | ||
| * 004 - Unexpected Success | ||
| * 005 - Skipped | ||
| * 006 - Failed | ||
| * 007 - Expected failure | ||
| After the flags field is a number field giving the length in bytes for the | ||
@@ -496,6 +510,12 @@ entire packet including the signature and the checksum. This length must | ||
| Classifier: Intended Audience :: Developers | ||
| Classifier: Operating System :: OS Independent | ||
| Classifier: Programming Language :: Python | ||
| Classifier: Programming Language :: Python :: 2.7 | ||
| Classifier: Programming Language :: Python :: 3 | ||
| Classifier: Programming Language :: Python | ||
| Classifier: Programming Language :: Python :: 3.5 | ||
| Classifier: Programming Language :: Python :: 3.6 | ||
| Classifier: Programming Language :: Python :: 3.7 | ||
| Classifier: Programming Language :: Python :: 3.8 | ||
| Classifier: Topic :: Software Development :: Testing | ||
| Provides-Extra: docs | ||
| Provides-Extra: test | ||
| Provides-Extra: docs |
@@ -0,4 +1,9 @@ | ||
| .travis.yml | ||
| Apache-2.0 | ||
| BSD | ||
| COPYING | ||
| MANIFEST.in | ||
| NEWS | ||
| README.rst | ||
| all_tests.py | ||
| setup.cfg | ||
@@ -20,2 +25,7 @@ setup.py | ||
| filters/tap2subunit | ||
| python/iso8601/LICENSE | ||
| python/iso8601/README | ||
| python/iso8601/README.subunit | ||
| python/iso8601/setup.py | ||
| python/iso8601/test_iso8601.py | ||
| python/subunit/__init__.py | ||
@@ -52,4 +62,3 @@ python/subunit/_output.py | ||
| python_subunit.egg-info/dependency_links.txt | ||
| python_subunit.egg-info/pbr.json | ||
| python_subunit.egg-info/requires.txt | ||
| python_subunit.egg-info/top_level.txt |
@@ -156,3 +156,3 @@ # | ||
| __version__ = (1, 3, 0, 'final', 0) | ||
| __version__ = (1, 4, 0, 'final', 0) | ||
@@ -583,6 +583,6 @@ PROGRESS_SET = 0 | ||
| :param pipe: A file-like object supporting readlines(). | ||
| :param pipe: A file-like object supporting __iter__. | ||
| :return: None. | ||
| """ | ||
| for line in pipe.readlines(): | ||
| for line in pipe: | ||
| self.lineReceived(line) | ||
@@ -589,0 +589,0 @@ self.lostConnection() |
@@ -8,3 +8,3 @@ # subunit: extensions to python unittest to get test results from subprocesses. | ||
| # compliance with one of these two licences. | ||
| # | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
@@ -147,3 +147,3 @@ # distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT | ||
| else: | ||
| output_to = file(output_path, 'wb') | ||
| output_to = open(output_path, 'w') | ||
@@ -150,0 +150,0 @@ try: |
+119
-92
@@ -75,2 +75,21 @@ # | ||
| def read_exactly(stream, size): | ||
| """Read exactly size bytes from stream. | ||
| :param stream: A file like object to read bytes from. Must support | ||
| read(<count>) and return bytes. | ||
| :param size: The number of bytes to retrieve. | ||
| """ | ||
| data = b'' | ||
| remaining = size | ||
| while remaining: | ||
| read = stream.read(remaining) | ||
| if len(read) == 0: | ||
| raise ParseError('Short read - got %d bytes, wanted %d bytes' % ( | ||
| len(data), size)) | ||
| data += read | ||
| remaining -= len(read) | ||
| return data | ||
| class ParseError(Exception): | ||
@@ -82,3 +101,3 @@ """Used to pass error messages within the parser.""" | ||
| """Convert StreamResult API calls to bytes. | ||
| The StreamResult API is defined by testtools.StreamResult. | ||
@@ -228,2 +247,4 @@ """ | ||
| written = self.output_stream.write(view[offset:]) | ||
| if written is None: | ||
| break | ||
| offset += written | ||
@@ -280,3 +301,3 @@ else: | ||
| """Parse source and emit events to result. | ||
| This is a blocking call: it will run until EOF is detected on source. | ||
@@ -410,91 +431,98 @@ """ | ||
| def _parse(self, packet, result): | ||
| # 2 bytes flags, at most 3 bytes length. | ||
| packet.append(self.source.read(5)) | ||
| if len(packet[-1]) != 5: | ||
| raise ParseError( | ||
| 'Short read - got %d bytes, wanted 5' % len(packet[-1])) | ||
| flag_bytes = packet[-1][:2] | ||
| flags = struct.unpack(FMT_16, flag_bytes)[0] | ||
| length, consumed = self._parse_varint( | ||
| packet[-1], 2, max_3_bytes=True) | ||
| remainder = self.source.read(length - 6) | ||
| if len(remainder) != length - 6: | ||
| raise ParseError( | ||
| 'Short read - got %d bytes, wanted %d bytes' % ( | ||
| len(remainder), length - 6)) | ||
| if consumed != 3: | ||
| # Avoid having to parse torn values | ||
| packet[-1] += remainder | ||
| pos = 2 + consumed | ||
| else: | ||
| # Avoid copying potentially lots of data. | ||
| packet.append(remainder) | ||
| pos = 0 | ||
| crc = zlib.crc32(packet[0]) | ||
| for fragment in packet[1:-1]: | ||
| crc = zlib.crc32(fragment, crc) | ||
| crc = zlib.crc32(packet[-1][:-4], crc) & 0xffffffff | ||
| packet_crc = struct.unpack(FMT_32, packet[-1][-4:])[0] | ||
| if crc != packet_crc: | ||
| # Bad CRC, report it and stop parsing the packet. | ||
| raise ParseError( | ||
| 'Bad checksum - calculated (0x%x), stored (0x%x)' | ||
| % (crc, packet_crc)) | ||
| if safe_hasattr(builtins, 'memoryview'): | ||
| body = memoryview(packet[-1]) | ||
| else: | ||
| body = packet[-1] | ||
| # Discard CRC-32 | ||
| body = body[:-4] | ||
| # One packet could have both file and status data; the Python API | ||
| # presents these separately (perhaps it shouldn't?) | ||
| if flags & FLAG_TIMESTAMP: | ||
| seconds = struct.unpack(FMT_32, self._to_bytes(body, pos, 4))[0] | ||
| nanoseconds, consumed = self._parse_varint(body, pos+4) | ||
| pos = pos + 4 + consumed | ||
| timestamp = EPOCH + datetime.timedelta( | ||
| seconds=seconds, microseconds=nanoseconds/1000) | ||
| else: | ||
| timestamp = None | ||
| if flags & FLAG_TEST_ID: | ||
| test_id, pos = self._read_utf8(body, pos) | ||
| else: | ||
| test_id = None | ||
| if flags & FLAG_TAGS: | ||
| tag_count, consumed = self._parse_varint(body, pos) | ||
| pos += consumed | ||
| test_tags = set() | ||
| for _ in range(tag_count): | ||
| tag, pos = self._read_utf8(body, pos) | ||
| test_tags.add(tag) | ||
| else: | ||
| test_tags = None | ||
| if flags & FLAG_MIME_TYPE: | ||
| mime_type, pos = self._read_utf8(body, pos) | ||
| else: | ||
| mime_type = None | ||
| if flags & FLAG_FILE_CONTENT: | ||
| file_name, pos = self._read_utf8(body, pos) | ||
| content_length, consumed = self._parse_varint(body, pos) | ||
| pos += consumed | ||
| file_bytes = self._to_bytes(body, pos, content_length) | ||
| if len(file_bytes) != content_length: | ||
| raise ParseError('File content extends past end of packet: ' | ||
| 'claimed %d bytes, %d available' % ( | ||
| content_length, len(file_bytes))) | ||
| pos += content_length | ||
| else: | ||
| file_name = None | ||
| file_bytes = None | ||
| if flags & FLAG_ROUTE_CODE: | ||
| route_code, pos = self._read_utf8(body, pos) | ||
| else: | ||
| route_code = None | ||
| runnable = bool(flags & FLAG_RUNNABLE) | ||
| eof = bool(flags & FLAG_EOF) | ||
| test_status = self.status_lookup[flags & 0x0007] | ||
| result.status(test_id=test_id, test_status=test_status, | ||
| test_tags=test_tags, runnable=runnable, mime_type=mime_type, | ||
| eof=eof, file_name=file_name, file_bytes=file_bytes, | ||
| route_code=route_code, timestamp=timestamp) | ||
| # 2 bytes flags, at most 3 bytes length. | ||
| header = read_exactly(self.source, 5) | ||
| packet.append(header) | ||
| flags = struct.unpack(FMT_16, header[:2])[0] | ||
| length, consumed = self._parse_varint(header, 2, max_3_bytes=True) | ||
| remainder = read_exactly(self.source, length - 6) | ||
| if consumed != 3: | ||
| # Avoid having to parse torn values | ||
| packet[-1] += remainder | ||
| pos = 2 + consumed | ||
| else: | ||
| # Avoid copying potentially lots of data. | ||
| packet.append(remainder) | ||
| pos = 0 | ||
| crc = zlib.crc32(packet[0]) | ||
| for fragment in packet[1:-1]: | ||
| crc = zlib.crc32(fragment, crc) | ||
| crc = zlib.crc32(packet[-1][:-4], crc) & 0xffffffff | ||
| packet_crc = struct.unpack(FMT_32, packet[-1][-4:])[0] | ||
| if crc != packet_crc: | ||
| # Bad CRC, report it and stop parsing the packet. | ||
| raise ParseError( | ||
| 'Bad checksum - calculated (0x%x), stored (0x%x)' % ( | ||
| crc, packet_crc)) | ||
| if safe_hasattr(builtins, 'memoryview'): | ||
| body = memoryview(packet[-1]) | ||
| else: | ||
| body = packet[-1] | ||
| # Discard CRC-32 | ||
| body = body[:-4] | ||
| # One packet could have both file and status data; the Python API | ||
| # presents these separately (perhaps it shouldn't?) | ||
| if flags & FLAG_TIMESTAMP: | ||
| seconds = struct.unpack(FMT_32, self._to_bytes(body, pos, 4))[0] | ||
| nanoseconds, consumed = self._parse_varint(body, pos+4) | ||
| pos = pos + 4 + consumed | ||
| timestamp = EPOCH + datetime.timedelta( | ||
| seconds=seconds, microseconds=nanoseconds/1000) | ||
| else: | ||
| timestamp = None | ||
| if flags & FLAG_TEST_ID: | ||
| test_id, pos = self._read_utf8(body, pos) | ||
| else: | ||
| test_id = None | ||
| if flags & FLAG_TAGS: | ||
| tag_count, consumed = self._parse_varint(body, pos) | ||
| pos += consumed | ||
| test_tags = set() | ||
| for _ in range(tag_count): | ||
| tag, pos = self._read_utf8(body, pos) | ||
| test_tags.add(tag) | ||
| else: | ||
| test_tags = None | ||
| if flags & FLAG_MIME_TYPE: | ||
| mime_type, pos = self._read_utf8(body, pos) | ||
| else: | ||
| mime_type = None | ||
| if flags & FLAG_FILE_CONTENT: | ||
| file_name, pos = self._read_utf8(body, pos) | ||
| content_length, consumed = self._parse_varint(body, pos) | ||
| pos += consumed | ||
| file_bytes = self._to_bytes(body, pos, content_length) | ||
| if len(file_bytes) != content_length: | ||
| raise ParseError('File content extends past end of packet: ' | ||
| 'claimed %d bytes, %d available' % ( | ||
| content_length, len(file_bytes))) | ||
| pos += content_length | ||
| else: | ||
| file_name = None | ||
| file_bytes = None | ||
| if flags & FLAG_ROUTE_CODE: | ||
| route_code, pos = self._read_utf8(body, pos) | ||
| else: | ||
| route_code = None | ||
| runnable = bool(flags & FLAG_RUNNABLE) | ||
| eof = bool(flags & FLAG_EOF) | ||
| test_status = self.status_lookup[flags & 0x0007] | ||
| result.status( | ||
| test_id=test_id, test_status=test_status, | ||
| test_tags=test_tags, runnable=runnable, mime_type=mime_type, | ||
| eof=eof, file_name=file_name, file_bytes=file_bytes, | ||
| route_code=route_code, timestamp=timestamp) | ||
| __call__ = run | ||
@@ -523,2 +551,1 @@ | ||
| raise ParseError('UTF8 string at offset %d is not UTF8' % (pos-2,)) | ||
+29
-17
@@ -266,23 +266,35 @@ | ||
| Feature bits: | ||
| Bit 11 - mask 0x0800 - Test id present. | ||
| Bit 10 - mask 0x0400 - Routing code present. | ||
| Bit 9 - mask 0x0200 - Timestamp present. | ||
| Bit 8 - mask 0x0100 - Test is 'runnable'. | ||
| Bit 7 - mask 0x0080 - Tags are present. | ||
| Bit 6 - mask 0x0040 - File content is present. | ||
| Bit 5 - mask 0x0020 - File MIME type is present. | ||
| Bit 4 - mask 0x0010 - EOF marker. | ||
| Bit 3 - mask 0x0008 - Must be zero in version 2. | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 11 | mask 0x0800 | Test id present. | | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 10 | mask 0x0400 | Routing code present. | | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 9 | mask 0x0200 | Timestamp present. | | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 8 | mask 0x0100 | Test is 'runnable'. | | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 7 | mask 0x0080 | Tags are present. | | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 6 | mask 0x0040 | File content is present. | | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 5 | mask 0x0020 | File MIME type is present.| | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 4 | mask 0x0010 | EOF marker. | | ||
| +---------+-------------+---------------------------+ | ||
| | Bit 3 | mask 0x0008 | Must be zero in version 2.| | ||
| +---------+-------------+---------------------------+ | ||
| Test status gets three bits: | ||
| Bit 2 | Bit 1 | Bit 0 - mask 0x0007 - A test status enum lookup: | ||
| 000 - undefined / no test | ||
| 001 - Enumeration / existence | ||
| 002 - In progress | ||
| 003 - Success | ||
| 004 - Unexpected Success | ||
| 005 - Skipped | ||
| 006 - Failed | ||
| 007 - Expected failure | ||
| * 000 - undefined / no test | ||
| * 001 - Enumeration / existence | ||
| * 002 - In progress | ||
| * 003 - Success | ||
| * 004 - Unexpected Success | ||
| * 005 - Skipped | ||
| * 006 - Failed | ||
| * 007 - Expected failure | ||
| After the flags field is a number field giving the length in bytes for the | ||
@@ -289,0 +301,0 @@ entire packet including the signature and the checksum. This length must |
+12
-1
@@ -56,4 +56,10 @@ #!/usr/bin/env python | ||
| 'Intended Audience :: Developers', | ||
| 'Operating System :: OS Independent', | ||
| 'Programming Language :: Python', | ||
| 'Programming Language :: Python :: 2.7', | ||
| 'Programming Language :: Python :: 3', | ||
| 'Programming Language :: Python', | ||
| 'Programming Language :: Python :: 3.5', | ||
| 'Programming Language :: Python :: 3.6', | ||
| 'Programming Language :: Python :: 3.7', | ||
| 'Programming Language :: Python :: 3.8', | ||
| 'Topic :: Software Development :: Testing', | ||
@@ -65,2 +71,7 @@ ], | ||
| url='http://launchpad.net/subunit', | ||
| license='Apache-2.0 or BSD', | ||
| project_urls={ | ||
| "Bug Tracker": "https://bugs.launchpad.net/subunit", | ||
| "Source Code": "https://github.com/testing-cabal/subunit/", | ||
| }, | ||
| packages=['subunit', 'subunit.tests'], | ||
@@ -67,0 +78,0 @@ package_dir={'subunit': 'python/subunit'}, |
| {"is_release": false, "git_version": "2a4d9f6"} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
471919
6.26%63
16.67%7381
2.67%