Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-Mathics for openSUSE:Factory checked in at 2023-07-30 20:57:53 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-Mathics (Old) and /work/SRC/openSUSE:Factory/.python-Mathics.new.32662 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-Mathics" Sun Jul 30 20:57:53 2023 rev:16 rq:1101333 version:6.0.2 Changes: -------- --- /work/SRC/openSUSE:Factory/python-Mathics/python-Mathics.changes 2023-07-26 13:24:07.068062623 +0200 +++ /work/SRC/openSUSE:Factory/.python-Mathics.new.32662/python-Mathics.changes 2023-07-30 20:57:56.195278340 +0200 @@ -1,0 +2,11 @@ +Wed Jul 26 15:24:55 UTC 2023 - Atri Bhattacharya <badshah...@gmail.com> + +- Update to version 6.0.2: + * Change testing to facilitate openSUSE Tumbleweed distribution + which uses Sympy 1.12 (gh#Mathics3/mathics-core#881). +- Drop python-Mathics-relax-module-versions.patch: No longer + required as upstream has removed numpy and scipy upper limits + from requirements. +- Re-enable test_calculus. + +------------------------------------------------------------------- Old: ---- Mathics3-6.0.1.tar.gz python-Mathics-relax-module-versions.patch New: ---- Mathics3-6.0.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-Mathics.spec ++++++ --- /var/tmp/diff_new_pack.4dnus6/_old 2023-07-30 20:57:56.863282306 +0200 +++ /var/tmp/diff_new_pack.4dnus6/_new 2023-07-30 20:57:56.867282330 +0200 @@ -32,15 +32,13 @@ %define skip_python311 1 %define pyname Mathics3 Name: python-Mathics%{psuffix} -Version: 6.0.1 +Version: 6.0.2 Release: 0 Summary: A general-purpose computer algebra system # Mathics itself is licensed as GPL-3.0 but it includes third-party software with MIT, BSD-3-Clause, and Apache-2.0 Licensing; also includes data from wikipedia licensed under CC-BY-SA-3.0 and GFDL-1.3 License: Apache-2.0 AND BSD-3-Clause AND GPL-3.0-only AND MIT URL: https://mathics.github.io/ Source0: https://github.com/Mathics3/mathics-core/releases/download/%{version}/%{pyname}-%{version}.tar.gz -# PATCH-FEATURE-OPENSUSE python-Mathics-relax-module-versions.patch gh#mathics-core/issues#881 badshah...@gmail.com -- Relax upper limits on sympy and numpy to get packages building for Tumbleweed -Patch0: python-Mathics-relax-module-versions.patch BuildRequires: %{python_module Cython} BuildRequires: %{python_module Django >= 1.8} BuildRequires: %{python_module colorama} @@ -117,8 +115,7 @@ %check # Home page tests require django server up and running, test_gudermannian needs network access # test_image: https://github.com/Mathics3/mathics-core/issues/837 -# test_calculus: https://github.com/Mathics3/mathics-core/issues/881 -%pytest_arch -k 'not (test_home_page or test_gudermannian or test_image or test_calculus)' +%pytest_arch -k 'not (test_home_page or test_gudermannian or test_image)' %endif %if %{without test} ++++++ Mathics3-6.0.1.tar.gz -> Mathics3-6.0.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mathics3-6.0.1/CHANGES.rst new/Mathics3-6.0.2/CHANGES.rst --- old/Mathics3-6.0.1/CHANGES.rst 2023-03-05 11:08:11.000000000 +0100 +++ new/Mathics3-6.0.2/CHANGES.rst 2023-07-23 23:23:47.000000000 +0200 @@ -3,6 +3,16 @@ CHANGES ======= +Change testing to facilitate openSUSE Tumbleweed distribution which uses Sympy 1.12. See `Issue #881 <https://github.com/Mathics3/mathics-core/issues/881>`_. + +6.0.2 +----- + +Package update +.............. + +#. SymPy 1.12 accepted + 6.0.1 ----- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mathics3-6.0.1/ChangeLog new/Mathics3-6.0.2/ChangeLog --- old/Mathics3-6.0.1/ChangeLog 2023-03-05 09:39:57.000000000 +0100 +++ new/Mathics3-6.0.2/ChangeLog 2023-07-23 23:01:20.000000000 +0200 @@ -1,3 +1,27 @@ +2023-07-23 rocky <r...@dustyfeet.com> + + * CHANGES.rst, mathics/version.py: Get ready for release 6.0.2 + +2023-07-20 R. Bernstein <ro...@users.noreply.github.com> + + * : Merge pull request #884 from Mathics3/601-get-windows-ci-working See if we can get Windows CI working again + +2023-07-19 R. Bernstein <ro...@users.noreply.github.com> + + * : Merge pull request #883 from Mathics3/fix881_601 fix #881 + +2023-03-05 rocky <r...@dustyfeet.com> + + * admin-tools/make-dist.sh: Administrivia doc->doctest + +2023-03-05 rocky <r...@dustyfeet.com> + + * CHANGES.rst: Spelling + +2023-03-05 R. Bernstein <ro...@users.noreply.github.com> + + * : Merge pull request #807 from Mathics3/release-6.0.1 Get ready for release 6.0.1 + 2023-03-02 R. Bernstein <ro...@users.noreply.github.com> * : Merge pull request #803 from Mathics3/combinatorica-91 Use recently-found V0.91 version diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mathics3-6.0.1/Mathics3.egg-info/PKG-INFO new/Mathics3-6.0.2/Mathics3.egg-info/PKG-INFO --- old/Mathics3-6.0.1/Mathics3.egg-info/PKG-INFO 2023-03-05 11:15:02.000000000 +0100 +++ new/Mathics3-6.0.2/Mathics3.egg-info/PKG-INFO 2023-07-23 23:37:36.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: Mathics3 -Version: 6.0.1 +Version: 6.0.2 Summary: A general-purpose computer algebra system. Home-page: https://mathics.org/ Download-URL: https://github.com/Mathics/mathics-core/releases diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mathics3-6.0.1/Mathics3.egg-info/SOURCES.txt new/Mathics3-6.0.2/Mathics3.egg-info/SOURCES.txt --- old/Mathics3-6.0.1/Mathics3.egg-info/SOURCES.txt 2023-03-05 11:15:02.000000000 +0100 +++ new/Mathics3-6.0.2/Mathics3.egg-info/SOURCES.txt 2023-07-23 23:37:36.000000000 +0200 @@ -52,6 +52,7 @@ mathics/autoload/formats/Text/Import.m mathics/autoload/formats/XML/Import.m mathics/builtin/__init__.py +mathics/builtin/_quantities-try.py mathics/builtin/arithmetic.py mathics/builtin/attributes.py mathics/builtin/base.py @@ -75,7 +76,6 @@ mathics/builtin/patterns.py mathics/builtin/physchemdata.py mathics/builtin/procedural.py -mathics/builtin/quantities-try.py mathics/builtin/quantities.py mathics/builtin/recurrence.py mathics/builtin/scoping.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mathics3-6.0.1/Mathics3.egg-info/requires.txt new/Mathics3-6.0.2/Mathics3.egg-info/requires.txt --- old/Mathics3-6.0.1/Mathics3.egg-info/requires.txt 2023-03-05 11:15:02.000000000 +0100 +++ new/Mathics3-6.0.2/Mathics3.egg-info/requires.txt 2023-07-23 23:37:36.000000000 +0200 @@ -1,7 +1,7 @@ Mathics-Scanner>=1.3.0 -numpy<=1.24 +numpy<1.25 llvmlite -sympy<1.12,>=1.8 +sympy>=1.8 pillow>=9.2 mpmath>=1.2.0 palettable diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mathics3-6.0.1/PKG-INFO new/Mathics3-6.0.2/PKG-INFO --- old/Mathics3-6.0.1/PKG-INFO 2023-03-05 11:15:02.929967600 +0100 +++ new/Mathics3-6.0.2/PKG-INFO 2023-07-23 23:37:37.116025200 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: Mathics3 -Version: 6.0.1 +Version: 6.0.2 Summary: A general-purpose computer algebra system. Home-page: https://mathics.org/ Download-URL: https://github.com/Mathics/mathics-core/releases diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mathics3-6.0.1/mathics/builtin/_quantities-try.py new/Mathics3-6.0.2/mathics/builtin/_quantities-try.py --- old/Mathics3-6.0.1/mathics/builtin/_quantities-try.py 1970-01-01 01:00:00.000000000 +0100 +++ new/Mathics3-6.0.2/mathics/builtin/_quantities-try.py 2023-02-27 01:35:42.000000000 +0100 @@ -0,0 +1,486 @@ +# -*- coding: utf-8 -*- +""" +Units and Quantities +""" + +from pint import UnitRegistry + +from mathics.builtin.base import Builtin, Test +from mathics.core.atoms import Atom, Integer, Integer1, Number, Real, String +from mathics.core.attributes import ( + A_HOLD_REST, + A_N_HOLD_REST, + A_PROTECTED, + A_READ_PROTECTED, +) +from mathics.core.convert.expression import to_mathics_list +from mathics.core.convert.python import from_python +from mathics.core.evaluation import Evaluation +from mathics.core.expression import Expression +from mathics.core.list import ListExpression +from mathics.core.symbols import Symbol +from mathics.core.systemsymbols import SymbolQuantity, SymbolRowBox + +# This tells documentation how to sort this module +sort_order = "mathics.builtin.units-and-quantites" + +ureg = UnitRegistry() +Q_ = ureg.Quantity + + +def get_converted_magnitude(magnitude_expr, evaluation: Evaluation) -> float: + """ + The Python "pint" library mixes in a Python numeric value as a multiplier inside + a Mathics Expression. here we pick out that multiplier and + convert it from a Python numeric to a Mathics numeric. + """ + magnitude_elements = list(magnitude_expr.elements) + magnitude_elements[1] = from_python(magnitude_elements[1]) + magnitude_expr._elements = tuple(magnitude_elements) + # FIXME: consider returning an int when that is possible + return magnitude_expr.evaluate(evaluation).get_float_value() + + +class KnownUnitQ(Test): + """ + <url> + :WMA link: + https://reference.wolfram.com/language/ref/KnownUnitQ.html</url> + + <dl> + <dt>'KnownUnitQ[$unit$]' + <dd>returns True if $unit$ is a canonical unit, and False otherwise. + </dl> + + >> KnownUnitQ["Feet"] + = True + + >> KnownUnitQ["Foo"] + = False + """ + + summary_text = "tests whether its argument is a canonical unit." + + def test(self, expr): + def validate(unit): + try: + Q_(1, unit) + except Exception: + return False + else: + return True + + return validate(expr.get_string_value().lower()) + + +class Quantity(Builtin): + """ + <url> + :WMA link: + https://reference.wolfram.com/language/ref/Quantity.html</url> + + <dl> + <dt>'Quantity[$magnitude$, $unit$]' + <dd>represents a quantity with size $magnitude$ and unit specified by $unit$. + + <dt>'Quantity[$unit$]' + <dd>assumes the magnitude of the specified $unit$ to be 1. + </dl> + + >> Quantity["Kilogram"] + = 1 kilogram + + >> Quantity[10, "Meters"] + = 10 meter + + >> Quantity[{10,20}, "Meters"] + = {10 meter, 20 meter} + + #> Quantity[10, Meters] + = Quantity[10, Meters] + + #> Quantity[Meters] + : Unable to interpret unit specification Meters. + = Quantity[Meters] + + #> Quantity[1, "foot"] + = 1 foot + """ + + attributes = A_HOLD_REST | A_N_HOLD_REST | A_PROTECTED | A_READ_PROTECTED + + messages = { + "unkunit": "Unable to interpret unit specification `1`.", + } + summary_text = "represents a quantity with units" + + def validate(self, unit, evaluation: Evaluation): + if KnownUnitQ(unit).evaluate(evaluation) is Symbol("False"): + return False + return True + + def eval_makeboxes(self, mag, unit, f, evaluation: Evaluation): + "MakeBoxes[Quantity[mag_, unit_String], f:StandardForm|TraditionalForm|OutputForm|InputForm]" + + q_unit = unit.value.lower() + if self.validate(unit, evaluation): + return Expression( + SymbolRowBox, ListExpression(mag, String(" "), String(q_unit)) + ) + else: + return Expression( + SymbolRowBox, + to_mathics_list(SymbolQuantity, "[", mag, ",", q_unit, "]"), + ) + + def eval_mag_unit(self, mag, unit, evaluation: Evaluation): + "Quantity[mag_, unit_String]" + + if self.validate(unit, evaluation): + if mag.has_form("List", None): + results = [] + for i in range(len(mag.elements)): + quantity = Q_(mag.elements[i], unit.value.lower()) + results.append( + Expression( + SymbolQuantity, quantity.magnitude, String(quantity.units) + ) + ) + return ListExpression(*results) + else: + quantity = Q_(mag, unit.value.lower()) + return Expression( + SymbolQuantity, quantity.magnitude, String(quantity.units) + ) + else: + evaluation.message("Quantity", "unkunit", unit) + + def eval(self, unit, evaluation: Evaluation): + "Quantity[unit_]" + if not isinstance(unit, String): + evaluation.message("Quantity", "unkunit", unit) + else: + return self.eval_n(Integer1, unit, evaluation) + + +class QuantityMagnitude(Builtin): + """ + <url> + :WMA link: + https://reference.wolfram.com/language/ref/QuantityMagnitude.html</url> + + <dl> + <dt>'QuantityMagnitude[$quantity$]' + <dd>gives the amount of the specified $quantity$. + + <dt>'QuantityMagnitude[$quantity$, $unit$]' + <dd>gives the value corresponding to $quantity$ when converted to $unit$. + </dl> + + >> QuantityMagnitude[Quantity["Kilogram"]] + = 1 + + >> QuantityMagnitude[Quantity[10, "Meters"]] + = 10 + + >> QuantityMagnitude[Quantity[{10,20}, "Meters"]] + = {10, 20} + + #> QuantityMagnitude[Quantity[1, "meter"], "centimeter"] + = 100 + + #> QuantityMagnitude[Quantity[{3,1}, "meter"], "centimeter"] + = {300, 100} + + #> QuantityMagnitude[Quantity[{300,100}, "centimeter"], "meter"] + = {3, 1} + + #> QuantityMagnitude[Quantity[{3, 1}, "meter"], "inch"] + = {118.11, 39.3701} + + #> QuantityMagnitude[Quantity[{3, 1}, "meter"], Quantity[3, "centimeter"]] + = {300, 100} + + #> QuantityMagnitude[Quantity[3,"mater"]] + : Unable to interpret unit specification mater. + = QuantityMagnitude[Quantity[3,mater]] + """ + + summary_text = "get magnitude associated with a quantity." + + def eval(self, expr, evaluation: Evaluation): + "QuantityMagnitude[expr_]" + + def get_magnitude(elements): + if len(elements) == 1: + return 1 + else: + return elements[0] + + if len(evaluation.out) > 0: + return + if expr.has_form("List", None): + results = [] + for i in range(len(expr.elements)): + results.append(get_magnitude(expr.elements[i].elements)) + return ListExpression(*results) + else: + return get_magnitude(expr.elements) + + def eval_unit(self, expr, unit, evaluation: Evaluation): + "QuantityMagnitude[expr_, unit_]" + + def get_magnitude(elements, targetUnit, evaluation: Evaluation): + quantity = Q_(elements[0], elements[1].get_string_value()) + converted_quantity = quantity.to(targetUnit) + q_mag = get_converted_magnitude(converted_quantity.magnitude, evaluation) + + # Displaying the magnitude in Integer form if the convert rate is an Integer + if q_mag - int(q_mag) > 0: + return Real(q_mag) + else: + return Integer(q_mag) + + if len(evaluation.out) > 0: + return + + # Getting the target unit + if unit.has_form("Quantity", None): + targetUnit = unit.elements[1].get_string_value().lower() + elif unit.has_form("List", None): + if not unit.elements[0].has_form("Quantity", None): + return + else: + targetUnit = unit.elements[0].elements[1].get_string_value().lower() + elif isinstance(unit, String): + targetUnit = unit.get_string_value().lower() + else: + return + + # convert the quantity to the target unit and return the magnitude + if expr.has_form("List", None): + results = [] + for i in range(len(expr.elements)): + results.append( + get_magnitude(expr.elements[i].elements, targetUnit, evaluation) + ) + return ListExpression(*results) + else: + return get_magnitude(expr.elements, targetUnit, evaluation) + + +class QuantityQ(Test): + """ + <url> + :WMA link: + https://reference.wolfram.com/language/ref/QuantityQ.html</url> + <dl> + <dt>'QuantityQ[$expr$]' + <dd>return True if $expr$ is a valid Association object, and False otherwise. + </dl> + + >> QuantityQ[Quantity[3, "Meters"]] + = True + + >> QuantityQ[Quantity[3, "Maters"]] + : Unable to interpret unit specification Maters. + = False + + #> QuantityQ[3] + = False + """ + + summary_text = "tests whether its the argument is a quantity" + + def test(self, expr): + def validate_unit(unit): + try: + Q_(1, unit) + except Exception: + return False + else: + return True + + def validate(elements): + if len(elements) < 1 or len(elements) > 2: + return False + elif len(elements) == 1: + if validate_unit(elements[0].get_string_value().lower()): + return True + else: + return False + else: + if isinstance(elements[0], Number): + if validate_unit(elements[1].get_string_value().lower()): + return True + else: + return False + else: + return False + + return expr.get_head() == SymbolQuantity and validate(expr.elements) + + +class QuantityUnit(Builtin): + """ + <url> + :WMA link: + https://reference.wolfram.com/language/ref/QuantityUnit.html</url> + + <dl> + <dt>'QuantityUnit[$quantity$]' + <dd>returns the unit associated with the specified $quantity$. + </dl> + + >> QuantityUnit[Quantity["Kilogram"]] + = kilogram + + >> QuantityUnit[Quantity[10, "Meters"]] + = meter + + >> QuantityUnit[Quantity[{10,20}, "Meters"]] + = {meter, meter} + + #> QuantityUnit[Quantity[10, "aaa"]] + : Unable to interpret unit specification aaa. + = QuantityUnit[Quantity[10,aaa]] + """ + + summary_text = "the unit associated to a quantity" + + def eval(self, expr, evaluation: Evaluation): + "QuantityUnit[expr_]" + + def get_unit(elements): + if len(elements) == 1: + return elements[0] + else: + return elements[1] + + if len(evaluation.out) > 0: + return + if expr.has_form("List", None): + results = [] + for i in range(len(expr.elements)): + results.append(get_unit(expr.elements[i].elements)) + return ListExpression(*results) + else: + return get_unit(expr.elements) + + +class UnitConvert(Builtin): + + """ + <url> + :WMA link: + https://reference.wolfram.com/language/ref/UnitConvert.html</url> + + <dl> + <dt>'UnitConvert[$quantity$, $targetunit$] ' + <dd> converts the specified $quantity$ to the specified $targetunit$. + + <dt>'UnitConvert[quantity]' + <dd> converts the specified $quantity$ to its "SIBase" units. + </dl> + + Convert from miles to kilometers: + >> UnitConvert[Quantity[5.2, "miles"], "kilometers"] + = 8.36859 kilometer + + Convert a Quantity object to the appropriate SI base units: + >> UnitConvert[Quantity[3.8, "Pounds"]] + = 1.72365 kilogram + + #> UnitConvert[Quantity[{3, 10}, "centimeter"]] + = {0.03 meter, 0.1 meter} + + #> UnitConvert[Quantity[3, "aaa"]] + : Unable to interpret unit specification aaa. + = UnitConvert[Quantity[3,aaa]] + + #> UnitConvert[Quantity[{300, 152}, "centimeter"], Quantity[10, "meter"]] + = {3 meter, 1.52 meter} + + #> UnitConvert[Quantity[{3, 1}, "meter"], "inch"] + = {118.11 inch, 39.3701 inch} + """ + + messages = { + "argrx": "UnitConvert called with `1` arguments; 2 arguments are expected" + } + summary_text = "convert between units." + + def eval(self, expr, toUnit, evaluation: Evaluation): + "UnitConvert[expr_, toUnit_]" + + def convert_unit(elements, target): + + mag = elements[0] + unit = elements[1].get_string_value() + quantity = Q_(mag, unit) + converted_quantity = quantity.to(target) + + q_mag = get_converted_magnitude(converted_quantity.magnitude, evaluation) + + # Displaying the magnitude in Integer form if the convert rate is an Integer + if q_mag - int(q_mag) > 0: + return Expression(SymbolQuantity, Real(q_mag), String(target)) + else: + return Expression(SymbolQuantity, Integer(q_mag), String(target)) + + if len(evaluation.out) > 0: + return + + if toUnit.has_form("Quantity", None): + targetUnit = toUnit.elements[1].get_string_value().lower() + elif toUnit.has_form("List", None): + if not toUnit.elements[0].has_form("Quantity", None): + return + else: + targetUnit = toUnit.elements[0].elements[1].get_string_value().lower() + elif isinstance(toUnit, String): + targetUnit = toUnit.get_string_value().lower() + else: + return + if expr.has_form("List", None): + abc = [] + for i in range(len(expr.elements)): + abc.append(convert_unit(expr.elements[i].elements, targetUnit)) + return ListExpression(*abc) + elif isinstance(expr, Atom): + # FIXME convert_unit doesn't handle this correctly + return convert_unit(expr) + else: + return convert_unit(expr.elements, targetUnit) + + def eval_base_unit(self, expr, evaluation: Evaluation): + "UnitConvert[expr_]" + + def convert_unit(elements): + + mag = elements[0] + unit = elements[1].get_string_value() + + quantity = Q_(mag, unit) + converted_quantity = quantity.to_base_units() + + mag = get_converted_magnitude(converted_quantity.magnitude, evaluation) + + return Expression( + SymbolQuantity, + converted_quantity.magnitude, + String(converted_quantity.units), + ) + + if len(evaluation.out) > 0: + return + if expr.has_form("List", None): + abc = [] + for i in range(len(expr.elements)): + abc.append(convert_unit(expr.elements[i].elements)) + return ListExpression(*abc) + elif isinstance(expr, Atom): + # FIXME convert_unit doesn't handle this correctly + return convert_unit(expr) + else: + return convert_unit(expr.elements) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mathics3-6.0.1/mathics/builtin/quantities-try.py new/Mathics3-6.0.2/mathics/builtin/quantities-try.py --- old/Mathics3-6.0.1/mathics/builtin/quantities-try.py 2023-02-27 01:35:42.000000000 +0100 +++ new/Mathics3-6.0.2/mathics/builtin/quantities-try.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,486 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Units and Quantities -""" - -from pint import UnitRegistry - -from mathics.builtin.base import Builtin, Test -from mathics.core.atoms import Atom, Integer, Integer1, Number, Real, String -from mathics.core.attributes import ( - A_HOLD_REST, - A_N_HOLD_REST, - A_PROTECTED, - A_READ_PROTECTED, -) -from mathics.core.convert.expression import to_mathics_list -from mathics.core.convert.python import from_python -from mathics.core.evaluation import Evaluation -from mathics.core.expression import Expression -from mathics.core.list import ListExpression -from mathics.core.symbols import Symbol -from mathics.core.systemsymbols import SymbolQuantity, SymbolRowBox - -# This tells documentation how to sort this module -sort_order = "mathics.builtin.units-and-quantites" - -ureg = UnitRegistry() -Q_ = ureg.Quantity - - -def get_converted_magnitude(magnitude_expr, evaluation: Evaluation) -> float: - """ - The Python "pint" library mixes in a Python numeric value as a multiplier inside - a Mathics Expression. here we pick out that multiplier and - convert it from a Python numeric to a Mathics numeric. - """ - magnitude_elements = list(magnitude_expr.elements) - magnitude_elements[1] = from_python(magnitude_elements[1]) - magnitude_expr._elements = tuple(magnitude_elements) - # FIXME: consider returning an int when that is possible - return magnitude_expr.evaluate(evaluation).get_float_value() - - -class KnownUnitQ(Test): - """ - <url> - :WMA link: - https://reference.wolfram.com/language/ref/KnownUnitQ.html</url> - - <dl> - <dt>'KnownUnitQ[$unit$]' - <dd>returns True if $unit$ is a canonical unit, and False otherwise. - </dl> - - >> KnownUnitQ["Feet"] - = True - - >> KnownUnitQ["Foo"] - = False - """ - - summary_text = "tests whether its argument is a canonical unit." - - def test(self, expr): - def validate(unit): - try: - Q_(1, unit) - except Exception: - return False - else: - return True - - return validate(expr.get_string_value().lower()) - - -class Quantity(Builtin): - """ - <url> - :WMA link: - https://reference.wolfram.com/language/ref/Quantity.html</url> - - <dl> - <dt>'Quantity[$magnitude$, $unit$]' - <dd>represents a quantity with size $magnitude$ and unit specified by $unit$. - - <dt>'Quantity[$unit$]' - <dd>assumes the magnitude of the specified $unit$ to be 1. - </dl> - - >> Quantity["Kilogram"] - = 1 kilogram - - >> Quantity[10, "Meters"] - = 10 meter - - >> Quantity[{10,20}, "Meters"] - = {10 meter, 20 meter} - - #> Quantity[10, Meters] - = Quantity[10, Meters] - - #> Quantity[Meters] - : Unable to interpret unit specification Meters. - = Quantity[Meters] - - #> Quantity[1, "foot"] - = 1 foot - """ - - attributes = A_HOLD_REST | A_N_HOLD_REST | A_PROTECTED | A_READ_PROTECTED - - messages = { - "unkunit": "Unable to interpret unit specification `1`.", - } - summary_text = "represents a quantity with units" - - def validate(self, unit, evaluation: Evaluation): - if KnownUnitQ(unit).evaluate(evaluation) is Symbol("False"): - return False - return True - - def eval_makeboxes(self, mag, unit, f, evaluation: Evaluation): - "MakeBoxes[Quantity[mag_, unit_String], f:StandardForm|TraditionalForm|OutputForm|InputForm]" - - q_unit = unit.value.lower() - if self.validate(unit, evaluation): - return Expression( - SymbolRowBox, ListExpression(mag, String(" "), String(q_unit)) - ) - else: - return Expression( - SymbolRowBox, - to_mathics_list(SymbolQuantity, "[", mag, ",", q_unit, "]"), - ) - - def eval_mag_unit(self, mag, unit, evaluation: Evaluation): - "Quantity[mag_, unit_String]" - - if self.validate(unit, evaluation): - if mag.has_form("List", None): - results = [] - for i in range(len(mag.elements)): - quantity = Q_(mag.elements[i], unit.value.lower()) - results.append( - Expression( - SymbolQuantity, quantity.magnitude, String(quantity.units) - ) - ) - return ListExpression(*results) - else: - quantity = Q_(mag, unit.value.lower()) - return Expression( - SymbolQuantity, quantity.magnitude, String(quantity.units) - ) - else: - evaluation.message("Quantity", "unkunit", unit) - - def eval(self, unit, evaluation: Evaluation): - "Quantity[unit_]" - if not isinstance(unit, String): - evaluation.message("Quantity", "unkunit", unit) - else: - return self.eval_n(Integer1, unit, evaluation) - - -class QuantityMagnitude(Builtin): - """ - <url> - :WMA link: - https://reference.wolfram.com/language/ref/QuantityMagnitude.html</url> - - <dl> - <dt>'QuantityMagnitude[$quantity$]' - <dd>gives the amount of the specified $quantity$. - - <dt>'QuantityMagnitude[$quantity$, $unit$]' - <dd>gives the value corresponding to $quantity$ when converted to $unit$. - </dl> - - >> QuantityMagnitude[Quantity["Kilogram"]] - = 1 - - >> QuantityMagnitude[Quantity[10, "Meters"]] - = 10 - - >> QuantityMagnitude[Quantity[{10,20}, "Meters"]] - = {10, 20} - - #> QuantityMagnitude[Quantity[1, "meter"], "centimeter"] - = 100 - - #> QuantityMagnitude[Quantity[{3,1}, "meter"], "centimeter"] - = {300, 100} - - #> QuantityMagnitude[Quantity[{300,100}, "centimeter"], "meter"] - = {3, 1} - - #> QuantityMagnitude[Quantity[{3, 1}, "meter"], "inch"] - = {118.11, 39.3701} - - #> QuantityMagnitude[Quantity[{3, 1}, "meter"], Quantity[3, "centimeter"]] - = {300, 100} - - #> QuantityMagnitude[Quantity[3,"mater"]] - : Unable to interpret unit specification mater. - = QuantityMagnitude[Quantity[3,mater]] - """ - - summary_text = "get magnitude associated with a quantity." - - def eval(self, expr, evaluation: Evaluation): - "QuantityMagnitude[expr_]" - - def get_magnitude(elements): - if len(elements) == 1: - return 1 - else: - return elements[0] - - if len(evaluation.out) > 0: - return - if expr.has_form("List", None): - results = [] - for i in range(len(expr.elements)): - results.append(get_magnitude(expr.elements[i].elements)) - return ListExpression(*results) - else: - return get_magnitude(expr.elements) - - def eval_unit(self, expr, unit, evaluation: Evaluation): - "QuantityMagnitude[expr_, unit_]" - - def get_magnitude(elements, targetUnit, evaluation: Evaluation): - quantity = Q_(elements[0], elements[1].get_string_value()) - converted_quantity = quantity.to(targetUnit) - q_mag = get_converted_magnitude(converted_quantity.magnitude, evaluation) - - # Displaying the magnitude in Integer form if the convert rate is an Integer - if q_mag - int(q_mag) > 0: - return Real(q_mag) - else: - return Integer(q_mag) - - if len(evaluation.out) > 0: - return - - # Getting the target unit - if unit.has_form("Quantity", None): - targetUnit = unit.elements[1].get_string_value().lower() - elif unit.has_form("List", None): - if not unit.elements[0].has_form("Quantity", None): - return - else: - targetUnit = unit.elements[0].elements[1].get_string_value().lower() - elif isinstance(unit, String): - targetUnit = unit.get_string_value().lower() - else: - return - - # convert the quantity to the target unit and return the magnitude - if expr.has_form("List", None): - results = [] - for i in range(len(expr.elements)): - results.append( - get_magnitude(expr.elements[i].elements, targetUnit, evaluation) - ) - return ListExpression(*results) - else: - return get_magnitude(expr.elements, targetUnit, evaluation) - - -class QuantityQ(Test): - """ - <url> - :WMA link: - https://reference.wolfram.com/language/ref/QuantityQ.html</url> - <dl> - <dt>'QuantityQ[$expr$]' - <dd>return True if $expr$ is a valid Association object, and False otherwise. - </dl> - - >> QuantityQ[Quantity[3, "Meters"]] - = True - - >> QuantityQ[Quantity[3, "Maters"]] - : Unable to interpret unit specification Maters. - = False - - #> QuantityQ[3] - = False - """ - - summary_text = "tests whether its the argument is a quantity" - - def test(self, expr): - def validate_unit(unit): - try: - Q_(1, unit) - except Exception: - return False - else: - return True - - def validate(elements): - if len(elements) < 1 or len(elements) > 2: - return False - elif len(elements) == 1: - if validate_unit(elements[0].get_string_value().lower()): - return True - else: - return False - else: - if isinstance(elements[0], Number): - if validate_unit(elements[1].get_string_value().lower()): - return True - else: - return False - else: - return False - - return expr.get_head() == SymbolQuantity and validate(expr.elements) - - -class QuantityUnit(Builtin): - """ - <url> - :WMA link: - https://reference.wolfram.com/language/ref/QuantityUnit.html</url> - - <dl> - <dt>'QuantityUnit[$quantity$]' - <dd>returns the unit associated with the specified $quantity$. - </dl> - - >> QuantityUnit[Quantity["Kilogram"]] - = kilogram - - >> QuantityUnit[Quantity[10, "Meters"]] - = meter - - >> QuantityUnit[Quantity[{10,20}, "Meters"]] - = {meter, meter} - - #> QuantityUnit[Quantity[10, "aaa"]] - : Unable to interpret unit specification aaa. - = QuantityUnit[Quantity[10,aaa]] - """ - - summary_text = "the unit associated to a quantity" - - def eval(self, expr, evaluation: Evaluation): - "QuantityUnit[expr_]" - - def get_unit(elements): - if len(elements) == 1: - return elements[0] - else: - return elements[1] - - if len(evaluation.out) > 0: - return - if expr.has_form("List", None): - results = [] - for i in range(len(expr.elements)): - results.append(get_unit(expr.elements[i].elements)) - return ListExpression(*results) - else: - return get_unit(expr.elements) - - -class UnitConvert(Builtin): - - """ - <url> - :WMA link: - https://reference.wolfram.com/language/ref/UnitConvert.html</url> - - <dl> - <dt>'UnitConvert[$quantity$, $targetunit$] ' - <dd> converts the specified $quantity$ to the specified $targetunit$. - - <dt>'UnitConvert[quantity]' - <dd> converts the specified $quantity$ to its "SIBase" units. - </dl> - - Convert from miles to kilometers: - >> UnitConvert[Quantity[5.2, "miles"], "kilometers"] - = 8.36859 kilometer - - Convert a Quantity object to the appropriate SI base units: - >> UnitConvert[Quantity[3.8, "Pounds"]] - = 1.72365 kilogram - - #> UnitConvert[Quantity[{3, 10}, "centimeter"]] - = {0.03 meter, 0.1 meter} - - #> UnitConvert[Quantity[3, "aaa"]] - : Unable to interpret unit specification aaa. - = UnitConvert[Quantity[3,aaa]] - - #> UnitConvert[Quantity[{300, 152}, "centimeter"], Quantity[10, "meter"]] - = {3 meter, 1.52 meter} - - #> UnitConvert[Quantity[{3, 1}, "meter"], "inch"] - = {118.11 inch, 39.3701 inch} - """ - - messages = { - "argrx": "UnitConvert called with `1` arguments; 2 arguments are expected" - } - summary_text = "convert between units." - - def eval(self, expr, toUnit, evaluation: Evaluation): - "UnitConvert[expr_, toUnit_]" - - def convert_unit(elements, target): - - mag = elements[0] - unit = elements[1].get_string_value() - quantity = Q_(mag, unit) - converted_quantity = quantity.to(target) - - q_mag = get_converted_magnitude(converted_quantity.magnitude, evaluation) - - # Displaying the magnitude in Integer form if the convert rate is an Integer - if q_mag - int(q_mag) > 0: - return Expression(SymbolQuantity, Real(q_mag), String(target)) - else: - return Expression(SymbolQuantity, Integer(q_mag), String(target)) - - if len(evaluation.out) > 0: - return - - if toUnit.has_form("Quantity", None): - targetUnit = toUnit.elements[1].get_string_value().lower() - elif toUnit.has_form("List", None): - if not toUnit.elements[0].has_form("Quantity", None): - return - else: - targetUnit = toUnit.elements[0].elements[1].get_string_value().lower() - elif isinstance(toUnit, String): - targetUnit = toUnit.get_string_value().lower() - else: - return - if expr.has_form("List", None): - abc = [] - for i in range(len(expr.elements)): - abc.append(convert_unit(expr.elements[i].elements, targetUnit)) - return ListExpression(*abc) - elif isinstance(expr, Atom): - # FIXME convert_unit doesn't handle this correctly - return convert_unit(expr) - else: - return convert_unit(expr.elements, targetUnit) - - def eval_base_unit(self, expr, evaluation: Evaluation): - "UnitConvert[expr_]" - - def convert_unit(elements): - - mag = elements[0] - unit = elements[1].get_string_value() - - quantity = Q_(mag, unit) - converted_quantity = quantity.to_base_units() - - mag = get_converted_magnitude(converted_quantity.magnitude, evaluation) - - return Expression( - SymbolQuantity, - converted_quantity.magnitude, - String(converted_quantity.units), - ) - - if len(evaluation.out) > 0: - return - if expr.has_form("List", None): - abc = [] - for i in range(len(expr.elements)): - abc.append(convert_unit(expr.elements[i].elements)) - return ListExpression(*abc) - elif isinstance(expr, Atom): - # FIXME convert_unit doesn't handle this correctly - return convert_unit(expr) - else: - return convert_unit(expr.elements) Binary files old/Mathics3-6.0.1/mathics/data/doctest_latex_data.pcl and new/Mathics3-6.0.2/mathics/data/doctest_latex_data.pcl differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mathics3-6.0.1/mathics/version.py new/Mathics3-6.0.2/mathics/version.py --- old/Mathics3-6.0.1/mathics/version.py 2023-03-05 11:06:29.000000000 +0100 +++ new/Mathics3-6.0.2/mathics/version.py 2023-07-23 23:23:47.000000000 +0200 @@ -5,4 +5,4 @@ # well as importing into Python. That's why there is no # space around "=" below. # fmt: off -__version__="6.0.1" # noqa +__version__="6.0.2" # noqa diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mathics3-6.0.1/setup.py new/Mathics3-6.0.2/setup.py --- old/Mathics3-6.0.1/setup.py 2023-02-26 14:06:01.000000000 +0100 +++ new/Mathics3-6.0.2/setup.py 2023-07-23 23:35:19.000000000 +0200 @@ -57,16 +57,16 @@ "numpy", "llvmlite<0.37", "pillow >= 8.4.0", - "sympy>=1.8,<1.12", + "sympy>=1.8", ] if is_PyPy: print("Mathics does not support PyPy Python 3.6" % sys.version_info[:2]) sys.exit(-1) else: INSTALL_REQUIRES += [ - "numpy<=1.24", + "numpy<1.25", "llvmlite", - "sympy>=1.8, < 1.12", + "sympy>=1.8", "pillow >= 9.2", ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mathics3-6.0.1/test/test_calculus.py new/Mathics3-6.0.2/test/test_calculus.py --- old/Mathics3-6.0.1/test/test_calculus.py 2023-01-15 04:50:39.000000000 +0100 +++ new/Mathics3-6.0.2/test/test_calculus.py 2023-07-23 23:23:47.000000000 +0200 @@ -9,13 +9,13 @@ def test_calculus(): for str_expr, str_expected, message in ( ( - "Solve[{(7+x)*ma == 167, (5+x)*mb == 167, (7+5)*(ma+mb) == 334}, {ma, mb, x}]", + "Solve[{(7+x)*ma == 167, (5+x)*mb == 167, (7+5)*(ma+mb) == 334}, {ma, mb, x}]//Sort", "{{ma -> 1169 / 12 - 167 Sqrt[37] / 12, mb -> -835 / 12 + 167 Sqrt[37] / 12, x -> Sqrt[37]}, {ma -> 1169 / 12 + 167 Sqrt[37] / 12, mb -> -835 / 12 - 167 Sqrt[37] / 12, x -> -Sqrt[37]}}", "Issue63", ), ( - "Solve[{(7+x)*ma == 167, (5+x)*mb == 167, (7+5)*(ma+mb) == 334}, {x, ma, mb}]", - "{{x -> -Sqrt[37], ma -> 1169 / 12 + 167 Sqrt[37] / 12, mb -> -835 / 12 - 167 Sqrt[37] / 12}, {x -> Sqrt[37], ma -> 1169 / 12 - 167 Sqrt[37] / 12, mb -> -835 / 12 + 167 Sqrt[37] / 12}}", + "Solve[{(7+x)*ma == 167, (5+x)*mb == 167, (7+5)*(ma+mb) == 334}, {x, ma, mb}]//Sort", + "{{x -> Sqrt[37], ma -> 1169 / 12 - 167 Sqrt[37] / 12, mb -> -835 / 12 + 167 Sqrt[37] / 12}, {x -> -Sqrt[37], ma -> 1169 / 12 + 167 Sqrt[37] / 12, mb -> -835 / 12 - 167 Sqrt[37] / 12}}", "Issue 208", ), (