In particular I want to use pystache but any guide for another template engine should be good enough to set it up.
If I understood correctly, I have to register the renderer factory in the __init__.py of my pyramid application.
config = Configurator(settings=settings)
config.add_renderer(None, 'pystache_renderer_factory')
Now I need to create the renderer factory and don't know how.
Even though I found the documentation about how to add a template engine, I didn't manage to set it up.
Finally I was able to add the pystache template engine following this guide:
https://groups.google.com/forum/#!searchin/pylons-discuss/add_renderer/pylons-discuss/Y4MoKwWKiUA/cyqldA-vHjkJ
What I did:
created the file mustacherenderer.py:
from pyramid.asset import abspath_from_asset_spec
import pystache
import os
def pystache_renderer_factory(info):
template = os.path.join(abspath_from_asset_spec('myproj:templates', False),
info.name)
f = open(template)
s = f.read()
f.close()
def _render(value, system):
return pystache.render(s, value)
return _render
added this to the __init__.py:
config.add_renderer('.pmt', 'myproj.mustacherenderer.pystache_renderer_factory')
working :)
add_renderer's second argument is supposed to be a class that implements the interface shown in "Adding a New Renderer". Pyramid will take pystache_renderer_factory and attempt to import it, so in your code the line import pystache_renderer_factory would have to work. This example won't ever resolve to a class, only a module or package, so you'll have to fix that first. It should be something like mypackage.pystache_renderer_factory.
The best way to learn how to write a renderer is probably to look at some that have been written already. Specifically the pyramid_jinja2 package, or in Pyramid's source there are very simple implementations of json and jsonp renderers. Notice how they all provide fairly unique ways to implement the required interface. Each factory accepts an info object, and returns a callable that accepts value and system objects.
https://github.com/Pylons/pyramid_jinja2/blob/master/pyramid_jinja2/init.py#L260
https://github.com/Pylons/pyramid/blob/master/pyramid/renderers.py#L135
Note that this answer works well until you create your Pyramid project with a scaffold. Once you do so, this related answer will prove more useful when constructing your Pystache/Mustache_Renderer_Factory: How to integrate pystache with pyramid?.
Related
I'm somewhat new to Python (but not at all to programming, already fluent in Perl, PHP, & Ruby).
I'm running into a major difference between all my previous languages and Python: Mainly that I can easily read in data from another file into an entire project.
there are two major examples of this that I would like to solve:
1) I would like to have a settings/config file (in YAML) that gets read in and parsed in a config.py file. I then want a resulting dict() to be accessible to all my other files in the project. I have figured out how to do this by from lib.project.config import cfg but that means that for each page that is importing the configs the system has to REparse the yaml. That seems just silly to me. Is there no way to have that file parsed just once and then have the results accessible to any other file in my project?
2) I would like to import a database.py file that then looks at my configs to see if we need to import a sqlite3, mysql, or postgresql version of a database class. Again, I can manage this by putting the logic directly in each page that I need the database class for. But I hate having to paste code like
if cfg.get('db_type') == 'sqlite':
from lib.project.databases.sqlite3 import database
elif cfg.get('db_type') == 'mysql':
from lib.project.databases.mysql import database
at the top of each file that needs the database class. I'd much rather just add:
import lib.project.database
Any help would be very much appreciated.
I've done a good deal of googling and SO searches and not found my answers. Hopefuly one of you wiz's out there can help.
Thanks.
UPDATE:
The reason I'm doing things this way (for #2) is because I'm also trying to make other classes inherit the database class.
So lib/project/databases/sqlite.py is a definition of a database class.
And so is lib/project/databases/mysql.py.
The idea being that after this import is complete I can import classes like the users class and define it like so:
class user(database):
...
And thus inherit all of the structure and methods of the database class.
Your suggestions to simply create an instance based on the sqlite/mysql logic/decision and then pass that where it needs to be is a good solution for that. But I need a bit more...
Ideas?
Thank you all for your help in understanding more about Python and how to get what I'm looking for done.
Here is what I ended up doing:
1) The config file issue:
This apparently was mostly solved to begin with. I confirmed what everyone was saying: that you can "import" a file as many times as you like, but it is only ever parsed/processed/compiled once. As for making it reachable to any file that needs it:
Config class:
import os
import yaml
class Config:
def __init__(self):
self.path = os.getcwd()
stream = open(self.path+"/conf/config.yaml", 'r')
data = yaml.load(stream)
config_keys = data.keys()
for k in config_keys:
setattr(self, k, data.get(k))
if (os.path.isfile(self.path+"/conf/config-override.yaml") ):
stream = open(self.path+"/conf/config-override.yaml", 'r')
data = yaml.load(stream)
config_keys = data.keys()
for k in config_keys:
setattr(self, k, data.get(k))
config = Config()
And then any file that wants to use it:
from lib.project.Config import config
This is all working swimmingly so far.
2) Dynamic database type for Database class:
I just altered my overall design a tiny bit to make a Database class (mostly empty) inherit from either the Sqlite or Mysql classes (both custom builds which are wrappers to existing Sqlite3 and mysql-connector classes). This way there is always a solid Database class to inherit from, I only load in what files I need to, and it's all defined by my config file. Example:
Database class:
from lib.project.Config import config
if config.db_type == 'sqlite' :
from lib.project.databases.Sqlite import Sqlite
elif config.db_type == 'mysql':
from lib.project.databases.Mysql import Mysql
class Database(Sqlite if config.db_type == 'sqlite' else Mysql):
''' documentation '''
I'd still love to hear people's feedback on this code/method.
As I said, I'm still newish to Python and could still be missing something.
Thanks again everyone.
1) you're all set - the file will only be read once.
2) Agreed you don't want to copy any paste code like that - if you want to use 1 instance of the database throughout your project, you'd do something like:
import lib.project
db = lib.project.database
where db is just a local variable used to access your already created database. You would instantiate your database as database (resolving as you've done with the if/elif code whether to use sqlite3 or mysql) in lib/project/databases.py and then in your lib/project/__init__.py file you would do a from .databases import database.
if you want to use multiple databases (of the same sqlite3/mysql type) throughout your project, you would resolve which constructor Database is bound to (or inherits from) in databases.py:
from lib.project.Config import config
if config.db_type == 'sqlite' :
import lib.project.databases.Sqlite as Db
elif config.db_type == 'mysql':
import lib.project.databases.Mysql as Db
class Database(Db):
'''docs'''
I'm currently using the Pyramid web framework and I have it configured with Mako templates. I know that I can render a template as a string from within a view method (Pyramid - Is it possible to render my mako template as a string within my view callable?), however, I was wondering if it is possible to get the actual template object from within a view and not just a function to render the template.
Looking through the Pyramid source code, in mako_templating.py I see that the default TemplateLookup class is overridden with a lookup method for Pyramid. Is there anyway to access this lookup object primarily so I can use the get_template function that is part of it?
Thanks for any direction on this issue.
This level of introspection is not officially supported by Pyramid's rendering API. That being said, here's a way to do it. This is completely undocumented, unsupported, private, etc, etc. Meaning, don't come complaining when this stops working.
from pyramid.mako_templating import IMakoLookup
lookup = request.registry.queryUtility(IMakoLookup, name='mako.')
tmpl = lookup.get_template('myapp:templates/foo.mako')
opts = {} # rendering context
result = tmpl.render_unicode(**opts)
This works for me:
from pyramid.renderers import render
sRenderedStuff = render('path/to/template.mak',dContext)
An example use case would be something like this:
sEmailHtml = render("email/welcome_message_html.mak",dContext)
With the following line in your pyramid settings file:
mako.directories = your_app:templates
The template is fetched from your_app/templates/email/welcome_message.html. All inheritance and include tags work just as they would for templates rendered to a view response.
I am setting up an application using Flask based on a tutorial I found on the web. The problem I am having is so far it seems like I will have to write a lot of code for each view/route that I want to make so I am trying to devise a better system but I think I dug myself into a hole where I wrote too much code before really testing each step and since im not familiar with the framework im kindof lost.
so what I want is a base view class that will extract away some boilerplate stuff. Here is my attempt so far.
import jinja2
from jinja2 import Environment as Jinja2Environment
from webassets import Environment as AssetsEnvironment
from webassets.loaders import YAMLLoader
from webassets.ext.jinja2 import AssetsExtension
from flask import render_template
from app import app
class BaseView(object):
def __init__(self):
"init"
def get_jinja_env(self):
jinja_env = Jinja2Environment(loader=jinja2.FileSystemLoader('templates/'), extensions=[AssetsExtension])
return jinja_env
def get_asset_env(self):
asset_loader = webassets.YAMLLoader('conf/assets.yml')
asset_env = asset_loader.load_environment()
bundles = asset_loader.load_bundles()
[asset_env.register(name, bundle) for name, bundle in bundles.iteritems()]
return asset_env
def render_tmpl(self, tmpl_file, **context):
"Renders Jinja Template"
jinja_env = self.get_jinja_env
jinja_env.assets_environment = self.get_asset_env
template = jinja_env.get_template(tmpl_file)
return template.render(context)
Class that attempts to inherit from BaseView
from app.BaseView import BaseView
from app import app
class HelloView(BaseView):
#app.route('/')
def respond(self):
self.render_tmpl('hello.html')
My reasoning behind this is later I intend to extend some Jinja functionality such as caching and have some data be available for every view and template.
You will want to use the View classes included in flask already.
As they are very well explained there is not much I could explain here. Just read through the docs and I think you will see, what you will have to do (the flask docs are awesome.)
If you want to cache you also might want to have a look at Flask-Cache.
This doesn't quite answer your question entirely, but I thought it was worth mentioning anyway.
You can 'export' variables into the Jinja environment globals:
app.jinja_env.globals['data'] = ['One', 'Two', 'Three']
Once you've done this, all templates have access to the data variable and can operate on it as if it were passed in via kargs. You don't really need to go to the trouble of creating a whole new view class; you can just process it once and then make it available everywhere. It's handy for sidebars and login statuses and whatnot.
I want to have dict / list to which I can add values, just like models can be added to the admin register in django !
My attempt : (package -> __init__.py)
# Singleton object
# __init__.py (Package: pack)
class remember:
a = []
def add(data):
a.append[data]
def get():
return a
obj = remember()
# models1.py
import pack
pack.obj.add("data")
# models2.py
import pack
pack.obj.add("data2")
print pack.obj.get()
# We should get: ["data", "data2"]
# We get : ["data2"]
How to achieve the desired functionality ?
Some say that methods can do this if you don't need sub-classing, how to do this with methods ?
Update:
To be more clear :
Just like django admin register any one can import and register itself with admin, so that register is persisted between imports.
If it's a singleton you're after, have a look at this old blog post. It contains a link to a well documented implementation (here).
Don't. If you think you need a global you don't and you should reevaluate how you are approaching the problem because 99% of the time you're doing it wrong.
If you have a really good reason to do it perhaps thread_locals() will really solve the problem you're trying to solve. This allows you to set up thread level global data. Note: This is only slightly better than a true global and should in general be avoided, and it can cause you a lot of headaches.
If you're looking for a cross request "global" then you most likely want to look into storing values in memcached.
I'm creating website based on Django (I know it's pure Python, so maybe it could be also answered by people who knows Python well) and I need to call some methods dynamically.
For example I have few applications (modules) in my website with the method "do_search()" in the views.py. Then I have one module called for example "search" and there I want to have an action which will be able to call all the existing "do_search()" in other applications. Of course I don't like to add each application to the import, then call it directly. I need some better way to do it dynamically.
I can read INSTALLED_APPS variable from settings and somehow run through all of the installed apps and look for the specific method? Piece of code will help here a lot :)
Thanks in advance!
Ignas
I'm not sure if I truly understand the question, but please clarify in a comment to my answer if I'm off.
# search.py
searchables = []
def search(search_string):
return [s.do_search(search_string) for s in searchables]
def register_search_engine(searchable):
if hasattr(searchable, 'do_search'):
# you want to see if this is callable also
searchables.append(searchable)
else:
# raise some error perhaps
# views.py
def do_search(search_string):
# search somehow, and return result
# models.py
# you need to ensure this method runs before any attempt at searching can begin
# like in models.py if this app is within installed_apps. the reason being that
# this module may not have been imported before the call to search.
import search
from views import do_search
search.register_search_engine(do_search)
As for where to register your search engine, there is some sort of helpful documentation in the signals docs for django which relates to this.
You can put signal handling and registration code anywhere you like. However, you'll need to make sure that the module it's in gets imported early on so that the signal handling gets registered before any signals need to be sent. This makes your app's models.py a good place to put registration of signal handlers.
So your models.py file should be a good place to register your search engine.
Alternative answer that I just thought of:
In your settings.py, you can have a setting that declares all your search functions. Like so:
# settings.py
SEARCH_ENGINES = ('app1.views.do_search', 'app2.views.do_search')
# search.py
from django.conf import settings
from django.utils import importlib
def search(search_string):
search_results = []
for engine in settings.SEARCH_ENGINES
i = engine.rfind('.')
module, attr = engine[:i], engine[i+1:]
mod = importlib.import_module(module)
do_search = getattr(mod, attr)
search_results.append(do_search(search_string))
return search_results
This works somewhat similar to registering MIDDLEWARE_CLASSES and TEMPLATE_CONTEXT_PROCESSORS. The above is all untested code, but if you look around the django source, you should be able to flesh this out and remove any errors.
If you can import the other applications through
import other_app
then it should be possible to perform
method = getattr(other_app, 'do_' + method_name)
result = method()
However your approach is questionable.