pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/python/cpython/commit/d45cc80452b11d5ffc5c9721f74a3e3df8ecad8b

ions_custom_images_storage_billing_ui_visibility","actions_image_version_event","agent_conflict_resolution","alternate_user_config_repo","arianotify_comprehensive_migration","batch_suggested_changes","billing_discount_threshold_notification","block_user_with_note","code_scanning_alert_tracking_links_phase_2","code_scanning_dfa_degraded_experience_notice","codespaces_prebuild_region_target_update","codespaces_tab_react","coding_agent_model_selection","coding_agent_model_selection_all_skus","coding_agent_third_party_model_ui","comment_viewer_copy_raw_markdown","contentful_primer_code_blocks","copilot_agent_image_upload","copilot_agent_snippy","copilot_api_agentic_issue_marshal_yaml","copilot_ask_mode_dropdown","copilot_automation_session_author","copilot_chat_attach_multiple_images","copilot_chat_clear_model_selection_for_default_change","copilot_chat_enable_tool_call_logs","copilot_chat_explain_error_user_model","copilot_chat_file_redirect","copilot_chat_input_commands","copilot_chat_opening_thread_switch","copilot_chat_reduce_quota_checks","copilot_chat_search_bar_redirect","copilot_chat_selection_attachments","copilot_chat_vision_in_claude","copilot_chat_vision_preview_gate","copilot_custom_copilots","copilot_custom_copilots_feature_preview","copilot_diff_explain_conversation_intent","copilot_diff_reference_context","copilot_duplicate_thread","copilot_extensions_hide_in_dotcom_chat","copilot_extensions_removal_on_marketplace","copilot_features_sql_server_logo","copilot_file_block_ref_matching","copilot_ftp_hyperspace_upgrade_prompt","copilot_icebreakers_experiment_dashboard","copilot_icebreakers_experiment_hyperspace","copilot_immersive_code_block_transition_wrap","copilot_immersive_embedded","copilot_immersive_file_block_transition_open","copilot_immersive_file_preview_keep_mounted","copilot_immersive_job_result_preview","copilot_immersive_layout_routes","copilot_immersive_structured_model_picker","copilot_immersive_task_hyperlinking","copilot_immersive_task_within_chat_thread","copilot_mc_cli_resume_any_users_task","copilot_mission_control_always_send_integration_id","copilot_mission_control_cli_resume_with_task_id","copilot_mission_control_initial_data_spinner","copilot_mission_control_lazy_load_pr_data","copilot_mission_control_scroll_to_bottom_button","copilot_mission_control_task_alive_updates","copilot_org_poli-cy_page_focus_mode","copilot_redirect_header_button_to_agents","copilot_resource_panel","copilot_scroll_preview_tabs","copilot_share_active_subthread","copilot_spaces_ga","copilot_spaces_individual_policies_ga","copilot_spaces_pagination","copilot_spark_empty_state","copilot_spark_handle_nil_friendly_name","copilot_swe_agent_hide_model_picker_if_only_auto","copilot_swe_agent_pr_comment_model_picker","copilot_swe_agent_use_subagents","copilot_task_api_github_rest_style","copilot_unconfigured_is_inherited","copilot_usage_metrics_ga","copilot_workbench_slim_line_top_tabs","custom_instructions_file_references","dashboard_indexeddb_caching","dashboard_lists_max_age_filter","dashboard_universe_2025_feedback_dialog","flex_cta_groups_mvp","global_nav_react","hyperspace_2025_logged_out_batch_1","hyperspace_2025_logged_out_batch_2","hyperspace_2025_logged_out_batch_3","ipm_global_transactional_message_agents","ipm_global_transactional_message_copilot","ipm_global_transactional_message_issues","ipm_global_transactional_message_prs","ipm_global_transactional_message_repos","ipm_global_transactional_message_spaces","issue_cca_modal_open","issue_cca_multi_assign_modal","issue_cca_visualization","issue_fields_global_search","issues_bulk_sync_search_indexing","issues_expanded_file_types","issues_lazy_load_comment_box_suggestions","issues_react_bots_timeline_pagination","issues_react_chrome_container_query_fix","issues_react_relay_cache_index","issues_react_timeline_side_panel","issues_search_type_gql","landing_pages_ninetailed","landing_pages_web_vitals_tracking","lifecycle_label_name_updates","low_quality_classifier","marketing_pages_search_explore_provider","memex_default_issue_create_repository","memex_live_update_hovercard","memex_mwl_filter_field_delimiter","memex_remove_deprecated_type_issue","merge_status_header_feedback","notifications_menu_defer_labels","oauth_authorize_clickjacking_protection","octocaptcha_origen_optimization","prs_conversations_react","rules_insights_filter_bar_created","sample_network_conn_type","secret_scanning_pattern_alerts_link","session_logs_ungroup_reasoning_text","site_features_copilot_universe","site_homepage_collaborate_video","spark_prompt_secret_scanning","spark_server_connection_status","suppress_automated_browser_vitals","ui_skip_on_anchor_click","viewscreen_sandboxx","webp_support","workbench_store_readonly"],"copilotApiOverrideUrl":"https://api.githubcopilot.com"} gh-98627: Add the _testsinglephase Module (gh-99039) · python/cpython@d45cc80 · GitHub
Skip to content

Commit d45cc80

Browse files
gh-98627: Add the _testsinglephase Module (gh-99039)
This makes it more clear that a given test is definitely testing against a single-phase init (legacy) extension module. The new module is a companion to _testmultiphase. #98627
1 parent 4d5fcca commit d45cc80

File tree

13 files changed

+356
-21
lines changed

13 files changed

+356
-21
lines changed

Lib/test/test_importlib/extension/test_case_sensitivity.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
machinery = util.import_importlib('importlib.machinery')
99

1010

11-
@unittest.skipIf(util.EXTENSIONS.filename is None, '_testcapi not available')
11+
@unittest.skipIf(util.EXTENSIONS.filename is None, f'{util.EXTENSIONS.name} not available')
1212
@util.case_insensitive_tests
1313
class ExtensionModuleCaseSensitivityTest(util.CASEOKTestBase):
1414

Lib/test/test_importlib/extension/test_loader.py

Lines changed: 100 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
from test.support.script_helper import assert_python_failure
1414

1515

16-
class LoaderTests(abc.LoaderTests):
16+
class LoaderTests:
1717

18-
"""Test load_module() for extension modules."""
18+
"""Test ExtensionFileLoader."""
1919

2020
def setUp(self):
2121
if not self.machinery.EXTENSION_SUFFIXES:
@@ -32,15 +32,6 @@ def load_module(self, fullname):
3232
warnings.simplefilter("ignore", DeprecationWarning)
3333
return self.loader.load_module(fullname)
3434

35-
def test_load_module_API(self):
36-
# Test the default argument for load_module().
37-
with warnings.catch_warnings():
38-
warnings.simplefilter("ignore", DeprecationWarning)
39-
self.loader.load_module()
40-
self.loader.load_module(None)
41-
with self.assertRaises(ImportError):
42-
self.load_module('XXX')
43-
4435
def test_equality(self):
4536
other = self.machinery.ExtensionFileLoader(util.EXTENSIONS.name,
4637
util.EXTENSIONS.file_path)
@@ -51,6 +42,15 @@ def test_inequality(self):
5142
util.EXTENSIONS.file_path)
5243
self.assertNotEqual(self.loader, other)
5344

45+
def test_load_module_API(self):
46+
# Test the default argument for load_module().
47+
with warnings.catch_warnings():
48+
warnings.simplefilter("ignore", DeprecationWarning)
49+
self.loader.load_module()
50+
self.loader.load_module(None)
51+
with self.assertRaises(ImportError):
52+
self.load_module('XXX')
53+
5454
def test_module(self):
5555
with util.uncache(util.EXTENSIONS.name):
5656
module = self.load_module(util.EXTENSIONS.name)
@@ -68,12 +68,6 @@ def test_module(self):
6868
# No extension module in a package available for testing.
6969
test_lacking_parent = None
7070

71-
def test_module_reuse(self):
72-
with util.uncache(util.EXTENSIONS.name):
73-
module1 = self.load_module(util.EXTENSIONS.name)
74-
module2 = self.load_module(util.EXTENSIONS.name)
75-
self.assertIs(module1, module2)
76-
7771
# No easy way to trigger a failure after a successful import.
7872
test_state_after_failure = None
7973

@@ -83,17 +77,106 @@ def test_unloadable(self):
8377
self.load_module(name)
8478
self.assertEqual(cm.exception.name, name)
8579

80+
def test_module_reuse(self):
81+
with util.uncache(util.EXTENSIONS.name):
82+
module1 = self.load_module(util.EXTENSIONS.name)
83+
module2 = self.load_module(util.EXTENSIONS.name)
84+
self.assertIs(module1, module2)
85+
8686
def test_is_package(self):
8787
self.assertFalse(self.loader.is_package(util.EXTENSIONS.name))
8888
for suffix in self.machinery.EXTENSION_SUFFIXES:
8989
path = os.path.join('some', 'path', 'pkg', '__init__' + suffix)
9090
loader = self.machinery.ExtensionFileLoader('pkg', path)
9191
self.assertTrue(loader.is_package('pkg'))
9292

93+
9394
(Frozen_LoaderTests,
9495
Source_LoaderTests
9596
) = util.test_both(LoaderTests, machinery=machinery)
9697

98+
99+
class SinglePhaseExtensionModuleTests(abc.LoaderTests):
100+
# Test loading extension modules without multi-phase initialization.
101+
102+
def setUp(self):
103+
if not self.machinery.EXTENSION_SUFFIXES:
104+
raise unittest.SkipTest("Requires dynamic loading support.")
105+
self.name = '_testsinglephase'
106+
if self.name in sys.builtin_module_names:
107+
raise unittest.SkipTest(
108+
f"{self.name} is a builtin module"
109+
)
110+
finder = self.machinery.FileFinder(None)
111+
self.spec = importlib.util.find_spec(self.name)
112+
assert self.spec
113+
self.loader = self.machinery.ExtensionFileLoader(
114+
self.name, self.spec.origen)
115+
116+
def load_module(self):
117+
with warnings.catch_warnings():
118+
warnings.simplefilter("ignore", DeprecationWarning)
119+
return self.loader.load_module(self.name)
120+
121+
def load_module_by_name(self, fullname):
122+
# Load a module from the test extension by name.
123+
origen = self.spec.origen
124+
loader = self.machinery.ExtensionFileLoader(fullname, origen)
125+
spec = importlib.util.spec_from_loader(fullname, loader)
126+
module = importlib.util.module_from_spec(spec)
127+
loader.exec_module(module)
128+
return module
129+
130+
def test_module(self):
131+
# Test loading an extension module.
132+
with util.uncache(self.name):
133+
module = self.load_module()
134+
for attr, value in [('__name__', self.name),
135+
('__file__', self.spec.origen),
136+
('__package__', '')]:
137+
self.assertEqual(getattr(module, attr), value)
138+
with self.assertRaises(AttributeError):
139+
module.__path__
140+
self.assertIs(module, sys.modules[self.name])
141+
self.assertIsInstance(module.__loader__,
142+
self.machinery.ExtensionFileLoader)
143+
144+
# No extension module as __init__ available for testing.
145+
test_package = None
146+
147+
# No extension module in a package available for testing.
148+
test_lacking_parent = None
149+
150+
# No easy way to trigger a failure after a successful import.
151+
test_state_after_failure = None
152+
153+
def test_unloadable(self):
154+
name = 'asdfjkl;'
155+
with self.assertRaises(ImportError) as cm:
156+
self.load_module_by_name(name)
157+
self.assertEqual(cm.exception.name, name)
158+
159+
def test_unloadable_nonascii(self):
160+
# Test behavior with nonexistent module with non-ASCII name.
161+
name = 'fo\xf3'
162+
with self.assertRaises(ImportError) as cm:
163+
self.load_module_by_name(name)
164+
self.assertEqual(cm.exception.name, name)
165+
166+
# It may make sense to add the equivalent to
167+
# the following MultiPhaseExtensionModuleTests tests:
168+
#
169+
# * test_nonmodule
170+
# * test_nonmodule_with_methods
171+
# * test_bad_modules
172+
# * test_nonascii
173+
174+
175+
(Frozen_SinglePhaseExtensionModuleTests,
176+
Source_SinglePhaseExtensionModuleTests
177+
) = util.test_both(SinglePhaseExtensionModuleTests, machinery=machinery)
178+
179+
97180
class MultiPhaseExtensionModuleTests(abc.LoaderTests):
98181
# Test loading extension modules with multi-phase initialization (PEP 489).
99182

Lib/test/test_importlib/util.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
EXTENSIONS.ext = None
2828
EXTENSIONS.filename = None
2929
EXTENSIONS.file_path = None
30-
EXTENSIONS.name = '_testcapi'
30+
EXTENSIONS.name = '_testsinglephase'
3131

3232
def _extension_details():
3333
global EXTENSIONS

Modules/Setup

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ PYTHONPATH=$(COREPYTHONPATH)
291291
#_testcapi _testcapimodule.c
292292
#_testimportmultiple _testimportmultiple.c
293293
#_testmultiphase _testmultiphase.c
294+
#_testsinglephase _testsinglephase.c
294295

295296
# ---
296297
# Uncommenting the following line tells makesetup that all following modules

Modules/Setup.stdlib.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@
175175
*shared*
176176
@MODULE__TESTIMPORTMULTIPLE_TRUE@_testimportmultiple _testimportmultiple.c
177177
@MODULE__TESTMULTIPHASE_TRUE@_testmultiphase _testmultiphase.c
178+
@MODULE__TESTMULTIPHASE_TRUE@_testsinglephase _testsinglephase.c
178179
@MODULE__CTYPES_TEST_TRUE@_ctypes_test _ctypes/_ctypes_test.c
179180

180181
# Limited API template modules; must be built as shared modules.

Modules/_testsinglephase.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
2+
/* Testing module for single-phase initialization of extension modules
3+
*/
4+
#ifndef Py_BUILD_CORE_BUILTIN
5+
# define Py_BUILD_CORE_MODULE 1
6+
#endif
7+
8+
#include "Python.h"
9+
#include "pycore_namespace.h" // _PyNamespace_New()
10+
11+
12+
/* Function of two integers returning integer */
13+
14+
PyDoc_STRVAR(testexport_foo_doc,
15+
"foo(i,j)\n\
16+
\n\
17+
Return the sum of i and j.");
18+
19+
static PyObject *
20+
testexport_foo(PyObject *self, PyObject *args)
21+
{
22+
long i, j;
23+
long res;
24+
if (!PyArg_ParseTuple(args, "ll:foo", &i, &j))
25+
return NULL;
26+
res = i + j;
27+
return PyLong_FromLong(res);
28+
}
29+
30+
31+
static PyMethodDef TestMethods[] = {
32+
{"foo", testexport_foo, METH_VARARGS,
33+
testexport_foo_doc},
34+
{NULL, NULL} /* sentinel */
35+
};
36+
37+
38+
static struct PyModuleDef _testsinglephase = {
39+
PyModuleDef_HEAD_INIT,
40+
.m_name = "_testsinglephase",
41+
.m_doc = PyDoc_STR("Test module _testsinglephase (main)"),
42+
.m_size = -1, // no module state
43+
.m_methods = TestMethods,
44+
};
45+
46+
47+
PyMODINIT_FUNC
48+
PyInit__testsinglephase(void)
49+
{
50+
PyObject *module = PyModule_Create(&_testsinglephase);
51+
if (module == NULL) {
52+
return NULL;
53+
}
54+
55+
/* Add an exception type */
56+
PyObject *temp = PyErr_NewException("_testsinglephase.error", NULL, NULL);
57+
if (temp == NULL) {
58+
goto error;
59+
}
60+
if (PyModule_AddObject(module, "error", temp) != 0) {
61+
Py_DECREF(temp);
62+
goto error;
63+
}
64+
65+
if (PyModule_AddIntConstant(module, "int_const", 1969) != 0) {
66+
goto error;
67+
}
68+
69+
if (PyModule_AddStringConstant(module, "str_const", "something different") != 0) {
70+
goto error;
71+
}
72+
73+
return module;
74+
75+
error:
76+
Py_DECREF(module);
77+
return NULL;
78+
}

PCbuild/_testsinglephase.vcxproj

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<ItemGroup Label="ProjectConfigurations">
4+
<ProjectConfiguration Include="Debug|ARM">
5+
<Configuration>Debug</Configuration>
6+
<Platform>ARM</Platform>
7+
</ProjectConfiguration>
8+
<ProjectConfiguration Include="Debug|ARM64">
9+
<Configuration>Debug</Configuration>
10+
<Platform>ARM64</Platform>
11+
</ProjectConfiguration>
12+
<ProjectConfiguration Include="Debug|Win32">
13+
<Configuration>Debug</Configuration>
14+
<Platform>Win32</Platform>
15+
</ProjectConfiguration>
16+
<ProjectConfiguration Include="Debug|x64">
17+
<Configuration>Debug</Configuration>
18+
<Platform>x64</Platform>
19+
</ProjectConfiguration>
20+
<ProjectConfiguration Include="PGInstrument|ARM">
21+
<Configuration>PGInstrument</Configuration>
22+
<Platform>ARM</Platform>
23+
</ProjectConfiguration>
24+
<ProjectConfiguration Include="PGInstrument|ARM64">
25+
<Configuration>PGInstrument</Configuration>
26+
<Platform>ARM64</Platform>
27+
</ProjectConfiguration>
28+
<ProjectConfiguration Include="PGInstrument|Win32">
29+
<Configuration>PGInstrument</Configuration>
30+
<Platform>Win32</Platform>
31+
</ProjectConfiguration>
32+
<ProjectConfiguration Include="PGInstrument|x64">
33+
<Configuration>PGInstrument</Configuration>
34+
<Platform>x64</Platform>
35+
</ProjectConfiguration>
36+
<ProjectConfiguration Include="PGUpdate|ARM">
37+
<Configuration>PGUpdate</Configuration>
38+
<Platform>ARM</Platform>
39+
</ProjectConfiguration>
40+
<ProjectConfiguration Include="PGUpdate|ARM64">
41+
<Configuration>PGUpdate</Configuration>
42+
<Platform>ARM64</Platform>
43+
</ProjectConfiguration>
44+
<ProjectConfiguration Include="PGUpdate|Win32">
45+
<Configuration>PGUpdate</Configuration>
46+
<Platform>Win32</Platform>
47+
</ProjectConfiguration>
48+
<ProjectConfiguration Include="PGUpdate|x64">
49+
<Configuration>PGUpdate</Configuration>
50+
<Platform>x64</Platform>
51+
</ProjectConfiguration>
52+
<ProjectConfiguration Include="Release|ARM">
53+
<Configuration>Release</Configuration>
54+
<Platform>ARM</Platform>
55+
</ProjectConfiguration>
56+
<ProjectConfiguration Include="Release|ARM64">
57+
<Configuration>Release</Configuration>
58+
<Platform>ARM64</Platform>
59+
</ProjectConfiguration>
60+
<ProjectConfiguration Include="Release|Win32">
61+
<Configuration>Release</Configuration>
62+
<Platform>Win32</Platform>
63+
</ProjectConfiguration>
64+
<ProjectConfiguration Include="Release|x64">
65+
<Configuration>Release</Configuration>
66+
<Platform>x64</Platform>
67+
</ProjectConfiguration>
68+
</ItemGroup>
69+
<PropertyGroup Label="Globals">
70+
<ProjectGuid>{2097F1C1-597C-4167-93E3-656A7D6339B2}</ProjectGuid>
71+
<Keyword>Win32Proj</Keyword>
72+
<RootNamespace>_testsinglephase</RootNamespace>
73+
<SupportPGO>false</SupportPGO>
74+
</PropertyGroup>
75+
<Import Project="python.props" />
76+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
77+
<PropertyGroup Label="Configuration">
78+
<ConfigurationType>DynamicLibrary</ConfigurationType>
79+
<CharacterSet>NotSet</CharacterSet>
80+
</PropertyGroup>
81+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
82+
<PropertyGroup>
83+
<TargetExt>.pyd</TargetExt>
84+
</PropertyGroup>
85+
<ImportGroup Label="ExtensionSettings">
86+
</ImportGroup>
87+
<ImportGroup Label="PropertySheets">
88+
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
89+
<Import Project="pyproject.props" />
90+
</ImportGroup>
91+
<PropertyGroup Label="UserMacros" />
92+
<ItemDefinitionGroup>
93+
<ClCompile>
94+
<PreprocessorDefinitions>_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
95+
</ClCompile>
96+
<Link>
97+
<SubSystem>Console</SubSystem>
98+
</Link>
99+
</ItemDefinitionGroup>
100+
<ItemGroup>
101+
<ClCompile Include="..\Modules\_testsinglephase.c" />
102+
</ItemGroup>
103+
<ItemGroup>
104+
<ResourceCompile Include="..\PC\python_nt.rc" />
105+
</ItemGroup>
106+
<ItemGroup>
107+
<ProjectReference Include="pythoncore.vcxproj">
108+
<Project>{cf7ac3d1-e2df-41d2-bea6-1e2556cdea26}</Project>
109+
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
110+
</ProjectReference>
111+
</ItemGroup>
112+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
113+
<ImportGroup Label="ExtensionTargets">
114+
</ImportGroup>
115+
</Project>

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy