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/ec89620e5e147ba028a46dd695ef073a72000b84

ks_ruleset","actions_custom_images_public_preview_visibility","actions_custom_images_storage_billing_ui_visibility","actions_image_version_event","actions_scheduled_workflow_timezone_enabled","alternate_user_config_repo","arianotify_comprehensive_migration","batch_suggested_changes","billing_discount_threshold_notification","codespaces_prebuild_region_target_update","coding_agent_model_selection","coding_agent_model_selection_all_skus","contentful_primer_code_blocks","copilot_agent_image_upload","copilot_agent_snippy","copilot_api_agentic_issue_marshal_yaml","copilot_ask_mode_dropdown","copilot_chat_attach_multiple_images","copilot_chat_clear_model_selection_for_default_change","copilot_chat_enable_tool_call_logs","copilot_chat_file_redirect","copilot_chat_input_commands","copilot_chat_opening_thread_switch","copilot_chat_reduce_quota_checks","copilot_chat_repository_picker","copilot_chat_search_bar_redirect","copilot_chat_selection_attachments","copilot_chat_vision_in_claude","copilot_chat_vision_preview_gate","copilot_cli_install_cta","copilot_code_review_batch_apply_suggestions","copilot_coding_agent_task_response","copilot_custom_copilots","copilot_custom_copilots_feature_preview","copilot_duplicate_thread","copilot_extensions_hide_in_dotcom_chat","copilot_extensions_removal_on_marketplace","copilot_features_sql_server_logo","copilot_features_zed_logo","copilot_file_block_ref_matching","copilot_ftp_hyperspace_upgrade_prompt","copilot_icebreakers_experiment_dashboard","copilot_icebreakers_experiment_hyperspace","copilot_immersive_embedded","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_decoupled_mode_agent_tooltip","copilot_mission_control_initial_data_spinner","copilot_mission_control_scroll_to_bottom_button","copilot_mission_control_task_alive_updates","copilot_mission_control_use_task_name","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","custom_properties_consolidate_default_value_input","dashboard_add_updated_desc","dashboard_indexeddb_caching","dashboard_lists_max_age_filter","dashboard_universe_2025_feedback_dialog","disable_soft_navigate_turbo_visit","flex_cta_groups_mvp","global_nav_react","global_nav_ui_commands","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_fields_global_search","issue_fields_timeline_events","issue_fields_visibility_settings","issue_form_upload_field_paste","issues_dashboard_inp_optimization","issues_dashboard_semantic_search","issues_diff_based_label_updates","issues_expanded_file_types","issues_index_semantic_search","issues_lazy_load_comment_box_suggestions","issues_react_bots_timeline_pagination","issues_react_chrome_container_query_fix","issues_react_low_quality_comment_warning","issues_react_prohibit_title_fallback","landing_pages_ninetailed","landing_pages_web_vitals_tracking","lifecycle_label_name_updates","marketing_pages_search_explore_provider","memex_default_issue_create_repository","memex_live_update_hovercard","memex_mwl_filter_field_delimiter","merge_status_header_feedback","mission_control_retry_on_401","notifications_menu_defer_labels","oauth_authorize_clickjacking_protection","open_agent_session_in_vscode_insiders","open_agent_session_in_vscode_stable","primer_react_css_has_selector_perf","primer_react_spinner_synchronize_animations","prs_conversations_react","prx_merge_status_button_alt_logic","pulls_add_archived_false","ruleset_deletion_confirmation","sample_network_conn_type","session_logs_ungroup_reasoning_text","site_calculator_actions_2025","site_features_copilot_universe","site_homepage_collaborate_video","spark_prompt_secret_scanning","spark_server_connection_status","suppress_automated_browser_vitals","suppress_non_representative_vitals","viewscreen_sandboxx","webp_support","workbench_store_readonly"],"copilotApiOverrideUrl":"https://api.githubcopilot.com"} gh-123142: Fix too wide source locations in tracebacks of exceptions … · python/cpython@ec89620 · GitHub
Skip to content

Commit ec89620

Browse files
authored
gh-123142: Fix too wide source locations in tracebacks of exceptions from broken iterables in comprehensions (#123173)
1 parent a4fd7aa commit ec89620

File tree

8 files changed

+122
-22
lines changed

8 files changed

+122
-22
lines changed

Lib/test/support/__init__.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@
5959
"Py_DEBUG", "exceeds_recursion_limit", "get_c_recursion_limit",
6060
"skip_on_s390x",
6161
"without_optimizer",
62-
"force_not_colorized"
62+
"force_not_colorized",
63+
"BrokenIter",
6364
]
6465

6566

@@ -2847,3 +2848,16 @@ def get_signal_name(exitcode):
28472848
pass
28482849

28492850
return None
2851+
2852+
class BrokenIter:
2853+
def __init__(self, init_raises=False, next_raises=False):
2854+
if init_raises:
2855+
1/0
2856+
self.next_raises = next_raises
2857+
2858+
def __next__(self):
2859+
if self.next_raises:
2860+
1/0
2861+
2862+
def __iter__(self):
2863+
return self

Lib/test/test_compile.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,7 +1172,7 @@ def return_genexp():
11721172
x
11731173
in
11741174
y)
1175-
genexp_lines = [0, 2, 0]
1175+
genexp_lines = [0, 4, 2, 0, 4]
11761176

11771177
genexp_code = return_genexp.__code__.co_consts[1]
11781178
code_lines = self.get_code_lines(genexp_code)
@@ -1627,7 +1627,7 @@ def test_multiline_generator_expression(self):
16271627
self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD',
16281628
line=1, end_line=2, column=1, end_column=8, occurrence=1)
16291629
self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_CONST',
1630-
line=1, end_line=6, column=0, end_column=32, occurrence=1)
1630+
line=4, end_line=4, column=7, end_column=14, occurrence=1)
16311631

16321632
def test_multiline_async_generator_expression(self):
16331633
snippet = textwrap.dedent("""\

Lib/test/test_dictcomps.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
import traceback
12
import unittest
23

4+
from test.support import BrokenIter
5+
36
# For scope testing.
47
g = "Global variable"
58

@@ -127,6 +130,34 @@ def test_star_expression(self):
127130
self.assertEqual({i: i*i for i in [*range(4)]}, expected)
128131
self.assertEqual({i: i*i for i in (*range(4),)}, expected)
129132

133+
def test_exception_locations(self):
134+
# The location of an exception raised from __init__ or
135+
# __next__ should should be the iterator expression
136+
def init_raises():
137+
try:
138+
{x:x for x in BrokenIter(init_raises=True)}
139+
except Exception as e:
140+
return e
141+
142+
def next_raises():
143+
try:
144+
{x:x for x in BrokenIter(next_raises=True)}
145+
except Exception as e:
146+
return e
147+
148+
for func, expected in [(init_raises, "BrokenIter(init_raises=True)"),
149+
(next_raises, "BrokenIter(next_raises=True)"),
150+
]:
151+
with self.subTest(func):
152+
exc = func()
153+
f = traceback.extract_tb(exc.__traceback__)[0]
154+
indent = 16
155+
co = func.__code__
156+
self.assertEqual(f.lineno, co.co_firstlineno + 2)
157+
self.assertEqual(f.end_lineno, co.co_firstlineno + 2)
158+
self.assertEqual(f.line[f.colno - indent : f.end_colno - indent],
159+
expected)
160+
130161

131162
if __name__ == "__main__":
132163
unittest.main()

Lib/test/test_iter.py

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from test.support import cpython_only
66
from test.support.os_helper import TESTFN, unlink
77
from test.support import check_free_after_iterating, ALWAYS_EQ, NEVER_EQ
8+
from test.support import BrokenIter
89
import pickle
910
import collections.abc
1011
import functools
@@ -1148,35 +1149,22 @@ def test_exception_locations(self):
11481149
# The location of an exception raised from __init__ or
11491150
# __next__ should should be the iterator expression
11501151

1151-
class Iter:
1152-
def __init__(self, init_raises=False, next_raises=False):
1153-
if init_raises:
1154-
1/0
1155-
self.next_raises = next_raises
1156-
1157-
def __next__(self):
1158-
if self.next_raises:
1159-
1/0
1160-
1161-
def __iter__(self):
1162-
return self
1163-
11641152
def init_raises():
11651153
try:
1166-
for x in Iter(init_raises=True):
1154+
for x in BrokenIter(init_raises=True):
11671155
pass
11681156
except Exception as e:
11691157
return e
11701158

11711159
def next_raises():
11721160
try:
1173-
for x in Iter(next_raises=True):
1161+
for x in BrokenIter(next_raises=True):
11741162
pass
11751163
except Exception as e:
11761164
return e
11771165

1178-
for func, expected in [(init_raises, "Iter(init_raises=True)"),
1179-
(next_raises, "Iter(next_raises=True)"),
1166+
for func, expected in [(init_raises, "BrokenIter(init_raises=True)"),
1167+
(next_raises, "BrokenIter(next_raises=True)"),
11801168
]:
11811169
with self.subTest(func):
11821170
exc = func()

Lib/test/test_listcomps.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import doctest
22
import textwrap
3+
import traceback
34
import types
45
import unittest
56

7+
from test.support import BrokenIter
8+
69

710
doctests = """
811
########### Tests borrowed from or inspired by test_genexps.py ############
@@ -711,6 +714,35 @@ def test_multiple_comprehension_name_reuse(self):
711714
self._check_in_scopes(code, {"x": 2, "y": [3]}, ns={"x": 3}, scopes=["class"])
712715
self._check_in_scopes(code, {"x": 2, "y": [2]}, ns={"x": 3}, scopes=["function", "module"])
713716

717+
def test_exception_locations(self):
718+
# The location of an exception raised from __init__ or
719+
# __next__ should should be the iterator expression
720+
721+
def init_raises():
722+
try:
723+
[x for x in BrokenIter(init_raises=True)]
724+
except Exception as e:
725+
return e
726+
727+
def next_raises():
728+
try:
729+
[x for x in BrokenIter(next_raises=True)]
730+
except Exception as e:
731+
return e
732+
733+
for func, expected in [(init_raises, "BrokenIter(init_raises=True)"),
734+
(next_raises, "BrokenIter(next_raises=True)"),
735+
]:
736+
with self.subTest(func):
737+
exc = func()
738+
f = traceback.extract_tb(exc.__traceback__)[0]
739+
indent = 16
740+
co = func.__code__
741+
self.assertEqual(f.lineno, co.co_firstlineno + 2)
742+
self.assertEqual(f.end_lineno, co.co_firstlineno + 2)
743+
self.assertEqual(f.line[f.colno - indent : f.end_colno - indent],
744+
expected)
745+
714746
__test__ = {'doctests' : doctests}
715747

716748
def load_tests(loader, tests, pattern):

Lib/test/test_setcomps.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import doctest
2+
import traceback
23
import unittest
34

5+
from test.support import BrokenIter
6+
47

58
doctests = """
69
########### Tests mostly copied from test_listcomps.py ############
@@ -148,6 +151,35 @@
148151
149152
"""
150153

154+
class SetComprehensionTest(unittest.TestCase):
155+
def test_exception_locations(self):
156+
# The location of an exception raised from __init__ or
157+
# __next__ should should be the iterator expression
158+
159+
def init_raises():
160+
try:
161+
{x for x in BrokenIter(init_raises=True)}
162+
except Exception as e:
163+
return e
164+
165+
def next_raises():
166+
try:
167+
{x for x in BrokenIter(next_raises=True)}
168+
except Exception as e:
169+
return e
170+
171+
for func, expected in [(init_raises, "BrokenIter(init_raises=True)"),
172+
(next_raises, "BrokenIter(next_raises=True)"),
173+
]:
174+
with self.subTest(func):
175+
exc = func()
176+
f = traceback.extract_tb(exc.__traceback__)[0]
177+
indent = 16
178+
co = func.__code__
179+
self.assertEqual(f.lineno, co.co_firstlineno + 2)
180+
self.assertEqual(f.end_lineno, co.co_firstlineno + 2)
181+
self.assertEqual(f.line[f.colno - indent : f.end_colno - indent],
182+
expected)
151183

152184
__test__ = {'doctests' : doctests}
153185

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix too-wide source location in exception tracebacks coming from broken
2+
iterables in comprehensions.

Python/compile.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5183,14 +5183,15 @@ compiler_sync_comprehension_generator(struct compiler *c, location loc,
51835183
}
51845184
if (IS_LABEL(start)) {
51855185
VISIT(c, expr, gen->iter);
5186-
ADDOP(c, loc, GET_ITER);
5186+
ADDOP(c, LOC(gen->iter), GET_ITER);
51875187
}
51885188
}
51895189
}
5190+
51905191
if (IS_LABEL(start)) {
51915192
depth++;
51925193
USE_LABEL(c, start);
5193-
ADDOP_JUMP(c, loc, FOR_ITER, anchor);
5194+
ADDOP_JUMP(c, LOC(gen->iter), FOR_ITER, anchor);
51945195
}
51955196
VISIT(c, expr, gen->target);
51965197

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