| | |
| | | it includes more than one way to resolve a URL to a :term:`view callable`: |
| | | via :term:`url dispatch` or :term:`traversal`. Multiple methods of |
| | | configuration exist: :term:`imperative configuration`, :term:`configuration |
| | | decoration`, and :term:`ZCML`. It works with multiple different kinds of |
| | | persistence and templating systems. And so on. However, the existence of |
| | | most of these overlapping ways to do things are not without reason and |
| | | purpose: we have a number of audiences to serve, and we believe that TIMTOWTI |
| | | at the web framework level actually *prevents* a much more insidious and |
| | | harmful set of duplication at higher levels in the Python web community. |
| | | decoration`, and :term:`ZCML` (optionally via :term:`pyramid_zcml`). It works |
| | | with multiple different kinds of persistence and templating systems. And so |
| | | on. However, the existence of most of these overlapping ways to do things |
| | | are not without reason and purpose: we have a number of audiences to serve, |
| | | and we believe that TIMTOWTI at the web framework level actually *prevents* a |
| | | much more insidious and harmful set of duplication at higher levels in the |
| | | Python web community. |
| | | |
| | | :app:`Pyramid` began its life as :mod:`repoze.bfg`, written by a team of |
| | | people with many years of prior :ref:`Zope` experience. The idea of |
| | | :term:`traversal`, the usage of :term:`ZCML` and the way :term:`view lookup` |
| | | works was stolen entirely from Zope. The authorization subsystem provided by |
| | | :app:`Pyramid` is a derivative of Zope's. The idea that an application can |
| | | be *extended* without forking is also a Zope derivative. |
| | | :term:`traversal` and the way :term:`view lookup` works was stolen entirely |
| | | from Zope. The authorization subsystem provided by :app:`Pyramid` is a |
| | | derivative of Zope's. The idea that an application can be *extended* without |
| | | forking is also a Zope derivative. |
| | | |
| | | Implementations of these features were *required* to allow the :app:`Pyramid` |
| | | authors to build the bread-and-butter CMS-type systems for customers in the |
| | |
| | | it works non-local. |
| | | |
| | | You've now bought in to the fact that there's a registry that is just |
| | | "hanging around". But how does the registry get populated? Why, |
| | | :term:`ZCML` of course. Sometimes. Or via imperative code. In this |
| | | particular case, however, the registration of ``ISettings`` is made by the |
| | | framework itself "under the hood": it's not present in any ZCML nor was it |
| | | performed imperatively. This is extremely hard to comprehend. Problem |
| | | number six. |
| | | "hanging around". But how does the registry get populated? Why, via code |
| | | that calls directives like ``config.add_view``. In this particular case, |
| | | however, the registration of ``ISettings`` is made by the framework itself |
| | | "under the hood": it's not present in any user configuration. This is |
| | | extremely hard to comprehend. Problem number six. |
| | | |
| | | Clearly there's some amount of cognitive load here that needs to be borne by |
| | | a reader of code that extends the :app:`Pyramid` framework due to its use of |
| | |
| | | |
| | | - Composability. A ZCA component registry can be populated imperatively, or |
| | | there's an existing mechanism to populate a registry via the use of a |
| | | configuration file (ZCML). We didn't need to write a frontend from scratch |
| | | to make use of configuration-file-driven registry population. |
| | | configuration file (ZCML, via :term:`pyramid_zcml`). We didn't need to |
| | | write a frontend from scratch to make use of configuration-file-driven |
| | | registry population. |
| | | |
| | | - Pluggability. Use of the ZCA registry allows for framework extensibility |
| | | via a well-defined and widely understood plugin architecture. As long as |
| | | framework developers and extenders understand the ZCA registry, it's |
| | | possible to extend :app:`Pyramid` almost arbitrarily. For example, it's |
| | | relatively easy to build a ZCML directive that registers several views "all |
| | | at once", allowing app developers to use that ZCML directive as a "macro" |
| | | in code that they write. This is somewhat of a differentiating feature |
| | | from other (non-Zope) frameworks. |
| | | relatively easy to build a directive that registers several views "all at |
| | | once", allowing app developers to use that directive as a "macro" in code |
| | | that they write. This is somewhat of a differentiating feature from other |
| | | (non-Zope) frameworks. |
| | | |
| | | - Testability. Judicious use of the ZCA registry in framework code makes |
| | | testing that code slightly easier. Instead of using monkeypatching or |
| | |
| | | for just these purposes. The ZCA registry contains optional C code for |
| | | this purpose which demonstrably has no (or very few) bugs. |
| | | |
| | | - Ecosystem. Many existing Zope packages can be used in |
| | | :app:`Pyramid` with few (or no) changes due to our use of the ZCA |
| | | registry and :term:`ZCML`. |
| | | - Ecosystem. Many existing Zope packages can be used in :app:`Pyramid` with |
| | | few (or no) changes due to our use of the ZCA registry. |
| | | |
| | | Conclusion |
| | | ++++++++++ |
| | |
| | | either need to get familiar with how we're using the ZCA registry or you'll |
| | | need to use only the documented APIs; that's why we document them as APIs. |
| | | |
| | | If you *extend* or *develop* :app:`Pyramid` (create new ZCML directives, use |
| | | some of the more obscure "ZCML hooks" as described in :ref:`hooks_chapter`, |
| | | or work on the :app:`Pyramid` core code), you will be faced with needing to |
| | | understand at least some ZCA concepts. In some places it's used unabashedly, |
| | | and will be forever. We know it's quirky, but it's also useful and |
| | | fundamentally understandable if you take the time to do some reading about |
| | | it. |
| | | If you *extend* or *develop* :app:`Pyramid` (create new directives, use some |
| | | of the more obscure "hooks" as described in :ref:`hooks_chapter`, or work on |
| | | the :app:`Pyramid` core code), you will be faced with needing to understand |
| | | at least some ZCA concepts. In some places it's used unabashedly, and will |
| | | be forever. We know it's quirky, but it's also useful and fundamentally |
| | | understandable if you take the time to do some reading about it. |
| | | |
| | | Pyramid Uses Interfaces Too Liberally |
| | | ------------------------------------- |
| | |
| | | completely optional. No ZCML is required at all to use :app:`Pyramid`, nor |
| | | any other sort of frameworky declarative frontend to application |
| | | configuration. |
| | | |
| | | Pyramid Uses ZCML; ZCML is XML and I Don't Like XML |
| | | --------------------------------------------------- |
| | | |
| | | :term:`ZCML` is a configuration language in the XML syntax. Due to the |
| | | "imperative configuration" feature (new in :mod:`repoze.bfg` 1.2), you don't |
| | | need to use ZCML at all. But if you really do want to perform declarative |
| | | configuration, perhaps because you want to build an extensible application, |
| | | you may need to use and understand it. |
| | | |
| | | :term:`ZCML` contains elements that are mostly singleton tags that are |
| | | called *declarations*. For an example: |
| | | |
| | | .. code-block:: xml |
| | | :linenos: |
| | | |
| | | <route |
| | | view=".views.my_view" |
| | | path="/" |
| | | name="root" |
| | | /> |
| | | |
| | | This declaration associates a :term:`view` with a route pattern. |
| | | |
| | | All :app:`Pyramid` declarations are singleton tags, unlike many other XML |
| | | configuration systems. No XML *values* in ZCML are meaningful; it's always |
| | | just XML tags and attributes. So in the very common case it's not really |
| | | very much different than an otherwise "flat" configuration format like |
| | | ``.ini``, except a developer can *create* a directive that requires nesting |
| | | (none of these exist in :app:`Pyramid` itself), and multiple "sections" can |
| | | exist with the same "name" (e.g. two ``<route>`` declarations) must be able |
| | | to exist simultaneously. |
| | | |
| | | You might think some other configuration file format would be better. But |
| | | all configuration formats suck in one way or another. I personally don't |
| | | think any of our lives would be markedly better if the declarative |
| | | configuration format used by :app:`Pyramid` were YAML, JSON, or INI. It's |
| | | all just plumbing that you mostly cut and paste once you've progressed 30 |
| | | minutes into your first project. Folks who tend to agitate for another |
| | | configuration file format are folks that haven't yet spent that 30 minutes. |
| | | |
| | | .. _model_traversal_confusion: |
| | | |
| | |
| | | other more domain-specific configuration plugpoints while developing an |
| | | application. The plugpoints you expose needn't be as coarse as the ones |
| | | provided automatically by :app:`Pyramid` itself. For example, you might |
| | | compose your own :term:`ZCML` directive that configures a set of views for a |
| | | prebaked purpose (e.g. ``restview`` or somesuch) , allowing other people to |
| | | refer to that directive when they make declarations in the ``configure.zcml`` |
| | | of their customization package. There is a cost for this: the developer of |
| | | an application that defines custom plugpoints for its deployers will need to |
| | | compose your own directive that configures a set of views for a prebaked |
| | | purpose (e.g. ``restview`` or somesuch) , allowing other people to refer to |
| | | that directive when they make declarations in the ``includeme`` of their |
| | | customization package. There is a cost for this: the developer of an |
| | | application that defines custom plugpoints for its deployers will need to |
| | | understand the ZCA or he will need to develop his own similar extensibility |
| | | system. |
| | | |