https://github.com/python/cpython/commit/dad34531298fc0ea91b9000aafdd2ea2fce5e54a
commit: dad34531298fc0ea91b9000aafdd2ea2fce5e54a
branch: main
author: Zhikang Yan <[email protected]>
committer: ncoghlan <[email protected]>
date: 2024-10-27T14:57:43+10:00
summary:

gh-125633: Add function `ispackage` to stdlib `inspect` (#125634)

---------

Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>

files:
A Misc/NEWS.d/next/Library/2024-10-17-04-52-00.gh-issue-125633.lMck06.rst
M Doc/library/inspect.rst
M Doc/whatsnew/3.14.rst
M Lib/inspect.py
M Lib/test/test_inspect/test_inspect.py

diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst
index 1eaf1cc5d9a68e..892f5ba9a7624e 100644
--- a/Doc/library/inspect.rst
+++ b/Doc/library/inspect.rst
@@ -374,6 +374,13 @@ 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 :term:`package`.
+
+   .. versionadded:: 3.14
+
+
 .. function:: isfunction(object)
 
    Return ``True`` if the object is a Python function, which includes functions
diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst
index d95f1848ad6d86..1ccfa329d5546a 100644
--- a/Doc/whatsnew/3.14.rst
+++ b/Doc/whatsnew/3.14.rst
@@ -326,6 +326,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
+  :term:`package` or not.
+  (Contributed by Zhikang Yan in :gh:`125634`.)
+
 
 json
 ----
diff --git a/Lib/inspect.py b/Lib/inspect.py
index 0c33c6cc995a03..ea0d992436eb17 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -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
@@ -128,6 +128,7 @@
     "ismethoddescriptor",
     "ismethodwrapper",
     "ismodule",
+    "ispackage",
     "isroutine",
     "istraceback",
     "markcoroutinefunction",
@@ -186,6 +187,10 @@ 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."""
+    return ismodule(object) and hasattr(object, "__path__")
+
 def ismethoddescriptor(object):
     """Return true if the object is a method descriptor.
 
diff --git a/Lib/test/test_inspect/test_inspect.py 
b/Lib/test/test_inspect/test_inspect.py
index 77fdc6f238437e..a4857dadec2d5c 100644
--- a/Lib/test/test_inspect/test_inspect.py
+++ b/Lib/test/test_inspect/test_inspect.py
@@ -51,7 +51,7 @@
 
 # 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
@@ -105,7 +105,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,
@@ -121,7 +121,10 @@ def istest(self, predicate, exp):
                predicate == inspect.iscoroutinefunction) and \
                other == inspect.isfunction:
                 continue
-            self.assertFalse(other(obj), 'not %s(%s)' % (other.__name__, exp))
+            if predicate == inspect.ispackage and other == inspect.ismodule:
+                self.assertTrue(predicate(obj), '%s(%s)' % 
(predicate.__name__, exp))
+            else:
+                self.assertFalse(other(obj), 'not %s(%s)' % (other.__name__, 
exp))
 
     def test__all__(self):
         support.check__all__(self, inspect, not_exported=("modulesbyfile",), 
extra=("get_annotations",))
@@ -201,7 +204,17 @@ def test_excluding_predicates(self):
         self.assertFalse(inspect.ismethodwrapper(int))
         self.assertFalse(inspect.ismethodwrapper(type("AnyClass", (), {})))
 
+    def test_ispackage(self):
+        self.istest(inspect.ispackage, 'asyncio')
+        self.istest(inspect.ispackage, 'importlib')
+        self.assertFalse(inspect.ispackage(inspect))
+        self.assertFalse(inspect.ispackage(mod))
+        self.assertFalse(inspect.ispackage(':)'))
+
+        class FakePackage:
+            __path__ = None
 
+        self.assertFalse(inspect.ispackage(FakePackage()))
 
     def test_iscoroutine(self):
         async_gen_coro = async_generator_function_example(1)
diff --git 
a/Misc/NEWS.d/next/Library/2024-10-17-04-52-00.gh-issue-125633.lMck06.rst 
b/Misc/NEWS.d/next/Library/2024-10-17-04-52-00.gh-issue-125633.lMck06.rst
new file mode 100644
index 00000000000000..e816a13b75e0c7
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-10-17-04-52-00.gh-issue-125633.lMck06.rst
@@ -0,0 +1,2 @@
+Add function :func:`inspect.ispackage` to determine whether an object is a
+:term:`package` or not.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to