diff --git a/setup.py b/setup.py index 97d6980..ef8516f 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ import codecs import os -VERSION = '1.2.6' +VERSION = '1.3' AUTHOR_NAME = 'Andy Port' AUTHOR_EMAIL = 'AndyAPort@gmail.com' diff --git a/svgpathtools/bezier.py b/svgpathtools/bezier.py index 7c82834..db4c869 100644 --- a/svgpathtools/bezier.py +++ b/svgpathtools/bezier.py @@ -5,6 +5,8 @@ points given by their standard representation.""" # External dependencies: from __future__ import division, absolute_import, print_function +from builtins import range +from builtins import object from math import factorial as fac, ceil, log, sqrt from numpy import poly1d diff --git a/svgpathtools/misctools.py b/svgpathtools/misctools.py index 787d000..5deb0bc 100644 --- a/svgpathtools/misctools.py +++ b/svgpathtools/misctools.py @@ -3,6 +3,7 @@ aren't specific to SVGs or related mathematical objects.""" # External dependencies: from __future__ import division, absolute_import, print_function +from builtins import range import os import sys import webbrowser diff --git a/svgpathtools/path.py b/svgpathtools/path.py index 1484b5a..f14ce0a 100644 --- a/svgpathtools/path.py +++ b/svgpathtools/path.py @@ -4,6 +4,10 @@ Arc.""" # External dependencies from __future__ import division, absolute_import, print_function +from builtins import map +from builtins import zip +from builtins import range +from builtins import object from math import sqrt, cos, sin, acos, degrees, radians, log, pi from cmath import exp, sqrt as csqrt, phase from collections import MutableSequence @@ -355,7 +359,8 @@ def inv_arclength(curve, s, s_tol=ILENGTH_S_TOL, maxits=ILENGTH_MAXITS, if curve is a Path object, then seg is a segment in curve. error - used to compute lengths of cubics and arcs min_depth - used to compute lengths of cubics and arcs - Note: This function is not designed to be efficient.""" + Note: This function is not designed to be efficient, but if it's slower + than you need, make sure you have scipy installed.""" curve_length = curve.length(error=error, min_depth=min_depth) assert curve_length > 0 @@ -1514,7 +1519,7 @@ class Arc(object): u1poly_mag2 = real(u1poly)**2 + imag(u1poly)**2 t2s = polyroots01(u1poly_mag2 - 1) t1s = [self.phase2t(phase(u1poly(t2))) for t2 in t2s] - return zip(t1s, t2s) + return list(zip(t1s, t2s)) elif isinstance(other_seg, Arc): assert other_seg != self # This could be made explicit to increase efficiency @@ -2126,7 +2131,7 @@ class Path(MutableSequence): """returns a bounding box for the input Path object in the form (xmin, xmax, ymin, ymax).""" bbs = [seg.bbox() for seg in self._segments] - xmins, xmaxs, ymins, ymaxs = zip(*bbs) + xmins, xmaxs, ymins, ymaxs = list(zip(*bbs)) xmin = min(xmins) xmax = max(xmaxs) ymin = min(ymins) diff --git a/svgpathtools/paths2svg.py b/svgpathtools/paths2svg.py index d09ff57..48a4ff9 100644 --- a/svgpathtools/paths2svg.py +++ b/svgpathtools/paths2svg.py @@ -3,6 +3,8 @@ segments.""" # External dependencies: from __future__ import division, absolute_import, print_function +from builtins import zip +from builtins import str from math import ceil from os import getcwd, path as os_path, makedirs from xml.dom.minidom import parse as md_xml_parse @@ -74,7 +76,7 @@ def big_bounding_box(paths_n_stuff): raise TypeError( "paths_n_stuff can only contains Path, CubicBezier, " "QuadraticBezier, Line, and complex objects.") - xmins, xmaxs, ymins, ymaxs = zip(*bbs) + xmins, xmaxs, ymins, ymaxs = list(zip(*bbs)) xmin = min(xmins) xmax = max(xmaxs) ymin = min(ymins) diff --git a/svgpathtools/smoothing.py b/svgpathtools/smoothing.py index 3bd7015..33f763e 100644 --- a/svgpathtools/smoothing.py +++ b/svgpathtools/smoothing.py @@ -5,6 +5,7 @@ curves.""" from __future__ import division, absolute_import, print_function # Internal Dependencies +from builtins import range from .path import Path, CubicBezier, Line from .misctools import isclose from .paths2svg import disvg diff --git a/svgpathtools/svg2paths.py b/svgpathtools/svg2paths.py index c3b66f9..1d3274c 100644 --- a/svgpathtools/svg2paths.py +++ b/svgpathtools/svg2paths.py @@ -3,6 +3,7 @@ The main tool being the svg2paths() function.""" # External dependencies from __future__ import division, absolute_import, print_function +from builtins import zip from xml.dom.minidom import parse from os import path as os_path, getcwd from shutil import copyfile @@ -64,9 +65,9 @@ def svg2paths(svg_file_location, def dom2dict(element): """Converts DOM elements to dictionaries of attributes.""" - keys = element.attributes.keys() - values = [val.value for val in element.attributes.values()] - return dict(zip(keys, values)) + keys = list(element.attributes.keys()) + values = [val.value for val in list(element.attributes.values())] + return dict(list(zip(keys, values))) # Use minidom to extract path strings from input SVG paths = [dom2dict(el) for el in doc.getElementsByTagName('path')] diff --git a/test/test_bezier.py b/test/test_bezier.py index 4c82e93..6051610 100644 --- a/test/test_bezier.py +++ b/test/test_bezier.py @@ -1,5 +1,6 @@ from __future__ import division, absolute_import, print_function import numpy as np +from builtins import range import unittest from svgpathtools.bezier import * from svgpathtools.path import bpoints2bezier diff --git a/test/test_generation.py b/test/test_generation.py index c1047cc..e5ee9ca 100644 --- a/test/test_generation.py +++ b/test/test_generation.py @@ -1,13 +1,14 @@ # Note: This file was taken mostly as is from the svg.path module (v 2.0) #------------------------------------------------------------------------------ from __future__ import division, absolute_import, print_function +from builtins import zip import unittest from svgpathtools import * class TestGeneration(unittest.TestCase): - def test_svg_examples(self): + def test_path_parsing(self): """Examples from the SVG spec""" paths = [ 'M 100,100 L 300,100 L 200,300 Z', @@ -26,7 +27,7 @@ class TestGeneration(unittest.TestCase): 'M 0,0 L 50,20 M 50,20 L 200,100 Z', 'M 600,350 L 650,325 A 25,25 -30 0,1 700,300 L 750,275', ] - pathsf = [ + float_paths = [ 'M 100.0,100.0 L 300.0,100.0 L 200.0,300.0 L 100.0,100.0', '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', 'M 100.0,100.0 L 200.0,200.0', @@ -41,11 +42,32 @@ class TestGeneration(unittest.TestCase): 'M 200.0,300.0 Q 400.0,50.0 600.0,300.0 Q 800.0,550.0 1000.0,300.0', 'M -3.4e+38,3.4e+38 L -3.4e-38,3.4e-38', 'M 0.0,0.0 L 50.0,20.0 L 200.0,100.0 L 50.0,20.0', - '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' + ('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 + '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 ] - for k, path in enumerate(paths): - self.assertTrue(parse_path(path).d() in (path, pathsf[k])) + for path, flpath in zip(paths[::-1], float_paths[::-1]): + # Note: Python 3 and Python 2 differ in the number of digits + # truncated when returning a string representation of a float + parsed_path = parse_path(path) + res = parsed_path.d() + if isinstance(flpath, tuple): + option3 = res == flpath[1] # Python 3 + flpath = flpath[0] + else: + option3 = False + option1 = res == path + option2 = res == flpath + + msg = ('\npath =\n {}\nflpath =\n {}\nparse_path(path).d() =\n {}' + ''.format(path, flpath, res)) + self.assertTrue(option1 or option2 or option3, msg=msg) + + for flpath in float_paths[:-1]: + res = parse_path(flpath).d() + msg = ('\nflpath =\n {}\nparse_path(path).d() =\n {}' + ''.format(flpath, res)) + self.assertTrue(res == flpath, msg=msg) def test_normalizing(self): # Relative paths will be made absolute, subpaths merged if they can, @@ -54,3 +76,7 @@ class TestGeneration(unittest.TestCase): ps = 'M 0,0 L 340,-10 L 100,100 L 200,0' psf = 'M 0.0,0.0 L 340.0,-10.0 L 100.0,100.0 L 200.0,0.0' self.assertTrue(parse_path(path).d() in (ps, psf)) + + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_path.py b/test/test_path.py index 208a55b..b6fcaf6 100644 --- a/test/test_path.py +++ b/test/test_path.py @@ -1,5 +1,7 @@ # External dependencies from __future__ import division, absolute_import, print_function +from builtins import zip +from builtins import str import unittest from math import sqrt, pi from operator import itemgetter @@ -661,11 +663,11 @@ class TestPath(unittest.TestCase): class Test_ilength(unittest.TestCase): - def test_ilength(self): - # See svgpathtools.notes.inv_arclength.py for information on how these - # test values were generated (using the .length() method). - ############################################################## - # Lines + # See svgpathtools.notes.inv_arclength.py for information on how these + # test values were generated (using the .length() method). + ############################################################## + + def test_ilength_lines(self): l = Line(1, 3-1j) nodall = Line(1+1j, 1+1j) @@ -678,8 +680,7 @@ class Test_ilength(unittest.TestCase): for (l, t, s) in tests: self.assertAlmostEqual(l.ilength(s), t) - ############################################################### - # Quadratics + def test_ilength_quadratics(self): q1 = QuadraticBezier(200 + 300j, 400 + 50j, 600 + 300j) q2 = QuadraticBezier(200 + 300j, 400 + 50j, 500 + 200j) closedq = QuadraticBezier(6 + 2j, 5 - 1j, 6 + 2j) @@ -716,8 +717,7 @@ class Test_ilength(unittest.TestCase): print(t) raise - ############################################################### - # Cubics + def test_ilength_cubics(self): c1 = CubicBezier(200 + 300j, 400 + 50j, 600+100j, -200) symc = CubicBezier(1-2j, 10-1j, 10+1j, 1+2j) closedc = CubicBezier(1-2j, 10-1j, 10+1j, 1-2j) @@ -741,8 +741,7 @@ class Test_ilength(unittest.TestCase): for (c, t, s) in tests: self.assertAlmostEqual(c.ilength(s), t) - ############################################################### - # Arcs + def test_ilength_arcs(self): arc1 = Arc(0j, 100 + 50j, 0, 0, 0, 100 + 50j) arc2 = Arc(0j, 100 + 50j, 0, 1, 0, 100 + 50j) arc3 = Arc(0j, 100 + 50j, 0, 0, 1, 100 + 50j) @@ -790,8 +789,7 @@ class Test_ilength(unittest.TestCase): for (c, t, s) in tests: self.assertAlmostEqual(c.ilength(s), t) - ############################################################### - # Paths + def test_ilength_paths(self): line1 = Line(600 + 350j, 650 + 325j) arc1 = Arc(650 + 325j, 25 + 25j, -30, 0, 1, 700 + 300j) cub1 = CubicBezier(650 + 325j, 25 + 25j, -30, 700 + 300j) @@ -890,10 +888,10 @@ class Test_ilength(unittest.TestCase): (apath, 1.0, 87.81018330500885)] for (c, t, s) in tests: - self.assertAlmostEqual(c.ilength(s), t) + self.assertAlmostEqual(c.ilength(s), t, msg=str((c, t, s))) - ############################################################### - # Exception Cases + # Exceptional Cases + def test_ilength_exceptions(self): nodalq = QuadraticBezier(1, 1, 1) with self.assertRaises(AssertionError): nodalq.ilength(1) @@ -954,4 +952,4 @@ class Test_intersect(unittest.TestCase): ################################################################### if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() diff --git a/test/test_pathtools.py b/test/test_pathtools.py index d688e0f..6f2083e 100644 --- a/test/test_pathtools.py +++ b/test/test_pathtools.py @@ -1,5 +1,6 @@ # External dependencies from __future__ import division, absolute_import, print_function +from builtins import range import unittest from numpy import poly1d @@ -57,11 +58,11 @@ class TestPathTools(unittest.TestCase): # Input poly1d object bez = poly2bez(p) bpoints = bez.bpoints() - self.assertAlmostEquals(distfcn(bpoints, correct_bpoints), 0) + self.assertAlmostEqual(distfcn(bpoints, correct_bpoints), 0) # Input list of coefficients bpoints = poly2bez(pcoeffs, return_bpoints=True) - self.assertAlmostEquals(distfcn(bpoints, correct_bpoints), 0) + self.assertAlmostEqual(distfcn(bpoints, correct_bpoints), 0) # Case: Quadratic pcoeffs = [(29.5+15.5j), (-31-19j), (7.5+5.5j)] @@ -71,11 +72,11 @@ class TestPathTools(unittest.TestCase): # Input poly1d object bez = poly2bez(p) bpoints = bez.bpoints() - self.assertAlmostEquals(distfcn(bpoints, correct_bpoints), 0) + self.assertAlmostEqual(distfcn(bpoints, correct_bpoints), 0) # Input list of coefficients bpoints = poly2bez(pcoeffs, return_bpoints=True) - self.assertAlmostEquals(distfcn(bpoints, correct_bpoints), 0) + self.assertAlmostEqual(distfcn(bpoints, correct_bpoints), 0) # Case: Cubic pcoeffs = [(-18.5-12.5j), (34.5+16.5j), (-18-6j), (6+2j)] @@ -85,11 +86,11 @@ class TestPathTools(unittest.TestCase): # Input poly1d object bez = poly2bez(p) bpoints = bez.bpoints() - self.assertAlmostEquals(distfcn(bpoints, correct_bpoints), 0) + self.assertAlmostEqual(distfcn(bpoints, correct_bpoints), 0) # Input list of coefficients object bpoints = poly2bez(pcoeffs, return_bpoints=True) - self.assertAlmostEquals(distfcn(bpoints, correct_bpoints), 0) + self.assertAlmostEqual(distfcn(bpoints, correct_bpoints), 0) def test_bpoints2bezier(self): cubic_bpoints = [(6+2j), 0, (5.5+3.5j), (4+0j)]