]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-125633: Add function `ispackage` to stdlib `inspect` (#125634)
authorZhikang Yan <2951256653@qq.com>
Sun, 27 Oct 2024 04:57:43 +0000 (12:57 +0800)
committerGitHub <noreply@github.com>
Sun, 27 Oct 2024 04:57:43 +0000 (14:57 +1000)
---------

Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
Doc/library/inspect.rst
Doc/whatsnew/3.14.rst
Lib/inspect.py
Lib/test/test_inspect/test_inspect.py
Misc/NEWS.d/next/Library/2024-10-17-04-52-00.gh-issue-125633.lMck06.rst [new file with mode: 0644]

index 1eaf1cc5d9a68e86b54888659020b1f10887cfcc..892f5ba9a7624e8f03a6a38acce43fde1cf29a21 100644 (file)
@@ -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
index d95f1848ad6d862550ced4a7e193ef34e40e697c..1ccfa329d5546af48a2daf94e83ec6a0f2618fe6 100644 (file)
@@ -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
 ----
index 0c33c6cc995a03a313e8904a2b598826d576788a..ea0d992436eb17fa84a9ebab5fddb43701d13427 100644 (file)
@@ -6,9 +6,9 @@ It also provides some help for examining source code and class layout.
 
 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 @@ __all__ = [
     "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.
 
index 77fdc6f238437eef320c9ca79b220c72463cdee0..a4857dadec2d5c06d8f85c5d7b3f75951e256629 100644 (file)
@@ -51,7 +51,7 @@ 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
@@ -105,7 +105,7 @@ unsorted_keyword_only_parameters = 'throw out the baby with_ the_ bathwater'.spl
 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 @@ class IsTestBase(unittest.TestCase):
                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 @@ class TestPredicates(IsTestBase):
         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 (file)
index 0000000..e816a13
--- /dev/null
@@ -0,0 +1,2 @@
+Add function :func:`inspect.ispackage` to determine whether an object is a
+:term:`package` or not.