Skip to content

Commit dad3453

Browse files
gh-125633: Add function ispackage to stdlib inspect (#125634)
--------- Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
1 parent c51b560 commit dad3453

File tree

5 files changed

+37
-6
lines changed

5 files changed

+37
-6
lines changed

Doc/library/inspect.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,13 @@ attributes (see :ref:`import-mod-attrs` for module attributes):
374374
Return ``True`` if the object is a bound method written in Python.
375375

376376

377+
.. function:: ispackage(object)
378+
379+
Return ``True`` if the object is a :term:`package`.
380+
381+
.. versionadded:: 3.14
382+
383+
377384
.. function:: isfunction(object)
378385

379386
Return ``True`` if the object is a Python function, which includes functions

Doc/whatsnew/3.14.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,10 @@ inspect
326326
If true, string :term:`annotations <annotation>` are displayed without surrounding quotes.
327327
(Contributed by Jelle Zijlstra in :gh:`101552`.)
328328

329+
* Add function :func:`inspect.ispackage` to determine whether an object is a
330+
:term:`package` or not.
331+
(Contributed by Zhikang Yan in :gh:`125634`.)
332+
329333

330334
json
331335
----

Lib/inspect.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
77
Here are some of the useful functions provided by this module:
88
9-
ismodule(), isclass(), ismethod(), isfunction(), isgeneratorfunction(),
10-
isgenerator(), istraceback(), isframe(), iscode(), isbuiltin(),
11-
isroutine() - check object types
9+
ismodule(), isclass(), ismethod(), ispackage(), isfunction(),
10+
isgeneratorfunction(), isgenerator(), istraceback(), isframe(),
11+
iscode(), isbuiltin(), isroutine() - check object types
1212
getmembers() - get members of an object that satisfy a given condition
1313
1414
getfile(), getsourcefile(), getsource() - find an object's source code
@@ -128,6 +128,7 @@
128128
"ismethoddescriptor",
129129
"ismethodwrapper",
130130
"ismodule",
131+
"ispackage",
131132
"isroutine",
132133
"istraceback",
133134
"markcoroutinefunction",
@@ -186,6 +187,10 @@ def ismethod(object):
186187
"""Return true if the object is an instance method."""
187188
return isinstance(object, types.MethodType)
188189

190+
def ispackage(object):
191+
"""Return true if the object is a package."""
192+
return ismodule(object) and hasattr(object, "__path__")
193+
189194
def ismethoddescriptor(object):
190195
"""Return true if the object is a method descriptor.
191196

Lib/test/test_inspect/test_inspect.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151

5252
# Functions tested in this suite:
5353
# ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode,
54-
# isbuiltin, isroutine, isgenerator, isgeneratorfunction, getmembers,
54+
# isbuiltin, isroutine, isgenerator, ispackage, isgeneratorfunction, getmembers,
5555
# getdoc, getfile, getmodule, getsourcefile, getcomments, getsource,
5656
# getclasstree, getargvalues, formatargvalues, currentframe,
5757
# stack, trace, ismethoddescriptor, isdatadescriptor, ismethodwrapper
@@ -105,7 +105,7 @@ def unsorted_keyword_only_parameters_fn(*, throw, out, the, baby, with_,
105105
class IsTestBase(unittest.TestCase):
106106
predicates = set([inspect.isbuiltin, inspect.isclass, inspect.iscode,
107107
inspect.isframe, inspect.isfunction, inspect.ismethod,
108-
inspect.ismodule, inspect.istraceback,
108+
inspect.ismodule, inspect.istraceback, inspect.ispackage,
109109
inspect.isgenerator, inspect.isgeneratorfunction,
110110
inspect.iscoroutine, inspect.iscoroutinefunction,
111111
inspect.isasyncgen, inspect.isasyncgenfunction,
@@ -121,7 +121,10 @@ def istest(self, predicate, exp):
121121
predicate == inspect.iscoroutinefunction) and \
122122
other == inspect.isfunction:
123123
continue
124-
self.assertFalse(other(obj), 'not %s(%s)' % (other.__name__, exp))
124+
if predicate == inspect.ispackage and other == inspect.ismodule:
125+
self.assertTrue(predicate(obj), '%s(%s)' % (predicate.__name__, exp))
126+
else:
127+
self.assertFalse(other(obj), 'not %s(%s)' % (other.__name__, exp))
125128

126129
def test__all__(self):
127130
support.check__all__(self, inspect, not_exported=("modulesbyfile",), extra=("get_annotations",))
@@ -201,7 +204,17 @@ def test_excluding_predicates(self):
201204
self.assertFalse(inspect.ismethodwrapper(int))
202205
self.assertFalse(inspect.ismethodwrapper(type("AnyClass", (), {})))
203206

207+
def test_ispackage(self):
208+
self.istest(inspect.ispackage, 'asyncio')
209+
self.istest(inspect.ispackage, 'importlib')
210+
self.assertFalse(inspect.ispackage(inspect))
211+
self.assertFalse(inspect.ispackage(mod))
212+
self.assertFalse(inspect.ispackage(':)'))
213+
214+
class FakePackage:
215+
__path__ = None
204216

217+
self.assertFalse(inspect.ispackage(FakePackage()))
205218

206219
def test_iscoroutine(self):
207220
async_gen_coro = async_generator_function_example(1)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add function :func:`inspect.ispackage` to determine whether an object is a
2+
:term:`package` or not.

0 commit comments

Comments
 (0)