From 3e573ca18d506365214dc5519f88124f62d161c8 Mon Sep 17 00:00:00 2001 From: terrycojones Date: Thu, 3 Dec 2020 01:32:39 +0100 Subject: [PATCH] Changed default stack order of args to functions and swapped the behaviour of :r. --- CHANGELOG.md | 7 ++ README.md | 114 ++++++++++++++++---------------- rpnpy/__init__.py | 2 +- rpnpy/calculator.py | 40 ++++++------ rpnpy/functions.py | 2 +- test/test_calculator.py | 139 ++++++++++++++++++++-------------------- 6 files changed, 157 insertions(+), 147 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3d2741..ca54cfe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# 2.0.0 December 3, 2020 + +Changed default behaviour of the `:r` modifier following discussion with +@nfraprado at https://github.com/terrycojones/rpnpy/issues/6. + +*Note that this is a backwards-incompatible change!* + # 1.0.31 December 2, 2020 Added special `store` command to save stack values into a variable, diff --git a/README.md b/README.md index abb3283..411d60f 100644 --- a/README.md +++ b/README.md @@ -122,43 +122,21 @@ the iterable, then call `map` (`reduce`, `filter`, etc). Like this: ```sh -$ rpn.py 'str:! [6,7,8] map:i' +$ rpn.py [6,7,8] 'str:! map:i' ['6', '7', '8'] ``` -### Notes -1. Here the `:!` modifier causes the `str` function to be pushed onto the - stack instead of being run, and the `:i` modifier causes the result of - `map` to be iterated before being added to the stack. -1. When you run a function (like `map` or `apply`) that needs a callable - (or a function like `join` that needs a string) and you don't specify a - count (using `:3` for example), `rpn.py` will search the stack for a - suitable item and use the first one it finds. It doesn't really have a - choice in this case because it doesn't know how many arguments the - function (once it is found) will be applied to. This should usually - work just fine. You can always use an explicit count (like `:3`) if not. - Note that this situation does not apply if you use the `:r` modifier - (see below) because in that case the callable (or string, in the case of - `join`) will be expected to be on the top of the stack (and its - signature can then be examined to know how many arguments to pass it). +Here the `:!` modifier causes the `str` function to be pushed onto the +stack instead of being run, and the `:i` modifier causes the result of +`map` to be iterated before being added to the stack. -You might find it more natural to use `map` and friends the other way -around. I.e., first push the iterable, then push the function to be -applied, and then call `map`. In that case, you can use the `:r` modifier -to tell the calculator to reverse the order of the arguments passed to a -function. In the following, we push in the other order and then use -`map:ir` (the `i` is just to iterate the `map` result to produce a list). - -```sh -$ rpn.py '[6,7,8] str:! map:ir' -['6', '7', '8'] -``` -Continuing on the map theme, you could instead simply reverse part of the -stack before running a function: +Continuing on the map theme, if you for some reason had the elements on the +stack in the wrong order, you could reverse part of the stack before +running a function: ```sh -$ rpn.py '[6,7,8] str:! reverse map:i' +$ rpn.py 'str:! [6,7,8] reverse map:i' ['6', '7', '8'] ``` @@ -530,7 +508,8 @@ There are two kinds of commands: special and normal. * `store`: Store the value on the top of the stack into a variable (whose name has previously been pushed onto the stack). If given a numeric argument, that number of items from the stack will be stored into the variable as a list. -* `swap`: Swap the top two stack elements. +* `swap`: Swap the top two stack elements (this is the same as calling + `reverse` with no arguments. * `undo`: Undo the last stack-changing operation and variable settings. * `variables`: Show all known variables and their values. @@ -597,6 +576,27 @@ attrgetter Function(attrgetter (calls operator.attrgetter with 1 arg)) # 300+ lines deleted ``` +## Variables + +You can set variables and push them (or their values) onto the stack: + +```sh +$ rpn.py --noSplit +--> a = 4 +--> a +--> f +[4] +--> a:! +--> f +[4, Variable(a, current value: 4)] +--> a = 10 +--> f +[4, Variable(a, current value: 10)] +--> 20 +--> +:p +30 +``` + ## Modifiers Modifiers for a command are introduced with a colon, `:`. The modifiers are @@ -632,22 +632,22 @@ The full list of modifiers is: * `P`: Toggle automatic printing of all command results. * `r`: When applied to a special command, reverses how the function (for `map`, `apply`, `reduce`) or a string (for `join`) is looked for on the - stack. Normally the function or string argument to one of those special - functions has to be pushed onto the stack first. If `:r` is used, the - function or string can be given last (i.e., can be on the top of the - stack). In other contexts, causes all arguments given to a function to be - reversed (i.e., to use a stack order opposite to the normal). + stack. If `:r` is used, the function or string argument to one of those special + functions has to be pushed onto the stack first. In other contexts, causes + all arguments given to a function to be reversed (i.e., to use a stack order + opposite to the normal): ```sh - $ rpn.py '+:! 5 4 apply' + $ rpn.py '5 4 +:! apply' 9 - $ rpn.py '5 4 +:! apply:r' + $ rpn.py '+:! 5 4 apply:r' 9 $ rpn.py '5 4 -' 1 $ rpn.py '5 4 -:r' -1 ``` + See below for more detail. * `s`: Turn on line splitting on whitespace. Note that this will only go into effect from the _next_ command on. @@ -655,27 +655,33 @@ If a count is given, it is either interpreted as a number of times to push something onto the stack or the number of arguments to act on, depending on context (um, sorry about that - should be clearer). -## Variables + +### Reversing argument ordering -You can set variables and push them (or their values) onto the stack: +You might find it more natural to use `map` and friends the other way +around. I.e., first push the function, then push the iterable to be acted +on, and then call `map`. In that case, you can use the `:r` modifier to +tell the calculator to reverse the order of the arguments passed to a +function. In the following, we push in the other order and then use +`map:ir` (the `i` is just to iterate the `map` result to produce a list). ```sh -$ rpn.py --noSplit ---> a = 4 ---> a ---> f -[4] ---> a:! ---> f -[4, Variable(a, current value: 4)] ---> a = 10 ---> f -[4, Variable(a, current value: 10)] ---> 20 ---> +:p -30 +$ rpn.py 'str:! [6,7,8] map:ir' +['6', '7', '8'] ``` +Note that if you use the `:r` modifier to when running a function (like +`map` or `apply`) that needs a callable (or a function like `join` that +needs a string) and you don't specify a count (using `:3` for example), +`rpn.py` will search the stack for a suitable item and use the first one it +finds. It doesn't really have a choice in this case because it doesn't know +how many arguments the function (once it is found) will be applied to. +This should usually work just fine. You can always use an explicit count +(like `:3`) if not. + +The argument ordering just described was the default in `rpn.py` prior to +version `2.0.0`. + ## Undo The effect of commands on the stack and variables can be undone with the diff --git a/rpnpy/__init__.py b/rpnpy/__init__.py index 837a377..542f632 100644 --- a/rpnpy/__init__.py +++ b/rpnpy/__init__.py @@ -9,7 +9,7 @@ # will not be found by the version() function in ../setup.py # # Remember to update ../CHANGELOG.md describing what's new in each version. -__version__ = '1.0.31' +__version__ = '2.0.0' # Keep Python linters quiet. _ = Calculator diff --git a/rpnpy/calculator.py b/rpnpy/calculator.py index 8121fe1..93f3f7f 100644 --- a/rpnpy/calculator.py +++ b/rpnpy/calculator.py @@ -661,26 +661,6 @@ def _findWithArgs(self, command, description, predicate, defaultArgCount, (command, stackLen, '' if stackLen == 1 else 's')) if modifiers.reverse: - item = self.stack[-1] - - if not predicate(item): - raise StackError('Top stack item (%r) is not %s' % - (item, description)) - - if count is None: - count = (stackLen - 1 if modifiers.all else - defaultArgCount(item)) - - nargsAvail = stackLen - 1 - if nargsAvail < count: - raise StackError( - 'Cannot run %r with %d argument%s ' - '(stack has only %d item%s available)' % - (command, count, '' if count == 1 else 's', - nargsAvail, '' if nargsAvail == 1 else 's')) - - args = self.stack[-(count + 1):-1] - else: if count is None: if modifiers.all: item = self.stack[0] @@ -708,6 +688,26 @@ def _findWithArgs(self, command, description, predicate, defaultArgCount, item, description)) args = self.stack[-count:] + else: + item = self.stack[-1] + + if not predicate(item): + raise StackError('Top stack item (%r) is not %s' % + (item, description)) + + if count is None: + count = (stackLen - 1 if modifiers.all else + defaultArgCount(item)) + + nargsAvail = stackLen - 1 + if nargsAvail < count: + raise StackError( + 'Cannot run %r with %d argument%s ' + '(stack has only %d item%s available)' % + (command, count, '' if count == 1 else 's', + nargsAvail, '' if nargsAvail == 1 else 's')) + + args = self.stack[-(count + 1):-1] return item, self.convertStackArgs(args) diff --git a/rpnpy/functions.py b/rpnpy/functions.py index 71b4b7c..dc69f6c 100644 --- a/rpnpy/functions.py +++ b/rpnpy/functions.py @@ -374,7 +374,7 @@ def map_(calc, modifiers, count): def addSpecialFunctions(calc): - """Add functions defined above + """Add functions defined above. @param calc: A C{Calculator} instance. """ diff --git a/test/test_calculator.py b/test/test_calculator.py index 1d59c9e..55cff67 100644 --- a/test/test_calculator.py +++ b/test/test_calculator.py @@ -247,9 +247,9 @@ def testIterateString(self): def testItemgetter(self): "itemgetter must work correctly" c = Calculator(splitLines=False) + c.execute('[[1, 2, 3], [4, 5, 6]]') c.execute('1') c.execute('itemgetter') - c.execute('[[1, 2, 3], [4, 5, 6]]') c.execute('map :i') (result,) = c.stack self.assertEqual([2, 5], result) @@ -265,7 +265,6 @@ def testList2(self): "Converting the top two items of the stack to a list must work" c = Calculator() c.execute('4 5 list:2') - c.printStack() (result,) = c.stack self.assertEqual([4, 5], result) @@ -273,7 +272,6 @@ def testListAll(self): "Converting all items of the stack to a list must work" c = Calculator() c.execute('4 5 6 list:*') - c.printStack() (result,) = c.stack self.assertEqual([4, 5, 6], result) @@ -354,8 +352,8 @@ def testReverseSubtractionArgs(self): def testMap(self): "Call map with args reversed from their normal order" c = Calculator() - c.execute('[1,2,3]') c.execute('str :!') + c.execute('[1,2,3]') c.execute('map :ir') (result,) = c.stack self.assertEqual(['1', '2', '3'], result) @@ -426,68 +424,68 @@ class TestJoin(TestCase): def testEmptyString(self): "Joining on an empty string must work" c = Calculator() - c.execute('"" ["4","5","6"] join') + c.execute('["4","5","6"] "" join') (result,) = c.stack self.assertEqual('456', result) def testNonEmptyString(self): "Joining on a non-empty string must work" c = Calculator() - c.execute('"-" ["4","5","6"] join') + c.execute('["4","5","6"] "-" join') (result,) = c.stack self.assertEqual('4-5-6', result) def testNonStrings(self): "Joining things that are not string must work" c = Calculator() - c.execute('"-" [4,5,6] join') + c.execute('[4,5,6] "-" join') (result,) = c.stack self.assertEqual('4-5-6', result) def testWithCount(self): "Joining several stack items must work" c = Calculator() - c.execute('3 "-" 4 5 6 join:3') + c.execute('3 4 5 6 "-" join:3') self.assertEqual([3, '4-5-6'], c.stack) def testAllStack(self): "Joining the whole stack" c = Calculator() - c.execute('"-" 3 4 5 6 join:*') + c.execute('3 4 5 6 "-" join:*') (result,) = c.stack self.assertEqual('3-4-5-6', result) def testEmptyStringReversed(self): "Joining on an empty string must work" c = Calculator() - c.execute('["4","5","6"] "" join:r') + c.execute('"" ["4","5","6"] join:r') (result,) = c.stack self.assertEqual('456', result) def testNonEmptyStringReversed(self): "Joining on a non-empty string must work" c = Calculator() - c.execute('["4","5","6"] "-" join:r') + c.execute('"-" ["4","5","6"] join:r') (result,) = c.stack self.assertEqual('4-5-6', result) def testNonStringsReversed(self): "Joining things that are not string must work" c = Calculator() - c.execute('[4,5,6] "-" join:r') + c.execute('"-" [4,5,6] join:r') (result,) = c.stack self.assertEqual('4-5-6', result) def testWithCountReversed(self): "Joining several stack items must work" c = Calculator() - c.execute('3 4 5 6 "-" join:3r') + c.execute('3 "-" 4 5 6 join:3r') self.assertEqual([3, '4-5-6'], c.stack) def testAllStackReversed(self): "Joining the whole stack" c = Calculator() - c.execute('3 4 5 6 "-" join:*r') + c.execute('"-" 3 4 5 6 join:*r') (result,) = c.stack self.assertEqual('3-4-5-6', result) @@ -508,7 +506,7 @@ def testStackWithOneItem(self): def testStackWithTwoItemsClearsStack(self): "Calling store on a stack with two items must result in an empty stack" c = Calculator() - c.execute('"a" 4 store') + c.execute('4 "a" store') self.assertEqual([], c.stack) def testStackWithTwoItemsPreservingStack(self): @@ -526,7 +524,7 @@ def testStackWithTwoItems(self): being set as expected. """ c = Calculator() - c.execute('"a" 4 store a') + c.execute('4 "a" store a') (result,) = c.stack self.assertEqual(4, result) @@ -536,7 +534,7 @@ def testStackWithThreeItems(self): result in the variable being set as expected. """ c = Calculator() - c.execute('"a" 4 5 store:2 a') + c.execute('4 5 "a" store:2 a') self.assertEqual([[4, 5]], c.stack) def testStackWithThreeItemsReversed(self): @@ -545,7 +543,7 @@ def testStackWithThreeItemsReversed(self): the reverse modifier must result in the variable being set as expected. """ c = Calculator() - c.execute('4 5 "a" store:r2 a') + c.execute('"a" 4 5 store:r2 a') self.assertEqual([[4, 5]], c.stack) def testStarModifier(self): @@ -554,7 +552,7 @@ def testStarModifier(self): result in the variable being set as expected. """ c = Calculator() - c.execute('"a" 4 5 6 store:* a') + c.execute('4 5 6 "a" store:* a') self.assertEqual([[4, 5, 6]], c.stack) def testStarModifierReversed(self): @@ -563,7 +561,7 @@ def testStarModifierReversed(self): reverse modifier must result in the variable being set as expected. """ c = Calculator() - c.execute('4 5 6 "a" store:r* a') + c.execute('"a" 4 5 6 store:r* a') self.assertEqual([[4, 5, 6]], c.stack) @@ -592,8 +590,8 @@ def testStackLengthTwoNoCount(self): correctly. The number of stack items is obtained from the function signature""" c = Calculator() - c.execute('log10 :!') c.execute('4') + c.execute('log10 :!') func, args = c.findCallableAndArgs('cmd', Modifiers(), None) self.assertIs(math.log10, func) self.assertEqual([4], args) @@ -602,31 +600,18 @@ def testStackLengthTwoWithCount(self): """Calling on a stack with two items and a count must return correctly.""" c = Calculator() - c.execute('log10 :!') c.execute('4') + c.execute('log10 :!') func, args = c.findCallableAndArgs('cmd', Modifiers(), 1) self.assertIs(math.log10, func) self.assertEqual([4], args) - def testStackLengthThreeWithCountError(self): - """Calling on a stack with three items and a count that points to a - non-callable must result in an error""" - errfp = StringIO() - c = Calculator(errfp=errfp) - c.execute('log10 :!') - c.execute('4') - c.execute('5') - error = (r"^Cannot run 'cmd' with 1 argument. Stack item \(4\) is " - r"not callable$") - self.assertRaisesRegex(StackError, error, c.findCallableAndArgs, - 'cmd', Modifiers(), 1) - def testStackLengthThree(self): "Calling on a stack with three items (count=2) must return correctly" c = Calculator() - c.execute('log10 :!') c.execute('4') c.execute('5') + c.execute('log10 :!') func, args = c.findCallableAndArgs('cmd', Modifiers(), 2) self.assertIs(math.log10, func) self.assertEqual([4, 5], args) @@ -634,10 +619,10 @@ def testStackLengthThree(self): def testAllStack(self): "Calling on all the stack must return correctly" c = Calculator() - c.execute('log10 :!') c.execute('4') c.execute('5') c.execute('6') + c.execute('log10 :!') func, args = c.findCallableAndArgs('cmd', strToModifiers('*'), None) self.assertIs(math.log10, func) self.assertEqual([4, 5, 6], args) @@ -666,8 +651,8 @@ def testStackLengthTwoNoCount(self): correctly. The number of stack items is obtained from the function signature""" c = Calculator() - c.execute('4') c.execute('log10 :!') + c.execute('4') func, args = c.findCallableAndArgs('cmd', strToModifiers('r'), None) self.assertIs(math.log10, func) self.assertEqual([4], args) @@ -676,8 +661,8 @@ def testStackLengthTwoWithCount(self): """Calling on a stack with two items and a count must return correctly.""" c = Calculator() - c.execute('4') c.execute('log10 :!') + c.execute('4') func, args = c.findCallableAndArgs('cmd', strToModifiers('r'), 1) self.assertIs(math.log10, func) self.assertEqual([4], args) @@ -685,20 +670,33 @@ def testStackLengthTwoWithCount(self): def testStackLengthThree(self): "Calling on a stack with three items (count=2) must return correctly" c = Calculator() + c.execute('log10 :!') c.execute('5') c.execute('4') - c.execute('log10 :!') func, args = c.findCallableAndArgs('cmd', strToModifiers('r'), 2) self.assertIs(math.log10, func) self.assertEqual([5, 4], args) + def testStackLengthThreeWithCountError(self): + """Calling on a stack with three items and a count that points to a + non-callable must result in an error""" + errfp = StringIO() + c = Calculator(errfp=errfp) + c.execute('log10 :!') + c.execute('4') + c.execute('5') + error = (r"^Cannot run 'cmd' with 1 argument. Stack item \(4\) is " + r"not callable$") + self.assertRaisesRegex(StackError, error, c.findCallableAndArgs, + 'cmd', strToModifiers('r'), 1) + def testAllStack(self): "Calling on all the stack must return correctly" c = Calculator() + c.execute('log10 :!') c.execute('4') c.execute('5') c.execute('6') - c.execute('log10 :!') func, args = c.findCallableAndArgs('cmd', strToModifiers('*r'), None) self.assertIs(math.log10, func) self.assertEqual([4, 5, 6], args) @@ -727,8 +725,8 @@ def testStackLengthTwoNoCount(self): correctly. The number of stack items is obtained from the function signature""" c = Calculator() - c.execute("'string'") c.execute('4') + c.execute("'string'") string, args = c.findStringAndArgs('cmd', Modifiers(), None) self.assertEqual('string', string) self.assertEqual([4], args) @@ -737,30 +735,18 @@ def testStackLengthTwoWithCount(self): """Calling on a stack with two items and a count must return correctly.""" c = Calculator() - c.execute("'string'") c.execute('4') + c.execute("'string'") string, args = c.findStringAndArgs('cmd', Modifiers(), 1) self.assertEqual('string', string) self.assertEqual([4], args) - def testStackLengthThreeWithCountError(self): - """Calling on a stack with three items and a count that points to a - non-string must result in an error""" - c = Calculator() - c.execute("'string'") - c.execute('4') - c.execute('5') - error = (r"^Cannot run 'cmd' with 1 argument. Stack item \(4\) is " - r"not a string$") - self.assertRaisesRegex(StackError, error, c.findStringAndArgs, - 'cmd', Modifiers(), 1) - def testStackLengthThree(self): "Calling on a stack with three items (count=2) must return correctly" c = Calculator() - c.execute("'string'") c.execute('4') c.execute('5') + c.execute("'string'") string, args = c.findStringAndArgs('cmd', Modifiers(), 2) self.assertEqual('string', string) self.assertEqual([4, 5], args) @@ -768,10 +754,10 @@ def testStackLengthThree(self): def testAllStack(self): "Calling on all the stack must return correctly" c = Calculator() - c.execute("'string'") c.execute('4') c.execute('5') c.execute('6') + c.execute("'string'") string, args = c.findStringAndArgs('cmd', strToModifiers('*'), None) self.assertEqual('string', string) self.assertEqual([4, 5, 6], args) @@ -800,8 +786,8 @@ def testStackLengthTwoNoCount(self): correctly. The number of stack items is obtained from the function signature""" c = Calculator() - c.execute('4') c.execute("'string'") + c.execute('4') string, args = c.findStringAndArgs('cmd', strToModifiers('r'), None) self.assertEqual('string', string) self.assertEqual([4], args) @@ -810,8 +796,8 @@ def testStackLengthTwoWithCount(self): """Calling on a stack with two items and a count must return correctly.""" c = Calculator() - c.execute('4') c.execute("'string'") + c.execute('4') string, args = c.findStringAndArgs('cmd', strToModifiers('r'), 1) self.assertEqual('string', string) self.assertEqual([4], args) @@ -819,20 +805,32 @@ def testStackLengthTwoWithCount(self): def testStackLengthThree(self): "Calling on a stack with three items (count=2) must return correctly" c = Calculator() + c.execute("'string'") c.execute('5') c.execute('4') - c.execute("'string'") string, args = c.findStringAndArgs('cmd', strToModifiers('r'), 2) self.assertEqual('string', string) self.assertEqual([5, 4], args) + def testStackLengthThreeWithCountError(self): + """Calling on a stack with three items and a count that points to a + non-string must result in an error""" + c = Calculator() + c.execute("'string'") + c.execute('4') + c.execute('5') + error = (r"^Cannot run 'cmd' with 1 argument. Stack item \(4\) is " + r"not a string$") + self.assertRaisesRegex(StackError, error, c.findStringAndArgs, + 'cmd', strToModifiers('r'), 1) + def testAllStack(self): "Calling on all the stack must return correctly" c = Calculator() + c.execute("'string'") c.execute('4') c.execute('5') c.execute('6') - c.execute("'string'") string, args = c.findStringAndArgs('cmd', strToModifiers('*r'), None) self.assertEqual('string', string) self.assertEqual([4, 5, 6], args) @@ -844,8 +842,8 @@ class TestApply(TestCase): def testApplyNoCount(self): "apply must work correctly when not given a count" c = Calculator() - c.execute('abs :!') c.execute('-1') + c.execute('abs :!') c.execute('apply') (result,) = c.stack self.assertEqual(1, result) @@ -853,8 +851,8 @@ def testApplyNoCount(self): def testApplyWithCount(self): "apply must work correctly when given a count" c = Calculator() - c.execute('+ :!') c.execute('3 5') + c.execute('+ :!') c.execute('apply :2') (result,) = c.stack self.assertEqual(8, result) @@ -863,9 +861,9 @@ def testApplyVariables(self): "apply must work correctly when Variable instances are on the stack" c = Calculator() c.execute('a=4 b=5') - c.execute('+ :!') c.execute('a :!') c.execute('b :!') + c.execute('+ :!') c.execute('apply') (result,) = c.stack self.assertEqual(9, result) @@ -877,10 +875,10 @@ class TestReduce(TestCase): def testReduceAl(self): "Reduce must work correctly when told to operate on the whole stack" c = Calculator() - c.execute('+ :!') c.execute('5') c.execute('6') c.execute('7') + c.execute('+ :!') c.execute('reduce :*') (result,) = c.stack self.assertEqual(18, result) @@ -888,9 +886,9 @@ def testReduceAl(self): def testReduceWithCount(self): "Reduce must work correctly when given a count" c = Calculator() - c.execute('+ :!') c.execute('5') c.execute('6') + c.execute('+ :!') c.execute('reduce :2') (result,) = c.stack self.assertEqual(11, result) @@ -902,10 +900,10 @@ class TestReduceReversed(TestCase): def testReduceAl(self): "Reduce must work correctly when told to operate on the whole stack" c = Calculator() + c.execute('+ :!') c.execute('5') c.execute('6') c.execute('7') - c.execute('+ :!') c.execute('reduce :*r') (result,) = c.stack self.assertEqual(18, result) @@ -914,9 +912,9 @@ def testReduceWithCount(self): "Reduce must work correctly when given a count" c = Calculator() c.execute('4') + c.execute('+ :!') c.execute('5') c.execute('6') - c.execute('+ :!') c.execute('reduce :2r') self.assertEqual([4, 11], c.stack) @@ -962,7 +960,6 @@ def testPopForcedCommandWhenAVariableCalledPopExists(self): c.execute('6') c.execute('5') c.execute('pop:c') - print(c.stack) (result,) = c.stack self.assertEqual(6, result) @@ -973,16 +970,16 @@ class TestMap(TestCase): def testWithCount(self): "map must work as expected when given a count" c = Calculator() - c.execute('str :!') c.execute('1 2 3') + c.execute('str :!') c.execute('map :3i') self.assertEqual(['1', '2', '3'], c.stack) def testIterateGenerator(self): "The :i (iterate) modifier must work as expected on a map generator" c = Calculator() - c.execute('str :!') c.execute('[1,2,3]') + c.execute('str :!') c.execute('map :i') (result,) = c.stack self.assertEqual(['1', '2', '3'], result)