8000 Support for namedtuples in Python 2. · shader/python-fire@337342e · GitHub
[go: up one dir, main page]

Skip to content

Commit 337342e

Browse files
dbiebercopybara-github
authored andcommitted
Support for namedtuples in Python 2.
PiperOrigin-RevId: 259626143 Change-Id: If87c68d56e5885aa43c9f7ce782e00cd77aa32ad
1 parent a9b4819 commit 337342e

File tree

3 files changed

+46
-2
lines changed

3 files changed

+46
-2
lines changed

fire/inspectutils.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ class with an __init__ method.
8686
def GetFullArgSpec(fn):
8787
"""Returns a FullArgSpec describing the given callable."""
8888

89+
original_fn = fn
8990
fn, skip_arg = _GetArgSpecInfo(fn)
9091

9192
try:
@@ -100,10 +101,26 @@ def GetFullArgSpec(fn):
100101
except TypeError:
101102
# If we can't get the argspec, how do we know if the fn should take args?
102103
# 1. If it's a builtin, it can take args.
103-
# 2. If it's an implicit __init__ function (a 'slot wrapper'), take no args.
104-
# Are there other cases?
104+
# 2. If it's an implicit __init__ function (a 'slot wrapper'), that comes
105+
# from a namedtuple, use _fields to determine the args.
106+
# 3. If it's another slot wrapper (that comes from not subclassing object in
107+
# Python 2), then there are no args.
108+
# Are there other cases? We just don't know.
109+
110+
# Case 1: Builtins accept args.
105111
if inspect.isbuiltin(fn):
106112
return FullArgSpec(varargs='vars', varkw='kwargs')
113+
114+
# Case 2: namedtuples store their args in their _fields attribute.
115+
# TODO(dbieber): Determine if there's a way to detect false positives.
116+
# In Python 2, a class that does not subclass anything, does not define
117+
# __init__, and has an attribute named _fields will cause Fire to think it
118+
# expects args for its constructor when in fact it does not.
119+
fields = getattr(original_fn, '_fields', None)
120+
if fields:
121+
return FullArgSpec(args=list(fields))
122+
123+
# Case 3: Other known slot wrappers do not accept args.
107124
return FullArgSpec()
108125

109126
if skip_arg and args:

fire/inspectutils_test.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,26 @@ def testGetFullArgSpecFromSlotWrapper(self):
7070
self.assertEqual(spec.kwonlydefaults, {})
7171
self.assertEqual(spec.annotations, {})
7272

73+
def testGetFullArgSpecFromNamedTuple(self):
74+
spec = inspectutils.GetFullArgSpec(tc.NamedTuplePoint)
75+
self.assertEqual(spec.args, ['x', 'y'])
76+
self.assertEqual(spec.defaults, ())
77+
self.assertEqual(spec.varargs, None)
78+
self.assertEqual(spec.varkw, None)
79+
self.assertEqual(spec.kwonlyargs, [])
80+
self.assertEqual(spec.kwonlydefaults, {})
81+
self.assertEqual(spec.annotations, {})
82+
83+
def testGetFullArgSpecFromNamedTupleSubclass(self):
84+
spec = inspectutils.GetFullArgSpec(tc.SubPoint)
85+
self.assertEqual(spec.args, ['x', 'y'])
86+
self.assertEqual(spec.defaults, ())
87+
self.assertEqual(spec.varargs, None)
88+
self.assertEqual(spec.varkw, None)
89+
self.assertEqual(spec.kwonlyargs, [])
90+
self.assertEqual(spec.kwonlydefaults, {})
91+
self.assertEqual(spec.annotations, {})
92+
7393
def testGetFullArgSpecFromClassNoInit(self):
7494
spec = inspectutils.GetFullArgSpec(tc.OldStyleEmpty)
7595
self.assertEqual(spec.args, [])

fire/test_components.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import collections
2222

23+
import enum
2324
import six
2425

2526
if six.PY3:
@@ -396,3 +397,9 @@ class Subdict(dict):
396397

397398
# An example subdict.
398399
SUBDICT = Subdict({1: 2, 'red': 'blue'})
400+
401+
402+
class Color(enum.Enum):
403+
RED = 1
404+
GREEN = 2
405+
BLUE = 3

0 commit comments

Comments
 (0)
0