Skip to content
Merged
5 changes: 5 additions & 0 deletions Doc/library/inspect.rst
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,11 @@ attributes (see :ref:`import-mod-attrs` for module attributes):
Return ``True`` if the object is a bound method written in Python.


.. function:: ispackage(object)

Return ``True`` if the object is a package.


.. function:: isfunction(object)

Return ``True`` if the object is a Python function, which includes functions
Expand Down
4 changes: 4 additions & 0 deletions Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,10 @@ inspect
If true, string :term:`annotations <annotation>` are displayed without surrounding quotes.
(Contributed by Jelle Zijlstra in :gh:`101552`.)

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


json
----
Expand Down
13 changes: 10 additions & 3 deletions Lib/inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

Here are some of the useful functions provided by this module:

ismodule(), isclass(), ismethod(), isfunction(), isgeneratorfunction(),
isgenerator(), istraceback(), isframe(), iscode(), isbuiltin(),
isroutine() - check object types
ismodule(), isclass(), ismethod(), ispackage(), isfunction(),
isgeneratorfunction(), isgenerator(), istraceback(), isframe(),
iscode(), isbuiltin(), isroutine() - check object types
getmembers() - get members of an object that satisfy a given condition

getfile(), getsourcefile(), getsource() - find an object's source code
Expand Down Expand Up @@ -128,6 +128,7 @@
"ismethoddescriptor",
"ismethodwrapper",
"ismodule",
"ispackage",
"isroutine",
"istraceback",
"markcoroutinefunction",
Expand Down Expand Up @@ -186,6 +187,12 @@ def ismethod(object):
"""Return true if the object is an instance method."""
return isinstance(object, types.MethodType)

def ispackage(object):
"""Return true if the object is a package."""
if ismodule(object) and object.__spec__ is not None:
return object.__spec__.parent == object.__spec__.name
return False

def ismethoddescriptor(object):
"""Return true if the object is a method descriptor.

Expand Down
Empty file.
8 changes: 6 additions & 2 deletions Lib/test/test_inspect/test_inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,14 @@

from test.test_inspect import inspect_fodder as mod
from test.test_inspect import inspect_fodder2 as mod2
from test.test_inspect import inspect_simple_pkg as pkg
from test.test_inspect import inspect_stringized_annotations
from test.test_inspect import inspect_deferred_annotations


# Functions tested in this suite:
# ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode,
# isbuiltin, isroutine, isgenerator, isgeneratorfunction, getmembers,
# isbuiltin, isroutine, isgenerator, ispackage, isgeneratorfunction, getmembers,
# getdoc, getfile, getmodule, getsourcefile, getcomments, getsource,
# getclasstree, getargvalues, formatargvalues, currentframe,
# stack, trace, ismethoddescriptor, isdatadescriptor, ismethodwrapper
Expand Down Expand Up @@ -105,7 +106,7 @@ def unsorted_keyword_only_parameters_fn(*, throw, out, the, baby, with_,
class IsTestBase(unittest.TestCase):
predicates = set([inspect.isbuiltin, inspect.isclass, inspect.iscode,
inspect.isframe, inspect.isfunction, inspect.ismethod,
inspect.ismodule, inspect.istraceback,
inspect.ismodule, inspect.istraceback, inspect.ispackage,
inspect.isgenerator, inspect.isgeneratorfunction,
inspect.iscoroutine, inspect.iscoroutinefunction,
inspect.isasyncgen, inspect.isasyncgenfunction,
Expand All @@ -121,6 +122,8 @@ def istest(self, predicate, exp):
predicate == inspect.iscoroutinefunction) and \
other == inspect.isfunction:
continue
if predicate == inspect.ispackage and other == inspect.ismodule:
continue
self.assertFalse(other(obj), 'not %s(%s)' % (other.__name__, exp))

def test__all__(self):
Expand Down Expand Up @@ -176,6 +179,7 @@ def test_excluding_predicates(self):
self.istest(inspect.ismethod, 'git.argue')
self.istest(inspect.ismethod, 'mod.custom_method')
self.istest(inspect.ismodule, 'mod')
self.istest(inspect.ispackage, 'pkg')
self.istest(inspect.ismethoddescriptor, 'int.__add__')
self.istest(inspect.isdatadescriptor, 'collections.defaultdict.default_factory')
self.istest(inspect.isgenerator, '(x for x in range(2))')
Expand Down
1 change: 1 addition & 0 deletions Makefile.pre.in
Original file line number Diff line number Diff line change
Expand Up @@ -2498,6 +2498,7 @@ TESTSUBDIRS= idlelib/idle_test \
test/test_importlib/resources \
test/test_importlib/source \
test/test_inspect \
test/test_inspect/inspect_simple_pkg \
test/test_interpreters \
test/test_json \
test/test_module \
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Adding function :func:`inspect.ispackage` to determine whether an object is a
package or not.
Loading