Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test suite fails depending on CPU (micro)architecture #183

Open
mia-0 opened this issue Jul 20, 2022 · 1 comment
Open

Test suite fails depending on CPU (micro)architecture #183

mia-0 opened this issue Jul 20, 2022 · 1 comment

Comments

@mia-0
Copy link

mia-0 commented Jul 20, 2022

The test suite fails on all non-x86_64 architectures and some x86_64 CPUs. I ran into this problem while trying to package it for openSUSE. Here’s a log excerpt of a failed aarch64 build:

[   27s] ============================= test session starts ==============================
[   27s] platform linux -- Python 3.8.13, pytest-7.1.1, pluggy-1.0.0 -- /usr/bin/python3.8
[   27s] cachedir: .pytest_cache
[   27s] rootdir: /home/abuild/rpmbuild/BUILD/svgpathtools-1.5.1
[   28s] collecting ... collected 90 items
[   28s] 
[   28s] test/test_bezier.py::TestBezier2Polynomial::test_bezier2polynomial PASSED [  1%]
[   28s] test/test_bezier.py::TestPolynomial2Bezier::test_polynomial2bezier PASSED [  2%]
[   28s] test/test_document.py::TestDocument::test_from_file_object PASSED        [  3%]
[   28s] test/test_document.py::TestDocument::test_from_file_path PASSED          [  4%]
[   28s] test/test_document.py::TestDocument::test_from_file_path_string PASSED   [  5%]
[   28s] test/test_document.py::TestDocument::test_from_string PASSED             [  6%]
[   28s] test/test_document.py::TestDocument::test_from_stringio PASSED           [  7%]
[   28s] test/test_generation.py::TestGeneration::test_normalizing PASSED         [  8%]
[   28s] test/test_generation.py::TestGeneration::test_path_parsing FAILED        [ 10%]
[   28s] test/test_groups.py::TestGroups::test_add_group PASSED                   [ 11%]
[   28s] test/test_groups.py::TestGroups::test_group_flatten PASSED               [ 12%]
[   28s] test/test_groups.py::TestGroups::test_nested_group PASSED                [ 13%]
[   28s] test/test_parsing.py::TestParser::test_errors PASSED                     [ 14%]
[   28s] test/test_parsing.py::TestParser::test_issue_99 PASSED                   [ 15%]
[   28s] test/test_parsing.py::TestParser::test_negative PASSED                   [ 16%]
[   28s] test/test_parsing.py::TestParser::test_numbers PASSED                    [ 17%]
[   28s] test/test_parsing.py::TestParser::test_others PASSED                     [ 18%]
[   28s] test/test_parsing.py::TestParser::test_pathd_init PASSED                 [ 20%]
[   28s] test/test_parsing.py::TestParser::test_svg_examples PASSED               [ 21%]
[   28s] test/test_parsing.py::TestParser::test_transform PASSED                  [ 22%]
[   28s] test/test_path.py::LineTest::test_equality PASSED                        [ 23%]
[   28s] test/test_path.py::LineTest::test_lines PASSED                           [ 24%]
[   29s] test/test_path.py::LineTest::test_point_to_t PASSED                      [ 25%]
[   29s] test/test_path.py::LineTest::test_radialrange PASSED                     [ 26%]
[   29s] test/test_path.py::CubicBezierTest::test_approx_circle PASSED            [ 27%]
[   29s] test/test_path.py::CubicBezierTest::test_equality PASSED                 [ 28%]
[   29s] test/test_path.py::CubicBezierTest::test_length PASSED                   [ 30%]
[   29s] test/test_path.py::CubicBezierTest::test_svg_examples PASSED             [ 31%]
[   29s] test/test_path.py::QuadraticBezierTest::test_equality PASSED             [ 32%]
[   29s] test/test_path.py::QuadraticBezierTest::test_length PASSED               [ 33%]
[   29s] test/test_path.py::QuadraticBezierTest::test_svg_examples PASSED         [ 34%]
[   30s] test/test_path.py::ArcTest::test_approx_cubic PASSED                     [ 35%]
[   30s] test/test_path.py::ArcTest::test_approx_quad PASSED                      [ 36%]
[   30s] test/test_path.py::ArcTest::test_equality PASSED                         [ 37%]
[   30s] test/test_path.py::ArcTest::test_length PASSED                           [ 38%]
[   30s] test/test_path.py::ArcTest::test_point PASSED                            [ 40%]
[   32s] test/test_path.py::ArcTest::test_point_to_t PASSED                       [ 41%]
[   32s] test/test_path.py::ArcTest::test_trusting_acos PASSED                    [ 42%]
[   32s] test/test_path.py::TestPath::test_circle PASSED                          [ 43%]
[   32s] test/test_path.py::TestPath::test_continuous_subpaths PASSED             [ 44%]
[   32s] test/test_path.py::TestPath::test_cropped PASSED                         [ 45%]
[   32s] test/test_path.py::TestPath::test_d PASSED                               [ 46%]
[   32s] test/test_path.py::TestPath::test_equality PASSED                        [ 47%]
[   32s] test/test_path.py::TestPath::test_hash FAILED                            [ 48%]
[   32s] test/test_path.py::TestPath::test_repr PASSED                            [ 50%]
[   32s] test/test_path.py::TestPath::test_svg_specs PASSED                       [ 51%]
[   32s] test/test_path.py::TestPath::test_transform_scale PASSED                 [ 52%]
[   33s] test/test_path.py::Test_ilength::test_ilength_arcs PASSED                [ 53%]
[   33s] test/test_path.py::Test_ilength::test_ilength_cubics PASSED              [ 54%]
[   33s] test/test_path.py::Test_ilength::test_ilength_exceptions PASSED          [ 55%]
[   33s] test/test_path.py::Test_ilength::test_ilength_lines PASSED               [ 56%]
[   34s] test/test_path.py::Test_ilength::test_ilength_paths PASSED               [ 57%]
[   34s] test/test_path.py::Test_ilength::test_ilength_quadratics PASSED          [ 58%]
[   34s] test/test_path.py::Test_intersect::test_arc_arc_0 PASSED                 [ 60%]
[   34s] test/test_path.py::Test_intersect::test_arc_arc_1 PASSED                 [ 61%]
[   34s] test/test_path.py::Test_intersect::test_arc_arc_2 PASSED                 [ 62%]
[   34s] test/test_path.py::Test_intersect::test_arc_arc_same_circle PASSED       [ 63%]
[   34s] test/test_path.py::Test_intersect::test_arc_arc_tangent_circles_inside PASSED [ 64%]
[   34s] test/test_path.py::Test_intersect::test_arc_arc_tangent_circles_outside PASSED [ 65%]
[   37s] test/test_path.py::Test_intersect::test_arc_line PASSED                  [ 66%]
[   38s] test/test_path.py::Test_intersect::test_intersect PASSED                 [ 67%]
[   38s] test/test_path.py::Test_intersect::test_intersect_arc_line_1 PASSED      [ 68%]
[   38s] test/test_path.py::Test_intersect::test_intersect_arc_line_2 PASSED      [ 70%]
[   38s] test/test_path.py::Test_intersect::test_intersect_arc_line_3 PASSED      [ 71%]
[   38s] test/test_path.py::Test_intersect::test_intersect_arc_line_disjoint_bboxes PASSED [ 72%]
[   38s] test/test_path.py::Test_intersect::test_line_line_0 PASSED               [ 73%]
[   38s] test/test_path.py::Test_intersect::test_line_line_1 PASSED               [ 74%]
[   38s] test/test_path.py::TestPathTools::test_bpoints2bezier PASSED             [ 75%]
[   38s] test/test_path.py::TestPathTools::test_closest_point_in_path PASSED      [ 76%]
[   38s] test/test_path.py::TestPathTools::test_farthest_point_in_path PASSED     [ 77%]
[   38s] test/test_path.py::TestPathTools::test_is_bezier_path PASSED             [ 78%]
[   38s] test/test_path.py::TestPathTools::test_is_bezier_segment PASSED          [ 80%]
[   38s] test/test_path.py::TestPathTools::test_is_contained_by PASSED            [ 81%]
[   38s] test/test_path.py::TestPathTools::test_path_area PASSED                  [ 82%]
[   38s] test/test_path.py::TestPathTools::test_path_encloses_pt PASSED           [ 83%]
[   38s] test/test_path.py::TestPathTools::test_polynomial2bezier PASSED          [ 84%]
[   38s] test/test_path.py::TestPathBugs::test_issue_113 PASSED                   [ 85%]
[   38s] test/test_path.py::TestPathBugs::test_issue_71 PASSED                    [ 86%]
[   38s] test/test_path.py::TestPathBugs::test_issue_94 PASSED                    [ 87%]
[   38s] test/test_path.py::TestPathBugs::test_issue_95 PASSED                    [ 88%]
[   38s] test/test_polytools.py::Test_polytools::test_rational_limit PASSED       [ 90%]
[   38s] test/test_sax_groups.py::TestSaxGroups::test_parse_display PASSED        [ 91%]
[   38s] test/test_svg2paths.py::TestSVG2Paths::test_from_file_object PASSED      [ 92%]
[   38s] test/test_svg2paths.py::TestSVG2Paths::test_from_file_path PASSED        [ 93%]
[   38s] test/test_svg2paths.py::TestSVG2Paths::test_from_file_path_string PASSED [ 94%]
[   38s] test/test_svg2paths.py::TestSVG2Paths::test_from_string PASSED           [ 95%]
[   38s] test/test_svg2paths.py::TestSVG2Paths::test_from_stringio PASSED         [ 96%]
[   38s] test/test_svg2paths.py::TestSVG2Paths::test_rect2pathd PASSED            [ 97%]
[   38s] test/test_svg2paths.py::TestSVG2Paths::test_svg2paths_ellipses PASSED    [ 98%]
[   38s] test/test_svg2paths.py::TestSVG2Paths::test_svg2paths_polygons PASSED    [100%]
[   38s] 
[   38s] =================================== FAILURES ===================================
[   38s] _______________________ TestGeneration.test_path_parsing _______________________
[   38s] 
[   38s] self = <test_generation.TestGeneration testMethod=test_path_parsing>
[   38s] 
[   38s]     def test_path_parsing(self):
[   38s]         """Examples from the SVG spec"""
[   38s]         paths = [
[   38s]             'M 100,100 L 300,100 L 200,300 Z',
[   38s]             'M 0,0 L 50,20 M 100,100 L 300,100 L 200,300 Z',
[   38s]             'M 100,100 L 200,200',
[   38s]             'M 100,200 L 200,100 L -100,-200',
[   38s]             'M 100,200 C 100,100 250,100 250,200 S 400,300 400,200',
[   38s]             'M 100,200 C 100,100 400,100 400,200',
[   38s]             'M 100,500 C 25,400 475,400 400,500',
[   38s]             'M 100,800 C 175,700 325,700 400,800',
[   38s]             'M 600,200 C 675,100 975,100 900,200',
[   38s]             'M 600,500 C 600,350 900,650 900,500',
[   38s]             'M 600,800 C 625,700 725,700 750,800 S 875,900 900,800',
[   38s]             'M 200,300 Q 400,50 600,300 T 1000,300',
[   38s]             'M -3.4E+38,3.4E+38 L -3.4E-38,3.4E-38',
[   38s]             'M 0,0 L 50,20 M 50,20 L 200,100 Z',
[   38s]             'M 600,350 L 650,325 A 25,25 -30 0,1 700,300 L 750,275',
[   38s]         ]
[   38s]         float_paths = [
[   38s]             'M 100.0,100.0 L 300.0,100.0 L 200.0,300.0 L 100.0,100.0',
[   38s]             'M 0.0,0.0 L 50.0,20.0 M 100.0,100.0 L 300.0,100.0 L 200.0,300.0 L 100.0,100.0',
[   38s]             'M 100.0,100.0 L 200.0,200.0',
[   38s]             'M 100.0,200.0 L 200.0,100.0 L -100.0,-200.0',
[   38s]             'M 100.0,200.0 C 100.0,100.0 250.0,100.0 250.0,200.0 C 250.0,300.0 400.0,300.0 400.0,200.0',
[   38s]             'M 100.0,200.0 C 100.0,100.0 400.0,100.0 400.0,200.0',
[   38s]             'M 100.0,500.0 C 25.0,400.0 475.0,400.0 400.0,500.0',
[   38s]             'M 100.0,800.0 C 175.0,700.0 325.0,700.0 400.0,800.0',
[   38s]             'M 600.0,200.0 C 675.0,100.0 975.0,100.0 900.0,200.0',
[   38s]             'M 600.0,500.0 C 600.0,350.0 900.0,650.0 900.0,500.0',
[   38s]             'M 600.0,800.0 C 625.0,700.0 725.0,700.0 750.0,800.0 C 775.0,900.0 875.0,900.0 900.0,800.0',
[   38s]             'M 200.0,300.0 Q 400.0,50.0 600.0,300.0 Q 800.0,550.0 1000.0,300.0',
[   38s]             'M -3.4e+38,3.4e+38 L -3.4e-38,3.4e-38',
[   38s]             'M 0.0,0.0 L 50.0,20.0 L 200.0,100.0 L 50.0,20.0',
[   38s]             ('M 600.0,350.0 L 650.0,325.0 A 27.9508497187,27.9508497187 -30.0 0,1 700.0,300.0 L 750.0,275.0',  # Python 2
[   38s]              'M 600.0,350.0 L 650.0,325.0 A 27.95084971874737,27.95084971874737 -30.0 0,1 700.0,300.0 L 750.0,275.0')  # Python 3
[   38s]         ]
[   38s]     
[   38s]         for path, flpath in zip(paths[::-1], float_paths[::-1]):
[   38s]             # Note:  Python 3 and Python 2 differ in the number of digits
[   38s]             # truncated when returning a string representation of a float
[   38s]             parsed_path = parse_path(path)
[   38s]             res = parsed_path.d()
[   38s]             if isinstance(flpath, tuple):
[   38s]                 option3 = res == flpath[1]  # Python 3
[   38s]                 flpath = flpath[0]
[   38s]             else:
[   38s]                 option3 = False
[   38s]             option1 = res == path
[   38s]             option2 = res == flpath
[   38s]     
[   38s]             msg = ('\npath =\n {}\nflpath =\n {}\nparse_path(path).d() =\n {}'
[   38s]                    ''.format(path, flpath, res))
[   38s] >           self.assertTrue(option1 or option2 or option3, msg=msg)
[   38s] E           AssertionError: False is not true : 
[   38s] E           path =
[   38s] E            M 600,350 L 650,325 A 25,25 -30 0,1 700,300 L 750,275
[   38s] E           flpath =
[   38s] E            M 600.0,350.0 L 650.0,325.0 A 27.9508497187,27.9508497187 -30.0 0,1 700.0,300.0 L 750.0,275.0
[   38s] E           parse_path(path).d() =
[   38s] E            M 600.0,350.0 L 650.0,325.0 A 27.950849718747367,27.950849718747367 -30.0 0,1 700.0,300.0 L 750.0,275.0
[   38s] 
[   38s] test/test_generation.py:63: AssertionError
[   38s] ______________________________ TestPath.test_hash ______________________________
[   38s] 
[   38s] self = <test_path.TestPath testMethod=test_hash>
[   38s] 
[   38s]     def test_hash(self):
[   38s]         line1 = Line(600.5 + 350.5j, 650.5 + 325.5j)
[   38s]         arc1 = Arc(650 + 325j, 25 + 25j, -30, 0, 1, 700 + 300j)
[   38s]         arc2 = Arc(650 + 325j, 30 + 25j, -30, 0, 0, 700 + 300j)
[   38s]         cub1 = CubicBezier(650 + 325j, 25 + 25j, -30, 700 + 300j)
[   38s]         cub2 = CubicBezier(700 + 300j, 800 + 400j, 750 + 200j, 600 + 100j)
[   38s]         quad3 = QuadraticBezier(600 + 100j, 600, 600 + 300j)
[   38s]         linez = Line(600 + 300j, 600 + 350j)
[   38s]     
[   38s]         bezpath = Path(line1, cub1, cub2, quad3)
[   38s]         bezpathz = Path(line1, cub1, cub2, quad3, linez)
[   38s]         path = Path(line1, arc1, cub2, quad3)
[   38s]         pathz = Path(line1, arc1, cub2, quad3, linez)
[   38s]         lpath = Path(linez)
[   38s]         qpath = Path(quad3)
[   38s]         cpath = Path(cub1)
[   38s]         apath = Path(arc1, arc2)
[   38s]     
[   38s]         test_curves = [bezpath, bezpathz, path, pathz, lpath, qpath, cpath,
[   38s]                        apath, line1, arc1, arc2, cub1, cub2, quad3, linez]
[   38s]     
[   38s]         # this is necessary due to changes to the builtin `hash` function
[   38s]         user_hash_seed = os.environ.get("PYTHONHASHSEED", "")
[   38s]         os.environ["PYTHONHASHSEED"] = "314"
[   38s]         if version_info >= (3, 8):
[   38s]             expected_hashes = [
[   38s]                 -6073024107272494569, -2519772625496438197, 8726412907710383506,
[   38s]                 2132930052750006195, 3112548573593977871, 991446120749438306,
[   38s]                 -5589397644574569777, -4438808571483114580, -3125333407400456536,
[   38s]                 -4418099728831808951, 702646573139378041, -6331016786776229094,
[   38s]                 5053050772929443013, 6102272282813527681, -5385294438006156225
[   38s]             ]
[   38s]         elif (3, 2) <= version_info < (3, 8):
[   38s]             expected_hashes = [
[   38s]                 -5662973462929734898, 5166874115671195563, 5223434942701471389,
[   38s]                 -7224979960884350294, -5178990533869800243, -4003140762934044601,
[   38s]                 8575549467429100514, -6692132994808317852, 1594848578230132678,
[   38s]                 -6374833902132909499, 4188352014604112779, -5090374009174854814,
[   38s]                 -7093907105533857815, 2036243740727202243, -8108488067585685407
[   38s]             ]
[   38s]         else:
[   38s]     
[   38s]             expected_hashes = [
[   38s]                 -5762846476463470127, -138736730317965290, -2005041722222729058,
[   38s]                 8448700906794235291, -5178990533869800243, -4003140762934044601,
[   38s]                 8575549467429100514, 5166859065265868968, 1373103287265872323,
[   38s]                 -1022491904150314631, 4188352014604112779, -5090374009174854814,
[   38s]                 -7093907105533857815, 2036243740727202243, -8108488067585685407
[   38s]             ]
[   38s]     
[   38s]         if version_info.major == 2 and os.name == 'nt':
[   38s]             # the expected hash values for 2.7 apparently differed on Windows
[   38s]             # if you work in Windows and want to fix this test, please do
[   38s]             return
[   38s]     
[   38s]         for c, h in zip(test_curves, expected_hashes):
[   38s] >           self.assertTrue(hash(c) == h, msg="hash {} was expected for curve = {}".format(h, c))
[   38s] E           AssertionError: False is not true : hash 8726412907710383506 was expected for curve = Path(Line(start=(600.5+350.5j), end=(650.5+325.5j)),
[   38s] E                Arc(start=(650+325j), radius=(27.950849718747367+27.950849718747367j), rotation=-30, large_arc=False, sweep=True, end=(700+300j)),
[   38s] E                CubicBezier(start=(700+300j), control1=(800+400j), control2=(750+200j), end=(600+100j)),
[   38s] E                QuadraticBezier(start=(600+100j), control=600, end=(600+300j)))
[   38s] 
[   38s] test/test_path.py:778: AssertionError
[   38s] =============================== warnings summary ===============================
[   38s] test/test_path.py::QuadraticBezierTest::test_length
[   38s] test/test_path.py::TestPath::test_transform_scale
[   38s] test/test_path.py::Test_ilength::test_ilength_paths
[   38s] test/test_path.py::Test_ilength::test_ilength_quadratics
[   38s] test/test_path.py::TestPathBugs::test_issue_113
[   38s]   /home/abuild/rpmbuild/BUILDROOT/python-svgpathtools-1.5.1-13.1.aarch64/usr/lib/python3.8/site-packages/svgpathtools/path.py:942: RuntimeWarning: divide by zero encountered in double_scalars
[   38s]     logarand = (sqrt(c2) * (t1 + beta) + dq1_mag) / \
[   38s] 
[   38s] test/test_path.py::QuadraticBezierTest::test_length
[   38s] test/test_path.py::TestPath::test_transform_scale
[   38s] test/test_path.py::Test_ilength::test_ilength_paths
[   38s] test/test_path.py::Test_ilength::test_ilength_quadratics
[   38s] test/test_path.py::TestPathBugs::test_issue_113
[   38s]   /home/abuild/rpmbuild/BUILDROOT/python-svgpathtools-1.5.1-13.1.aarch64/usr/lib/python3.8/site-packages/svgpathtools/path.py:945: RuntimeWarning: invalid value encountered in double_scalars
[   38s]     gamma * sqrt(c2) * log(logarand)
[   38s] 
[   38s] test/test_path.py::QuadraticBezierTest::test_length
[   38s] test/test_path.py::Test_ilength::test_ilength_paths
[   38s] test/test_path.py::Test_ilength::test_ilength_quadratics
[   38s] test/test_path.py::TestPathBugs::test_issue_113
[   38s]   /home/abuild/rpmbuild/BUILDROOT/python-svgpathtools-1.5.1-13.1.aarch64/usr/lib/python3.8/site-packages/svgpathtools/path.py:942: RuntimeWarning: invalid value encountered in double_scalars
[   38s]     logarand = (sqrt(c2) * (t1 + beta) + dq1_mag) / \
[   38s] 
[   38s] test/test_path.py::Test_ilength::test_ilength_paths
[   38s] test/test_path.py::Test_ilength::test_ilength_quadratics
[   38s] test/test_path.py::TestPathBugs::test_issue_113
[   38s]   /home/abuild/rpmbuild/BUILDROOT/python-svgpathtools-1.5.1-13.1.aarch64/usr/lib/python3.8/site-packages/svgpathtools/path.py:945: RuntimeWarning: invalid value encountered in log
[   38s]     gamma * sqrt(c2) * log(logarand)
[   38s] 
[   38s] test/test_path.py::TestPathTools::test_path_area
[   38s]   /home/abuild/rpmbuild/BUILD/svgpathtools-1.5.1/test/test_path.py:1981: UserWarning: Skipping `test_path_area` as RUN_SLOW_TESTS is false.
[   38s]     warnings.warn("Skipping `test_path_area` as RUN_SLOW_TESTS is false.")
[   38s] 
[   38s] test/test_path.py::TestPathBugs::test_issue_113
[   38s]   /home/abuild/rpmbuild/BUILDROOT/python-svgpathtools-1.5.1-13.1.aarch64/usr/lib/python3.8/site-packages/svgpathtools/path.py:940: RuntimeWarning: invalid value encountered in sqrt
[   38s]     dq1_mag = sqrt(c2 * t1 ** 2 + c1 * t1 + c0)
[   38s] 
[   38s] test/test_path.py::TestPathBugs::test_issue_71
[   38s]   /home/abuild/rpmbuild/BUILDROOT/python-svgpathtools-1.5.1-13.1.aarch64/usr/lib/python3.8/site-packages/svgpathtools/path.py:2624: UserWarning: This attribute is deprecated, consider using isclosed() method instead.
[   38s]   
[   38s]   This attribute is kept for compatibility with scripts created using svg.path (v2.0). You can prevent this warning in the future by setting CLOSED_WARNING_ON=False.
[   38s]     warn(mes)
[   38s] 
[   38s] -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
[   38s] =========================== short test summary info ============================
[   38s] FAILED test/test_generation.py::TestGeneration::test_path_parsing - Assertion...
[   38s] FAILED test/test_path.py::TestPath::test_hash - AssertionError: False is not ...
[   38s] ================== 2 failed, 88 passed, 20 warnings in 11.10s ==================
@mathandy
Copy link
Owner

I'm usually on an apple SoC so I know this isn't all non-x86 architectures.

There's a known issue regarding the hash method being OS (and maybe also architecture) dependent. I'm not surprised to see fails related to precision when it comes to converting floats to strings on different systems.

I'd like to add GitHub CI actions to test for architecture-level issues like these if that's possible.

Any addition information you could give about when these tests fail is appreciated.

And of course, feel free to make a pull request if there are fixes you have in mind.

bmwiedemann pushed a commit to bmwiedemann/openSUSE that referenced this issue Jul 21, 2022
https://build.opensuse.org/request/show/990460
by user mia + RBrownFactory
- Update to 1.5.1
  * Fix float rounding error in elliptic arc radius check
    (#gh/mathandy/svgpathtools#171)
- Disable test suite because it can only work on specific CPU
  (micro-)architectures.
  (#gh/mathandy/svgpathtools#183)
- Update to 1.5.0
  * Fix implementation of points()
    (#gh/mathandy/svgpathtools#155)
  * Add support for rounded rectangles
    (#gh/mathandy/svgpathtools#161)
  * Fix Document.add_path for empty groups
    (#gh/mathandy/svgpathtools#170)
  * Allow file-like object as input to Documents ctor and
    svg2paths function
  * Add convenience functions for converting svgs contained in a
    string to paths
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants