Skip to content

Commit

Permalink
remove six: Replace six.string_types and six.integer_types, etc. (#541)
Browse files Browse the repository at this point in the history
This commit includes:

* assuming Python 3 for test skipping
* assuming Python 3 for fire's various type checks
* assuming Python 3 for imports (like asyncio)
* assuming Python 3 for getting function signatures
* six is no longer considered a hidden module (and so if a user of fire has six in their globals when they call Fire(), six will now show up where it used to be hidden)

This commit does not remove six from console/ code.
  • Loading branch information
dbieber authored Sep 20, 2024
1 parent 8b063b9 commit 5d0706d
Show file tree
Hide file tree
Showing 13 changed files with 30 additions and 96 deletions.
21 changes: 7 additions & 14 deletions fire/completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import inspect

from fire import inspectutils
import six


def Script(name, component, default_options=None, shell='bash'):
Expand Down Expand Up @@ -308,18 +307,19 @@ def MemberVisible(component, name, member, class_attrs=None, verbose=False):
Returns
A boolean value indicating whether the member should be included.
"""
if isinstance(name, six.string_types) and name.startswith('__'):
if isinstance(name, str) and name.startswith('__'):
return False
if verbose:
return True
if (member is absolute_import
or member is division
or member is print_function):
return False
if isinstance(member, type(absolute_import)) and six.PY34:
if isinstance(member, type(absolute_import)):
return False
if inspect.ismodule(member) and member is six:
# TODO(dbieber): Determine more generally which modules to hide.
# TODO(dbieber): Determine more generally which modules to hide.
modules_to_hide = []
if inspect.ismodule(member) and member in modules_to_hide:
return False
if inspect.isclass(component):
# If class_attrs has not been provided, compute it.
Expand All @@ -336,14 +336,7 @@ def MemberVisible(component, name, member, class_attrs=None, verbose=False):
tuplegetter = getattr(collections, '_tuplegetter', type(None))
if isinstance(class_attr.object, tuplegetter):
return False
if (six.PY2 and inspect.isfunction(component)
and name in ('func_closure', 'func_code', 'func_defaults',
'func_dict', 'func_doc', 'func_globals', 'func_name')):
return False
if (six.PY2 and inspect.ismethod(component)
and name in ('im_class', 'im_func', 'im_self')):
return False
if isinstance(name, six.string_types):
if isinstance(name, str):
return not name.startswith('_')
return True # Default to including the member

Expand Down Expand Up @@ -438,7 +431,7 @@ def _FormatForCommand(token):
Returns:
The transformed token.
"""
if not isinstance(token, six.string_types):
if not isinstance(token, str):
token = str(token)

if token.startswith('_'):
Expand Down
8 changes: 3 additions & 5 deletions fire/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,8 @@ def main(argv):
from fire import trace
from fire import value_types
from fire.console import console_io
import six

if six.PY34:
import asyncio # pylint: disable=import-error,g-import-not-at-top # pytype: disable=import-error
import asyncio # pylint: disable=import-error,g-import-not-at-top # pytype: disable=import-error


def Fire(component=None, command=None, name=None, serialize=None):
Expand Down Expand Up @@ -109,7 +107,7 @@ def Fire(component=None, command=None, name=None, serialize=None):
name = name or os.path.basename(sys.argv[0])

# Get args as a list.
if isinstance(command, six.string_types):
if isinstance(command, str):
args = shlex.split(command)
elif isinstance(command, (list, tuple)):
args = command
Expand Down Expand Up @@ -344,7 +342,7 @@ def _DictAsString(result, verbose=False):
def _OneLineResult(result):
"""Returns result serialized to a single line string."""
# TODO(dbieber): Ensure line is fewer than eg 120 characters.
if isinstance(result, six.string_types):
if isinstance(result, str):
return str(result).replace('\n', ' ')

# TODO(dbieber): Show a small amount of usage information about the function
Expand Down
4 changes: 0 additions & 4 deletions fire/core_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@
from fire import trace
import mock

import six


class CoreTest(testutils.BaseTestCase):

Expand Down Expand Up @@ -214,13 +212,11 @@ def serialize(x):
with self.assertRaises(core.FireError):
core.Fire(ident, command=['asdf'], serialize=55)

@testutils.skipIf(six.PY2, 'lru_cache is Python 3 only.')
def testLruCacheDecoratorBoundArg(self):
self.assertEqual(
core.Fire(tc.py3.LruCacheDecoratedMethod, # pytype: disable=module-attr
command=['lru_cache_in_class', 'foo']), 'foo')

@testutils.skipIf(six.PY2, 'lru_cache is Python 3 only.')
def testLruCacheDecorator(self):
self.assertEqual(
core.Fire(tc.py3.lru_cache_decorated, # pytype: disable=module-attr
Expand Down
9 changes: 3 additions & 6 deletions fire/custom_descriptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
"""

from fire import formatting
import six

TWO_DOUBLE_QUOTES = '""'
STRING_DESC_PREFIX = 'The string '
Expand All @@ -60,13 +59,11 @@ def NeedsCustomDescription(component):
Whether the component should use a custom description and summary.
"""
type_ = type(component)
if (type_ in six.string_types
or type_ in six.integer_types
or type_ is six.text_type
or type_ is six.binary_type
if (
type_ in (str, int, bytes)
or type_ in (float, complex, bool)
or type_ in (dict, tuple, list, set, frozenset)
):
):
return True
return False

Expand Down
3 changes: 0 additions & 3 deletions fire/fire_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
from fire import testutils

import mock
import six


class FireTest(testutils.BaseTestCase):
Expand Down Expand Up @@ -180,7 +179,6 @@ def testFireAnnotatedArgs(self):
self.assertEqual(fire.Fire(tc.Annotations, command=['double', '5']), 10)
self.assertEqual(fire.Fire(tc.Annotations, command=['triple', '5']), 15)

@testutils.skipIf(six.PY2, 'Keyword-only arguments not in Python 2.')
def testFireKeywordOnlyArgs(self):
with self.assertRaisesFireExit(2):
# Keyword arguments must be passed with flag syntax.
Expand Down Expand Up @@ -717,7 +715,6 @@ def testHelpKwargsDecorator(self):
with self.assertRaisesFireExit(0):
fire.Fire(tc.decorated_method, command=['--help'])

@testutils.skipIf(six.PY2, 'Asyncio not available in Python 2.')
def testFireAsyncio(self):
self.assertEqual(fire.Fire(tc.py3.WithAsyncio,
command=['double', '--count', '10']), 20)
Expand Down
11 changes: 0 additions & 11 deletions fire/helptext_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
from fire import test_components as tc
from fire import testutils
from fire import trace
import six


class HelpTest(testutils.BaseTestCase):
Expand Down Expand Up @@ -276,27 +275,20 @@ def testHelpTextNoInit(self):
self.assertIn('NAME\n OldStyleEmpty', help_screen)
self.assertIn('SYNOPSIS\n OldStyleEmpty', help_screen)

@testutils.skipIf(
six.PY2, 'Python 2 does not support keyword-only arguments.')
def testHelpTextKeywordOnlyArgumentsWithDefault(self):
component = tc.py3.KeywordOnly.with_default # pytype: disable=module-attr
output = helptext.HelpText(
component=component, trace=trace.FireTrace(component, 'with_default'))
self.assertIn('NAME\n with_default', output)
self.assertIn('FLAGS\n -x, --x=X', output)

@testutils.skipIf(
six.PY2, 'Python 2 does not support keyword-only arguments.')
def testHelpTextKeywordOnlyArgumentsWithoutDefault(self):
component = tc.py3.KeywordOnly.double # pytype: disable=module-attr
output = helptext.HelpText(
component=component, trace=trace.FireTrace(component, 'double'))
self.assertIn('NAME\n double', output)
self.assertIn('FLAGS\n -c, --count=COUNT (required)', output)

@testutils.skipIf(
six.PY2,
'Python 2 does not support required name-only arguments.')
def testHelpTextFunctionMixedDefaults(self):
component = tc.py3.HelpTextComponent().identity
t = trace.FireTrace(component, name='FunctionMixedDefaults')
Expand Down Expand Up @@ -523,9 +515,6 @@ def testUsageOutputFunctionWithDocstring(self):
textwrap.dedent(expected_output).lstrip('\n'),
usage_output)

@testutils.skipIf(
six.PY2,
'Python 2 does not support required name-only arguments.')
def testUsageOutputFunctionMixedDefaults(self):
component = tc.py3.HelpTextComponent().identity
t = trace.FireTrace(component, name='FunctionMixedDefaults')
Expand Down
27 changes: 4 additions & 23 deletions fire/inspectutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@

from fire import docstrings

import six

if six.PY34:
import asyncio # pylint: disable=import-error,g-import-not-at-top # pytype: disable=import-error
import asyncio # pylint: disable=import-error,g-import-not-at-top # pytype: disable=import-error


class FullArgSpec(object):
Expand Down Expand Up @@ -74,8 +71,6 @@ class with an __init__ method.
if inspect.isclass(fn):
# If the function is a class, we try to use its init method.
skip_arg = True
if six.PY2 and hasattr(fn, '__init__'):
fn = fn.__init__
elif inspect.ismethod(fn):
# If the function is a bound method, we skip the `self` argument.
skip_arg = fn.__self__ is not None
Expand All @@ -91,16 +86,6 @@ class with an __init__ method.
return fn, skip_arg


def Py2GetArgSpec(fn):
"""A wrapper around getargspec that tries both fn and fn.__call__."""
try:
return inspect.getargspec(fn) # pylint: disable=deprecated-method,no-member
except TypeError:
if hasattr(fn, '__call__'):
return inspect.getargspec(fn.__call__) # pylint: disable=deprecated-method,no-member
raise


def Py3GetFullArgSpec(fn):
"""A alternative to the builtin getfullargspec.
Expand Down Expand Up @@ -185,13 +170,9 @@ def GetFullArgSpec(fn):
if sys.version_info[0:2] >= (3, 5):
(args, varargs, varkw, defaults,
kwonlyargs, kwonlydefaults, annotations) = Py3GetFullArgSpec(fn)
elif six.PY3: # Specifically Python 3.4.
else: # Specifically Python 3.4.
(args, varargs, varkw, defaults,
kwonlyargs, kwonlydefaults, annotations) = inspect.getfullargspec(fn) # pylint: disable=deprecated-method,no-member
else: # six.PY2
args, varargs, varkw, defaults = Py2GetArgSpec(fn)
kwonlyargs = kwonlydefaults = None
annotations = getattr(fn, '__annotations__', None)

except TypeError:
# If we can't get the argspec, how do we know if the fn should take args?
Expand Down Expand Up @@ -221,7 +202,7 @@ def GetFullArgSpec(fn):
return FullArgSpec()

# In Python 3.5+ Py3GetFullArgSpec uses skip_bound_arg=True already.
skip_arg_required = six.PY2 or sys.version_info[0:2] == (3, 4)
skip_arg_required = sys.version_info[0:2] == (3, 4)
if skip_arg_required and skip_arg and args:
args.pop(0) # Remove 'self' or 'cls' from the list of arguments.
return FullArgSpec(args, varargs, varkw, defaults,
Expand Down Expand Up @@ -363,6 +344,6 @@ def GetClassAttrsDict(component):

def IsCoroutineFunction(fn):
try:
return six.PY34 and asyncio.iscoroutinefunction(fn)
return asyncio.iscoroutinefunction(fn)
except: # pylint: disable=bare-except
return False
9 changes: 1 addition & 8 deletions fire/inspectutils_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,11 @@
"""Tests for the inspectutils module."""

import os
import unittest

from fire import inspectutils
from fire import test_components as tc
from fire import testutils

import six


class InspectUtilsTest(testutils.BaseTestCase):

Expand All @@ -36,7 +33,6 @@ def testGetFullArgSpec(self):
self.assertEqual(spec.kwonlydefaults, {})
self.assertEqual(spec.annotations, {'arg2': int, 'arg4': int})

@unittest.skipIf(six.PY2, 'No keyword arguments in python 2')
def testGetFullArgSpecPy3(self):
spec = inspectutils.GetFullArgSpec(tc.py3.identity)
self.assertEqual(spec.args, ['arg1', 'arg2', 'arg3', 'arg4'])
Expand Down Expand Up @@ -121,10 +117,7 @@ def testInfoClass(self):

def testInfoClassNoInit(self):
info = inspectutils.Info(tc.OldStyleEmpty)
if six.PY2:
self.assertEqual(info.get('type_name'), 'classobj')
else:
self.assertEqual(info.get('type_name'), 'type')
self.assertEqual(info.get('type_name'), 'type')
self.assertIn(os.path.join('fire', 'test_components.py'), info.get('file'))
self.assertGreater(info.get('line'), 0)

Expand Down
7 changes: 3 additions & 4 deletions fire/parser_fuzz_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
from hypothesis import settings
from hypothesis import strategies as st
import Levenshtein
import six


class ParserFuzzTest(testutils.BaseTestCase):
Expand Down Expand Up @@ -64,8 +63,8 @@ def testDefaultParseValueFuzz(self, value):
raise

try:
uvalue = six.text_type(value)
uresult = six.text_type(result)
uvalue = str(value)
uresult = str(result)
except UnicodeDecodeError:
# This is not what we're testing.
return
Expand All @@ -82,7 +81,7 @@ def testDefaultParseValueFuzz(self, value):
if '#' in value:
max_distance += len(value) - value.index('#')

if not isinstance(result, six.string_types):
if not isinstance(result, str):
max_distance += value.count('0') # Leading 0s are stripped.

# Note: We don't check distance for dicts since item order can be changed.
Expand Down
5 changes: 1 addition & 4 deletions fire/test_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@
import enum
import functools

import six

if six.PY3:
from fire import test_components_py3 as py3 # pylint: disable=unused-import,no-name-in-module,g-import-not-at-top
from fire import test_components_py3 as py3 # pylint: disable=unused-import,no-name-in-module,g-import-not-at-top


def identity(arg1, arg2, arg3=10, arg4=20, *arg5, **arg6): # pylint: disable=keyword-arg-before-vararg
Expand Down
11 changes: 4 additions & 7 deletions fire/testutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"""Utilities for Python Fire's tests."""

import contextlib
import io
import os
import re
import sys
Expand All @@ -24,7 +25,6 @@
from fire import trace

import mock
import six


class BaseTestCase(unittest.TestCase):
Expand All @@ -45,8 +45,8 @@ def assertOutputMatches(self, stdout='.*', stderr='.*', capture=True):
Yields:
Yields to the wrapped context.
"""
stdout_fp = six.StringIO()
stderr_fp = six.StringIO()
stdout_fp = io.StringIO()
stderr_fp = io.StringIO()
try:
with mock.patch.object(sys, 'stdout', stdout_fp):
with mock.patch.object(sys, 'stderr', stderr_fp):
Expand All @@ -69,10 +69,7 @@ def assertOutputMatches(self, stdout='.*', stderr='.*', capture=True):
(name, value, regexp))

def assertRaisesRegex(self, *args, **kwargs): # pylint: disable=arguments-differ
if sys.version_info.major == 2:
return super(BaseTestCase, self).assertRaisesRegexp(*args, **kwargs) # pylint: disable=deprecated-method,no-member
else:
return super(BaseTestCase, self).assertRaisesRegex(*args, **kwargs) # pylint: disable=no-member
return super(BaseTestCase, self).assertRaisesRegex(*args, **kwargs) # pylint: disable=no-member

@contextlib.contextmanager
def assertRaisesFireExit(self, code, regexp='.*'):
Expand Down
Loading

0 comments on commit 5d0706d

Please sign in to comment.