如何在Pyramid可调用配置中用config.add_settings设置pyramid.includes?
Let me break down what's going on here and how to fix it—this is a gotcha that trips up a lot of Pyramid developers when working with shared config functions.
The Problem Recap
You're working with a default Pyramid app generated via Cookiecutter, where the INI config uses pyramid.includes = pyramid_debugtoolbar to load the debug toolbar automatically. When trying to replicate this in Python code (specifically in a shared common_config() function used across multiple apps), you noticed:
- Adding
config.include('pyramid_debugtoolbar')directly works, but just usingconfig.add_settings({'pyramid.includes': 'pyramid_debugtoolbar'})doesn't. - Updating the
settingsdictionary before initializing theConfiguratorworks, but callingconfig.add_settings()after instantiation does nothing.
Why This Happens
Pyramid processes the pyramid.includes setting early in the Configurator lifecycle—immediately when you create the Configurator instance with your initial settings. It parses that value, splits the comma-separated includes, and runs config.include() for each one right away.
When you call config.add_settings() later (like inside your common_config() function), you're adding the setting to the config's state, but Pyramid has already passed the phase where it automatically processes pyramid.includes. There's no re-scan for this setting after initialization, so your new includes never get loaded.
The Solution
To replicate the INI-style behavior in your shared common_config() function, you need to do two things:
- Update the
pyramid.includessetting in the config's settings (so other parts of your app see the correct value if they read it later). - Manually call
config.include()for each entry you want to add—since Pyramid won't do this automatically after initialization.
Here's a clean way to implement this:
def common_config(config): # Define the includes you want to add across all apps desired_includes = ['pyramid_debugtoolbar'] # Get existing includes (if any) from settings current_includes = config.settings.get('pyramid.includes', '') # Combine existing and new includes, avoiding duplicates and extra commas updated_includes_list = [inc.strip() for inc in current_includes.split(',') if inc.strip()] updated_includes_list.extend([inc for inc in desired_includes if inc not in updated_includes_list]) updated_includes = ','.join(updated_includes_list) # Update the settings to reflect the combined includes config.add_settings({'pyramid.includes': updated_includes}) # Manually include each module to match INI's automatic behavior for include in desired_includes: config.include(include)
Why This Works
- We first merge any existing
pyramid.includesvalues with our new ones (so we don't overwrite settings from other sources, like the INI file). - Updating
config.settingsensures that if any part of your app readsrequest.registry.settings['pyramid.includes'], it will see the full list of includes. - Calling
config.include()manually triggers the same loading logic that Pyramid uses during initial setup for the INI config.
Alternative: Pre-Update the Settings Dictionary
If you prefer to stick closer to the initial behavior where Pyramid handles the includes automatically, you can modify the settings dictionary before passing it to the Configurator in each app's __init__.py:
from pyramid.config import Configurator def main(global_config, **settings): # Add shared includes to settings before initializing Configurator settings['pyramid.includes'] = settings.get('pyramid.includes', '') + ',pyramid_debugtoolbar' settings['pyramid.includes'] = settings['pyramid.includes'].strip(',') config = Configurator(settings=settings) config.include('common_config') # ... rest of your config setup ... return config.make_wsgi_app()
This works because the Configurator will process the updated pyramid.includes value during initialization, just like it does with the INI file.
Key Takeaway
The pyramid.includes setting is a special case—it's processed at Configurator startup, not dynamically after. If you need to add includes in a shared config function, you have to manually trigger the include() calls alongside updating the settings.
内容的提问来源于stack exchange,提问作者Arthur Hebert-Ryan

