diff --git a/mathics/builtin/atomic/strings.py b/mathics/builtin/atomic/strings.py index 81bd10052..d6b9a3b9a 100644 --- a/mathics/builtin/atomic/strings.py +++ b/mathics/builtin/atomic/strings.py @@ -881,7 +881,7 @@ class ToString(Builtin): """ options = { - "CharacterEncoding": '"Unicode"', + "CharacterEncoding": "$CharacterEncoding", "FormatType": "OutputForm", "NumberMarks": "$NumberMarks", "PageHeight": "Infinity", @@ -898,8 +898,21 @@ def eval_default(self, value, evaluation: Evaluation, options: dict): def eval_form(self, expr, form, evaluation: Evaluation, options: dict): "ToString[expr_, form_Symbol, OptionsPattern[ToString]]" - encoding = options["System`CharacterEncoding"] - return eval_ToString(expr, form, encoding.value, evaluation) + encoding = options["System`CharacterEncoding"].evaluate(evaluation) + if isinstance(encoding, String): + encoding_str = encoding.value + if encoding_str not in _encodings: + evaluation.message("$CharacterEncoding", "charcode", encoding) + encoding_str = evaluation.definitions.get_ownvalue( + "System`$SystemCharacterEncoding" + ).value + else: + evaluation.message("$CharacterEncoding", "charcode", encoding) + encoding_str = evaluation.definitions.get_ownvalue( + "System`$SystemCharacterEncoding" + ).value + + return eval_ToString(expr, form, encoding_str, evaluation) class Transliterate(Builtin): diff --git a/mathics/core/element.py b/mathics/core/element.py index dff595127..aa43f9224 100644 --- a/mathics/core/element.py +++ b/mathics/core/element.py @@ -424,6 +424,7 @@ def to_tex(self, **options) -> str: return self.to_format("latex", **options) def to_text(self, **options) -> str: + options.setdefault("encoding", "Unicode") return self.to_format("text", **options) # Deprecated diff --git a/mathics/core/evaluation.py b/mathics/core/evaluation.py index e048c7418..4ea7b93e6 100644 --- a/mathics/core/evaluation.py +++ b/mathics/core/evaluation.py @@ -419,10 +419,15 @@ def format_output(self, expr, format=None): if result is None: return None + try: + encoding = self.definitions.get_ownvalue("System`$CharacterEncoding").value + except AttributeError: + encoding = "Unicode" + try: # With the new implementation, if result is not a ``BoxExpression`` # then we should raise a BoxError here. - boxes = result.to_text(evaluation=self) + boxes = result.to_text(evaluation=self, encoding=encoding) except BoxError: self.message( "General", "notboxes", Expression(SymbolFullForm, result).evaluate(self) diff --git a/mathics/doc/doc_entries.py b/mathics/doc/doc_entries.py index 3d50a5736..c6eff64ad 100644 --- a/mathics/doc/doc_entries.py +++ b/mathics/doc/doc_entries.py @@ -13,6 +13,7 @@ from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Sequence, Tuple from mathics.core.evaluation import Message, Print, _Out +from mathics.eval.encoding import encode_string_value if TYPE_CHECKING: from mathics.doc.structure import DocSection @@ -406,14 +407,18 @@ def strip_sentinal(line: str): def __str__(self) -> str: return self.test - def compare(self, result: Optional[str], out: tuple = tuple()) -> bool: + def compare( + self, result: Optional[str], out: tuple = tuple(), encoding="ASCII" + ) -> bool: """ Performs a doctest comparison between ``result`` and ``wanted`` and returns True if the test should be considered a success. """ - return self.compare_result(result) and self.compare_out(out) + return self.compare_result(result, encoding=encoding) and self.compare_out( + out, encoding=encoding + ) - def compare_out(self, outs: tuple = tuple()) -> bool: + def compare_out(self, outs: tuple = tuple(), encoding="ASCII") -> bool: """Compare messages and warnings produced during the evaluation of the test with the expected messages and warnings.""" # Check out @@ -434,12 +439,14 @@ def tabs_to_spaces(val): for got, wanted in zip(outs, wanted_outs): if wanted.text == "...": return True - if not tabs_to_spaces(got) == tabs_to_spaces(wanted): + if not tabs_to_spaces(got) == encode_string_value( + tabs_to_spaces(wanted), encoding=encoding + ): return False return True - def compare_result(self, result: Optional[str]): + def compare_result(self, result: Optional[str], encoding="ASCII"): """Compare a result with the expected result""" wanted = self.result # Check result @@ -458,6 +465,9 @@ def compare_result(self, result: Optional[str]): return False for res, want in zip(result_list, wanted_list): + # TODO_ Be more careful with special characters used in + # pattern matching. + want = encode_string_value(want, encoding=encoding) wanted_re = re.escape(want.strip()) wanted_re = wanted_re.replace("\\.\\.\\.", ".*?") wanted_re = f"^{wanted_re}$" diff --git a/mathics/doc/documentation/1-Manual.mdoc b/mathics/doc/documentation/1-Manual.mdoc index e4116375f..c0ce24a43 100644 --- a/mathics/doc/documentation/1-Manual.mdoc +++ b/mathics/doc/documentation/1-Manual.mdoc @@ -656,10 +656,10 @@ You can also specify a list of rules: There is a "delayed" version of 'Rule' which can be specified by ':>' (similar to the relation of ':=' to '='): >> a :> 1 + 2 - = a :> 1 + 2 + = a ⧴ 1 + 2 >> a -> 1 + 2 - = a -> 3 + = a ⇾ 3 This is useful when the right side of a rule should not be evaluated immediately (before matching): >> {1, 2} /. x_Integer -> N[x] diff --git a/mathics/docpipeline.py b/mathics/docpipeline.py index 403f3372f..c46ce0ce6 100644 --- a/mathics/docpipeline.py +++ b/mathics/docpipeline.py @@ -45,6 +45,8 @@ # When 3.8 is base, the below can be a Literal type. INVALID_TEST_GROUP_SETUP = (None, None) +CHARACTER_ENCODING = settings.SYSTEM_CHARACTER_ENCODING + TestParameters = namedtuple( "TestParameters", [ @@ -138,10 +140,6 @@ def validate_group_setup( else: self.output_data = {} - # For consistency set the character encoding ASCII which is - # the lowest common denominator available on all systems. - settings.SYSTEM_CHARACTER_ENCODING = "ASCII" - if self.session.definitions is None: self.print_and_log("Definitions are not initialized.") return INVALID_TEST_GROUP_SETUP @@ -224,7 +222,7 @@ def test_case( return False time_start = datetime.now() - comparison_result = test.compare_result(result) + comparison_result = test.compare_result(result, encoding=CHARACTER_ENCODING) if test_parameters.check_partial_elapsed_time: test_pipeline.print_and_log( @@ -498,10 +496,7 @@ def test_tests( """ test_status: TestStatus = test_pipeline.status test_parameters: TestParameters = test_pipeline.parameters - # For consistency set the character encoding ASCII which is - # the lowest common denominator available on all systems. - settings.SYSTEM_CHARACTER_ENCODING = "ASCII" test_pipeline.reset_user_definitions() output_data, names = test_pipeline.validate_group_setup( diff --git a/mathics/eval/encoding.py b/mathics/eval/encoding.py new file mode 100644 index 000000000..5e90239f5 --- /dev/null +++ b/mathics/eval/encoding.py @@ -0,0 +1,72 @@ +""" +Functions to format strings in a given encoding. +""" + +from typing import Dict + +from mathics.core.convert.op import operator_to_ascii, operator_to_unicode + +# Map WMA encoding names to Python encoding names +ENCODING_WMA_TO_PYTHON = { + "WindowsEastEurope": "cp1250", + "WindowsCyrillic": "cp1251", + "WindowsANSI": "cp1252", + "WindowsGreek": "cp1252", + "WindowsTurkish": "cp1254", +} + +UNICODE_CHARACTER_TO_ASCII = { + ch: operator_to_ascii.get(name, rf"\[{name}]") + for name, ch in operator_to_unicode.items() +} + +# These characters are used in encoding +# in WMA, and differs from what we have +# in Mathics3-scanner tables: +UNICODE_CHARACTER_TO_ASCII.update( + { + operator_to_unicode["Times"]: r" x ", + "": r"\[DifferentialD]", + } +) + + +class EncodingNameError(Exception): + pass + + +def get_encoding_table(encoding: str) -> Dict[str, str]: + """ + Return a dictionary with a map from + character codes in the internal (Unicode) + representation to the request encoding. + """ + if encoding == "Unicode": + return {} + + # In the final implementation, this should load the corresponding + # json table or an encoding file as in WMA + # SystemFiles/CharacterEncodings/*.m + # If the encoding is not available, raise an EncodingError + try: + return { + "ASCII": UNICODE_CHARACTER_TO_ASCII, + "UTF-8": {}, + }[encoding] + except KeyError: + raise EncodingNameError + + +def encode_string_value(value: str, encoding: str) -> str: + """Convert an Unicode string `value` to the required `encoding`""" + + # In WMA, encodings are readed from SystemFiles/CharacterEncodings/*.m + # on the fly. We should load them from Mathics3-Scanner tables. + encoding_table = get_encoding_table(encoding) + if not encoding_table: + return value + result = "" + for ch in value: + ch = encoding_table.get(ch, ch) + result += ch + return result diff --git a/mathics/eval/strings.py b/mathics/eval/strings.py index 4e83e2848..56f27815a 100644 --- a/mathics/eval/strings.py +++ b/mathics/eval/strings.py @@ -17,15 +17,23 @@ from mathics.core.expression_predefined import MATHICS3_INFINITY from mathics.core.list import ListExpression from mathics.core.symbols import Symbol, SymbolTrue +from mathics.eval.encoding import EncodingNameError from mathics.format.box import format_element def eval_ToString( expr: BaseElement, form: Symbol, encoding: String, evaluation: Evaluation ) -> String: - boxes = format_element(expr, evaluation, form, encoding=encoding) - text = boxes.to_text(evaluation=evaluation) - return String(text) + + boxes = format_element(expr, evaluation, form) + try: + return String(boxes.to_text(evaluation=evaluation, encoding=encoding)) + except EncodingNameError: + # Mimic the WMA behavior. In the future, we can implement the mechanism + # with encodings stored in .m files, and give a chance with it. + evaluation.message("Get", "noopen", String("encodings/" + encoding + "." + "m")) + + return String(boxes.to_text(evaluation=evaluation, encoding="Unicode")) def eval_StringContainsQ(name, string, patt, evaluation, options, matched): diff --git a/mathics/format/box/numberform.py b/mathics/format/box/numberform.py index a6dbd9eda..81a040bf3 100644 --- a/mathics/format/box/numberform.py +++ b/mathics/format/box/numberform.py @@ -17,6 +17,7 @@ Real, String, ) +from mathics.core.convert.op import operator_to_unicode from mathics.core.element import BaseElement, BoxElementMixin from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression @@ -49,7 +50,7 @@ def default_numberformat_outputform(man, base, exp, opts): "ExponentFunction": lambda x: (SymbolNull if abs(x.value) <= 5 else x), "ExponentStep": 1, "NumberFormat": default_numberformat_outputform, - "NumberMultiplier": "×", + "NumberMultiplier": operator_to_unicode["Times"], "NumberPadding": ["", "0"], "NumberPoint": ".", "NumberSeparator": [",", ""], diff --git a/mathics/format/form/inputform.py b/mathics/format/form/inputform.py index 5fd1b2564..233198f97 100644 --- a/mathics/format/form/inputform.py +++ b/mathics/format/form/inputform.py @@ -39,7 +39,6 @@ SymbolRight, ) from mathics.format.box.formatvalues import do_format # , format_element -from mathics.settings import SYSTEM_CHARACTER_ENCODING from .util import ( ARITHMETIC_OPERATOR_STRINGS, @@ -154,7 +153,6 @@ def _infix_expression_to_inputform_text( # has a head that matches with a symbol associated to an infix # operator, WMA builds its inputform without passing through # its "Infix" form. - kwargs["encoding"] = kwargs.get("encoding", SYSTEM_CHARACTER_ENCODING) operands, ops_lst, precedence, group = collect_in_pre_post_arguments( expr, evaluation, **kwargs ) @@ -198,7 +196,6 @@ def _prefix_expression_to_inputform_text( """ Convert Prefix[...] into a OutputForm string. """ - kwargs["encoding"] = kwargs.get("encoding", SYSTEM_CHARACTER_ENCODING) operands, op_head, precedence, group = collect_in_pre_post_arguments( expr, evaluation, **kwargs ) @@ -206,7 +203,6 @@ def _prefix_expression_to_inputform_text( if len(operands) != 1: raise _WrongFormattedExpression operand = operands[0] - kwargs["encoding"] = kwargs.get("encoding", SYSTEM_CHARACTER_ENCODING) target_txt = render_input_form(operand, evaluation, **kwargs) parenthesized = group in (None, SymbolRight, SymbolNonAssociative) target_txt = parenthesize(precedence, operand, target_txt, parenthesized) @@ -220,7 +216,6 @@ def _postfix_expression_to_inputform_text( """ Convert Postfix[...] into a OutputForm string. """ - kwargs["encoding"] = kwargs.get("encoding", SYSTEM_CHARACTER_ENCODING) operands, op_head, precedence, group = collect_in_pre_post_arguments( expr, evaluation, **kwargs ) @@ -295,7 +290,6 @@ def _rule_to_inputform_text(expr, evaluation: Evaluation, **kwargs) -> str: """Rule|RuleDelayed[{...}]""" head = expr.head elements = expr.elements - kwargs["encoding"] = kwargs.get("encoding", SYSTEM_CHARACTER_ENCODING) if len(elements) != 2: return _generic_to_inputform_text(expr, evaluation, **kwargs) pat, rule = (render_input_form(elem, evaluation, **kwargs) for elem in elements) diff --git a/mathics/format/form/outputform.py b/mathics/format/form/outputform.py index a2e118459..83f1b0b1f 100644 --- a/mathics/format/form/outputform.py +++ b/mathics/format/form/outputform.py @@ -47,7 +47,6 @@ get_numberform_parameters, numberform_to_boxes, ) -from mathics.settings import SYSTEM_CHARACTER_ENCODING from .inputform import render_input_form from .util import ( @@ -338,7 +337,7 @@ def other_forms(expr, evaluation, **kwargs): raise _WrongFormattedExpression result = format_element(expr, evaluation, SymbolStandardForm, **kwargs) - return result.to_text() + return result.to_text(evaluation=evaluation, **kwargs) @register_outputform("System`Integer") @@ -357,7 +356,7 @@ def integer_outputform(n, evaluation, **kwargs): result = numberform_to_boxes(n, digits, padding, evaluation, py_options) if isinstance(result, String): return result.value - return result.to_text() + return result.to_text(**kwargs) @register_outputform("System`Image") @@ -381,7 +380,6 @@ def _infix_outputform_text(expr: Expression, evaluation: Evaluation, **kwargs) - # has a head that matches with a symbol associated to an infix # operator, WMA builds its inputform without passing through # its "Infix" form. - kwargs["encoding"] = kwargs.get("encoding", SYSTEM_CHARACTER_ENCODING) operands, ops_lst, precedence, group = collect_in_pre_post_arguments( expr, evaluation, **kwargs ) @@ -681,7 +679,6 @@ def _prefix_output_text(expr: Expression, evaluation: Evaluation, **kwargs) -> s if not isinstance(expr.head, Symbol): raise _WrongFormattedExpression - kwargs["encoding"] = kwargs.get("encoding", SYSTEM_CHARACTER_ENCODING) operands, op_head, precedence, group = collect_in_pre_post_arguments( expr, evaluation, **kwargs ) @@ -691,7 +688,6 @@ def _prefix_output_text(expr: Expression, evaluation: Evaluation, **kwargs) -> s if not isinstance(op_head, str): raise _WrongFormattedExpression operand = operands[0] - kwargs["encoding"] = kwargs.get("encoding", SYSTEM_CHARACTER_ENCODING) target_txt = render_output_form(operand, evaluation, **kwargs) parenthesized = group in (None, SymbolRight, SymbolNonAssociative) target_txt = parenthesize(precedence, operand, target_txt, parenthesized) @@ -706,7 +702,6 @@ def _postfix_output_text(expr: Expression, evaluation: Evaluation, **kwargs) -> if not isinstance(expr.head, Symbol): raise _WrongFormattedExpression - kwargs["encoding"] = kwargs.get("encoding", SYSTEM_CHARACTER_ENCODING) operands, op_head, precedence, group = collect_in_pre_post_arguments( expr, evaluation, **kwargs ) @@ -776,7 +771,6 @@ def rule_to_outputform_text(expr, evaluation: Evaluation, **kwargs): raise _WrongFormattedExpression elements = expr.elements - kwargs["encoding"] = kwargs.get("encoding", SYSTEM_CHARACTER_ENCODING) if len(elements) != 2: return _default_render_output_form(expr, evaluation, **kwargs) pat, rule = (render_output_form(elem, evaluation, **kwargs) for elem in elements) diff --git a/mathics/format/form/util.py b/mathics/format/form/util.py index a3a7a7584..1160396ac 100644 --- a/mathics/format/form/util.py +++ b/mathics/format/form/util.py @@ -145,7 +145,6 @@ def collect_in_pre_post_arguments( def get_operator_str(head, evaluation, **kwargs) -> str: - encoding = kwargs["encoding"] if isinstance(head, String): op_str = head.value elif isinstance(head, Symbol): @@ -154,10 +153,7 @@ def get_operator_str(head, evaluation, **kwargs) -> str: render_function = kwargs["_render_function"] return render_function(head, evaluation, **kwargs) - if encoding == "ASCII": - operator = operator_to_ascii.get(op_str, op_str) - else: - operator = operator_to_unicode.get(op_str, op_str) + operator = operator_to_unicode.get(op_str, op_str) return operator diff --git a/mathics/format/render/mathml.py b/mathics/format/render/mathml.py index 0594a2f8b..f71dfb6a6 100644 --- a/mathics/format/render/mathml.py +++ b/mathics/format/render/mathml.py @@ -69,10 +69,25 @@ def convert_inner_box(box, **options): def encode_mathml(text: str) -> str: + """ + Convert a string into a MathML code. + * Escape special characters + * Replace non-ANSI characters by character codes. + """ text = text.replace("&", "&").replace("<", "<").replace(">", ">") text = text.replace('"', """).replace(" ", " ") text = text.replace("\n", '') - return text + # Now, handle non-ansi characters using the + # the form '&#{code};' + # Notice that this should happend after escaping special characters: + result = "" + for c in text: + code = ord(c) + if code > 127: + result += f"&#{code};" + else: + result += c + return result extra_operators = { diff --git a/mathics/format/render/text.py b/mathics/format/render/text.py index 1b07691e3..91f05c4c5 100644 --- a/mathics/format/render/text.py +++ b/mathics/format/render/text.py @@ -2,7 +2,6 @@ """ Mathics3 box rendering to plain text. """ - from mathics.builtin.box.graphics import GraphicsBox from mathics.builtin.box.graphics3d import Graphics3DBox from mathics.builtin.box.layout import ( @@ -27,6 +26,7 @@ convert_inner_box_field, ) from mathics.core.symbols import Atom, SymbolTrue +from mathics.eval.encoding import encode_string_value from mathics.format.box.graphics import prepare_elements as prepare_elements2d from mathics.format.box.graphics3d import prepare_elements as prepare_elements3d from mathics.format.form.util import _WrongFormattedExpression, text_cells_to_grid @@ -159,7 +159,7 @@ def string(s: String, **options) -> str: if value.startswith('"') and value.endswith('"'): # nopep8 if not show_string_characters: value = value[1:-1] - return value + return encode_string_value(value, options["encoding"]) add_render_function(String, string) diff --git a/test/builtin/files_io/test_files.py b/test/builtin/files_io/test_files.py index 7cf17f603..91a49fa91 100644 --- a/test/builtin/files_io/test_files.py +++ b/test/builtin/files_io/test_files.py @@ -231,28 +231,28 @@ def test_close(): ( 'stream = StringToStream["1.523E-19"]; Read[stream, Real]', None, - "1.523×10^-19", + "1.523 x 10^-19", "", ), ("Close[stream];", None, "Null", ""), ( 'stream = StringToStream["-1.523e19"]; Read[stream, Real]', None, - "-1.523×10^19", + "-1.523 x 10^19", "", ), ("Close[stream];", None, "Null", ""), ( 'stream = StringToStream["3*^10"]; Read[stream, Real]', None, - "3.×10^10", + "3. x 10^10", "", ), ("Close[stream];", None, "Null", ""), ( 'stream = StringToStream["3.*^10"]; Read[stream, Real]', None, - "3.×10^10", + "3. x 10^10", "", ), ("Close[stream];", None, "Null", ""), diff --git a/test/builtin/files_io/test_importexport.py b/test/builtin/files_io/test_importexport.py index 64b09973b..a19b13930 100644 --- a/test/builtin/files_io/test_importexport.py +++ b/test/builtin/files_io/test_importexport.py @@ -310,7 +310,7 @@ def test_inividually(): ( r'System`Convert`B64Dump`B64Decode["4oirIGYg752MIHg="]', None, - r"∫ f  x", + r"\[Integral] f \[DifferentialD] x", None, ), ], diff --git a/test/builtin/numbers/test_trig.py b/test/builtin/numbers/test_trig.py index 89d4d7100..c24226608 100644 --- a/test/builtin/numbers/test_trig.py +++ b/test/builtin/numbers/test_trig.py @@ -42,9 +42,9 @@ def test_ArcCos(): ("ArcTan[-1, 0]", None, "Pi", None), ("ArcTan[0, 1]", None, "Pi / 2", None), ("ArcTan[0, -1]", None, "-Pi / 2", None), - ("Cos[1.5 Pi]", None, "-1.83697×10^-16", None), + ("Cos[1.5 Pi]", None, "-1.83697 x 10^-16", None), ("N[Sin[1], 40]", None, "0.8414709848078965066525023216302989996226", None), - ("Tan[0.5 Pi]", None, "1.63312×10^16", None), + ("Tan[0.5 Pi]", None, "1.63312 x 10^16", None), ], ) def test_trig(str_expr, msgs, str_expected, fail_msg): diff --git a/test/builtin/test_binary.py b/test/builtin/test_binary.py index 0aebbb817..2506b054d 100644 --- a/test/builtin/test_binary.py +++ b/test/builtin/test_binary.py @@ -236,8 +236,12 @@ ('WbR[{1, 0, 0, 0, 0, 0, 240, 255}, "Real64"]', "Indeterminate", None), ## Real128 ## 0x0000 - ('WbR[{0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}, "Real128"]', "0.×10^-4965", None), - ('WbR[{0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,128}, "Real128"]', "0.×10^-4965", None), + ('WbR[{0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}, "Real128"]', "0. x 10^-4965", None), + ( + 'WbR[{0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,128}, "Real128"]', + "0. x 10^-4965", + None, + ), ## 0x0001 - 0x7FFE ( 'WbR[{0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,255,63}, "Real128"]', @@ -256,12 +260,12 @@ ), ( 'WbR[{135, 62, 233, 137, 22, 208, 233, 210, 133, 82, 251, 92, 220, 216, 207, 72}, "Real128"]', - "2.45563355727491021879689747166252×10^679", + "2.45563355727491021879689747166252 x 10^679", None, ), ( 'z=WbR[{74, 95, 30, 234, 116, 130, 1, 84, 20, 133, 245, 221, 113, 110, 219, 212}, "Real128"]', - "-4.52840681592341879518366539335138×10^1607", + "-4.52840681592341879518366539335138 x 10^1607", None, ), ("z // Precision", "33.", None), @@ -427,8 +431,8 @@ def test_ByteOrdering(str_expr, str_expected, fail_msg): @pytest.mark.parametrize( ("str_expr", "str_expected"), [ - ("NumericArray[{{1,2},{3,4}}]", ""), - ("ToString[NumericArray[{{1,2},{3,4}}]]", ""), + ("NumericArray[{{1,2},{3,4}}]", ""), + ("ToString[NumericArray[{{1,2},{3,4}}]]", ""), ("Head[NumericArray[{1,2}]]", "NumericArray"), ("AtomQ[NumericArray[{1,2}]]", "True"), ("First[NumericArray[{1,2,3}]]", "1"), diff --git a/test/builtin/test_forms.py b/test/builtin/test_forms.py index 16650ebcb..ff61794ce 100644 --- a/test/builtin/test_forms.py +++ b/test/builtin/test_forms.py @@ -46,8 +46,8 @@ def test_makeboxes_form(expr, form, head, subhead): ("NumberForm[14310983091809]", None, "14310983091809", None), ## Zero case ("z0 = 0.0;z1 = 0.0000000000000000000000000000;", None, "Null", None), - ("NumberForm[{z0, z1}, 10]", None, "{0., 0.×10^-28}", None), - ("NumberForm[{z0, z1}, {10, 4}]", None, "{0.0000, 0.0000×10^-28}", None), + ("NumberForm[{z0, z1}, 10]", None, "{0., 0. x 10^-28}", None), + ("NumberForm[{z0, z1}, {10, 4}]", None, "{0.0000, 0.0000 x 10^-28}", None), ("z0=.;z1=.;", None, "Null", None), ## Trailing zeros ("NumberForm[1.0, 10]", None, "1.", None), @@ -67,7 +67,7 @@ def test_makeboxes_form(expr, form, head, subhead): ( "NumberForm[{2^123, 2^123.}, 4, ExponentFunction -> ((#1) &)]", None, - "{10633823966279326983230456482242756608, 1.063×10^37}", + "{10633823966279326983230456482242756608, 1.063 x 10^37}", None, ), ("NumberForm[{0, 10, -512}, {10, 3}]", None, "{0.000, 10.000, -512.000}", None), @@ -178,7 +178,7 @@ def test_makeboxes_form(expr, form, head, subhead): ( "NumberForm[12345.123456789, 14, ExponentFunction -> ((#) &)]", None, - "1.2345123456789×10^4", + "1.2345123456789 x 10^4", None, ), ( @@ -191,7 +191,7 @@ def test_makeboxes_form(expr, form, head, subhead): ( "NumberForm[y, 10, ExponentFunction -> (3 Quotient[#, 3] &)]", None, - "{114.0256472×10^-12, 3.267763643×10^-3, 93.64804748×10^3, 2.683779414×10^12, 76.91214221×10^18}", + "{114.0256472 x 10^-12, 3.267763643 x 10^-3, 93.64804748 x 10^3, 2.683779414 x 10^12, 76.91214221 x 10^18}", None, ), ( @@ -207,7 +207,7 @@ def test_makeboxes_form(expr, form, head, subhead): ( "NumberForm[10^8 N[Pi], 10, ExponentStep -> 3]", None, - "314.1592654×10^6", + "314.1592654 x 10^6", None, ), ( @@ -225,7 +225,7 @@ def test_makeboxes_form(expr, form, head, subhead): ( "NumberForm[y, 10, ExponentStep -> 6]", None, - "{114.0256472×10^-12, 3267.763643×10^-6, 93648.04748, 2.683779414×10^12, 76.91214221×10^18}", + "{114.0256472 x 10^-12, 3267.763643 x 10^-6, 93648.04748, 2.683779414 x 10^12, 76.91214221 x 10^18}", None, ), ## NumberFormat @@ -318,7 +318,7 @@ def test_makeboxes_form(expr, form, head, subhead): ( 'NumberForm[N[10^ 7 Pi], 15, DigitBlock -> 3, NumberSeparator -> {",", " "}]', None, - "3.141 592 653 589 79×10^7", + "3.141 592 653 589 79 x 10^7", None, ), ( diff --git a/test/builtin/test_numeric.py b/test/builtin/test_numeric.py index 78d3a25a4..1ca38e27c 100644 --- a/test/builtin/test_numeric.py +++ b/test/builtin/test_numeric.py @@ -76,19 +76,19 @@ def test_realvalued(): ( "N[3^200]", None, - "2.65614×10^95", + "2.65614 x 10^95", "Numeric converts a large integer to a MachineReal without losing precision", ), ( "N[2^1023]", None, - "8.98847×10^307", + "8.98847 x 10^307", "Numeric display digits for value under 2^1024 is DefaultPrintDisplay value 6", ), ( "N[2^1024]", None, - "1.797693134862316×10^308", + "1.797693134862316 x 10^308", "Numeric display digits for value on or over= 2^1024 is $MachineDigits", ), ( diff --git a/test/format/format_tests.yaml b/test/format/format_tests.yaml index 569bb769b..71e70a839 100644 --- a/test/format/format_tests.yaml +++ b/test/format/format_tests.yaml @@ -70,10 +70,10 @@ System`StandardForm: "\\text{$\\pi$ is a trascendental number}" System`TraditionalForm: "\\text{$\\pi$ is a trascendental number}" mathml: - System`InputForm: "\u03C0 is a trascendental number" - System`OutputForm: "\u03C0 is a trascendental number" - System`StandardForm: "\u03C0 is a trascendental number" - System`TraditionalForm: "\u03C0 is a trascendental number" + System`InputForm: "π is a trascendental number" + System`OutputForm: "π is a trascendental number" + System`StandardForm: "π is a trascendental number" + System`TraditionalForm: "π is a trascendental number" text: System`InputForm: "\"\u03C0 is a trascendental number\"" System`OutputForm: "\u03C0 is a trascendental number" @@ -100,7 +100,7 @@ mathml: {} text: System`InputForm: -1.*^-6 - System`OutputForm: "-1.\xD710^-6" + System`OutputForm: "-1. x 10^-6" -1. 10^5: @@ -124,9 +124,9 @@ mathml: {} text: System`InputForm: -1.*^6 - System`OutputForm: "-1.\xD710^6" + System`OutputForm: "-1. x 10^6" System`StandardForm: -1.`*^6 - System`TraditionalForm: "-1.`\xD710^6" + System`TraditionalForm: "-1.` x 10^6" '-4': @@ -224,7 +224,7 @@ mathml: {} text: System`InputForm: 1.*^-6 - System`OutputForm: "1.\xD710^-6" + System`OutputForm: "1. x 10^-6" 1. 10^5: @@ -252,9 +252,9 @@ mathml: {} text: System`InputForm: 1.*^6 - System`OutputForm: "1.\xD710^6" + System`OutputForm: "1. x 10^6" System`StandardForm: 1.`*^6 - System`TraditionalForm: "1.`\xD710^6" + System`TraditionalForm: "1.` x 10^6" 1/(1+1/(1+1/a)): @@ -287,13 +287,13 @@ <|a -> x, b -> y, c -> <|d -> t|>|>: msg: Association latex: - System`InputForm: '\text{$<$$\vert$a -$>$ x, b -$>$ y, c -$>$ $<$$\vert$d -$>$ t$\vert$$>$$\vert$$>$}' - System`OutputForm: '\text{$<$$\vert$a -$>$ x, b -$>$ y, c -$>$ $<$$\vert$d -$>$ t$\vert$$>$$\vert$$>$}' + System`InputForm: '\text{$<$$\vert$a $\to$ x, b $\to$ y, c $\to$ $<$$\vert$d $\to$ t$\vert$$>$$\vert$$>$}' + System`OutputForm: '\text{$<$$\vert$a $\to$ x, b $\to$ y, c $\to$ $<$$\vert$d $\to$ t$\vert$$>$$\vert$$>$}' System`StandardForm: '\langle\vert a->x, b->y, c->\langle\vert d->t\vert\rangle \vert\rangle' System`TraditionalForm: '\langle\vert a->x, b->y, c->\langle\vert d->t\vert\rangle \vert\rangle' mathml: - System`InputForm: <|a -> x, b -> y, c -> <|d -> t|>|> - System`OutputForm: '<|a -> x, b -> y, c -> <|d -> t|>|>' + System`InputForm: <|a ⇾ x, b ⇾ y, c ⇾ <|d ⇾ t|>|> + System`OutputForm: '<|a ⇾ x, b ⇾ y, c ⇾ <|d ⇾ t|>|>' System`StandardForm: "\n <|\n \n \n a\n ->\n x\n \n ,\n \n b\n ->\n y\n \n ,\n \n c\n ->\n \n <|\n \n d\n ->\n t\n \n |>\n \n \n \n |>\n" System`TraditionalForm: "\n <|\n \n \n a\n ->\n x\n \n ,\n \n b\n ->\n y\n \n ,\n \n c\n ->\n \n <|\n \n d\n ->\n t\n \n |>\n \n \n \n |>\n" text: @@ -306,13 +306,13 @@ Association[a -> x, b -> y, c -> Association[d -> t, Association[e -> u]]]: msg: Nested Association latex: - System`InputForm: '\text{$<$$\vert$a -$>$ x, b -$>$ y, c -$>$ $<$$\vert$d -$>$ t, e -$>$ u$\vert$$>$$\vert$$>$}' - System`OutputForm: '\text{$<$$\vert$a -$>$ x, b -$>$ y, c -$>$ $<$$\vert$d -$>$ t, e -$>$ u$\vert$$>$$\vert$$>$}' + System`InputForm: '\text{$<$$\vert$a $\to$ x, b $\to$ y, c $\to$ $<$$\vert$d $\to$ t, e $\to$ u$\vert$$>$$\vert$$>$}' + System`OutputForm: '\text{$<$$\vert$a $\to$ x, b $\to$ y, c $\to$ $<$$\vert$d $\to$ t, e $\to$ u$\vert$$>$$\vert$$>$}' System`StandardForm: '\langle\vert a->x, b->y, c->\langle\vert d->t, e->u\vert\rangle \vert\rangle' System`TraditionalForm: '\langle\vert a->x, b->y, c->\langle\vert d->t, e->u\vert\rangle \vert\rangle' mathml: - System`InputForm: "<|a -> x, b -> y, c -> <|d -> t, e -> u|>|>" - System`OutputForm: '<|a -> x, b -> y, c -> <|d -> t, e -> u|>|>' + System`InputForm: "<|a ⇾ x, b ⇾ y, c ⇾ <|d ⇾ t, e ⇾ u|>|>" + System`OutputForm: '<|a ⇾ x, b ⇾ y, c ⇾ <|d ⇾ t, e ⇾ u|>|>' System`StandardForm: "\n <|\n \n \n a\n ->\n x\n \n ,\n \n b\n ->\n y\n \n ,\n \n c\n ->\n \n <|\n \n \n d\n ->\n t\n \n ,\n \n e\n ->\n u\n \n \n |>\n \n \n \n |>\n" System`TraditionalForm: "\n <|\n \n \n a\n ->\n x\n \n ,\n \n b\n ->\n y\n \n ,\n \n c\n ->\n \n <|\n \n \n d\n ->\n t\n \n ,\n \n e\n ->\n u\n \n \n |>\n \n \n \n |>\n" text: @@ -331,14 +331,14 @@ Complex[1.09*^12, 3.]: System`TraditionalForm: 1.09\times 10^{12}+3. I mathml: System`InputForm: 1.09*^12 + 3.*I - System`OutputForm: '1.09×10^12 + 3. I' + System`OutputForm: '1.09×10^12 + 3. I' System`StandardForm: "\n \n 1.09\n *^\n 12\n \n +\n \n 3.\n  \n I\n \n" - System`TraditionalForm: "\n \n 1.09\n ×\n \n 10\n 12\n \n \n +\n \n 3.\n \n I\n \n" + System`TraditionalForm: "\n \n 1.09\n ×\n \n 10\n 12\n \n \n +\n \n 3.\n \n I\n \n" text: System`InputForm: 1.09*^12 + 3.*I - System`OutputForm: "1.09\xD710^12 + 3. I" + System`OutputForm: "1.09 x 10^12 + 3. I" System`StandardForm: 1.09`*^12+3.` I - System`TraditionalForm: "1.09`\xD710^12+3.`\u2062I" + System`TraditionalForm: "1.09` x 10^12+3.`\u2062I" Graphics[{Text[a^b,{0,0}]}]: @@ -458,10 +458,10 @@ Graphics[{}]: System`TraditionalForm: "\\begin{array}{cc} \\text{Spanish} & \\text{Hola!}\\\\\ \ \\text{Portuguese} & \\text{Ol\\`{a}!}\\\\ \\text{English} & \\text{Hi!}\\end{array}" mathml: - System`InputForm: "Grid[{{"Spanish", "Hola!"}, {"Portuguese", "Olà!"}, {"English", "Hi!"}}]" - System`OutputForm: 'Spanish      Hola!Portuguese   Olà!English      Hi!' - System`StandardForm: "\n \n \n Spanish\n \n \n Hola!\n \n \n \n \n Portuguese\n \n \n Olà!\n \n \n \n \n English\n \n \n Hi!\n \n \n" - System`TraditionalForm: "\n \n \n Spanish\n \n \n Hola!\n \n \n \n \n Portuguese\n \n \n Olà!\n \n \n \n \n English\n \n \n Hi!\n \n \n" + System`InputForm: "Grid[{{"Spanish", "Hola!"}, {"Portuguese", "Olà!"}, {"English", "Hi!"}}]" + System`OutputForm: 'Spanish      Hola!Portuguese   Olà!English      Hi!' + System`StandardForm: "\n \n \n Spanish\n \n \n Hola!\n \n \n \n \n Portuguese\n \n \n Olà!\n \n \n \n \n English\n \n \n Hi!\n \n \n" + System`TraditionalForm: "\n \n \n Spanish\n \n \n Hola!\n \n \n \n \n Portuguese\n \n \n Olà!\n \n \n \n \n English\n \n \n Hi!\n \n \n" text: System`InputForm: "Grid[{{\"Spanish\", \"Hola!\"}, {\"Portuguese\", \"Ol\xE0!\"\ }, {\"English\", \"Hi!\"}}]" @@ -523,13 +523,13 @@ Integrate[F[x], {x, a, g[b]}]: mathml: System`InputForm: 'Integrate[F[x], {x, a, g[b]}]' System`OutputForm: 'Integrate[F[x], {x, a, g[b]}]' - System`StandardForm: "\n \n \n a\n \n g\n [\n b\n ]\n \n \n \u2062\n \n F\n [\n x\n ]\n \n \u2062\n \n 𝑑\n x\n \n" - System`TraditionalForm: "\n \n \n a\n \n g\n (\n b\n )\n \n \n \u2062\n \n F\n (\n x\n )\n \n \u2062\n \n 𝑑\n x\n \n" + System`StandardForm: "\n \n \n a\n \n g\n [\n b\n ]\n \n \n \n \n F\n [\n x\n ]\n \n \n \n 𝑑\n x\n \n" + System`TraditionalForm: "\n \n \n a\n \n g\n (\n b\n )\n \n \n \n \n F\n (\n x\n )\n \n \n \n 𝑑\n x\n \n" text: System`InputForm: Integrate[F[x], {x, a, g[b]}] System`OutputForm: Integrate[F[x], {x, a, g[b]}] - System`StandardForm: 'Subsuperscript[∫, a, g[b]]⁢F[x]⁢𝑑x' - System`TraditionalForm: 'Subsuperscript[∫, a, g(b)]⁢F(x)⁢𝑑x' + System`StandardForm: 'Subsuperscript[\[Integral], a, g[b]]⁢F[x]⁢\[DifferentialD]x' + System`TraditionalForm: 'Subsuperscript[\[Integral], a, g(b)]⁢F(x)⁢\[DifferentialD]x' MatrixForm[{{a,b},{c,d}}]: msg: GridBox in a matrix @@ -730,8 +730,8 @@ TableForm[{{a,b},{c,d}}]: mathml: System`InputForm: Pi System`OutputForm: 'Pi' - System`StandardForm: "\u03C0" - System`TraditionalForm: "\u03C0" + System`StandardForm: "π" + System`TraditionalForm: "π" text: System`InputForm: Pi System`OutputForm: Pi @@ -747,10 +747,10 @@ TableForm[{{a,b},{c,d}}]: System`StandardForm: \alpha System`TraditionalForm: \alpha mathml: - System`InputForm: 'α' - System`OutputForm: 'α' - System`StandardForm: 'α' - System`TraditionalForm: 'α' + System`InputForm: 'α' + System`OutputForm: 'α' + System`StandardForm: 'α' + System`TraditionalForm: 'α' text: System`InputForm: 'α' System`OutputForm: 'α' diff --git a/test/format/test_format.py b/test/format/test_format.py index f6aeea269..bd824201f 100644 --- a/test/format/test_format.py +++ b/test/format/test_format.py @@ -115,10 +115,13 @@ def test_makeboxes_text_fragile(str_expr, str_expected, form, msg): format_result = result.format(session.evaluation, form) if msg: assert ( - format_result.to_text(evaluation=session.evaluation) == str_expected + format_result.to_text(evaluation=session.evaluation, encoding="ASCII") + == str_expected ), msg else: - strresult = format_result.to_text(evaluation=session.evaluation) + strresult = format_result.to_text( + evaluation=session.evaluation, encoding="ASCII" + ) assert strresult == str_expected @@ -130,9 +133,14 @@ def test_makeboxes_text(str_expr, str_expected, form, msg): result = session.evaluate(str_expr) format_result = result.format(session.evaluation, form) if msg: - assert format_result.to_text(evaluation=session.evaluation) == str_expected, msg + assert ( + format_result.to_text(evaluation=session.evaluation, encoding="ASCII") + == str_expected + ), msg else: - strresult = format_result.to_text(evaluation=session.evaluation) + strresult = format_result.to_text( + evaluation=session.evaluation, encoding="ASCII" + ) assert strresult == str_expected @@ -175,7 +183,9 @@ def test_makeboxes_tex(str_expr, str_expected, form, msg): == str_expected.strip() ), msg else: - strresult = format_result.to_text(evaluation=session.evaluation).strip() + strresult = format_result.to_text( + evaluation=session.evaluation, encoding="ASCII" + ).strip() assert strresult == str_expected @@ -209,7 +219,8 @@ def test_makeboxes_mathml(str_expr, str_expected, form, msg): format_result = result.format(session.evaluation, form) if msg: assert ( - format_result.to_mathml(evaluation=session.evaluation) == str_expected + format_result.to_mathml(evaluation=session.evaluation, encoding="ASCII") + == str_expected ), msg else: strresult = format_result.to_mathml(evaluation=session.evaluation) @@ -221,7 +232,7 @@ def test_makeboxes_mathml(str_expr, str_expected, form, msg): [ ( "OutputForm[Complex[2.0 ^ 40, 3]]", - "1.09951×10^12 + 3. I", + "1.09951 x 10^12 + 3. I", "OutputForm Complex", ), ( diff --git a/test/helper.py b/test/helper.py index dc0900eb4..7407920da 100644 --- a/test/helper.py +++ b/test/helper.py @@ -189,7 +189,7 @@ def check_evaluation_as_in_cli( if failure_message: assert res.result == str_expected, failure_message - assert res.result == str_expected + assert res.result == str_expected, f"'{res.result}'!='{str_expected}'" # List below could be a Tuple, but List looks better in the tests