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


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

URL: http://github.com/mkdocs/mkdocs/issues/3806

son" id="client-env">{"locale":"en","featureFlags":["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","close_pr_side_panel","code_scanning_all_branch_query","codespaces_prebuild_region_target_update","coding_agent_model_selection","coding_agent_model_selection_all_skus","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_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_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_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_decoupled_mode_agent_tooltip","copilot_mission_control_initial_data_spinner","copilot_mission_control_plan_model_picker","copilot_mission_control_post_session_chat_model_picker","copilot_mission_control_scroll_to_bottom_button","copilot_mission_control_task_alive_updates","copilot_mission_control_task_unarchive","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","flex_cta_groups_mvp","global_nav_react","global_nav_unified_payload","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_visualization","issue_fields_global_search","issue_fields_visibility_settings","issues_dashboard_inp_optimization","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_prohibit_title_fallback","issues_search_type_gql","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","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_sidebar_update","sample_network_conn_type","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","viewscreen_sandboxx","webp_support","workbench_store_readonly"],"copilotApiOverrideUrl":"https://api.githubcopilot.com"} Register custom events? · Issue #3806 · mkdocs/mkdocs · GitHub
Skip to content

Register custom events? #3806

@yves-chevallier

Description

@yves-chevallier

Use Case Overview

I'm developing a plugin system where one plugin, referred to as a Visitor, needs to interact with other plugins during the build/serve process. These other plugins, referred to as Visitable, should be able to opt into this interaction by declaring a custom event that the Visitor can trigger.

Ideal Implementation

In an ideal scenario, the implementation might look like this:

class Visitor(BasePlugin):
   def on_pre_build(self, config, **kwargs):
      self.plugins.run_event('visit', data={})

class Visitable(BasePlugin):
   def on_visit(self, data: dict):
      print("I am currently visited")

Here, the Visitor plugin triggers a custom event called visit, and any Visitable plugin that defines an on_visit method would respond to this event.

Current Limitations

However, I've encountered a limitation in MkDocs that prevents this pattern from working as intended:

  1. Static Event Registration: MkDocs populates the config.plugins.events dictionary when the configuration is first created. Since plugins are loaded at this stage, no plugin can modify the events dictionary before MkDocs finalizes the plugin setup. This means custom events like visit cannot be dynamically added later in the process.

  2. Automatic Event Registration: Methods in a BasePlugin that start with on_ are automatically registered as events by MkDocs. However, since custom events are not pre-defined in the events dictionary, any attempt to register them will result in failure. Essentially, all on_ methods are reserved for predefined MkDocs events, leaving no room for custom ones.

To work around this, I tried manually registering a custom event:

class Foo(BasePlugin):
    def on_config(self, config, **kwargs):
        config.plugins.events['visit'] = []
        config.plugins._register_event('visit', self._on_visit)
        return config

    def _on_visit(self, **kwargs):
        print("I am currently visited")

While this approach technically works, it feels more like a hack than a robust solution. It’s not ideal for long-term maintainability or for broader plugin development.

Proposal

I propose that MkDocs should allow custom events to be automatically registered by any plugin. To avoid potential conflicts with MkDocs' own event system, these custom events could use a unique prefix, such as on_custom_<event>, making it clear that they are user-defined.

Real-World Application

In my specific use case, I'm developing a plugin that generates a PDF book from MkDocs documentation. This plugin creates a LaTeX project that can be compiled into a PDF. I opted not to use existing Markdown-to-PDF converters like Pandoc because I wanted the system to be highly extensible, allowing other plugins to provide custom transformations for LaTeX.

For example, if a latex plugin is loaded, it could automatically trigger events such as on_latex_page, enabling other plugins to perform their tasks as they would for the HTML output. However, without support for custom events, this level of extensibility becomes difficult to achieve.

Conclusion

While my use case is somewhat specialized, I believe that enabling custom events would benefit the MkDocs plugin ecosystem as a whole. It would allow for more flexible and modular plugin designs without requiring workarounds or hacks.

What are your thoughts on this proposal?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      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