-
Notifications
You must be signed in to change notification settings - Fork 887
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
improve config file support #2419
Comments
My goal is for pyramid to stop caring about the file format but rather interface with a top-level api that can return it the logging, app, and server configs for a particular file path. The rest is up to you the interface to define. This is not unlike montague, but I would like the added support for loading arbitrarily named sections from the file such that 1) it can be re-parsed for settings without actually loading the app or server and 2) the same parser can be used for other purposes other than just the wsgi apps. The downfall of all approaches right now is that the parser is hidden behind apis that can only load wsgi/server/filter (montague adds logging) objects and every other use-case is ignored (any non-wsgi apps that also need settings). |
I don't mind the ini format at all. It's simply and does what it needs to do for the most part. The lack of being able to use environment variables is what drives me nuts That being said alternative config formats like yaml would be very welcome. |
You briefly mention multiple config files. Paste has some support for an include-like function, but it's not well-known and has some sharp edges. Might that be in scope? That is, the abstraction is capable of loading multiple files, possibly in different formats, and make them sections in a global config abstraction? |
@pauleveritt What do you mean "in scope"? I'm aware of that feature and it definitely has its limitations but you're right it can be used as a poor-man's inheritance. In my proposal PasteDeploy would basically be used for the ini format, alongside some extra support for using its private parser to pull in other non-wsgi sections so all of that functionality would remain unchanged for bw-compat. |
What to do about logging?So There is currently an assumption that logging config will exist in the same ini file as the PasteDeploy stuff, so it all gets lumped together which makes it hard to change stuff. It seems a bit weird to me that two different code paths are used for different sections of the same file. In other words, I have a I see two options:
|
The whole point in my discussion up above is that things are currently separated which is causing these issues. PasteDeploy does not control returning a dict of logging values and thus Pyramid must parse the file again itself. I would like to normalize this under a single interface with a single parser. Let me try to be more specific with a concrete api that I'm tossing around here: class ILoader(Interface):
def get_wsgi_app(name):
""" Return a WSGI application by the given name."""
def get_wsgi_filter(name):
""" Return a callable that accepts a WSGI application and returns a new WSGI application."""
def get_wsgi_server(name):
""" Return a callable that accepts a WSGI application and starts serving requests."""
def get_app_settings(name):
""" Return a settings dictionary for an entry point defined with the given name."""
def setup_logging():
""" Apply logging configuration to the Python stdlib logging module."""
def get_loader(uri):
""" Return an implementation of ``ILoader`` that supports the given ``uri``.""" It is then up to the implementation of the loader to define where globals and logging come from. For example, it could load a yaml dict, or it could call |
|
I'd prefer pyramid didn't care about dicts but rather just asked the loader to do the job. We are stuck calling |
I can't really have a discussion about that without someone who cares attempting to implement an example using the interface I provided and then telling me why it doesn't work. From my perspective (pyramid) it doesn't give a damn what logging you are using, it simply calls |
Sorry @inklesspen just realized you said that. I'd still like to stay away from the dict itself and focus on the task that pyramid cares about which is just "setup logging". Is there any reason anyone can see for passing around the dict instead? My problem with the dict is then we are coupled to python stdlib logging by design versus hiding whatever happens behind the function call. |
pastedeploy is actually three things: an ini file format, a python api, and some entry point types for apps, servers, etc. So far, I've seen a proposal for a replacement for the second item in the list, which would be implemented in a way that allows for the first item to be swapped out. But that still leaves the question of entry points. The pastedeploy entry point types are a little annoying, because the global conf is passed as a dict while local conf is passed as keyword arguments. Also, there's two different entry point styles for apps and filters, as well as a second entry point style for servers that takes the wsgi app and immediately starts running the server! Since ideally I should be able to convert a scaffolded app from JSON to YAML config just by changing the loader implementation, I think we need a common set of entry point signatures as well. I also think we shouldn't just blindly reuse pastedeploy's; we deserve to fix the warts. Off-the-cuff proposal: def app_factory(local_conf, global_conf):
return wsgi_app
def filter_factory(local_conf, global_conf):
return wsgi_filter
def server_factory(local_conf, global_conf):
return wsgi_server Simple and boring, which is good. The only real thing we've lost here is Paste's "Composite" app type, which I think is not really used much these days. (The filter_app_factory filter type is just a trivial adjustment from filter_factory.) There is, unfortunately, one other issue with PasteDeploy's ini syntax, compared to your proposed Loader interface. PasteDeploy provides three ways to get an app with a filter applied to it: the If I define the following INI file: [filter-app:main]
use = lowerify
next = actual
[filter:lowerify]
egg:montague_testapps#caps
method_to_call = lower
[app:actual]
use = egg:montague_testapps#basic_app I can load the On the other hand, compare this INI file: [app:main]
use = egg:montague_testapps#basic_app
filter-with = upperfilter
[filter:upperfilter]
use = egg:montague_testapps#caps
method_to_call = upper Here, since I have specified the In montague, I solved this problem by parsing the INI file into a tree structure, then rewriting it into a Lastly, I'm not really a fan of |
All of this is true, but they are PasteDeploy features. They are not features of Pyramid and they are not features that Pyramid uses or depends on. Pyramid core currently cares about 5 APIs and that's it: There's 2 steps here:
What I'm trying to spec out here is an API that gets AWAY from PasteDeploy as much as possible and focuses on what top-level applications need. That is almost entirely distilled down to We should probably update the loader methods to accept some Entry points and filters are both things that are loader-specific. Now, I know I'm focusing on Pyramid's point of view so let me cross to the other side for a second and focus on the implementation. It would obviously be a good idea for most loaders to support similar entry points and logging configuration so that montague or whatever we end up with would provide some support for things like taking a
Where does Pyramid call For the |
My off-the-cuff proposal was intended for Pyramid apps, not Pyramid itself. Currently, if I have a scaffolded Pyramid app, it contains a function like this: def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
config = Configurator(settings=settings)
# do many configurations here
return config.make_wsgi_app() That |
I don't think Pyramid is interested in dictating a common signature. I say this because Pyramid itself advocates example apps without that signature in single-file apps. That is only there for PasteDeploy integration. It does make for a nice standard entry point that I think custom loaders should adopt but when you decide to write your app with a particular loader+format then you conform to its expectations. The sad part is that those apps are no longer loadable by Pyramid's tools like |
The one thing I'd love to see on the pyramid side of things is exposing the things the p* commands needs as properties on the wsgi app.
If pyramid didn't care about the configuration format and exposed everything the commands would need to build a CLI around it then that would allow an ecosystem to grow around it. If someone wants to create a pyramid CLI system today that loads YAML or TOML they also have to re-implement pserve, proutes, ptweens, etc. Especially since single file apps lose the ability to print their routes right now because the commands require a config file. I'd love to see this: app.pyapp = config.make_wsgi_app() proutespython -c 'from app import app;print(app.routes)' and pserve would just be using standard server: gunicorn app:app |
This also similar to what projects like flask do: http://flask.pocoo.org/snippets/117/ |
As a status update on this issue, @huntcsg and I started https://github.com/mmerickel/plaster and https://github.com/mmerickel/plaster_pastedeploy at the sprints. I think they're starting to come together nicely but I would very much appreciate some help with some of the finer points. The library is basically a thin wrapper around entry points to allow a loader to be selected via a path or url. Plaster is focused only on lookup, leaving basically everything (including wsgi logic) up to the loaders themselves making the library hopefully very useful for non-Pyramid apps as well. The idea is that Pyramid will document what it expects a loader to implement in order to work. The wsgi-specific methods will be I very much expect that a significant amount of the work done in montague_yaml or montague_toml could be converted easily into a plaster loader. The reason for writing plaster instead of modifying montague is because it just takes a very different approach - as badly as I feel about that, it felt unavoidable at this stage. I feel I handled the efforts with montague pretty poorly and I hope that offering up this solution can help keep the ball rolling. We likely wouldn't be even considering replacing this part of Pyramid right now if it weren't for montague. |
Since these exciting changes are forthcoming, I wanted to suggest/request a tangential feature -- a hook/feature to note the configuration file path (and loader type) into the registry or registry.settings when/if that information is available The desire for this is largely for testing and development purposes. |
#2985 is open for evaluation. It is a branch of pyramid that allows completely replacing the config file parser. See http://docs.pylonsproject.org/projects/plaster/en/latest/ for more info on how to do that. If you have a chance to look please let me know how it goes. |
Pyramid's config file support has been dependent for a long time on PasteDeploy much to the chagrin of many users who hate ini files due to lack of support for types, environment variable support and non-wsgi scripts.
This issue is about coming up with a better design, so let me first layout some goals:
main(global_conf, **settings)
.Looking at what we have right now. We have
pserve
which is cli app that loads settings from a couple parts of an ini file. 1) It loads a[server]
and then 2) it loads a wsgi app which can be composed from other wsgi apps. In a very general sensepserve
is just running some code which is loading settings for isolated targets that it composes together. Great. That's pserve.I think it should be possible to accomplish these goals without completely overhauling what exists but rather just adding a layer of indirection between Pyramid and PasteDeploy as well as implementing some alternate backends for popular formats (YAML).
So, what can we simplify?
PasteDeploy is doing too much. It is a tightly coupled library between an ini file and wsgi components (app, server). We need to remove PasteDeploy from the pipeline as much as possible and focus on converting arbitrary file formats into sections. Each parser should, on its own, provide support for default values as well as values from environment vars.
A good parser can then be written to support the PasteDeploy format that
pserve
requires.@inklesspen has put a lot of work into montague and it improves on several of these points including abstracting the file format from the PasteDeploy format. I think the parser itself is where things falls short. An explicit goal I have is to be able to use montague (or simply the underlying parser) to load sections. The WSGI component is a layer on top of this. The difference here is that I'm trying to make it an explicit goal to make the config file itself reusable outside of a WSGI context. This is only semi-possible right now, and a source of endless problems when using PasteDeploy.
ConfigParser
.The text was updated successfully, but these errors were encountered: