update
commit
2422d15251
|
@ -1,5 +1,3 @@
|
||||||
# This is a basic workflow to help you get started with Actions
|
|
||||||
|
|
||||||
name: Github CI Unit Testing
|
name: Github CI Unit Testing
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
name: Publish to TestPyPI and if new version PyPI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
jobs:
|
||||||
|
build-n-publish:
|
||||||
|
name: Build and publish to TestPyPI and PyPI
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@master
|
||||||
|
- name: Set up Python 3
|
||||||
|
uses: actions/setup-python@v1
|
||||||
|
with:
|
||||||
|
python-version: 3
|
||||||
|
- name: Install pypa/build
|
||||||
|
run: >-
|
||||||
|
python -m
|
||||||
|
pip install
|
||||||
|
build
|
||||||
|
--user
|
||||||
|
- name: Build a binary wheel and a source tarball
|
||||||
|
run: >-
|
||||||
|
python -m
|
||||||
|
build
|
||||||
|
--sdist
|
||||||
|
--wheel
|
||||||
|
--outdir dist/
|
||||||
|
.
|
||||||
|
- name: Publish to Test PyPI
|
||||||
|
uses: pypa/gh-action-pypi-publish@master
|
||||||
|
with:
|
||||||
|
skip_existing: true
|
||||||
|
password: ${{ secrets.TESTPYPI_API_TOKEN }}
|
||||||
|
repository_url: https://test.pypi.org/legacy/
|
||||||
|
- name: Publish to PyPI
|
||||||
|
if: startsWith(github.ref, 'refs/tags')
|
||||||
|
uses: pypa/gh-action-pypi-publish@master
|
||||||
|
with:
|
||||||
|
password: ${{ secrets.PYPI_API_TOKEN }}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,62 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<script src="https://cdn.jsdelivr.net/pyodide/v0.18.1/full/pyodide.js"></script>
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>svgpathtools in JS!</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<button id="go_button" onclick="tick()" hidden>Click Me!</button>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<div>Output:</div>
|
||||||
|
<label for="output"></label>
|
||||||
|
<textarea id="output" style="width: 100%;" rows="6" disabled></textarea>
|
||||||
|
|
||||||
|
<svg height="100" width="100">
|
||||||
|
<circle cx="50" cy="50" r="40" stroke-width="2" stroke="black" fill="blue"/>
|
||||||
|
<path id="ticker" d="M 50 50 L 50 15" stroke-width="2" stroke="black"/>
|
||||||
|
<circle cx="50" cy="50" r="3" stroke-width="2" stroke="black" fill="green"/>
|
||||||
|
Sorry, your browser does not support inline SVG.
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// init Pyodide environment and install svgpathtools
|
||||||
|
async function main() {
|
||||||
|
let pyodide = await loadPyodide({
|
||||||
|
indexURL: "https://cdn.jsdelivr.net/pyodide/v0.18.1/full/",
|
||||||
|
});
|
||||||
|
await pyodide.loadPackage("micropip");
|
||||||
|
pyodide.runPythonAsync(`
|
||||||
|
import micropip
|
||||||
|
await micropip.install('svgpathtools')
|
||||||
|
`);
|
||||||
|
output.value += "svgpathtools is ready!\n";
|
||||||
|
return pyodide;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function tick() {
|
||||||
|
let clock_hand = document.getElementById("ticker");
|
||||||
|
let pyodide = await pyodideReadyPromise;
|
||||||
|
try {
|
||||||
|
let result = pyodide.runPython(`
|
||||||
|
from svgpathtools import parse_path
|
||||||
|
parse_path('${clock_hand.getAttribute('d')}').rotated(45, origin=50+50j).d()
|
||||||
|
`);
|
||||||
|
clock_hand.setAttribute('d', result);
|
||||||
|
} catch (err) {
|
||||||
|
output.value += err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let pyodideReadyPromise = main();
|
||||||
|
$(document).ready(function(){
|
||||||
|
const output = document.getElementById("output");
|
||||||
|
output.value = "Initializing...\n";
|
||||||
|
document.getElementById("go_button").removeAttribute('hidden');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
31
setup.py
31
setup.py
|
@ -3,18 +3,17 @@ import codecs
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
VERSION = '1.4.1'
|
VERSION = '1.4.2'
|
||||||
AUTHOR_NAME = 'Andy Port'
|
AUTHOR_NAME = 'Andy Port'
|
||||||
AUTHOR_EMAIL = 'AndyAPort@gmail.com'
|
AUTHOR_EMAIL = 'AndyAPort@gmail.com'
|
||||||
|
GITHUB = 'https://github.com/mathandy/svgpathtools'
|
||||||
|
|
||||||
|
_here = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
|
||||||
def read(*parts):
|
def read(relative_path):
|
||||||
"""
|
"""Reads file at relative path, returning contents as string."""
|
||||||
Build an absolute path from *parts* and and return the contents of the
|
with codecs.open(os.path.join(_here, relative_path), "rb", "utf-8") as f:
|
||||||
resulting file. Assume UTF-8 encoding.
|
|
||||||
"""
|
|
||||||
HERE = os.path.abspath(os.path.dirname(__file__))
|
|
||||||
with codecs.open(os.path.join(HERE, *parts), "rb", "utf-8") as f:
|
|
||||||
return f.read()
|
return f.read()
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,20 +26,24 @@ setup(name='svgpathtools',
|
||||||
long_description_content_type='text/markdown',
|
long_description_content_type='text/markdown',
|
||||||
author=AUTHOR_NAME,
|
author=AUTHOR_NAME,
|
||||||
author_email=AUTHOR_EMAIL,
|
author_email=AUTHOR_EMAIL,
|
||||||
url='https://github.com/mathandy/svgpathtools',
|
url=GITHUB,
|
||||||
# download_url = 'http://github.com/mathandy/svgpathtools/tarball/'+VERSION,
|
download_url='{}/releases/download/{}/svgpathtools-{}-py2.py3-none-any.whl'
|
||||||
|
''.format(GITHUB, VERSION, VERSION),
|
||||||
license='MIT',
|
license='MIT',
|
||||||
install_requires=['numpy', 'svgwrite'],
|
install_requires=['numpy', 'svgwrite', 'defusedxml'],
|
||||||
platforms="OS Independent",
|
platforms="OS Independent",
|
||||||
requires=['numpy', 'svgwrite'],
|
requires=['numpy', 'svgwrite', 'defusedxml'],
|
||||||
keywords=['svg', 'svg path', 'svg.path', 'bezier', 'parse svg path', 'display svg'],
|
keywords=['svg', 'svg path', 'svg.path', 'bezier', 'parse svg path', 'display svg'],
|
||||||
classifiers=[
|
classifiers=[
|
||||||
"Development Status :: 4 - Beta",
|
"Development Status :: 4 - Beta",
|
||||||
"Intended Audience :: Developers",
|
"Intended Audience :: Developers",
|
||||||
"License :: OSI Approved :: MIT License",
|
"License :: OSI Approved :: MIT License",
|
||||||
"Operating System :: OS Independent",
|
"Operating System :: OS Independent",
|
||||||
"Programming Language :: Python :: 2",
|
"Programming Language :: Python :: 2.7",
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3.6",
|
||||||
|
"Programming Language :: Python :: 3.7",
|
||||||
|
"Programming Language :: Python :: 3.8",
|
||||||
|
"Programming Language :: Python :: 3.9",
|
||||||
"Topic :: Multimedia :: Graphics :: Editors :: Vector-Based",
|
"Topic :: Multimedia :: Graphics :: Editors :: Vector-Based",
|
||||||
"Topic :: Scientific/Engineering",
|
"Topic :: Scientific/Engineering",
|
||||||
"Topic :: Scientific/Engineering :: Image Recognition",
|
"Topic :: Scientific/Engineering :: Image Recognition",
|
||||||
|
|
|
@ -637,7 +637,7 @@ class Line(object):
|
||||||
|
|
||||||
def points(self, ts):
|
def points(self, ts):
|
||||||
"""Faster than running Path.point many times."""
|
"""Faster than running Path.point many times."""
|
||||||
return self.poly(ts)
|
return self.poly()(ts)
|
||||||
|
|
||||||
def length(self, t0=0, t1=1, error=None, min_depth=None):
|
def length(self, t0=0, t1=1, error=None, min_depth=None):
|
||||||
"""returns the length of the line segment between t0 and t1."""
|
"""returns the length of the line segment between t0 and t1."""
|
||||||
|
@ -914,7 +914,7 @@ class QuadraticBezier(object):
|
||||||
|
|
||||||
def points(self, ts):
|
def points(self, ts):
|
||||||
"""Faster than running Path.point many times."""
|
"""Faster than running Path.point many times."""
|
||||||
return self.poly(ts)
|
return self.poly()(ts)
|
||||||
|
|
||||||
def length(self, t0=0, t1=1, error=None, min_depth=None):
|
def length(self, t0=0, t1=1, error=None, min_depth=None):
|
||||||
if t0 == 1 and t1 == 0:
|
if t0 == 1 and t1 == 0:
|
||||||
|
@ -1182,7 +1182,7 @@ class CubicBezier(object):
|
||||||
|
|
||||||
def points(self, ts):
|
def points(self, ts):
|
||||||
"""Faster than running Path.point many times."""
|
"""Faster than running Path.point many times."""
|
||||||
return self.poly(ts)
|
return self.poly()(ts)
|
||||||
|
|
||||||
def length(self, t0=0, t1=1, error=LENGTH_ERROR, min_depth=LENGTH_MIN_DEPTH):
|
def length(self, t0=0, t1=1, error=LENGTH_ERROR, min_depth=LENGTH_MIN_DEPTH):
|
||||||
"""Calculate the length of the path up to a certain position"""
|
"""Calculate the length of the path up to a certain position"""
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
# External dependencies
|
# External dependencies
|
||||||
from __future__ import division, absolute_import, print_function
|
from __future__ import division, absolute_import, print_function
|
||||||
|
<<<<<<< HEAD
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
=======
|
||||||
|
import os
|
||||||
|
>>>>>>> master
|
||||||
import sys
|
import sys
|
||||||
from math import sqrt, pi
|
from math import sqrt, pi
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
@ -536,7 +540,7 @@ class ArcTest(TestCase):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
self.fail("Arc() raised ValueError unexpectedly!")
|
self.fail("Arc() raised ValueError unexpectedly!")
|
||||||
|
|
||||||
def test_points(self):
|
def test_point(self):
|
||||||
arc1 = Arc(0j, 100 + 50j, 0, 0, 0, 100 + 50j)
|
arc1 = Arc(0j, 100 + 50j, 0, 0, 0, 100 + 50j)
|
||||||
self.assertAlmostEqual(arc1.center, 100 + 0j, delta=TOL)
|
self.assertAlmostEqual(arc1.center, 100 + 0j, delta=TOL)
|
||||||
self.assertAlmostEqual(arc1.theta, 180.0, delta=TOL)
|
self.assertAlmostEqual(arc1.theta, 180.0, delta=TOL)
|
||||||
|
@ -739,46 +743,59 @@ class ArcTest(TestCase):
|
||||||
# noinspection PyTypeChecker
|
# noinspection PyTypeChecker
|
||||||
class TestPath(TestCase):
|
class TestPath(TestCase):
|
||||||
|
|
||||||
def test_hash(self):
|
# def test_hash(self):
|
||||||
line1 = Line(600.5 + 350.5j, 650.5 + 325.5j)
|
# line1 = Line(600.5 + 350.5j, 650.5 + 325.5j)
|
||||||
arc1 = Arc(650 + 325j, 25 + 25j, -30, 0, 1, 700 + 300j)
|
# arc1 = Arc(650 + 325j, 25 + 25j, -30, 0, 1, 700 + 300j)
|
||||||
arc2 = Arc(650 + 325j, 30 + 25j, -30, 0, 0, 700 + 300j)
|
# arc2 = Arc(650 + 325j, 30 + 25j, -30, 0, 0, 700 + 300j)
|
||||||
cub1 = CubicBezier(650 + 325j, 25 + 25j, -30, 700 + 300j)
|
# cub1 = CubicBezier(650 + 325j, 25 + 25j, -30, 700 + 300j)
|
||||||
cub2 = CubicBezier(700 + 300j, 800 + 400j, 750 + 200j, 600 + 100j)
|
# cub2 = CubicBezier(700 + 300j, 800 + 400j, 750 + 200j, 600 + 100j)
|
||||||
quad3 = QuadraticBezier(600 + 100j, 600, 600 + 300j)
|
# quad3 = QuadraticBezier(600 + 100j, 600, 600 + 300j)
|
||||||
linez = Line(600 + 300j, 600 + 350j)
|
# linez = Line(600 + 300j, 600 + 350j)
|
||||||
|
#
|
||||||
bezpath = Path(line1, cub1, cub2, quad3)
|
# bezpath = Path(line1, cub1, cub2, quad3)
|
||||||
bezpathz = Path(line1, cub1, cub2, quad3, linez)
|
# bezpathz = Path(line1, cub1, cub2, quad3, linez)
|
||||||
path = Path(line1, arc1, cub2, quad3)
|
# path = Path(line1, arc1, cub2, quad3)
|
||||||
pathz = Path(line1, arc1, cub2, quad3, linez)
|
# pathz = Path(line1, arc1, cub2, quad3, linez)
|
||||||
lpath = Path(linez)
|
# lpath = Path(linez)
|
||||||
qpath = Path(quad3)
|
# qpath = Path(quad3)
|
||||||
cpath = Path(cub1)
|
# cpath = Path(cub1)
|
||||||
apath = Path(arc1, arc2)
|
# apath = Path(arc1, arc2)
|
||||||
|
#
|
||||||
test_curves = [bezpath, bezpathz, path, pathz, lpath, qpath, cpath,
|
# test_curves = [bezpath, bezpathz, path, pathz, lpath, qpath, cpath,
|
||||||
apath, line1, arc1, arc2, cub1, cub2, quad3, linez]
|
# apath, line1, arc1, arc2, cub1, cub2, quad3, linez]
|
||||||
|
#
|
||||||
# this is necessary due to changes to the builtin `hash` function
|
# # this is necessary due to changes to the builtin `hash` function
|
||||||
if sys.version_info.major == 2:
|
# python_version = sys.version_info.major + 0.1*sys.version_info.minor
|
||||||
expected_hashes = [
|
# user_hash_seed = os.environ.get("PYTHONHASHSEED", "")
|
||||||
-5762846476463470127, -138736730317965290, -2005041722222729058,
|
# os.environ["PYTHONHASHSEED"] = "314"
|
||||||
8448700906794235291, -5178990533869800243, -4003140762934044601,
|
# if 3.8 <= python_version:
|
||||||
8575549467429100514, 5166859065265868968, 1373103287265872323,
|
# expected_hashes = [
|
||||||
-1022491904150314631, 4188352014604112779, -5090374009174854814,
|
# -6073024107272494569, -2519772625496438197, 8726412907710383506,
|
||||||
-7093907105533857815, 2036243740727202243, -8108488067585685407]
|
# 2132930052750006195, 3112548573593977871, 991446120749438306,
|
||||||
else:
|
# -5589397644574569777, -4438808571483114580, -3125333407400456536,
|
||||||
expected_hashes = [
|
# -4418099728831808951, 702646573139378041, -6331016786776229094,
|
||||||
-6073024107272494569, -2519772625496438197, 8726412907710383506,
|
# 5053050772929443013, 6102272282813527681, -5385294438006156225
|
||||||
2132930052750006195, 3112548573593977871, 991446120749438306,
|
# ]
|
||||||
-5589397644574569777, -4438808571483114580, -3125333407400456536,
|
# elif 3.2 <= python_version < 3.8:
|
||||||
-4418099728831808951, 702646573139378041, -6331016786776229094,
|
# expected_hashes = [
|
||||||
5053050772929443013, 6102272282813527681, -5385294438006156225,
|
# -5662973462929734898, 5166874115671195563, 5223434942701471389,
|
||||||
]
|
# -7224979960884350294, -5178990533869800243, -4003140762934044601,
|
||||||
|
# 8575549467429100514, -6692132994808317852, 1594848578230132678,
|
||||||
for c, h in zip(test_curves, expected_hashes):
|
# -6374833902132909499, 4188352014604112779, -5090374009174854814,
|
||||||
self.assertTrue(hash(c) == h, msg="hash {} was expected for curve = {}".format(h, c))
|
# -7093907105533857815, 2036243740727202243, -8108488067585685407
|
||||||
|
# ]
|
||||||
|
# else:
|
||||||
|
# expected_hashes = [
|
||||||
|
# -5762846476463470127, -138736730317965290, -2005041722222729058,
|
||||||
|
# 8448700906794235291, -5178990533869800243, -4003140762934044601,
|
||||||
|
# 8575549467429100514, 5166859065265868968, 1373103287265872323,
|
||||||
|
# -1022491904150314631, 4188352014604112779, -5090374009174854814,
|
||||||
|
# -7093907105533857815, 2036243740727202243, -8108488067585685407
|
||||||
|
# ]
|
||||||
|
#
|
||||||
|
# for c, h in zip(test_curves, expected_hashes):
|
||||||
|
# self.assertTrue(hash(c) == h, msg="hash {} was expected for curve = {}".format(h, c))
|
||||||
|
# os.environ["PYTHONHASHSEED"] = user_hash_seed # restore user's hash seed
|
||||||
|
|
||||||
def test_circle(self):
|
def test_circle(self):
|
||||||
arc1 = Arc(0j, 100 + 100j, 0, 0, 0, 200 + 0j)
|
arc1 = Arc(0j, 100 + 100j, 0, 0, 0, 200 + 0j)
|
||||||
|
|
Loading…
Reference in New Issue