diff --git a/pymathics/asy/__init__.py b/pymathics/asy/__init__.py index ca81c75..00c5e0a 100644 --- a/pymathics/asy/__init__.py +++ b/pymathics/asy/__init__.py @@ -10,21 +10,28 @@ import os from pymathics.asy.version import __version__ -from pymathics.asy.exportasy import (ExportToJPG, - ExportToPNG, - ExportToSVG, - ExportToPDF) -from pymathics.asy.graphics import (AsyGraphicsBox) +from pymathics.asy.exportasy import ExportToJPG, ExportToPNG, ExportToSVG, ExportToPDF +from pymathics.asy.graphics import AsyGraphicsBox from mathics.core.expression import Expression, String, SymbolTrue from mathics.core.evaluation import Evaluation from mathics.builtin.files_io.importexport import Export as MathicsExport -__all__ = ("__version__", "ExportToJPG", "ExportToPNG", "ExportToSVG", "ExportToPDF", - "AsyGraphicsBox", "pymathics_version_data", "asy_path") +__all__ = ( + "__version__", + "ExportToJPG", + "ExportToPNG", + "ExportToSVG", + "ExportToPDF", + "AsyGraphicsBox", + "pymathics_version_data", + "asy_path", +) -ROOT_DIR = pkg_resources.resource_filename('pymathics.asy', '') + +ROOT_DIR = pkg_resources.resource_filename("pymathics.asy", "") import shutil + try: asy_path = shutil.which("asy") print("asy found in ", asy_path) @@ -32,26 +39,26 @@ print("asy path couldn't be found. Set to asy") asy_path = "asy" + def onload(definitions): -# from mathics.builtin import box_constructs -# box_constructs["System`GraphicsBox"] = AsyGraphicsBox(expression=False) -# box_constructs["System`Graphics3DBox"] = AsyGraphics3DBox(expression=False) + # from mathics.builtin import box_constructs + # box_constructs["System`GraphicsBox"] = AsyGraphicsBox(expression=False) + # box_constructs["System`Graphics3DBox"] = AsyGraphics3DBox(expression=False) MathicsExport._extdict["pdf"] = "PDF" definitions.set_ownvalue("Settings`UseAsyForGraphics2D", SymbolTrue) for root, dirs, files in os.walk(os.path.join(ROOT_DIR, "autoload")): for path in [os.path.join(root, f) for f in files if f.endswith(".m")]: Expression("Get", String(path)).evaluate(Evaluation(definitions)) + # To be recognized as an external mathics module, the following variable # is required: # - - pymathics_version_data = { "author": "The Mathics Team", "version": __version__, "requires": [], - "onload" : onload + "onload": onload, } diff --git a/pymathics/asy/__main__.py b/pymathics/asy/__main__.py index 78966a2..d7232ee 100644 --- a/pymathics/asy/__main__.py +++ b/pymathics/asy/__main__.py @@ -1,5 +1,2 @@ # -*- coding: utf-8 -*- from mathics.builtin.base import Builtin, String - - - diff --git a/pymathics/asy/exportasy.py b/pymathics/asy/exportasy.py index 72e2abc..0eb9ef6 100644 --- a/pymathics/asy/exportasy.py +++ b/pymathics/asy/exportasy.py @@ -11,67 +11,76 @@ import tempfile import os from subprocess import DEVNULL, STDOUT, check_call -from mathics.core.expression import (Expression, String, BoxError, SymbolFailed, SymbolNull) +from mathics.core.expression import ( + Expression, + String, + BoxError, + SymbolFailed, + SymbolNull, +) from mathics_scanner import replace_wl_with_plain_text from mathics.builtin.drawing.image import Image from mathics.builtin import Builtin +from mathics.core.attributes import hold_rest, protected + class _AsyExporter(Builtin): - attributes = ("HoldRest", ) + attributes = hold_rest | protected - messages = {"boxerr": "Not able to interpret box `1`", - "nowrtacs": "ExportToPDF requires write access.", - "asyfld" : "Asymptote failed to generate the file", + messages = { + "boxerr": "Not able to interpret box `1`", + "nowrtacs": "ExportToPDF requires write access.", + "asyfld": "Asymptote failed to generate the file", } extension = None def apply_asy(self, filename, expr, evaluation, **options): - '%(name)s[filename_String, expr_, OptionsPattern[%(name)s]]' + "%(name)s[filename_String, expr_, OptionsPattern[%(name)s]]" if expr.get_head_name() == "System`Image": - res = Expression("System`ImageExport", filename, expr) + res = Expression("System`ImageExport", filename, expr) return res.evaluate(evaluation) filename = filename.value if expr.get_head_name() not in ("System`Graphics", "System`Graphics3D"): expr = Expression("Text", expr) - expr = Expression("Graphics", - Expression("List", - expr) - ) + expr = Expression("Graphics", Expression("List", expr)) asy_code = Expression("MakeBoxes", expr).evaluate(evaluation) try: asy_code = asy_code.boxes_to_tex(evaluation=evaluation) except BoxError as e: - evaluation.message(self.get_name(),"boxerr", e.box) + evaluation.message(self.get_name(), "boxerr", e.box) return SymbolFailed asy_code = asy_code[13:-10] asy_code = replace_wl_with_plain_text(asy_code, False) # TODO: Handle properly WL characters to latex commands asy_code = asy_code.replace("\\[DifferentialD]", "d ") - fin = os.path.join(tempfile._get_default_tempdir(), - next(tempfile._get_candidate_names())) + fin = os.path.join( + tempfile._get_default_tempdir(), next(tempfile._get_candidate_names()) + ) from pymathics.asy import asy_path + try: - with open(fin, 'w+') as borrador: + with open(fin, "w+") as borrador: borrador.write(asy_code) except: - evaluation.message(self.get_name(),"nowrtacs") + evaluation.message(self.get_name(), "nowrtacs") return SymbolFailed if self.extension == "svg": - cmdline = [asy_path, '-f', self.extension, - '--svgemulation' , - '-o', - filename, - fin] + cmdline = [ + asy_path, + "-f", + self.extension, + "--svgemulation", + "-o", + filename, + fin, + ] else: - cmdline = [asy_path, '-f', self.extension, - '-o', - filename, - fin] + cmdline = [asy_path, "-f", self.extension, "-o", filename, fin] try: check_call(cmdline, stdout=DEVNULL, stderr=DEVNULL) except: @@ -91,6 +100,7 @@ class ExportToSVG(_AsyExporter): Then, from the asy set of instructions, a pdf is built """ + extension = "svg" context = "System`Convert`TextDump`" @@ -122,6 +132,7 @@ class ExportToPNG(_AsyExporter): Then, from the asy set of instructions, a pdf is built """ + extension = "png" context = "System`Convert`Image`" @@ -137,6 +148,6 @@ class ExportToJPG(_AsyExporter): Then, from the asy set of instructions, a pdf is built """ + extension = "jpeg" context = "System`Convert`Image`" - diff --git a/pymathics/asy/graphics.py b/pymathics/asy/graphics.py index b8fe357..9009ff2 100644 --- a/pymathics/asy/graphics.py +++ b/pymathics/asy/graphics.py @@ -14,7 +14,6 @@ import numbers - from mathics.builtin.base import ( Builtin, InstanceableBuiltin, @@ -37,26 +36,30 @@ from_python, ) -from mathics.builtin.graphics import (GRAPHICS_OPTIONS, - GraphicsBox, - Graphics, - asy_number, - RGBColor) +from mathics.builtin.graphics import ( + GRAPHICS_OPTIONS, + GraphicsBox, + Graphics, + asy_number, + RGBColor, +) from mathics.formatter.asy import asy_create_pens from mathics.builtin.drawing.graphics3d import Graphics3D, Graphics3DElements +from mathics.core.attributes import hold_all, protected, read_protected + class AsyGraphicsBox(GraphicsBox): - context="System`" + context = "System`" options = Graphics.options _graphics = Graphics(expression=False) - attributes = ("HoldAll", "ReadProtected") + attributes = hold_all | protected | read_protected messages = { - "asynotav": 'Asymptote is not available in this system. Using the buggy backend.', - "noasyfile": 'Asy requires write permisions over a temporary file, but it was not available. Using the buggy backend', - "asyfail": 'Asymptote failed building the svg picture. Using the buggy backend.', + "asynotav": "Asymptote is not available in this system. Using the buggy backend.", + "noasyfile": "Asy requires write permisions over a temporary file, but it was not available. Using the buggy backend", + "asyfail": "Asymptote failed building the svg picture. Using the buggy backend.", } def apply_makeboxes(self, content, evaluation, options): @@ -82,8 +85,8 @@ def boxes_to_tex(self, leaves=None, **options): endline = widthheight.find("\n") widthheight = widthheight[:endline] width, height = widthheight.split(",") - width = float(width[:-2])*60 - height = float(height[:-4])*60 + width = float(width[:-2]) * 60 + height = float(height[:-4]) * 60 return (tex, width, height) def boxes_to_mathml(self, leaves=None, **options): @@ -92,7 +95,9 @@ def boxes_to_mathml(self, leaves=None, **options): evaluation = options.get("evaluation", None) check_asy = False if evaluation: - check_asy = evaluation.definitions.get_ownvalue("Settings`UseAsyForGraphics2D") + check_asy = evaluation.definitions.get_ownvalue( + "Settings`UseAsyForGraphics2D" + ) if check_asy: check_asy = check_asy.replace.is_true() if check_asy: @@ -100,19 +105,24 @@ def boxes_to_mathml(self, leaves=None, **options): from subprocess import DEVNULL, STDOUT, check_call from pymathics.asy import asy_path import tempfile + try: - check_call([asy_path, '--version'], stdout=DEVNULL, stderr=DEVNULL) + check_call([asy_path, "--version"], stdout=DEVNULL, stderr=DEVNULL) except: check_asy = False evaluation.message("AsyGraphicsBox", "asynotav") - Expression("Set", Symbol("Settings`UseAsyForGraphics2D"), SymbolFalse).evaluate(evaluation) + Expression( + "Set", Symbol("Settings`UseAsyForGraphics2D"), SymbolFalse + ).evaluate(evaluation) if check_asy: asy, width, height = self.boxes_to_tex(leaves, forxml=True, **options) - fin = os.path.join(tempfile._get_default_tempdir(), next(tempfile._get_candidate_names())) + fin = os.path.join( + tempfile._get_default_tempdir(), next(tempfile._get_candidate_names()) + ) fout = fin + ".png" try: - with open(fin, 'w+') as borrador: + with open(fin, "w+") as borrador: borrador.write(asy) except: evaluation.message("AsyGraphicsBox", "noasyfile") @@ -121,26 +131,25 @@ def boxes_to_mathml(self, leaves=None, **options): if check_asy: try: # check_call(['asy', '-f', 'svg', '--svgemulation' ,'-o', fout, fin], stdout=DEVNULL, stderr=DEVNULL) - check_call([asy_path, '-f', 'png', '-render', '16', '-o', fout, fin], stdout=DEVNULL, stderr=DEVNULL) + check_call( + [asy_path, "-f", "png", "-render", "16", "-o", fout, fin], + stdout=DEVNULL, + stderr=DEVNULL, + ) except: evaluation.message("AsyGraphicsBox", "asyfail") check_asy = False if check_asy: - with open(fout, 'rb') as ff: + with open(fout, "rb") as ff: png = ff.read() - return ( - ''' - ''' - % ( - int(width), - int(height), - base64.b64encode(png).decode("utf8"), -# base64.b64encode(svg.encode("utf8")).decode("utf8"), - ) + return """ + """ % ( + int(width), + int(height), + base64.b64encode(png).decode("utf8"), + # base64.b64encode(svg.encode("utf8")).decode("utf8"), ) # Not using asymptote. Continue with the buggy backend... return super(AsyGraphicsBox, self).boxes_to_mathml(leaves=leaves, **options) - - diff --git a/pymathics/asy/version.py b/pymathics/asy/version.py index b14a045..20720e6 100644 --- a/pymathics/asy/version.py +++ b/pymathics/asy/version.py @@ -5,4 +5,4 @@ # This file is suitable for sourcing inside POSIX shell as # well as importing into Python. That's why there is no # space around "=" below. -__version__="1.0.0" +__version__ = "1.0.0" diff --git a/setup.py b/setup.py index 4fc4f22..d6aa2eb 100644 --- a/setup.py +++ b/setup.py @@ -28,7 +28,7 @@ version=__version__, packages=find_namespace_packages(include=["pymathics.asy.*"]), install_requires=["mathics3>=1.1.0"], - package_data = {"pymathics-asy": ["autoload/formats/*/Export.m"]}, + package_data={"pymathics-asy": ["autoload/formats/*/Export.m"]}, # don't pack Mathics in egg because of media files, etc. zip_safe=False, # metadata for upload to PyPI @@ -53,5 +53,3 @@ # Install autoload path - - diff --git a/test/helper.py b/test/helper.py index dd30e46..d38ad0e 100644 --- a/test/helper.py +++ b/test/helper.py @@ -7,6 +7,7 @@ session = MathicsSession(add_builtin=True, catch_interrupt=False) # session.evaluate('LoadModule["pymathics.asy"]') + def check_evaluation(str_expr: str, str_expected: str, message=""): """Helper function to test that a WL expression against its results""" diff --git a/test/test_asy.py b/test/test_asy.py index 8cbcc1c..2fa2a81 100644 --- a/test/test_asy.py +++ b/test/test_asy.py @@ -6,6 +6,7 @@ import shutil + try: asy_path = shutil.which("asy") print("asy found in ", asy_path) @@ -16,7 +17,7 @@ def test_asycmd(): try: - assert os.system(asy_path +" -version") == 0 + assert os.system(asy_path + " -version") == 0 except: print("path=", asy_path) assert False diff --git a/test/test_exporters.py b/test/test_exporters.py index d7b7f14..1f12040 100644 --- a/test/test_exporters.py +++ b/test/test_exporters.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- -#import sys +# import sys import pytest # from helper import session, check_evaluation @@ -18,47 +18,53 @@ def test_asymptote_cmd(): from subprocess import DEVNULL, STDOUT, check_call from pymathics.asy import asy_path - res = check_call([asy_path, '--version'], stdout=DEVNULL, stderr=DEVNULL) + + res = check_call([asy_path, "--version"], stdout=DEVNULL, stderr=DEVNULL) assert res == 0 + def check_evaluation(str_expr: str, str_expected: str, message=""): """Helper function to test that a WL expression against its results""" result = session.evaluate(str_expr) expected = session.evaluate(str_expected) -# print(time.asctime()) -# print(message) + # print(time.asctime()) + # print(message) if message: assert result == expected, message else: assert result == expected -tests = ['A', - 'MatrixForm[{{a,n},{c,d}}]; a+b', - 'Integrate[f[x],x]', - 'Evaluate[Plot[Cos[x],{x,0,20}]]', -# 'Evaluate[Plot3D[Cos[x*y],{x,-1,1},{y,-1,1}]]', - 'Evaluate[DensityPlot[Cos[x*y],{x,-1,1},{y,-1,1}]]', +tests = [ + "A", + "MatrixForm[{{a,n},{c,d}}]; a+b", + "Integrate[f[x],x]", + "Evaluate[Plot[Cos[x],{x,0,20}]]", + # 'Evaluate[Plot3D[Cos[x*y],{x,-1,1},{y,-1,1}]]', + "Evaluate[DensityPlot[Cos[x*y],{x,-1,1},{y,-1,1}]]", ] -fileformats = ["test.pdf", - "test.svg", - "test.png", -# "test.jpg" +fileformats = [ + "test.pdf", + "test.svg", + "test.png", + # "test.jpg" ] + @pytest.mark.parametrize( "str_expr, str_expected", - [ ('LoadModule["pymathics.asy"]', '"pymathics.asy"') ] +\ - [ ('Export[$TemporaryDirectory<>"/"<>"'+ filename +'", '+ test + ']', - f'$TemporaryDirectory <> "/" <> "{filename}"') + [('LoadModule["pymathics.asy"]', '"pymathics.asy"')] + + [ + ( + 'Export[$TemporaryDirectory<>"/"<>"' + filename + '", ' + test + "]", + f'$TemporaryDirectory <> "/" <> "{filename}"', + ) for test in tests for filename in fileformats - ] + ], ) def test_evaluation(str_expr: str, str_expected: str, message=""): check_evaluation(str_expr, str_expected, message) - - diff --git a/test/tmp_exporters.py b/test/tmp_exporters.py index dbc6004..4d8c5b2 100644 --- a/test/tmp_exporters.py +++ b/test/tmp_exporters.py @@ -24,9 +24,11 @@ def test_asymptote_cmd(): from subprocess import DEVNULL, STDOUT, check_call from pymathics.asy import asy_path - res = check_call([asy_path, '--version'], stdout=DEVNULL, stderr=DEVNULL) + + res = check_call([asy_path, "--version"], stdout=DEVNULL, stderr=DEVNULL) assert res == 0 + print("Try calling asy") test_asymptote_cmd() print(" now the other tests...") @@ -38,7 +40,7 @@ def check_evaluation(str_expr: str, str_expected: str, message=""): result = session.evaluate(str_expr) expected = session.evaluate(str_expected) -# print(time.asctime()) + # print(time.asctime()) print(message) if message: if result == (expected, message): @@ -51,40 +53,41 @@ def check_evaluation(str_expr: str, str_expected: str, message=""): else: print(" unexpected result =", result) + print(" * building tests ") -tests = ['A', - 'MatrixForm[{{a,n},{c,d}}]; a+b', - 'Integrate[f[x],x]', - 'Evaluate[Plot[Cos[x],{x,0,20}]]', -# 'Evaluate[Plot3D[Cos[x*y],{x,-1,1},{y,-1,1}]]', - 'Evaluate[DensityPlot[Cos[x*y],{x,-1,1},{y,-1,1}]]', +tests = [ + "A", + "MatrixForm[{{a,n},{c,d}}]; a+b", + "Integrate[f[x],x]", + "Evaluate[Plot[Cos[x],{x,0,20}]]", + # 'Evaluate[Plot3D[Cos[x*y],{x,-1,1},{y,-1,1}]]', + "Evaluate[DensityPlot[Cos[x*y],{x,-1,1},{y,-1,1}]]", ] -fileformats = ["test.pdf", - "test.svg", - "test.png", - "test.jpg" -] +fileformats = ["test.pdf", "test.svg", "test.png", "test.jpg"] + def format_tests(str_expr: str, str_expected: str, message=""): check_evaluation(str_expr, str_expected, message) -test_inputs = [ ('LoadModule["pymathics.asy"]', '"pymathics.asy"') ] +\ - [ ('Export[$TemporaryDirectory<>"/"<>"'+ filename +'", '+ test + ']', - f'$TemporaryDirectory <> "/" <> "{filename}"') - for test in tests - for filename in fileformats - ] +test_inputs = [('LoadModule["pymathics.asy"]', '"pymathics.asy"')] + [ + ( + 'Export[$TemporaryDirectory<>"/"<>"' + filename + '", ' + test + "]", + f'$TemporaryDirectory <> "/" <> "{filename}"', + ) + for test in tests + for filename in fileformats +] print(" * starting tests") for expr, expected in test_inputs: - print("\n", 30*"*") + print("\n", 30 * "*") print("Expr:", expr) print("Expected:", expected) # check_evaluation(expr, expected) - print(30*"*","\n") + print(30 * "*", "\n") print("done") diff --git a/test/tmp_test_mpl.py b/test/tmp_test_mpl.py index 58c9448..db680a8 100644 --- a/test/tmp_test_mpl.py +++ b/test/tmp_test_mpl.py @@ -2,7 +2,8 @@ try: import matplotlib.pyplot as plt - plt.plot([1,2,3],[1,2,3]) + + plt.plot([1, 2, 3], [1, 2, 3]) print("OK") except: - print("mpl failed") + print("mpl failed")