Skip to content

Commit e2c57f4

Browse files
authored
Correct doc for QuantityQ, add param # checking (#1475)
Correct documentation for `QuantityQ[]`. Add parameter number checking. Fixes #1474
1 parent 88fa00f commit e2c57f4

File tree

4 files changed

+110
-57
lines changed

4 files changed

+110
-57
lines changed

mathics/builtin/quantities.py

Lines changed: 70 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -64,65 +64,75 @@ def test(self, expr) -> bool:
6464

6565
class Quantity(Builtin):
6666
"""
67-
<url>
68-
:WMA link:
69-
https://reference.wolfram.com/language/ref/Quantity.html</url>
67+
<url>
68+
:WMA link:
69+
https://reference.wolfram.com/language/ref/Quantity.html</url>
7070
71-
<dl>
72-
<dt>'Quantity'[$magnitude$, $unit$]
73-
<dd>represents a quantity with size $magnitude$ and unit specified by $unit$.
71+
<dl>
72+
<dt>'Quantity'[$magnitude$, $unit$]
73+
<dd>represents a quantity with size $magnitude$ and unit specified by $unit$.
7474
75-
<dt>'Quantity'[$unit$]
76-
<dd>assumes the magnitude of the specified $unit$ to be 1.
77-
</dl>
75+
<dt>'Quantity'[$unit$]
76+
<dd>assumes the magnitude of the specified $unit$ to be 1.
77+
</dl>
7878
79-
>> Quantity["Kilogram"]
80-
= 1 kilogram
79+
>> Quantity["Kilogram"]
80+
= 1 kilogram
8181
82-
>> Quantity[10, "Meters"]
83-
= 10 meter
82+
>> Quantity[10, "Meters"]
83+
= 10 meter
8484
85-
If the first argument is an array, then the unit is distributed on each element
86-
>> Quantity[{10, 20}, "Meters"]
87-
= {10 meter, 20 meter}
85+
If the first argument is an array, then the unit is distributed on each element
86+
>> Quantity[{10, 20}, "Meters"]
87+
= {10 meter, 20 meter}
8888
89-
If the second argument is a number, then the expression is evaluated to
90-
the product of the magnitude and that number
91-
>> Quantity[2, 3/2]
92-
= 3
89+
If the second argument is a number, then the expression is evaluated to
90+
the product of the magnitude and that number
91+
>> Quantity[2, 3/2]
92+
= 3
9393
94-
Notice that units are specified as Strings. If the unit is not a Symbol or a Number,
95-
the expression is not interpreted as a Quantity object:
94+
Notice that units are specified as Strings. If the unit is not a Symbol or a Number,
95+
the expression is not interpreted as a Quantity object:
9696
97-
>> QuantityQ[Quantity[2, Second]]
98-
: Unable to interpret unit specification Second.
99-
= False
97+
>> QuantityQ[Quantity[2, Second]]
98+
: Unable to interpret unit specification Second.
99+
= False
100100
101-
Quantities can be multiplied and raised to integer powers:
102-
>> Quantity[3, "centimeter"] / Quantity[2, "second"]^2
103-
= 3 / 4 centimeter / second ^ 2
101+
Quantities can be multiplied and raised to integer powers:
102+
>> Quantity[3, "centimeter"] / Quantity[2, "second"]^2
103+
= 3 / 4 centimeter / second ^ 2
104104
105-
## TODO: Allow to simplify producs:
106-
## >> Quantity[3, "centimeter"] Quantity[2, "meter"]
107-
## = 600 centimeter ^ 2
105+
## TODO: Allow to simplify producs:
106+
## >> Quantity[3, "centimeter"] Quantity[2, "meter"]
107+
## = 600 centimeter ^ 2
108108
109-
Quantities of the same kind can be added:
110-
>> Quantity[6, "meter"] + Quantity[3, "centimeter"]
111-
= 603 centimeter
109+
Quantities of the same kind can be added:
110+
>> Quantity[6, "meter"] + Quantity[3, "centimeter"]
111+
= 603 centimeter
112112
113113
114-
Quantities of different kind can not:
115-
>> Quantity[6, "meter"] + Quantity[3, "second"]
116-
: second and meter are incompatible units.
117-
= 3 second + 6 meter
114+
Quantities of different kind can not:
115+
>> Quantity[6, "meter"] + Quantity[3, "second"]
116+
: second and meter are incompatible units.
117+
= 3 second + 6 meter
118+
119+
## TODO: Implement quantities with composed units:
120+
## >> UnitConvert[Quantity[2, "Ampere" * "Second"], "Coulomb"]
121+
## = Quantity[2, Coulomb]
122+
123+
See also <url>
124+
:'QuantityQ':
125+
/doc/reference-of-built-in-symbols/units-and-quantities
126+
/quantityq/</url>.
118127
119-
## TODO: Implement quantities with composed units:
120-
## >> UnitConvert[Quantity[2, "Ampere" * "Second"], "Coulomb"]
121-
## = Quantity[2, Coulomb]
122128
"""
123129

124130
attributes = A_HOLD_REST | A_N_HOLD_REST | A_PROTECTED | A_READ_PROTECTED
125131

132+
# Set checking that the number of arguments.
133+
eval_error = Builtin.generic_argument_error
134+
expected_args = 1 # In 14.1 this is (1, 2)
135+
126136
messages = {
127137
"unkunit": "Unable to interpret unit specification `1`.",
128138
"compat": "`1` and `2` are incompatible units.",
@@ -299,22 +309,27 @@ def eval_quantity_unit(self, quantity, targetUnit, evaluation: Evaluation):
299309

300310
class QuantityQ(Test):
301311
"""
302-
<url>
303-
:WMA link:
304-
https://reference.wolfram.com/language/ref/QuantityQ.html</url>
305-
<dl>
306-
<dt>'QuantityQ'[$expr$]
307-
<dd>return True if $expr$ is a valid Association object, and False otherwise.
308-
</dl>
309-
310-
>> QuantityQ[Quantity[3, "Meters"]]
311-
= True
312-
313-
>> QuantityQ[Quantity[3, "Maters"]]
314-
: Unable to interpret unit specification Maters.
315-
= False
312+
<url>
313+
:WMA link:
314+
https://reference.wolfram.com/language/ref/QuantityQ.html</url>
315+
<dl>
316+
<dt>'QuantityQ'[$expr$]
317+
<dd>return 'True' if $expr$ is a valid <url>:'Quantity':/doc/reference-of-built-in-symbols/units-and-quantities
318+
/quantity/</url> with valid arguments, and 'False' otherwise.
319+
</dl>
320+
321+
>> QuantityQ[Quantity[3, "Meters"]]
322+
= True
323+
324+
>> QuantityQ[Quantity[3, "Maters"]]
325+
: Unable to interpret unit specification Maters.
326+
= False
316327
"""
317328

329+
# Set checking that the number of arguments required is one.
330+
eval_error = Builtin.generic_argument_error
331+
expected_args = 1
332+
318333
summary_text = "tests whether its the argument is a quantity"
319334

320335
def test(self, expr) -> bool:

mathics/core/util.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ def permutations(items):
4545
# already_taken.add(item)
4646

4747

48+
def strip_string_quotes(s: str) -> str:
49+
"""
50+
Remove leading and trailing string quotes if they exist.
51+
Note: we need this too often probably a bad design decision in String.
52+
"""
53+
return s[1:-1] if len(s) >= 2 and s[0] == s[-1] == '"' else s
54+
55+
4856
def subsets(items, min: int, max: Optional[int], included=None, less_first=False):
4957
if max is None:
5058
max = len(items)

mathics/eval/quantities.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,15 @@
2121
from mathics.core.evaluation import Evaluation
2222
from mathics.core.expression import Expression
2323
from mathics.core.systemsymbols import SymbolPower, SymbolQuantity, SymbolTimes
24+
from mathics.core.util import strip_string_quotes
2425

2526
ureg = UnitRegistry()
2627
Q_ = ureg.Quantity
2728

2829

2930
def add_quantities(
3031
mag_1: float, u_1: BaseElement, mag_2: float, u_2: BaseElement, evaluation=None
31-
) -> Expression:
32+
) -> Optional[Expression]:
3233
"""Try to add two quantities"""
3334
cmp = compare_units(u_1, u_2)
3435
if cmp is None:
@@ -285,7 +286,8 @@ def validate_pint_unit(unit: str) -> bool:
285286
def validate_unit_expression(unit: BaseElement) -> bool:
286287
"""Test if `unit` is a valid unit"""
287288
if isinstance(unit, String):
288-
return validate_pint_unit(unit.value)
289+
unit_value = strip_string_quotes(unit.value)
290+
return validate_pint_unit(unit_value)
289291
if unit.has_form("Power", 2):
290292
base, exp = unit.elements
291293
if not isinstance(exp, Integer):

test/builtin/test_quantities.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,3 +178,31 @@ def test_quantity_operations(str_expr, str_expected):
178178
to_string_expected=True,
179179
hold_expected=True,
180180
)
181+
182+
183+
@pytest.mark.parametrize(
184+
("str_expr", "msgs", "assert_fail_msg"),
185+
[
186+
(
187+
"QuantityQ[a, b]",
188+
["QuantityQ called with 2 arguments; 1 argument is expected."],
189+
"QuantityQ with wrong number of arguments",
190+
),
191+
(
192+
"Quantity[]",
193+
["Quantity called with 0 arguments; 1 argument is expected."],
194+
"Quantity called with wrong number of arguments",
195+
),
196+
],
197+
)
198+
def test_wrong_number_of_arguments(str_expr, msgs, assert_fail_msg):
199+
""" """
200+
check_evaluation(
201+
str_expr,
202+
str_expr,
203+
to_string_expr=True,
204+
to_string_expected=True,
205+
hold_expected=True,
206+
failure_message=assert_fail_msg,
207+
expected_messages=msgs,
208+
)

0 commit comments

Comments
 (0)