From 12cb666cbe9a82d19d60db2e8e3137f9195f93b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E5=BA=B72022?= <2951256653@qq.com> Date: Thu, 17 Oct 2024 11:22:01 +0800 Subject: [PATCH 01/14] Add function `ispackage` to stdlib `inspect` --- Lib/inspect.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py index 0c33c6cc995a03..1a2788677471b4 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,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. From 2105a1089f4ae44e0cce6b730bfa1ef42526d98f Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2024 04:52:01 +0000 Subject: [PATCH 02/14] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2024-10-17-04-52-00.gh-issue-125633.lMck06.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2024-10-17-04-52-00.gh-issue-125633.lMck06.rst 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..835e2bd074cdbd --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-17-04-52-00.gh-issue-125633.lMck06.rst @@ -0,0 +1 @@ +Adding function `ispackage` to determine whether an object is a package or not. From efa661db13d805af3275059a12844d6e52ec6f10 Mon Sep 17 00:00:00 2001 From: Xiaokang2022 <2951256653@qq.com> Date: Thu, 17 Oct 2024 16:57:14 +0800 Subject: [PATCH 03/14] Fixed the sphinx markup --- .../Library/2024-10-17-04-52-00.gh-issue-125633.lMck06.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 index 835e2bd074cdbd..fc0ffb48c67d15 100644 --- 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 @@ -1 +1,2 @@ -Adding function `ispackage` to determine whether an object is a package or not. +Adding function :func:`inspect.ispackage` to determine whether an object is a +package or not. From 40d5a49b069fc7d6cf2b35afc37bab5d9336e9ad Mon Sep 17 00:00:00 2001 From: Xiaokang2022 <2951256653@qq.com> Date: Thu, 17 Oct 2024 18:35:29 +0800 Subject: [PATCH 04/14] Added tests --- Lib/test/test_inspect/inspect_simple_pkg/__init__.py | 0 Lib/test/test_inspect/test_inspect.py | 8 ++++++-- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 Lib/test/test_inspect/inspect_simple_pkg/__init__.py diff --git a/Lib/test/test_inspect/inspect_simple_pkg/__init__.py b/Lib/test/test_inspect/inspect_simple_pkg/__init__.py new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index 9fa6d23d15f06a..c50cc123f88580 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -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 @@ -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, @@ -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): @@ -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))') From 658ef94ab2f302995de0256352d9f6422a30a04b Mon Sep 17 00:00:00 2001 From: Xiaokang2022 <2951256653@qq.com> Date: Thu, 17 Oct 2024 18:55:59 +0800 Subject: [PATCH 05/14] Added document --- Doc/library/inspect.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 1eaf1cc5d9a68e..df4f629fdeaf66 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -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 From 0943c6259ed214c2c7c5ae101a2ecaac641710af Mon Sep 17 00:00:00 2001 From: Xiaokang2022 <2951256653@qq.com> Date: Thu, 17 Oct 2024 19:03:31 +0800 Subject: [PATCH 06/14] Added to 3.14 what's new --- Doc/whatsnew/3.14.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 9543af3c7ca225..ba369a93bca4ae 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -317,6 +317,10 @@ inspect If true, string :term:`annotations ` 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 ---- From a0b64f7e976376925e484a17876d0ca81fa72a0f Mon Sep 17 00:00:00 2001 From: Xiaokang2022 <2951256653@qq.com> Date: Thu, 17 Oct 2024 19:30:28 +0800 Subject: [PATCH 07/14] Added the new test folder to the Makefile --- Makefile.pre.in | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.pre.in b/Makefile.pre.in index 07c8a4d20142db..51b06fa3c93c73 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -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 \ From 4c183ee489b32ec1d1d8ba70f86294fd8bac36d7 Mon Sep 17 00:00:00 2001 From: Xiaokang2022 <2951256653@qq.com> Date: Thu, 17 Oct 2024 23:03:59 +0800 Subject: [PATCH 08/14] Added the missing markup --- Doc/library/inspect.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index df4f629fdeaf66..38a8fa88ab5896 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -378,6 +378,8 @@ attributes (see :ref:`import-mod-attrs` for module attributes): Return ``True`` if the object is a package. + .. versionadded:: 3.14 + .. function:: isfunction(object) From a2eb627352e333c08e0f0c5fe423b68dbca6050e Mon Sep 17 00:00:00 2001 From: Xiaokang2022 <2951256653@qq.com> Date: Fri, 18 Oct 2024 00:10:49 +0800 Subject: [PATCH 09/14] Changed news --- .../Library/2024-10-17-04-52-00.gh-issue-125633.lMck06.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index fc0ffb48c67d15..e816a13b75e0c7 100644 --- 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 @@ -1,2 +1,2 @@ -Adding function :func:`inspect.ispackage` to determine whether an object is a -package or not. +Add function :func:`inspect.ispackage` to determine whether an object is a +:term:`package` or not. From c256e0142ac72e64ed7745f9e34263b896706a4a Mon Sep 17 00:00:00 2001 From: Xiaokang2022 <2951256653@qq.com> Date: Fri, 18 Oct 2024 00:18:06 +0800 Subject: [PATCH 10/14] Changed 3.14 what's new --- Doc/whatsnew/3.14.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index ba369a93bca4ae..19c5f13f8ed2e4 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -318,7 +318,7 @@ inspect (Contributed by Jelle Zijlstra in :gh:`101552`.) * Add function :func:`inspect.ispackage` to determine whether an object is a - package or not. + :term:`package` or not. (Contributed by Zhikang Yan in :gh:`125634`.) From 20f497f2e532825cd05a5a2a6d62e90ec464242b Mon Sep 17 00:00:00 2001 From: Xiaokang2022 <2951256653@qq.com> Date: Fri, 18 Oct 2024 00:20:40 +0800 Subject: [PATCH 11/14] Changed doc --- Doc/library/inspect.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 38a8fa88ab5896..892f5ba9a7624e 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -376,7 +376,7 @@ attributes (see :ref:`import-mod-attrs` for module attributes): .. function:: ispackage(object) - Return ``True`` if the object is a package. + Return ``True`` if the object is a :term:`package`. .. versionadded:: 3.14 From ef7eebd47db61e8c76c146cf2c5c7f6b7ec80ba4 Mon Sep 17 00:00:00 2001 From: Xiaokang2022 <2951256653@qq.com> Date: Fri, 18 Oct 2024 01:02:45 +0800 Subject: [PATCH 12/14] Improved the code --- Lib/inspect.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py index 1a2788677471b4..ea0d992436eb17 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -189,9 +189,7 @@ def ismethod(object): 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 + return ismodule(object) and hasattr(object, "__path__") def ismethoddescriptor(object): """Return true if the object is a method descriptor. From adfc70b9aa3f84c0f4328d6801d81f53ca319ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E5=BA=B72022?= <2951256653@qq.com> Date: Sat, 19 Oct 2024 19:42:59 +0800 Subject: [PATCH 13/14] Improved tests --- Lib/test/test_inspect/inspect_simple_pkg/__init__.py | 0 Lib/test/test_inspect/test_inspect.py | 11 +++++++---- Makefile.pre.in | 1 - 3 files changed, 7 insertions(+), 5 deletions(-) delete mode 100644 Lib/test/test_inspect/inspect_simple_pkg/__init__.py diff --git a/Lib/test/test_inspect/inspect_simple_pkg/__init__.py b/Lib/test/test_inspect/inspect_simple_pkg/__init__.py deleted file mode 100644 index e69de29bb2d1d6..00000000000000 diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index c50cc123f88580..6edd87a37aebc4 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -45,7 +45,6 @@ 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 @@ -123,8 +122,9 @@ def istest(self, predicate, exp): other == inspect.isfunction: continue if predicate == inspect.ispackage and other == inspect.ismodule: - continue - self.assertFalse(other(obj), 'not %s(%s)' % (other.__name__, exp)) + 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",)) @@ -179,7 +179,10 @@ 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.ispackage, 'asyncio') + self.istest(inspect.ispackage, 'importlib') + self.assertFalse(inspect.ispackage(mod)) + self.assertFalse(inspect.ispackage(':)')) self.istest(inspect.ismethoddescriptor, 'int.__add__') self.istest(inspect.isdatadescriptor, 'collections.defaultdict.default_factory') self.istest(inspect.isgenerator, '(x for x in range(2))') diff --git a/Makefile.pre.in b/Makefile.pre.in index 51b06fa3c93c73..07c8a4d20142db 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2498,7 +2498,6 @@ 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 \ From 95ac2c6febeef52bf6c7eb5fef81be453d8d1587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E5=BA=B72022?= <2951256653@qq.com> Date: Sat, 19 Oct 2024 20:48:51 +0800 Subject: [PATCH 14/14] Improved tests --- Lib/test/test_inspect/test_inspect.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index 6edd87a37aebc4..23dc6d29534f5f 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -179,10 +179,6 @@ 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, 'asyncio') - self.istest(inspect.ispackage, 'importlib') - self.assertFalse(inspect.ispackage(mod)) - self.assertFalse(inspect.ispackage(':)')) self.istest(inspect.ismethoddescriptor, 'int.__add__') self.istest(inspect.isdatadescriptor, 'collections.defaultdict.default_factory') self.istest(inspect.isgenerator, '(x for x in range(2))') @@ -208,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)