722 lines
28 KiB
Python
722 lines
28 KiB
Python
# Copyright (C) 2018 Google Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""Tests for the fire module."""
|
|
|
|
import os
|
|
import sys
|
|
from unittest import mock
|
|
|
|
import fire
|
|
from fire import test_components as tc
|
|
from fire import testutils
|
|
|
|
|
|
class FireTest(testutils.BaseTestCase):
|
|
|
|
def testFire(self):
|
|
with mock.patch.object(sys, 'argv', ['progname']):
|
|
fire.Fire(tc.Empty)
|
|
fire.Fire(tc.OldStyleEmpty)
|
|
fire.Fire(tc.WithInit)
|
|
# Test both passing command as a sequence and as a string.
|
|
self.assertEqual(fire.Fire(tc.NoDefaults, command='triple 4'), 12)
|
|
self.assertEqual(fire.Fire(tc.WithDefaults, command=('double', '2')), 4)
|
|
self.assertEqual(fire.Fire(tc.WithDefaults, command=['triple', '4']), 12)
|
|
self.assertEqual(fire.Fire(tc.OldStyleWithDefaults,
|
|
command=['double', '2']), 4)
|
|
self.assertEqual(fire.Fire(tc.OldStyleWithDefaults,
|
|
command=['triple', '4']), 12)
|
|
|
|
def testFirePositionalCommand(self):
|
|
# Test passing command as a positional argument.
|
|
self.assertEqual(fire.Fire(tc.NoDefaults, 'double 2'), 4)
|
|
self.assertEqual(fire.Fire(tc.NoDefaults, ['double', '2']), 4)
|
|
|
|
def testFireInvalidCommandArg(self):
|
|
with self.assertRaises(ValueError):
|
|
# This is not a valid command.
|
|
fire.Fire(tc.WithDefaults, command=10)
|
|
|
|
def testFireDefaultName(self):
|
|
with mock.patch.object(sys, 'argv',
|
|
[os.path.join('python-fire', 'fire',
|
|
'base_filename.py')]):
|
|
with self.assertOutputMatches(stdout='SYNOPSIS.*base_filename.py',
|
|
stderr=None):
|
|
fire.Fire(tc.Empty)
|
|
|
|
def testFireNoArgs(self):
|
|
self.assertEqual(fire.Fire(tc.MixedDefaults, command=['ten']), 10)
|
|
|
|
def testFireExceptions(self):
|
|
# Exceptions of Fire are printed to stderr and a FireExit is raised.
|
|
with self.assertRaisesFireExit(2):
|
|
fire.Fire(tc.Empty, command=['nomethod']) # Member doesn't exist.
|
|
with self.assertRaisesFireExit(2):
|
|
fire.Fire(tc.NoDefaults, command=['double']) # Missing argument.
|
|
with self.assertRaisesFireExit(2):
|
|
fire.Fire(tc.TypedProperties, command=['delta', 'x']) # Missing key.
|
|
|
|
# Exceptions of the target components are still raised.
|
|
with self.assertRaises(ZeroDivisionError):
|
|
fire.Fire(tc.NumberDefaults, command=['reciprocal', '0.0'])
|
|
|
|
def testFireNamedArgs(self):
|
|
self.assertEqual(fire.Fire(tc.WithDefaults,
|
|
command=['double', '--count', '5']), 10)
|
|
self.assertEqual(fire.Fire(tc.WithDefaults,
|
|
command=['triple', '--count', '5']), 15)
|
|
self.assertEqual(
|
|
fire.Fire(tc.OldStyleWithDefaults, command=['double', '--count', '5']),
|
|
10)
|
|
self.assertEqual(
|
|
fire.Fire(tc.OldStyleWithDefaults, command=['triple', '--count', '5']),
|
|
15)
|
|
|
|
def testFireNamedArgsSingleHyphen(self):
|
|
self.assertEqual(fire.Fire(tc.WithDefaults,
|
|
command=['double', '-count', '5']), 10)
|
|
self.assertEqual(fire.Fire(tc.WithDefaults,
|
|
command=['triple', '-count', '5']), 15)
|
|
self.assertEqual(
|
|
fire.Fire(tc.OldStyleWithDefaults, command=['double', '-count', '5']),
|
|
10)
|
|
self.assertEqual(
|
|
fire.Fire(tc.OldStyleWithDefaults, command=['triple', '-count', '5']),
|
|
15)
|
|
|
|
def testFireNamedArgsWithEquals(self):
|
|
self.assertEqual(fire.Fire(tc.WithDefaults,
|
|
command=['double', '--count=5']), 10)
|
|
self.assertEqual(fire.Fire(tc.WithDefaults,
|
|
command=['triple', '--count=5']), 15)
|
|
|
|
def testFireNamedArgsWithEqualsSingleHyphen(self):
|
|
self.assertEqual(fire.Fire(tc.WithDefaults,
|
|
command=['double', '-count=5']), 10)
|
|
self.assertEqual(fire.Fire(tc.WithDefaults,
|
|
command=['triple', '-count=5']), 15)
|
|
|
|
def testFireAllNamedArgs(self):
|
|
self.assertEqual(fire.Fire(tc.MixedDefaults, command=['sum', '1', '2']), 5)
|
|
self.assertEqual(fire.Fire(tc.MixedDefaults,
|
|
command=['sum', '--alpha', '1', '2']), 5)
|
|
self.assertEqual(fire.Fire(tc.MixedDefaults,
|
|
command=['sum', '--beta', '1', '2']), 4)
|
|
self.assertEqual(fire.Fire(tc.MixedDefaults,
|
|
command=['sum', '1', '--alpha', '2']), 4)
|
|
self.assertEqual(fire.Fire(tc.MixedDefaults,
|
|
command=['sum', '1', '--beta', '2']), 5)
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['sum', '--alpha', '1', '--beta', '2']), 5)
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['sum', '--beta', '1', '--alpha', '2']), 4)
|
|
|
|
def testFireAllNamedArgsOneMissing(self):
|
|
self.assertEqual(fire.Fire(tc.MixedDefaults, command=['sum']), 0)
|
|
self.assertEqual(fire.Fire(tc.MixedDefaults, command=['sum', '1']), 1)
|
|
self.assertEqual(fire.Fire(tc.MixedDefaults,
|
|
command=['sum', '--alpha', '1']), 1)
|
|
self.assertEqual(fire.Fire(tc.MixedDefaults,
|
|
command=['sum', '--beta', '2']), 4)
|
|
|
|
def testFirePartialNamedArgs(self):
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults, command=['identity', '1', '2']), (1, 2))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '--alpha', '1', '2']), (1, 2))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '--beta', '1', '2']), (2, 1))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '1', '--alpha', '2']), (2, 1))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '1', '--beta', '2']), (1, 2))
|
|
self.assertEqual(
|
|
fire.Fire(
|
|
tc.MixedDefaults,
|
|
command=['identity', '--alpha', '1', '--beta', '2']), (1, 2))
|
|
self.assertEqual(
|
|
fire.Fire(
|
|
tc.MixedDefaults,
|
|
command=['identity', '--beta', '1', '--alpha', '2']), (2, 1))
|
|
|
|
def testFirePartialNamedArgsOneMissing(self):
|
|
# Errors are written to standard out and a FireExit is raised.
|
|
with self.assertRaisesFireExit(2):
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity']) # Identity needs an arg.
|
|
|
|
with self.assertRaisesFireExit(2):
|
|
# Identity needs a value for alpha.
|
|
fire.Fire(tc.MixedDefaults, command=['identity', '--beta', '2'])
|
|
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults, command=['identity', '1']), (1, '0'))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults, command=['identity', '--alpha', '1']),
|
|
(1, '0'))
|
|
|
|
def testFireAnnotatedArgs(self):
|
|
self.assertEqual(fire.Fire(tc.Annotations, command=['double', '5']), 10)
|
|
self.assertEqual(fire.Fire(tc.Annotations, command=['triple', '5']), 15)
|
|
|
|
def testFireKeywordOnlyArgs(self):
|
|
with self.assertRaisesFireExit(2):
|
|
# Keyword arguments must be passed with flag syntax.
|
|
fire.Fire(tc.py3.KeywordOnly, command=['double', '5'])
|
|
|
|
self.assertEqual(
|
|
fire.Fire(tc.py3.KeywordOnly, command=['double', '--count', '5']), 10)
|
|
self.assertEqual(
|
|
fire.Fire(tc.py3.KeywordOnly, command=['triple', '--count', '5']), 15)
|
|
|
|
def testFireProperties(self):
|
|
self.assertEqual(fire.Fire(tc.TypedProperties, command=['alpha']), True)
|
|
self.assertEqual(fire.Fire(tc.TypedProperties, command=['beta']), (1, 2, 3))
|
|
|
|
def testFireRecursion(self):
|
|
self.assertEqual(
|
|
fire.Fire(tc.TypedProperties,
|
|
command=['charlie', 'double', 'hello']), 'hellohello')
|
|
self.assertEqual(fire.Fire(tc.TypedProperties,
|
|
command=['charlie', 'triple', 'w']), 'www')
|
|
|
|
def testFireVarArgs(self):
|
|
self.assertEqual(
|
|
fire.Fire(tc.VarArgs,
|
|
command=['cumsums', 'a', 'b', 'c', 'd']),
|
|
['a', 'ab', 'abc', 'abcd'])
|
|
self.assertEqual(
|
|
fire.Fire(tc.VarArgs, command=['cumsums', '1', '2', '3', '4']),
|
|
[1, 3, 6, 10])
|
|
|
|
def testFireVarArgsWithNamedArgs(self):
|
|
self.assertEqual(
|
|
fire.Fire(tc.VarArgs, command=['varchars', '1', '2', 'c', 'd']),
|
|
(1, 2, 'cd'))
|
|
self.assertEqual(
|
|
fire.Fire(tc.VarArgs, command=['varchars', '3', '4', 'c', 'd', 'e']),
|
|
(3, 4, 'cde'))
|
|
|
|
def testFireKeywordArgs(self):
|
|
self.assertEqual(
|
|
fire.Fire(
|
|
tc.Kwargs,
|
|
command=['props', '--name', 'David', '--age', '24']),
|
|
{'name': 'David', 'age': 24})
|
|
# Run this test both with a list command and a string command.
|
|
self.assertEqual(
|
|
fire.Fire(
|
|
tc.Kwargs,
|
|
command=['props', '--message',
|
|
'"This is a message it has -- in it"']), # Quotes stripped
|
|
{'message': 'This is a message it has -- in it'})
|
|
self.assertEqual(
|
|
fire.Fire(
|
|
tc.Kwargs,
|
|
command=['props', '--message',
|
|
'This is a message it has -- in it']),
|
|
{'message': 'This is a message it has -- in it'})
|
|
self.assertEqual(
|
|
fire.Fire(
|
|
tc.Kwargs,
|
|
command='props --message "This is a message it has -- in it"'),
|
|
{'message': 'This is a message it has -- in it'})
|
|
self.assertEqual(
|
|
fire.Fire(tc.Kwargs,
|
|
command=['upper', '--alpha', 'A', '--beta', 'B']),
|
|
'ALPHA BETA')
|
|
self.assertEqual(
|
|
fire.Fire(
|
|
tc.Kwargs,
|
|
command=['upper', '--alpha', 'A', '--beta', 'B', '-', 'lower']),
|
|
'alpha beta')
|
|
|
|
def testFireKeywordArgsWithMissingPositionalArgs(self):
|
|
self.assertEqual(
|
|
fire.Fire(tc.Kwargs, command=['run', 'Hello', 'World', '--cell', 'is']),
|
|
('Hello', 'World', {'cell': 'is'}))
|
|
self.assertEqual(
|
|
fire.Fire(tc.Kwargs, command=['run', 'Hello', '--cell', 'ok']),
|
|
('Hello', None, {'cell': 'ok'}))
|
|
|
|
def testFireObject(self):
|
|
self.assertEqual(
|
|
fire.Fire(tc.WithDefaults(), command=['double', '--count', '5']), 10)
|
|
self.assertEqual(
|
|
fire.Fire(tc.WithDefaults(), command=['triple', '--count', '5']), 15)
|
|
|
|
def testFireDict(self):
|
|
component = {
|
|
'double': lambda x=0: 2 * x,
|
|
'cheese': 'swiss',
|
|
}
|
|
self.assertEqual(fire.Fire(component, command=['double', '5']), 10)
|
|
self.assertEqual(fire.Fire(component, command=['cheese']), 'swiss')
|
|
|
|
def testFireObjectWithDict(self):
|
|
self.assertEqual(
|
|
fire.Fire(tc.TypedProperties, command=['delta', 'echo']), 'E')
|
|
self.assertEqual(
|
|
fire.Fire(tc.TypedProperties, command=['delta', 'echo', 'lower']), 'e')
|
|
self.assertIsInstance(
|
|
fire.Fire(tc.TypedProperties, command=['delta', 'nest']), dict)
|
|
self.assertEqual(
|
|
fire.Fire(tc.TypedProperties, command=['delta', 'nest', '0']), 'a')
|
|
|
|
def testFireSet(self):
|
|
component = tc.simple_set()
|
|
result = fire.Fire(component, command=[])
|
|
self.assertEqual(len(result), 3)
|
|
|
|
def testFireFrozenset(self):
|
|
component = tc.simple_frozenset()
|
|
result = fire.Fire(component, command=[])
|
|
self.assertEqual(len(result), 3)
|
|
|
|
def testFireList(self):
|
|
component = ['zero', 'one', 'two', 'three']
|
|
self.assertEqual(fire.Fire(component, command=['2']), 'two')
|
|
self.assertEqual(fire.Fire(component, command=['3']), 'three')
|
|
self.assertEqual(fire.Fire(component, command=['-1']), 'three')
|
|
|
|
def testFireObjectWithList(self):
|
|
self.assertEqual(fire.Fire(tc.TypedProperties, command=['echo', '0']),
|
|
'alex')
|
|
self.assertEqual(fire.Fire(tc.TypedProperties, command=['echo', '1']),
|
|
'bethany')
|
|
|
|
def testFireObjectWithTuple(self):
|
|
self.assertEqual(fire.Fire(tc.TypedProperties, command=['fox', '0']),
|
|
'carry')
|
|
self.assertEqual(fire.Fire(tc.TypedProperties, command=['fox', '1']),
|
|
'divide')
|
|
|
|
def testFireObjectWithListAsObject(self):
|
|
self.assertEqual(
|
|
fire.Fire(tc.TypedProperties, command=['echo', 'count', 'bethany']),
|
|
1)
|
|
|
|
def testFireObjectWithTupleAsObject(self):
|
|
self.assertEqual(
|
|
fire.Fire(tc.TypedProperties, command=['fox', 'count', 'divide']),
|
|
1)
|
|
|
|
def testFireNoComponent(self):
|
|
self.assertEqual(fire.Fire(command=['tc', 'WithDefaults', 'double', '10']),
|
|
20)
|
|
last_char = lambda text: text[-1] # pylint: disable=unused-variable
|
|
self.assertEqual(fire.Fire(command=['last_char', '"Hello"']), 'o')
|
|
self.assertEqual(fire.Fire(command=['last-char', '"World"']), 'd')
|
|
rset = lambda count=0: set(range(count)) # pylint: disable=unused-variable
|
|
self.assertEqual(fire.Fire(command=['rset', '5']), {0, 1, 2, 3, 4})
|
|
|
|
def testFireUnderscores(self):
|
|
self.assertEqual(
|
|
fire.Fire(tc.Underscores,
|
|
command=['underscore-example']), 'fish fingers')
|
|
self.assertEqual(
|
|
fire.Fire(tc.Underscores,
|
|
command=['underscore_example']), 'fish fingers')
|
|
|
|
def testFireUnderscoresInArg(self):
|
|
self.assertEqual(
|
|
fire.Fire(tc.Underscores,
|
|
command=['underscore-function', 'example']), 'example')
|
|
self.assertEqual(
|
|
fire.Fire(tc.Underscores,
|
|
command=['underscore_function', '--underscore-arg=score']),
|
|
'score')
|
|
self.assertEqual(
|
|
fire.Fire(tc.Underscores,
|
|
command=['underscore_function', '--underscore_arg=score']),
|
|
'score')
|
|
|
|
def testBoolParsing(self):
|
|
self.assertEqual(fire.Fire(tc.BoolConverter, command=['as-bool', 'True']),
|
|
True)
|
|
self.assertEqual(
|
|
fire.Fire(tc.BoolConverter, command=['as-bool', 'False']), False)
|
|
self.assertEqual(
|
|
fire.Fire(tc.BoolConverter, command=['as-bool', '--arg=True']), True)
|
|
self.assertEqual(
|
|
fire.Fire(tc.BoolConverter, command=['as-bool', '--arg=False']), False)
|
|
self.assertEqual(fire.Fire(tc.BoolConverter, command=['as-bool', '--arg']),
|
|
True)
|
|
self.assertEqual(
|
|
fire.Fire(tc.BoolConverter, command=['as-bool', '--noarg']), False)
|
|
|
|
def testBoolParsingContinued(self):
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', 'True', 'False']), (True, False))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '--alpha=False', '10']), (False, 10))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '--alpha', '--beta', '10']), (True, 10))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '--alpha', '--beta=10']), (True, 10))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '--noalpha', '--beta']), (False, True))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults, command=['identity', '10', '--beta']),
|
|
(10, True))
|
|
|
|
def testBoolParsingSingleHyphen(self):
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '-alpha=False', '10']), (False, 10))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '-alpha', '-beta', '10']), (True, 10))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '-alpha', '-beta=10']), (True, 10))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '-noalpha', '-beta']), (False, True))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '-alpha', '-10', '-beta']), (-10, True))
|
|
|
|
def testBoolParsingLessExpectedCases(self):
|
|
# Note: Does not return (True, 10).
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '--alpha', '10']), (10, '0'))
|
|
# To get (True, 10), use one of the following:
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '--alpha', '--beta=10']),
|
|
(True, 10))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', 'True', '10']), (True, 10))
|
|
|
|
# Note: Does not return (True, '--test') or ('--test', 0).
|
|
with self.assertRaisesFireExit(2):
|
|
fire.Fire(tc.MixedDefaults, command=['identity', '--alpha', '--test'])
|
|
|
|
self.assertEqual(
|
|
fire.Fire(
|
|
tc.MixedDefaults,
|
|
command=['identity', '--alpha', 'True', '"--test"']),
|
|
(True, '--test'))
|
|
# To get ('--test', '0'), use one of the following:
|
|
self.assertEqual(fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '--alpha=--test']),
|
|
('--test', '0'))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults, command=r'identity --alpha \"--test\"'),
|
|
('--test', '0'))
|
|
|
|
def testSingleCharFlagParsing(self):
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '-a']), (True, '0'))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '-a', '--beta=10']), (True, 10))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '-a', '-b']), (True, True))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '-a', '42', '-b']), (42, True))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '-a', '42', '-b', '10']), (42, 10))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '--alpha', 'True', '-b', '10']),
|
|
(True, 10))
|
|
with self.assertRaisesFireExit(2):
|
|
# This test attempts to use an ambiguous shortcut flag on a function with
|
|
# a naming conflict for the shortcut, triggering a FireError.
|
|
fire.Fire(tc.SimilarArgNames, command=['identity', '-b'])
|
|
|
|
def testSingleCharFlagParsingEqualSign(self):
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '-a=True']), (True, '0'))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '-a=3', '--beta=10']), (3, 10))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '-a=False', '-b=15']), (False, 15))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '-a', '42', '-b=12']), (42, 12))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '-a=42', '-b', '10']), (42, 10))
|
|
|
|
def testSingleCharFlagParsingExactMatch(self):
|
|
self.assertEqual(
|
|
fire.Fire(tc.SimilarArgNames,
|
|
command=['identity2', '-a']), (True, None))
|
|
self.assertEqual(
|
|
fire.Fire(tc.SimilarArgNames,
|
|
command=['identity2', '-a=10']), (10, None))
|
|
self.assertEqual(
|
|
fire.Fire(tc.SimilarArgNames,
|
|
command=['identity2', '--a']), (True, None))
|
|
self.assertEqual(
|
|
fire.Fire(tc.SimilarArgNames,
|
|
command=['identity2', '-alpha']), (None, True))
|
|
self.assertEqual(
|
|
fire.Fire(tc.SimilarArgNames,
|
|
command=['identity2', '-a', '-alpha']), (True, True))
|
|
|
|
def testSingleCharFlagParsingCapitalLetter(self):
|
|
self.assertEqual(
|
|
fire.Fire(tc.CapitalizedArgNames,
|
|
command=['sum', '-D', '5', '-G', '10']), 15)
|
|
|
|
def testBoolParsingWithNo(self):
|
|
# In these examples --nothing always refers to the nothing argument:
|
|
def fn1(thing, nothing):
|
|
return thing, nothing
|
|
|
|
self.assertEqual(fire.Fire(fn1, command=['--thing', '--nothing']),
|
|
(True, True))
|
|
self.assertEqual(fire.Fire(fn1, command=['--thing', '--nonothing']),
|
|
(True, False))
|
|
|
|
with self.assertRaisesFireExit(2):
|
|
# In this case nothing=False (since rightmost setting of a flag gets
|
|
# precedence), but it errors because thing has no value.
|
|
fire.Fire(fn1, command=['--nothing', '--nonothing'])
|
|
|
|
# In these examples, --nothing sets thing=False:
|
|
def fn2(thing, **kwargs):
|
|
return thing, kwargs
|
|
self.assertEqual(fire.Fire(fn2, command=['--thing']), (True, {}))
|
|
self.assertEqual(fire.Fire(fn2, command=['--nothing']), (False, {}))
|
|
with self.assertRaisesFireExit(2):
|
|
# In this case, nothing=True, but it errors because thing has no value.
|
|
fire.Fire(fn2, command=['--nothing=True'])
|
|
self.assertEqual(fire.Fire(fn2, command=['--nothing', '--nothing=True']),
|
|
(False, {'nothing': True}))
|
|
|
|
def fn3(arg, **kwargs):
|
|
return arg, kwargs
|
|
self.assertEqual(fire.Fire(fn3, command=['--arg=value', '--thing']),
|
|
('value', {'thing': True}))
|
|
self.assertEqual(fire.Fire(fn3, command=['--arg=value', '--nothing']),
|
|
('value', {'thing': False}))
|
|
self.assertEqual(fire.Fire(fn3, command=['--arg=value', '--nonothing']),
|
|
('value', {'nothing': False}))
|
|
|
|
def testTraceFlag(self):
|
|
with self.assertRaisesFireExit(0, 'Fire trace:\n'):
|
|
fire.Fire(tc.BoolConverter, command=['as-bool', 'True', '--', '--trace'])
|
|
with self.assertRaisesFireExit(0, 'Fire trace:\n'):
|
|
fire.Fire(tc.BoolConverter, command=['as-bool', 'True', '--', '-t'])
|
|
with self.assertRaisesFireExit(0, 'Fire trace:\n'):
|
|
fire.Fire(tc.BoolConverter, command=['--', '--trace'])
|
|
|
|
def testHelpFlag(self):
|
|
with self.assertRaisesFireExit(0):
|
|
fire.Fire(tc.BoolConverter, command=['as-bool', 'True', '--', '--help'])
|
|
with self.assertRaisesFireExit(0):
|
|
fire.Fire(tc.BoolConverter, command=['as-bool', 'True', '--', '-h'])
|
|
with self.assertRaisesFireExit(0):
|
|
fire.Fire(tc.BoolConverter, command=['--', '--help'])
|
|
|
|
def testHelpFlagAndTraceFlag(self):
|
|
with self.assertRaisesFireExit(0, 'Fire trace:\n.*SYNOPSIS'):
|
|
fire.Fire(tc.BoolConverter,
|
|
command=['as-bool', 'True', '--', '--help', '--trace'])
|
|
with self.assertRaisesFireExit(0, 'Fire trace:\n.*SYNOPSIS'):
|
|
fire.Fire(tc.BoolConverter, command=['as-bool', 'True', '--', '-h', '-t'])
|
|
with self.assertRaisesFireExit(0, 'Fire trace:\n.*SYNOPSIS'):
|
|
fire.Fire(tc.BoolConverter, command=['--', '-h', '--trace'])
|
|
|
|
def testTabCompletionNoName(self):
|
|
completion_script = fire.Fire(tc.NoDefaults, command=['--', '--completion'])
|
|
self.assertIn('double', completion_script)
|
|
self.assertIn('triple', completion_script)
|
|
|
|
def testTabCompletion(self):
|
|
completion_script = fire.Fire(
|
|
tc.NoDefaults, command=['--', '--completion'], name='c')
|
|
self.assertIn('double', completion_script)
|
|
self.assertIn('triple', completion_script)
|
|
|
|
def testTabCompletionWithDict(self):
|
|
actions = {'multiply': lambda a, b: a * b}
|
|
completion_script = fire.Fire(
|
|
actions, command=['--', '--completion'], name='actCLI')
|
|
self.assertIn('actCLI', completion_script)
|
|
self.assertIn('multiply', completion_script)
|
|
|
|
def testBasicSeparator(self):
|
|
# '-' is the default separator.
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '+', '_']), ('+', '_'))
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '_', '+', '-']), ('_', '+'))
|
|
|
|
# If we change the separator we can use '-' as an argument.
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['identity', '-', '_', '--', '--separator', '&']),
|
|
('-', '_'))
|
|
|
|
# The separator triggers a function call, but there aren't enough arguments.
|
|
with self.assertRaisesFireExit(2):
|
|
fire.Fire(tc.MixedDefaults, command=['identity', '-', '_', '+'])
|
|
|
|
def testNonComparable(self):
|
|
"""Fire should work with classes that disallow comparisons."""
|
|
# Make sure this test passes both with a string command or a list command.
|
|
self.assertIsInstance(
|
|
fire.Fire(tc.NonComparable, command=''), tc.NonComparable)
|
|
self.assertIsInstance(
|
|
fire.Fire(tc.NonComparable, command=[]), tc.NonComparable)
|
|
|
|
# The first separator instantiates the NonComparable object.
|
|
# The second separator causes Fire to check if the separator was necessary.
|
|
self.assertIsInstance(
|
|
fire.Fire(tc.NonComparable, command=['-', '-']), tc.NonComparable)
|
|
|
|
def testExtraSeparators(self):
|
|
self.assertEqual(
|
|
fire.Fire(
|
|
tc.ReturnsObj,
|
|
command=['get-obj', 'arg1', 'arg2', '-', '-', 'as-bool', 'True']),
|
|
True)
|
|
self.assertEqual(
|
|
fire.Fire(
|
|
tc.ReturnsObj,
|
|
command=['get-obj', 'arg1', 'arg2', '-', '-', '-', 'as-bool',
|
|
'True']),
|
|
True)
|
|
|
|
def testSeparatorForChaining(self):
|
|
# Without a separator all args are consumed by get_obj.
|
|
self.assertIsInstance(
|
|
fire.Fire(tc.ReturnsObj,
|
|
command=['get-obj', 'arg1', 'arg2', 'as-bool', 'True']),
|
|
tc.BoolConverter)
|
|
# With a separator only the preceding args are consumed by get_obj.
|
|
self.assertEqual(
|
|
fire.Fire(
|
|
tc.ReturnsObj,
|
|
command=['get-obj', 'arg1', 'arg2', '-', 'as-bool', 'True']), True)
|
|
self.assertEqual(
|
|
fire.Fire(tc.ReturnsObj,
|
|
command=['get-obj', 'arg1', 'arg2', '&', 'as-bool', 'True',
|
|
'--', '--separator', '&']),
|
|
True)
|
|
self.assertEqual(
|
|
fire.Fire(tc.ReturnsObj,
|
|
command=['get-obj', 'arg1', '$$', 'as-bool', 'True', '--',
|
|
'--separator', '$$']),
|
|
True)
|
|
|
|
def testNegativeNumbers(self):
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['sum', '--alpha', '-3', '--beta', '-4']), -11)
|
|
|
|
def testFloatForExpectedInt(self):
|
|
self.assertEqual(
|
|
fire.Fire(tc.MixedDefaults,
|
|
command=['sum', '--alpha', '2.2', '--beta', '3.0']), 8.2)
|
|
self.assertEqual(
|
|
fire.Fire(
|
|
tc.NumberDefaults,
|
|
command=['integer_reciprocal', '--divisor', '5.0']), 0.2)
|
|
self.assertEqual(
|
|
fire.Fire(tc.NumberDefaults, command=['integer_reciprocal', '4.0']),
|
|
0.25)
|
|
|
|
def testClassInstantiation(self):
|
|
self.assertIsInstance(fire.Fire(tc.InstanceVars,
|
|
command=['--arg1=a1', '--arg2=a2']),
|
|
tc.InstanceVars)
|
|
with self.assertRaisesFireExit(2):
|
|
# Cannot instantiate a class with positional args.
|
|
fire.Fire(tc.InstanceVars, command=['a1', 'a2'])
|
|
|
|
def testTraceErrors(self):
|
|
# Class needs additional value but runs out of args.
|
|
with self.assertRaisesFireExit(2):
|
|
fire.Fire(tc.InstanceVars, command=['a1'])
|
|
with self.assertRaisesFireExit(2):
|
|
fire.Fire(tc.InstanceVars, command=['--arg1=a1'])
|
|
|
|
# Routine needs additional value but runs out of args.
|
|
with self.assertRaisesFireExit(2):
|
|
fire.Fire(tc.InstanceVars, command=['a1', 'a2', '-', 'run', 'b1'])
|
|
with self.assertRaisesFireExit(2):
|
|
fire.Fire(tc.InstanceVars,
|
|
command=['--arg1=a1', '--arg2=a2', '-', 'run b1'])
|
|
|
|
# Extra args cannot be consumed.
|
|
with self.assertRaisesFireExit(2):
|
|
fire.Fire(tc.InstanceVars,
|
|
command=['a1', 'a2', '-', 'run', 'b1', 'b2', 'b3'])
|
|
with self.assertRaisesFireExit(2):
|
|
fire.Fire(
|
|
tc.InstanceVars,
|
|
command=['--arg1=a1', '--arg2=a2', '-', 'run', 'b1', 'b2', 'b3'])
|
|
|
|
# Cannot find member to access.
|
|
with self.assertRaisesFireExit(2):
|
|
fire.Fire(tc.InstanceVars, command=['a1', 'a2', '-', 'jog'])
|
|
with self.assertRaisesFireExit(2):
|
|
fire.Fire(tc.InstanceVars, command=['--arg1=a1', '--arg2=a2', '-', 'jog'])
|
|
|
|
def testClassWithDefaultMethod(self):
|
|
self.assertEqual(
|
|
fire.Fire(tc.DefaultMethod, command=['double', '10']), 20
|
|
)
|
|
|
|
def testClassWithInvalidProperty(self):
|
|
self.assertEqual(
|
|
fire.Fire(tc.InvalidProperty, command=['double', '10']), 20
|
|
)
|
|
|
|
def testHelpKwargsDecorator(self):
|
|
# Issue #190, follow the wrapped method instead of crashing.
|
|
with self.assertRaisesFireExit(0):
|
|
fire.Fire(tc.decorated_method, command=['-h'])
|
|
with self.assertRaisesFireExit(0):
|
|
fire.Fire(tc.decorated_method, command=['--help'])
|
|
|
|
def testFireAsyncio(self):
|
|
self.assertEqual(fire.Fire(tc.py3.WithAsyncio,
|
|
command=['double', '--count', '10']), 20)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
testutils.main()
|