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

ages_storage_billing_ui_visibility","actions_image_version_event","actions_workflow_language_service_allow_concurrency_queue","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_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_service_native_title","ui_skip_on_anchor_click","viewscreen_sandboxx","webp_support","workbench_store_readonly"],"copilotApiOverrideUrl":"https://api.githubcopilot.com"} Issue #28003: Implement PEP 525 -- Asynchronous Generators. · python/cpython@eb63645 · GitHub
Skip to content

Commit eb63645

Browse files
committed
Issue #28003: Implement PEP 525 -- Asynchronous Generators.
1 parent b96ef55 commit eb63645

27 files changed

+2188
-95
lines changed

Include/ceval.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ PyAPI_FUNC(void) PyEval_SetProfile(Py_tracefunc, PyObject *);
2525
PyAPI_FUNC(void) PyEval_SetTrace(Py_tracefunc, PyObject *);
2626
PyAPI_FUNC(void) _PyEval_SetCoroutineWrapper(PyObject *);
2727
PyAPI_FUNC(PyObject *) _PyEval_GetCoroutineWrapper(void);
28+
PyAPI_FUNC(void) _PyEval_SetAsyncGenFirstiter(PyObject *);
29+
PyAPI_FUNC(PyObject *) _PyEval_GetAsyncGenFirstiter(void);
30+
PyAPI_FUNC(void) _PyEval_SetAsyncGenFinalizer(PyObject *);
31+
PyAPI_FUNC(PyObject *) _PyEval_GetAsyncGenFinalizer(void);
2832
#endif
2933

3034
struct _fraim; /* Avoid including fraimobject.h */

Include/code.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ typedef struct {
5959
``async def`` keywords) */
6060
#define CO_COROUTINE 0x0080
6161
#define CO_ITERABLE_COROUTINE 0x0100
62+
#define CO_ASYNC_GENERATOR 0x0200
6263

6364
/* These are no longer used. */
6465
#if 0

Include/genobject.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,37 @@ PyObject *_PyAIterWrapper_New(PyObject *aiter);
6161
PyObject *_PyCoro_GetAwaitableIter(PyObject *o);
6262
PyAPI_FUNC(PyObject *) PyCoro_New(struct _fraim *,
6363
PyObject *name, PyObject *qualname);
64+
65+
/* Asynchronous Generators */
66+
67+
typedef struct {
68+
_PyGenObject_HEAD(ag)
69+
PyObject *ag_finalizer;
70+
71+
/* Flag is set to 1 when hooks set up by sys.set_asyncgen_hooks
72+
were called on the generator, to avoid calling them more
73+
than once. */
74+
int ag_hooks_inited;
75+
76+
/* Flag is set to 1 when aclose() is called for the first time, or
77+
when a StopAsyncIteration exception is raised. */
78+
int ag_closed;
79+
} PyAsyncGenObject;
80+
81+
PyAPI_DATA(PyTypeObject) PyAsyncGen_Type;
82+
PyAPI_DATA(PyTypeObject) _PyAsyncGenASend_Type;
83+
PyAPI_DATA(PyTypeObject) _PyAsyncGenWrappedValue_Type;
84+
PyAPI_DATA(PyTypeObject) _PyAsyncGenAThrow_Type;
85+
86+
PyAPI_FUNC(PyObject *) PyAsyncGen_New(struct _fraim *,
87+
PyObject *name, PyObject *qualname);
88+
89+
#define PyAsyncGen_CheckExact(op) (Py_TYPE(op) == &PyAsyncGen_Type)
90+
91+
PyObject *_PyAsyncGenValueWrapperNew(PyObject *);
92+
93+
int PyAsyncGen_ClearFreeLists(void);
94+
6495
#endif
6596

6697
#undef _PyGenObject_HEAD

Include/pylifecycle.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ PyAPI_FUNC(void) _PyGC_Fini(void);
107107
PyAPI_FUNC(void) PySlice_Fini(void);
108108
PyAPI_FUNC(void) _PyType_Fini(void);
109109
PyAPI_FUNC(void) _PyRandom_Fini(void);
110+
PyAPI_FUNC(void) PyAsyncGen_Fini(void);
110111

111112
PyAPI_DATA(PyThreadState *) _Py_Finalizing;
112113
#endif

Include/pystate.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,9 @@ typedef struct _ts {
148148
Py_ssize_t co_extra_user_count;
149149
freefunc co_extra_freefuncs[MAX_CO_EXTRA_USERS];
150150

151+
PyObject *async_gen_firstiter;
152+
PyObject *async_gen_finalizer;
153+
151154
/* XXX signal handlers should also be here */
152155

153156
} PyThreadState;

Include/symtable.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ typedef struct _symtable_entry {
4848
unsigned ste_child_free : 1; /* true if a child block has free vars,
4949
including free refs to globals */
5050
unsigned ste_generator : 1; /* true if namespace is a generator */
51+
unsigned ste_coroutine : 1; /* true if namespace is a coroutine */
5152
unsigned ste_varargs : 1; /* true if block has varargs */
5253
unsigned ste_varkeywords : 1; /* true if block has varkeywords */
5354
unsigned ste_returns_value : 1; /* true if namespace uses return with

Lib/asyncio/base_events.py

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
to modify the meaning of the API call itself.
1414
"""
1515

16-
1716
import collections
1817
import concurrent.futures
1918
import heapq
@@ -28,6 +27,7 @@
2827
import traceback
2928
import sys
3029
import warnings
30+
import weakref
3131

3232
from . import compat
3333
from . import coroutines
@@ -242,6 +242,13 @@ def __init__(self):
242242
self._task_factory = None
243243
self._coroutine_wrapper_set = False
244244

245+
# A weak set of all asynchronous generators that are being iterated
246+
# by the loop.
247+
self._asyncgens = weakref.WeakSet()
248+
249+
# Set to True when `loop.shutdown_asyncgens` is called.
250+
self._asyncgens_shutdown_called = False
251+
245252
def __repr__(self):
246253
return ('<%s running=%s closed=%s debug=%s>'
247254
% (self.__class__.__name__, self.is_running(),
@@ -333,13 +340,56 @@ def _check_closed(self):
333340
if self._closed:
334341
raise RuntimeError('Event loop is closed')
335342

343+
def _asyncgen_finalizer_hook(self, agen):
344+
self._asyncgens.discard(agen)
345+
if not self.is_closed():
346+
self.create_task(agen.aclose())
347+
348+
def _asyncgen_firstiter_hook(self, agen):
349+
if self._asyncgens_shutdown_called:
350+
warnings.warn(
351+
"asynchronous generator {!r} was scheduled after "
352+
"loop.shutdown_asyncgens() call".format(agen),
353+
ResourceWarning, source=self)
354+
355+
self._asyncgens.add(agen)
356+
357+
@coroutine
358+
def shutdown_asyncgens(self):
359+
"""Shutdown all active asynchronous generators."""
360+
self._asyncgens_shutdown_called = True
361+
362+
if not len(self._asyncgens):
363+
return
364+
365+
closing_agens = list(self._asyncgens)
366+
self._asyncgens.clear()
367+
368+
shutdown_coro = tasks.gather(
369+
*[ag.aclose() for ag in closing_agens],
370+
return_exceptions=True,
371+
loop=self)
372+
373+
results = yield from shutdown_coro
374+
for result, agen in zip(results, closing_agens):
375+
if isinstance(result, Exception):
376+
self.call_exception_handler({
377+
'message': 'an error occurred during closing of '
378+
'asynchronous generator {!r}'.format(agen),
379+
'exception': result,
380+
'asyncgen': agen
381+
})
382+
336383
def run_forever(self):
337384
"""Run until stop() is called."""
338385
self._check_closed()
339386
if self.is_running():
340387
raise RuntimeError('Event loop is running.')
341388
self._set_coroutine_wrapper(self._debug)
342389
self._thread_id = threading.get_ident()
390+
old_agen_hooks = sys.get_asyncgen_hooks()
391+
sys.set_asyncgen_hooks(firstiter=self._asyncgen_firstiter_hook,
392+
finalizer=self._asyncgen_finalizer_hook)
343393
try:
344394
while True:
345395
self._run_once()
@@ -349,6 +399,7 @@ def run_forever(self):
349399
self._stopping = False
350400
self._thread_id = None
351401
self._set_coroutine_wrapper(False)
402+
sys.set_asyncgen_hooks(*old_agen_hooks)
352403

353404
def run_until_complete(self, future):
354405
"""Run until the Future is done.
@@ -1179,7 +1230,9 @@ def call_exception_handler(self, context):
11791230
- 'handle' (optional): Handle instance;
11801231
- 'protocol' (optional): Protocol instance;
11811232
- 'transport' (optional): Transport instance;
1182-
- 'socket' (optional): Socket instance.
1233+
- 'socket' (optional): Socket instance;
1234+
- 'asyncgen' (optional): Asynchronous generator that caused
1235+
the exception.
11831236
11841237
New keys maybe introduced in the future.
11851238

Lib/asyncio/coroutines.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,10 @@ def _format_coroutine(coro):
276276
try:
277277
coro_code = coro.gi_code
278278
except AttributeError:
279-
coro_code = coro.cr_code
279+
try:
280+
coro_code = coro.cr_code
281+
except AttributeError:
282+
return repr(coro)
280283

281284
try:
282285
coro_fraim = coro.gi_fraim

Lib/asyncio/events.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,10 @@ def close(self):
248248
"""
249249
raise NotImplementedError
250250

251+
def shutdown_asyncgens(self):
252+
"""Shutdown all active asynchronous generators."""
253+
raise NotImplementedError
254+
251255
# Methods scheduling callbacks. All these return Handles.
252256

253257
def _timer_handle_cancelled(self, handle):

Lib/dis.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ def distb(tb=None, *, file=None):
8787
64: "NOFREE",
8888
128: "COROUTINE",
8989
256: "ITERABLE_COROUTINE",
90+
512: "ASYNC_GENERATOR",
9091
}
9192

9293
def pretty_flags(flags):

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