Package: betahaus.viewcomponent
betahaus.viewcomponent READMEReusable components in web pages make them a lot more fun and rewarding to write.
The goal of this package is to make them easy to add, remove and change.
While it’s usable in a regular webapp, it’s probably more interesting to use
in something that others will extend or change, like a framework.It’s written to be flexible and easy to adapt, rather than being the perfect solution to everything.Basic example - adding a logoFirst, create a method that returns an html tag.
We also need to decorate this method.
The va positional argument is a ViewAction - we can ignore that
in this example.frombetahaus.viewcomponentimportview_action@view_action('stuff','logo')deflogo_tag(context,request,va):return'<img src="img.png" />'When you runconfig.scan('your-apps-name')with this code present,
it will create a ViewGroup with the name ‘stuff’, that has a ViewAction
called ‘logo’.You may optionally use a directive of the config object.
You need to includebetahaus.viewcomponentin that case.#Code in your packagedeflogo_tag(context,request,va):return'<img src="img.png" />'defincludeme(config):config.add_view_action(logo_tag,'stuff','logo')The ViewGroup is an ordered dict-like Utility, that keeps track of ViewActions.If you want to get the result of a ViewGroup, simply do this:frombetahaus.viewcomponentimportrender_view_grouprender_view_group(context,request,'stuff')Since there’s nothing else in this ViewGroup, only the logo tag will be returned.To get the result of a single ViewAction only, you can callrender_view_action:frombetahaus.viewcomponentimportrender_view_actionrender_view_action(context,request,'stuff','logo')Another example - building a menuSo you have a webapp, and you want a menu somewhere. And then package X, Y and Z
works as plugins, but how do they add to that menu of yours?
(Read the Pyramid docs on how to create views)First, let’s create minimal Python view code:frombetahaus.viewcomponentimportrender_view_groupfrompyramid.viewimportview_config@view_config(renderer='some/template.pt')defmain_template(context,request):returndict(render_view_group=render_view_group)And then the template:<html><body><ul>${render_view_group(context, request, 'menu')}</ul></body></html>The menu will be simple html strings, a<li>for each statement.
To return them, we need decorated methods. Note that the ViewGroupmenuwill be created as soon as it’s populated. (the first argument in the decorator)frombetahaus.viewcomponentimportview_action@view_action('menu','login')deflogin_link(context,request,va):return'<li><a href="/login">Login</a></li>'@view_action('menu','logout')deflogout_link(context,request,va):return'<li><a href="/logout">Logout</a></li>'@view_action('menu','my_personal_stuff',permission='ViewStuff')defpersonal_link(context,request,va):""" This will only render if user has permission 'ViewStuff'"""return'<li><a href="/my-stuff">My stuff</a></li>'After your app has been started, you’ll have a menu now. Also, other apps may add to it the same way,
or remove your initial alternatives.Advanced example - a pluggable json rendererUsecase: You pull JSON from a database. Some information is sensitive
and should only be visible to some users. Other plugins want to be able
to attach or change information to the JSON response.Our context will be a mock user object where the email
field is to be treated as sensitive information.classUser(object):userid=""email=""#etc...First, add two view actions for userid and email. The email one will have the permissionShow secret.frombetahaus.viewcomponentimportview_action@view_action('json','userid')defget_userid(context,request,va,**kw):returngetattr(context,'userid','')@view_action('json','email',permission='Show secret')defget_email(context,request,va,**kw):returngetattr(context,'email','')Second, lets register a regular view, that will return the view groupjson.frombetahaus.viewcomponentimportrender_view_groupfrompyramid.viewimportview_config@view_config(context='User',renderer='json',name='user.json')defuser_view(context,request):""" Render json."""returnrender_view_group(context,request,'json',as_type='dict',empty_val='')Email will now only be included if the user/thing requesting the view
has theShow secretpermission.
Theas_typeargument will render the view results as a dict where the keys
will be the view actions name. (user and email in this case)empty_valspecifies that any None or empty strings returned should be replaced by this value.
So even if userid returns ‘’, that value will still be included.Bonus: SpacerSpacer will be added when the view action output is joined as a string,
the default behaviour. It’s the same thing as doing spacer.join([view1, view2, etc])Bonus: PriorityThe priority argument sets the order when a view action is added.
Priority is sorted acending, so 10 is called before 20.RequirementsThis package currently isn’t usable outside ofPyramid, but it could be
changed to be more generic and only require the basicZope Component Architechture.
It also depends on venusian, which will be fetched by Pyramid.Feedback and featuresThe source code of the package is really small, and it should be commented enough so it’s
easy to pick up what to do with it. The package is still under development, but used on several
production servers today.If you have suggestions, criticism, feedback, ideas - please don’t hesitate to contact me
or add anissue at GitHub.CreditsRobin Harms Oredsson / robinharms (Initial author)Parnell Springmeyer / ixmatusPaul Bonser / pibA lot of good ideas were taken from Pyramid (http://www.pylonsproject.org) itself and from different repoze software.
The code itself was written as part of the VoteIT project (http://www.voteit.se).Changes0.4.1 (2015-04-04)Added: Option to return dict, generator or list instead of just joined strings.Added: Spacer option for the join statement.Added: A config directive ‘’add_view_action’’ to att view actions without scanning.Fixed instance when replacing a ViewAction caused the new action to be displayed twice.Bugfix: When replacing, the order should be preserved unless priority is set.Removed debug panel since the code was outdated and didn’t work with
the newer version of pyramid_debugtoolbar0.3.1b (2014-05-05)Unicode wasn’t an allowed string-type… (Brown paperbag for me) [robinharms]0.3b (2014-03-19)View groups don’t catch exceptions any longer. This was a cause of a lot of
odd error messages on Python 2.Ordering with bad keys don’t cause exceptions - they’re logged as warnings instead.New argument priority for view actions. [ixmatus]0.2b (2013-06-18)Python3 support fixed by pib (Paul Bonser) - thanks a lot!Fetch and execution of vas changed - empty result should be ignored,
and yield isn’t used now. This should make error messages clearer. [robinharms]Checks for containment, interface, permission etc moved to ViewAction object, since
they weren’t performed if the object was called directly. [robinharms]0.1bInitial version