Re: How to get request object inside decorator?

2012-06-20 Thread Rob Miller
See 
http://docs.pylonsproject.org/projects/pyramid/en/1.3-branch/designdefense.html#stacked-object-proxies-are-too-clever-thread-locals-are-a-nuisance


When a request object is provided magically by the framework, then the 
unit tests have to create a fake request object and then jump through 
whatever hooks the framework requires to make the request available. 
When a request object is expected as an argument, you don't have to do 
this, you can just create the request object and pass it in to the 
function that you're calling.


Even so, as Chris said, it's your software. `get_current_request` is 
available. Do what you want. There's no need to get indignant just 
because someone has an opinion that contradicts yours, even if your 
opinion *is* based on 3 years of Pylons experience.


-r



On Wed Jun 20 09:14:33 2012, Max Avanov wrote:

I don't used to blindly believe something just because it was written
that way. The docs are not just a collection of essay about web
development. It should be explanatory and clear. That is their main
purpose.
I came to Pyramid after three years of Pylons-based web development.
It wasn't hard to test pylons-based applications. So, why the
get_current_request makes it possible to write code that can be
neither easily tested nor scripted?

On Wednesday, June 20, 2012 7:57:34 PM UTC+4, Chris McDonough wrote:

On 06/20/2012 11:55 AM, Max Avanov wrote:
 I wonder why pyramid documentation prefers one solution to
another. If
 some method is objectively better than another, I would like to
know it
 before I make a decision.

It's discussed in the docs about get_current_registry and
threadlocals.
  You can read it and believe it, or not (it says something like
makes
testing harder and more fragile).  If you believe it, don't use
threadlocals.  If you don't believe it or don't care, use them.

- C

--
You received this message because you are subscribed to the Google
Groups pylons-discuss group.
To view this discussion on the web visit
https://groups.google.com/d/msg/pylons-discuss/-/ZmB9gWa-zkMJ.
To post to this group, send email to pylons-discuss@googlegroups.com.
To unsubscribe from this group, send email to
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at
http://groups.google.com/group/pylons-discuss?hl=en.


--
You received this message because you are subscribed to the Google Groups 
pylons-discuss group.
To post to this group, send email to pylons-discuss@googlegroups.com.
To unsubscribe from this group, send email to 
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.



Re: Storing settings on module level -- bad idea?

2012-02-01 Thread Rob Miller
These are reasonable points to make. But Pyramid is explicitly not 
trying to be the same thing that either Django or Rails is trying to be. 
Those are what we call opinionated frameworks, which make things 
easier on less experienced developers by making many choices for them. 
This usually comes at a cost; you lose flexibility, and you have to 
wrestle w/ the framework when you realize that the choice you want to 
make isn't in fact the one your tool has made.


Pyramid has some opinions, sure, but far fewer of them. It's intended to 
strike the right balance between flexibility, performance, and ease of 
use for more experienced developers. Some people complain about certain 
features b/c I'm never gonna need this, and it confuses me, can't we 
just rip it out? But in every case that feature is there b/c SOMEone 
had to solve a hard problem and that was the best way to do it. Ripping 
it out would make those hard problems harder to solve. But Pyramid 
targets those hard problems, and thus the features stay.


This case w/ globals is similar, although slightly inverted. In many 
cases module-level global settings are fine; they make the developers 
life a little bit easier, and they don't cause any problems. But in some 
cases they *do* cause problems. Real, honest to god developer pain. 
Django and Pylons have both hit this in the real world. For Django it's 
fine, it's a trade-off that makes sense given their philosophy and their 
target audience. For Pyramid it doesn't, b/c Pyramid is just as 
interested in reducing developer friction in the hard cases as it is the 
easy cases, and so they make a different set of trade-offs.


Does this mean that Pyramid will never be as widely used as Django? 
Probably. Does that matter? Nope.


-r

On 1/31/12 8:16 PM, Jonathan Vanasco wrote:

my .02¢ is this:

App Developers like features like 'Globals'. It's something that is
familiar-from, and present-in many other frameworks.

Granted, pyramid is a low-level framework - and one that a more
'webmonkey' friendly framework might be built upon itself. But those
frameworks are likely to end up implementing those features
themselves... both in bad ways, and in many numerous different ways. If
pyramid can find a way to pull it off correctly, it would be great.

Rails didn't succeed because it was a great framework, its success is
largely do to it being usable-by and appealing-to really bad developers
( i mean really awful ones ). PHP got to be ubiquitous and installed on
every platform, by just doing a shoddy job implementing everything, so
even the worst developers flocked to it. People I've been introduced to
by recruiters as Top Django Pros! commanding 160k salaries, have been
robots that barely know python.

I loved pylons, I love pyramid. I only get to code about 20% of my time,
and love being able to work in them, because they're implemented in a
way that really resonates with how I like to work. The problem though,
is that I'm usually running operations, tech or product at a company --
not implementing it. Having to source people to execute on goals is a pain.

I understand why technically some things might not be right or ideal,
and why they shouldn't be done -- but sometimes the best route for
adoption and continued health isn't to do the right thing.

sorry for ranting on this.
/j




--
You received this message because you are subscribed to the Google
Groups pylons-discuss group.
To view this discussion on the web visit
https://groups.google.com/d/msg/pylons-discuss/-/ddSQnMKjZZ4J.
To post to this group, send email to pylons-discuss@googlegroups.com.
To unsubscribe from this group, send email to
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at
http://groups.google.com/group/pylons-discuss?hl=en.


--
You received this message because you are subscribed to the Google Groups 
pylons-discuss group.
To post to this group, send email to pylons-discuss@googlegroups.com.
To unsubscribe from this group, send email to 
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.



Re: Crazy behavior of `Making A “User Object” Available as a Request Attribute`

2011-10-17 Thread Rob Miller

On 10/17/11 1:42 PM, neurino wrote:

Reading one more time Michael mail about the recipe:

  It advocates a mechanism to query the user the first time you access
that property of the request object and cache the result in memory for
the lifetime of that request

*That's right the way I wanted it to work!*

So why if I reload a page my user is not queried again and stills to an
older state?


Um, is it possible that you're just getting the same page from your 
browser cache, and therefore you're not hitting your server at all? 
Have you tried shift-reload to see if that changes the behaviour?


-r



I *don't want* at all to have session variables, I want a brand new
queried request.user attribute each time the user loads its profile page.

Thanks for your support
neurino



On Mon, Oct 17, 2011 at 7:24 PM, Michael Merickel mmeri...@gmail.com
mailto:mmeri...@gmail.com wrote:

It advocates a mechanism to query the user the first time you access
that property of the request object and cache the result in memory
for the lifetime of that request


--
You received this message because you are subscribed to the Google
Groups pylons-discuss group.
To post to this group, send email to pylons-discuss@googlegroups.com.
To unsubscribe from this group, send email to
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at
http://groups.google.com/group/pylons-discuss?hl=en.


--
You received this message because you are subscribed to the Google Groups 
pylons-discuss group.
To post to this group, send email to pylons-discuss@googlegroups.com.
To unsubscribe from this group, send email to 
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.



Re: in defense of traversal

2011-10-12 Thread Rob Miller

On 10/12/11 10:10 AM, Iain Duncan wrote:

(was going to be one post, split in two). I'm wondering about making
this into a larger article that could be posted on the docs.


This is insightful, thanks for sharing your experiences here.  If you're 
serious about contributing to the docs, you might consider revising the 
Much Ado About Traversal chapter to include some of this information 
in the Use Cases section.  You could even move that section to the 
start of the chapter, renaming it to Why should you care about 
traversal? or something similar, so folks can decide up front if they 
care enough to bother reading the rest of it to learn how traversal works.


-r



A lot of people don't get what the heck good traversal is. Part of the
issue is that it's a bit harder to make it really shine without using
the zodb, but it's certainly possible. We've done it using SQLAlchemy by
having all content types in our cms inherit from one base content type
using SA table inheritance. The base type holds the parent child
relationships, the path, the title, and links into our system wide
permission persistancy scheme. This works like a charm. Sure, the table
structure is more complicated, but security is rock solid, and the real
kicker:

USERS FREAKING LOVE TRAVERSAL!

I challenge anyone who has dismissed it, to sit a client down in front
of a traversal based CMS and watch them. Wow, you don't need to tell
them anything, they get it right away because it looks and acts *just
like their file system*. We, the *developers*, love Rest APIs. They make
perfect clean sense, but look at those urls. They match our persistancy
scheme, they match how the database thinks, not how the user thinks. As
we try to sell people on our CMS compared to Drupal, the main selling
point is honestly that they find administering a traversal based CMS
very easy to understand, and they can find things easily. Users hate not
being able to find how to changes something ( looking at you, Drupal, gag! )

We use rest-ful schemes all the time in our admin back end and for ajax
serving, I'm not anti rest by any stretch. But since we changed to a
traversal scheme for the public side of our cms and introduced admin
features on that side ( much like plone ), our users are way way
happier. Even administering row-level permissions is simple for them,
because they get the idea instantly that by default every child has the
same permissions as it's parent. They are way happier thinking about the
tree and not the content type. It makes more sense to user that a piece
of content has a set of permissions because of *where* it is than *what
it is*. You put something somewhere, it's in that folder. Of course if
you can't access a folder you can't access it's contents, it makes
intrinsic sense.

Users think in traversal. Bottom line, that's what matters.

Now aside from ranting, would it perhaps be useful for me to post
sometime a more detailed example of how we accomplished traversal based
permissions and editing using an SQLAlchemy back end? ( It will be a
while, but I need to write lots of documentation for internal company
purposes anyway so maybe could kill two birds with one stone)

iain

--
You received this message because you are subscribed to the Google
Groups pylons-discuss group.
To post to this group, send email to pylons-discuss@googlegroups.com.
To unsubscribe from this group, send email to
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at
http://groups.google.com/group/pylons-discuss?hl=en.


--
You received this message because you are subscribed to the Google Groups 
pylons-discuss group.
To post to this group, send email to pylons-discuss@googlegroups.com.
To unsubscribe from this group, send email to 
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.



Re: in defense of traversal

2011-10-12 Thread Rob Miller

On 10/12/11 11:00 AM, Parnell Springmeyer wrote:

One quick thing to add: I am building/maintaining a *big* production
application that is 100% on top of Pyramid and strictly uses Traversal
and SQLAlchemy.


One thing worth noting when using traversal w/ SQL is that you often pay 
a lookup penalty, since every part of the requested URL path usually 
results in an additional database query (e.g. GET /foo/bar/baz would 
be at least 3 queries).  And modeling trees in SQL is trickier than it 
seems, it's easy to build inefficient lookups (although to be fair 
usually find child of X named Y isn't too heavy).


This won't matter for many uses, but at scale it can have significant 
impact.


-r

--
You received this message because you are subscribed to the Google Groups 
pylons-discuss group.
To post to this group, send email to pylons-discuss@googlegroups.com.
To unsubscribe from this group, send email to 
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.



Re: in defense of traversal

2011-10-12 Thread Rob Miller



On 10/12/11 2:18 PM, Thomas G. Willis wrote:

On Wednesday, October 12, 2011 2:53:09 PM UTC-4, Rob Miller wrote:

On 10/12/11 11:00 AM, Parnell Springmeyer wrote:
  One quick thing to add: I am building/maintaining a *big* production
  application that is 100% on top of Pyramid and strictly uses
Traversal
  and SQLAlchemy.

One thing worth noting when using traversal w/ SQL is that you often
pay
a lookup penalty, since every part of the requested URL path usually
results in an additional database query (e.g. GET /foo/bar/baz would
be at least 3 queries).


or 3 requests to memcached. :)


Indeed.


Also,

I can imagine that it would be possible in the root factory to have
enough information to everything for the context path that it can in one
batch. I haven't needed to implement this yet, but it's in the tech debt
at work for if things go down in flames.


Right, as Michael suggested a custom traverser could be used here.

-r

--
You received this message because you are subscribed to the Google Groups 
pylons-discuss group.
To post to this group, send email to pylons-discuss@googlegroups.com.
To unsubscribe from this group, send email to 
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.



Re: uhh web2pyramid?

2011-09-07 Thread Rob Miller
Yup, and docs.pylonshq.com was misconfigured to still be pointing at the 
joke page.  Now fixed.


-r


On 9/7/11 11:30 AM, Joe Dallago wrote:

Nah it was an April Fools' Day joke.

On Wed, Sep 7, 2011 at 12:54 PM, Siddhartha Kasivajhula
countvajh...@gmail.com mailto:countvajh...@gmail.com wrote:

Has the pylons site been hacked?
http://docs.pylonshq.com/

--
You received this message because you are subscribed to the Google
Groups pylons-discuss group.
To post to this group, send email to pylons-discuss@googlegroups.com
mailto:pylons-discuss@googlegroups.com.
To unsubscribe from this group, send email to
pylons-discuss+unsubscr...@googlegroups.com
mailto:pylons-discuss%2bunsubscr...@googlegroups.com.
For more options, visit this group at
http://groups.google.com/group/pylons-discuss?hl=en.


--
You received this message because you are subscribed to the Google
Groups pylons-discuss group.
To post to this group, send email to pylons-discuss@googlegroups.com.
To unsubscribe from this group, send email to
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at
http://groups.google.com/group/pylons-discuss?hl=en.


--
You received this message because you are subscribed to the Google Groups 
pylons-discuss group.
To post to this group, send email to pylons-discuss@googlegroups.com.
To unsubscribe from this group, send email to 
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.



Re: pyramid - traversal struggle

2011-06-15 Thread Rob Miller
yeah, if you want to nest your URLs arbitrarily deep and you want 
human-readable URLs traversal might be a good choice... that need wasn't clear 
from your original description.


in any event, i tried to point you in the right direction.  hopefully it was 
useful.  :)


-r


On 06/15/2011 03:07 AM, toudi wrote:

I did read 'Much ado about traversal and it was one of the reasons i
decided to go that way. Let me give you a quick example:

Let's assume, that in e-commerce application we have a place for
logged in user. He can access it via:

/account

So far so good. Now, this account panel should have some modules.
Let's say, that it has a 'shop' module which gives some basic
information about user's shop:

/account/shop

now we can have another submodule, let's say about products:

/account/shop/products

and so on.

When using URL matching approach we would need to define those routes
manually:

config.add_route(/account, views.account)
config.add_route(/account/shop, views.account.shop)

and so on (because we don't know how nested the modules can be i
believe we cannot regexp it)

But it isn't very flexible - an ideal approach for me would be the
sittuation when somebody could somehow create url matches and / or
traversal contexts inside the actual modules. So for example:

#/views/account/account.py
config.add_route(/account/ ... )
#/views/account/shop.py
and so on.

however, when using URL matching we still must define those routes. I
was hoping to use traversal in order to do something like this:

#views/account/account.py
root.add_child(account)
#views/account/shop.py
root[account].add_child(shop)
#views/account/shop/products.py
root[account][shop].add_child(products)

and so on. (however i believe i cannot have both shop.py and a folder
named shop, but that's just an example ;) )

Another classic scenario is an admin backend for application - it also
has many submodules.

And i used a dict because i was trying to follow the docs section
about Resources - there's an example there:

class Resource(dict):
  pass

however when i used it like this i got some error about a dict not
being callable or hashable ( i don't know for sure right now because i
don't have the code ). Then i read about locations and the need of
using __name__ and __parent__ in resources therefore i created an
object.

The wiki tutorial had another implementation of resources, however it
used ZODB which i was not going to use ( in pylons i used
sqlalchemy ).
Also, a wiki tutorial didn't quite fit into my problem because (i
don't know the technical term for that) wiki uses 'flat' urls ( i.e. /
wiki/pagename/action ).

On 15 Cze, 02:30, Rob Millerr...@kalistra.com  wrote:

/me dons his traversal explainer cape and mask...

first, and foremost, i don't think you actually need or want traversal here.
you say you read the traversal and resources chapters of the docs, but did
you read the much ado about traversal piece (http://tinyurl.com/4exxjvw)?
especially the use cases section, where it describes the cases where
traversal is a better choice than URL matching.  your use case meets none of
those criteria, AFAICT, so you probably don't want to use traversal at all.
i'm pretty sure you CAN still use config.scan to register your views even w/o
traversal, so i'm not entirely sure what the problem is there.

but, just for the fun of it, let's say traversal was a good idea.  what are
you doing wrong?  there are a few things that seem a bit wonky in the code
(e.g. the fact that your resource class inherits from dict but then doesn't
act like a dict, delegating to a contained dictionary attribute instead), but
i'll ignore those for now.  the main problem seems to be that you're trying to
use specific instances as your context, when really context is better suited
to using types.

something like this is probably closer to what you want (totally untested, use
at your own risk, this code may steal your car and eat your cookies, etc.):

class Resource(object):
  def __init__(self, name=None, parent=None):
  self.__name__ = name
  self.__parent__ = parent
  self.children = {}

  def add_child(self, name, klass=None, **kw):
  if klass is None:
  child = Resource(name, self)
  else:
  child = klass(name, self, **kw)
  self.children[name] = child

  def __getitem__(self, name):
  return self.children[name]

class Task(Resource):
  pass

then you'll need to instantiate some of these things:

root = Resource('root')
root.add_child('some_task', Task)
root.add_child('another_task', Task)

now you can register a view on Task objects like this:

@view_config(name=method, context=Task)
def task_method(request):
  task = request.context
  ... do something w/ your task object ...
  return Response(...)

if this is all wired up correctly then the following paths should resolve to
your view:

/some_task/method
/another_task/method

now it might be 

Re: pyramid - traversal struggle

2011-06-14 Thread Rob Miller

/me dons his traversal explainer cape and mask...

first, and foremost, i don't think you actually need or want traversal here. 
you say you read the traversal and resources chapters of the docs, but did 
you read the much ado about traversal piece (http://tinyurl.com/4exxjvw)? 
especially the use cases section, where it describes the cases where 
traversal is a better choice than URL matching.  your use case meets none of 
those criteria, AFAICT, so you probably don't want to use traversal at all. 
i'm pretty sure you CAN still use config.scan to register your views even w/o 
traversal, so i'm not entirely sure what the problem is there.


but, just for the fun of it, let's say traversal was a good idea.  what are 
you doing wrong?  there are a few things that seem a bit wonky in the code 
(e.g. the fact that your resource class inherits from dict but then doesn't 
act like a dict, delegating to a contained dictionary attribute instead), but 
i'll ignore those for now.  the main problem seems to be that you're trying to 
use specific instances as your context, when really context is better suited 
to using types.


something like this is probably closer to what you want (totally untested, use 
at your own risk, this code may steal your car and eat your cookies, etc.):


class Resource(object):
def __init__(self, name=None, parent=None):
self.__name__ = name
self.__parent__ = parent
self.children = {}

def add_child(self, name, klass=None, **kw):
if klass is None:
child = Resource(name, self)
else:
child = klass(name, self, **kw)
self.children[name] = child

def __getitem__(self, name):
return self.children[name]

class Task(Resource):
pass

then you'll need to instantiate some of these things:

root = Resource('root')
root.add_child('some_task', Task)
root.add_child('another_task', Task)

now you can register a view on Task objects like this:

@view_config(name=method, context=Task)
def task_method(request):
task = request.context
... do something w/ your task object ...
return Response(...)

if this is all wired up correctly then the following paths should resolve to 
your view:


/some_task/method
/another_task/method

now it might be possible to achieve the same thing by using a specific 
instance as your context rather than a class... the view config docs don't say 
anything about that, though, and i've never done it; i'd find it a bit confusing.


hope this helps,

-r


On 06/14/2011 01:58 PM, toudi wrote:

hello.

before i begin i would like to say, that i have read both 'Traversal'
and 'Resources' chapters from pyramid docs. I also read this thread -
http://groups.google.com/group/pylons-devel/browse_thread/thread/a8d4cc7e8d0c9855
which is a similar problem i have, but i still cannot wrap my mind
around traversal. However, i think it's the best approach for me,
because of it's config.scan() capabilities. I also have a background
in pylons, which i was using without any problems.

So - to keep my long story short, i am trying to implement a fairly
simplistic application (task / bugtracker) in order to learn pyramid.
Here are the models:

User - a developer
Task - a Bug, that can have one developer and many comments.
Comment - a Task comment.

i have named my project 'flyswatter', therefore:

#flyswatter/__init__.py

...
 config = Configurator(settings=settings)
 config.add_static_view('static', 'flyswatter:static')
 config.scan(.views)
...

#flyswatter/resources.py

class Resource(dict, object):
def __init__(self, name = None, parent = None):
self.__name__ = name
self.__parent__ = parent
self.children = {}

def add_child(self, name):
self.children[name] = Resource(name = name, parent = self)

def __getitem__(self, name):
return self.children.get(name)

root = Resource()

now - onto my problem. I would like to use config.scan() and traversal
in order to map url's to the views. my view directory structure looks
like this:

#flyswatter/flyswatter/views
__init__.py
default.py
task.py
admin
admin/__init__.py
admin/foo.py

The only way i managed to combine the traversal with views mapping is
like this:

#views/default.py
from flyswatter.resources import root

@view_config(context = root)
def index(request):
return Response('root::index')

@view_config(name=method, context = root)
def method(self):
return Response('root::method')

so far so good - url's / and /method are correctly mapped.

#views/task.py
from flyswatter.resources import root, Resource

root.add_child(task)
root[task].add_child(method)


@view_config(name=task_index, context = root[task])
def index(request):
return Response('task::index')

@view_config(name=task_method, context=root[task])
def method(request):
return Response('task::method')

not so good - in order to access task.method 

Re: Pyramid question...

2011-03-02 Thread Rob Miller

On 03/02/2011 07:34 PM, Joe Dallago wrote:

So I am relatively new to the Pyramid scene, so correct me if I am
wrong, but this is the conclusion I have come to on this topic.  B/c I
too struggled for a few days over this.

Resources:  First of all, resources were originally called models,
but the name was purposely changed to avoid confusion with SQLAlchemy
models or with the normal idea of what a MVC model is.  A
resource is simply one element in the resource tree.  The entire
purpose of the resource tree is to define the structure of your site.
A resource isn't necessarily connected to a persistence system, such
as an RDBMS, but it definitely can be.  It is also important to note
that the resource tree is only used when traversal is used as the
routing system.  Traversal is simply the process by which the router
moves down the resource tree according to the url, and assigns the
context and view.

Context:  In traversal, the context is the last resource that is
loaded as the router traverses the resource tree, either due to the
fact that there are no elements left in the url or that the router has
reached the bottom of the tree.

View:  The view is element of the url that directly follows the
context(i.e. /pages/add, if 'pages' is loaded as the context, then
'add' becomes the view).  It is essentially the function that does all
of the business logic and sends important information to the template.
  In traversal the context found through the traversal is passed into
this view function, whereas in Url Dispatch, the root_factory defined
when the view is added to the registry creates an object that is
passed into the view as the context(this could be the root of your
application or even another resource that you might want to use in the
view, it just has to be a class).


As Chris said, great description, thank you!


I don't know about the zope.interfaces question.


Disclaimer: Many (most?) Pyramid apps, even ones that use traversal, never 
need to use interfaces.  You can build all sorts of useful stuff w/o 
interfaces.  If you don't want to know about interfaces, please happily 
pretend they don't exist, and don't read any further.


For those of you still interested, however, interfaces can be useful when you 
want more pluggability.  In most of Pyramid's traversal examples, views are 
registered against resource classes, so the edit view for a BlogPost class 
would be different than the edit view for a User class, which would be 
different again from the edit view for a Photo class.  But what if all of your 
different resource types support tags, and you have a single ``tags`` view 
that would work for all of them?  You could register the same view 3 times, 
for 3 different context types.  Or you could register your view against an 
ITaggable interface:


  from myproject.interfaces import ITaggable
  @view_config(name='tags', context=ITaggable)
  def tags_view(request):
  context = request.context
  ... {do tags stuff here } ..


Now you'd declare that all of the taggable resource types support the 
ITaggable interface, by putting an ``implements(ITaggable)`` in the class 
definition, like so:


  from zope.interface import implements
  from myproject.interfaces import ITaggable
  class BlogPost(object):
  implements(ITaggable)
  def __init__(self):
  ... {do blogpost stuff here} ...

If you're building a framework of some sort, then someone else who develops a 
taggable custom resource type can get the tags view for free by adding the 
``implements(ITaggable)`` line to their class definition.


Note that interfaces used as such are really just flags on the class; an 
interface doesn't actually have to define an API.  In fact, an interface can 
be completely empty:


  from zope.interface import Interface
  class ITaggable(Interface):
  pass

An interface CAN define an API, however.  If it does so, then any class that 
declares support for the interface should implement the specified API.  This 
will not be enforced... you can lie about it and declare a class to support an 
interface when it actually doesn't.  Not typically a good idea, though.  ;)


-r

--
You received this message because you are subscribed to the Google Groups 
pylons-discuss group.
To post to this group, send email to pylons-discuss@googlegroups.com.
To unsubscribe from this group, send email to 
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.



Re: Using DB-API with Pyramid

2011-02-10 Thread Rob Miller

On 2/10/11 6:40 PM, Christopher Weimann wrote:

I'm using DB-API in my Pylons app as described in on this wiki page.

http://wiki.pylonshq.com/display/pylonscookbook/Using+the+DB-API+in+Pylons

The gist of which is  to add the following to lib/app_globals.py

from pylons import config
import psycopg2
from DBUtils.PooledDB import PooledDB

class Globals(object):
 def __init__(self):
 self.pool = PooledDB( psycopg2, 5,
 database=config['app_conf']['pool.database'],
 user=config['app_conf']['pool.user'],
 host=config['app_conf']['pool.host']
 )

then in a controller you can get a connection with conn = g.pool.connection()

How would I do the equivalent with Pyramid?


This is untested, but i think you could do something like this in your 
startup code::


  from pyramid.registry import global_registry
  global_registry.pool = PooledDB(...)

Then in your view code, or anywhere you have a request object, you 
should be able to get at it via `request.registry.pool`.


-r

--
You received this message because you are subscribed to the Google Groups 
pylons-discuss group.
To post to this group, send email to pylons-discuss@googlegroups.com.
To unsubscribe from this group, send email to 
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.



Re: pyramid doc bugs/requests/suggestions

2011-02-06 Thread Rob Miller

On 02/06/2011 12:45 PM, Iain Duncan wrote:

I'm a reasonably competent BFG user who was a pylons user before that, and am
now going through the pyramid docs. Can someone tell me where I should send
details of mistakes, typos, or things that could be clearer?


The sphinx source for the docs are in the source tree, which is on github. 
You can file bug reports on the github tracker, or (even better) clone the 
repo, make some edits, and make a pull request to have your changes reviewed.  :)


-r

--
You received this message because you are subscribed to the Google Groups 
pylons-discuss group.
To post to this group, send email to pylons-discuss@googlegroups.com.
To unsubscribe from this group, send email to 
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.



Re: [Pylons 1.0] Decomposing complex actions, DB queries in model's methods

2011-01-21 Thread Rob Miller

On 01/21/2011 01:47 AM, Andrey Popp wrote:

Hello,

On Jan 21, 2011, at 1:48 AM, Juliusz Gonera wrote:


Is it considered bad practice to make DB queries in model's methods? Or is this 
the way to go?


Yes, it's a bad practice in general -- model should be persistence-agnostic.


for the record, there are lots of folks who disagree with this statement. 
while there are certainly cases where the extra abstractions that you detail 
below are useful, IMHO they're overkill for most applications, which are only 
intended to work w/ a single persistence engine and which gain little benefit 
from the added complexity.


-r


And even if you're not planning to use the same models with different storage 
options or outside of SQLAlchemy context, I still recommend you to separate 
queries and data manipulation routines in separate class -- ModelManager, 
ModelRepository, ...

The rules that I follow are:

   * If function operates on entire table (insert something into table, query 
from table or etc.) -- it should become a member or model's manager.

   * If function is a part of behavior of model (in a sense of its domain)-- it 
should become model's method.

So, I think it's worth to delegate such relationship management to model's 
manager:

   class MainModelManager(object):

   def add_some_related_object(self, main_obj, param1, param2):
   # query something
   related = SomeRelatedObject()
   main_obj.some_related_objects.append(related)

If you think, that this method would require also some participation of main 
model's inner state, you can replace 
`main_obj.some_related_objects.append(related)` with special method of 
MainModel:

class MainModel(object):
def add_some_related_object(self, related):
   # some business logic, which is not require database access
   main_obj.some_related_objects.append(related)

   class MainModelManager(object):

   def add_some_related_object(self, main_obj, param1, param2):
   # query something
   related = SomeRelatedObject()
   main_obj.add_some_related_objects(related)

This way you can separate business logic from persistence.

It also helps to provide better testability of you code, cause you can test 
domain logic inside `MainModel.add_some_related_object` without requiring 
existence of test SQL database.



--
You received this message because you are subscribed to the Google Groups 
pylons-discuss group.
To post to this group, send email to pylons-discuss@googlegroups.com.
To unsubscribe from this group, send email to 
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.



Re: [Pylons 1.0] Decomposing complex actions, DB queries in model's methods

2011-01-21 Thread Rob Miller

On 1/21/11 9:31 AM, Juliusz Gonera wrote:

Rob Miller wrote:


for the record, there are lots of folks who disagree with this
statement. while there are certainly cases where the extra abstractions
that you detail below are useful, IMHO they're overkill for most
applications, which are only intended to work w/ a single persistence
engine and which gain little benefit from the added complexity.


I'm also a bit scared of this because I don't want my Pylons app to look
like Spring or EJB app ;) It looks a bit like the anemic model
anti-pattern:
http://martinfowler.com/bliki/AnemicDomainModel.html

I mean, making separate manager object could be useful, but I'm 99% sure
that I won't replace SQLAlchemy with something else.

I just remember reading that using SQLAlchemy queries makes transition
to Pyramid harder.


do you happen to remember where you read this?  i wouldn't think this 
would be the case.  while the sqlalchemy idioms used in the 
documentation and/or paster templates might vary a bit btn pylons and 
pyramid (specifically pyramid usually shows the use of the repoze.tm2 
middleware to handle transaction commits), neither framework actually 
has any formal opinion about how persistence should be handled, and i 
can't think of any reason why you'd have to make any significant changes 
to how you interact w/ the database when porting from one to the other.



This also isn't something I would worry about, but I
just wondered if using the Session object in model is actually a bad
practice.


i don't see anything inherently wrong w/ it, as long as you're willing 
to accept the repercussions: you'll be more closely tied to sqlalchemy, 
and you'll have to either provide or mock a database session in order to 
test your models.


-r

--
You received this message because you are subscribed to the Google Groups 
pylons-discuss group.
To post to this group, send email to pylons-discuss@googlegroups.com.
To unsubscribe from this group, send email to 
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.



Re: [Pylons 1.0] Decomposing complex actions, DB queries in model's methods

2011-01-21 Thread Rob Miller

On 1/20/11 11:36 PM, Nathan Wright wrote:

As Mariano was saying, it might be possible save yourself some trouble
by using mappers directly instead of DeclarativeBase. You'd likely be
able to make your python objects easier to work with because they won't
be tied 1-to-1 to the schema that you're building on. This isn't about
defining relations so much as composing your mapped classes into their
most logical form. A single mapped class can span multiple tables or do
practically whatever else you want. YMMV but it's worth a look.


this!  sqlalchemy is deliberately very flexible, and it allows you to 
have nice separation between your data model and your object model.  you 
might pay a performance hit for this abstraction, of course, but in many 
(most?) cases it's an acceptable one.


sqlalchemy is the only ORM i've used with which i've never had to make 
any design compromises.  i can put together my table structures and my 
object models separately, and then wire them up with mappers so they 
work as desired.  and i've done some pretty weird stuff, where the 
attributes for a given class were actually dynamically generated by an 
attributes table, with a separate table storing the values of these 
attributes.  i had to dig in pretty deeply (i had to implement my own 
MappedCollection subclass to handle some tricky relationships between 
my models), but it worked like a charm when i fully expected it to be 
impossible.


-r

--
You received this message because you are subscribed to the Google Groups 
pylons-discuss group.
To post to this group, send email to pylons-discuss@googlegroups.com.
To unsubscribe from this group, send email to 
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.



Re: setup.py

2011-01-14 Thread Rob Miller

On 01/14/2011 07:05 PM, webjunkie wrote:

I'm in the process of deploying my app, and when I take a look at setup.py I
see that the install_requires section only has Pylons and SQLAlchemy but I've
been installing other components through easy install like
turbomail,repoze.who, etc. Why they don't show up in the install_requires
section?, do I have to type them manually?, is there a way to update
install_requires in setup.py when you add new components?.


as mentioned, your project's setup.py doesn't get automatically updated, 
tracking dependencies is primarily a manual process.


however, if you've got a virtualenv that has only your requirements installed, 
you can use pip freeze to generate a list of the installed packages.  then 
you can either use this as a requirements file for future installs w/ pip, or 
you can extract the pertinent package info and put it into your package's 
setup.py.


-r

--
You received this message because you are subscribed to the Google Groups 
pylons-discuss group.
To post to this group, send email to pylons-discuss@googlegroups.com.
To unsubscribe from this group, send email to 
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.



Re: setup.py

2011-01-14 Thread Rob Miller

On 01/14/2011 10:23 PM, Rob Miller wrote:

On 01/14/2011 07:05 PM, webjunkie wrote:

I'm in the process of deploying my app, and when I take a look at setup.py I
see that the install_requires section only has Pylons and SQLAlchemy but I've
been installing other components through easy install like
turbomail,repoze.who, etc. Why they don't show up in the install_requires
section?, do I have to type them manually?, is there a way to update
install_requires in setup.py when you add new components?.


as mentioned, your project's setup.py doesn't get automatically updated,
tracking dependencies is primarily a manual process.

however, if you've got a virtualenv that has only your requirements installed,
you can use pip freeze to generate a list of the installed packages. then
you can either use this as a requirements file for future installs w/ pip, or
you can extract the pertinent package info and put it into your package's
setup.py.


whoops, meant to include this url:

http://pip.openplans.org/#freezing-requirements

-r

--
You received this message because you are subscribed to the Google Groups 
pylons-discuss group.
To post to this group, send email to pylons-discuss@googlegroups.com.
To unsubscribe from this group, send email to 
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.



Much Ado About Traversal

2010-12-31 Thread Rob Miller
Since resource traversal is a new concept to most Pylons-ers, and since 
it's clear that many folks are having a hard time understanding it and 
why they'd want to use it, I decided to write up an article demystifying 
the topic:


http://blog.nonsequitarian.org/2010/much-ado-about-traversal/

It was conveniently also an excuse for me to finally get off my ass and 
get a blog together... I'm still working out the kinks and getting feeds 
set up, but I hope to get it wired through Planet Python soon.  Expect 
more posts on Pyramid-related topics in the future.


-r

--
You received this message because you are subscribed to the Google Groups 
pylons-discuss group.
To post to this group, send email to pylons-disc...@googlegroups.com.
To unsubscribe from this group, send email to 
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.



Re: Pyramid Traversal

2010-12-30 Thread Rob Miller

On 12/30/10 5:15 PM, Burak Cankurtaran wrote:

Thanks Rob,

I'll look into using the predicates to narrow down the traversal.
I guess in the future there will be higher-level wrappers built
into pyramid to hide the resource tree etc when it is only
used for URL matching.


Not sure what you mean here.  If you're only doing URL matching, there 
IS no resource tree.  A resource tree is only in play when you're using 
traversal, in which case you most certainly don't want to hide it.



P.S The reason I'm not using URL dispatch is because my problem
is not properly defined yet. Traversal seems more powerful than
URL dispatch even though I can't fully yet appreciate/comprehend
using traversal as a persistent data store, so better safe than sorry.


If your problem isn't properly defined, you probably shouldn't yet be 
building software to solve it.  Traversal is preferable to URL matching 
in a handful of well-defined cases:


  - your URL structures may be nested arbitrarily deep
  - your users may be modifying your URL structures at run-time, e.g. 
w/ a CMS-type application, where people are adding new content in a 
specific place.  (note that this is really a special case of the first 
condition.)
  - you need context-sensitive ACL type (sometimes known as 
instance-based or row-level) security.


If you have none of these requirements, then URL matching is probably a 
better bet for you.


-r




Happy New Year!


On 31 December 2010 05:23, Rob Millerr...@kalistra.com  wrote:

On 12/30/10 6:43 AM, Burak Cankurtaran wrote:


Hi,

I'm new to python and pyramid. I am currently trying to get traversal
working. I started with
the pyramid_starter project template. Currently there is the default
view generated by the
template and a Welcome view I created. Question at bottom of post.

The views.py module:

#
from pyramid.response import Response

def my_view(request):
 return {'project':'test'}

def welcome(request):
 return Response(Welcome)
###

My resource tree is generated in the resources.py module:

###
class Resource(dict):
 pass

root = Resource({'Welcome': Resource()})

def get_root(request):
 return root

###

and the views are configured in the __init__ module as:

###
from pyramid.config import Configurator
from test.resources import get_root, Resource

def main(global_config, **settings):
  This function returns a Pyramid WSGI application.
 
 config = Configurator(root_factory=get_root, settings=settings)

 config.add_view('test.views.my_view',
 context='test.Resource',
 renderer='test:templates/mytemplate.pt')


if i'm understanding correctly, the context here should actually be
'test:resources.Resource', correct?


 config.add_view('test.views.welcome',
 context='test:resources.Resource',
 renderer='welcome.mak')

 config.add_static_view('static', 'test:static')
 return config.make_wsgi_app()
##

I am having issues with the context of the welcome view configuration.
As you can see it is
defined as context='test:resources.Resource' which is the same as
my_view.

I realise that the context must somehow reference the Welcome resource
in the resource tree.


Actually, this isn't quite true.  A view context must be a class or an
interface, not an instance.  Another way to put this is that, with the
context predicate, you're registering views against particular _types_ of
objects, not specific instances.

Let's suppose that you do want to register the welcome view so that it only
shows up on your Welcome object and no other one.  You've got a couple of
options.  You could define a Welcome class::

  class Welcome(Resource):
  Empty subclass used for view registration

then you'd define your root like so::

  root = Resource({'Welcome': Welcome()})

and your view registration would look like this::

  config.add_view('test.views.welcome',
  context='test:resources.Welcome',
  renderer='welcome.mak')

That'd work, but if that's the only ``Welcome`` object you're going to have
in the entire site, it smells a bit funny to be creating a subclass just for
the view registration.  Luckily, you can use any of the other view
predicates (see
http://docs.pylonshq.com/pyramid/dev/narr/views.html#predicate-arguments).
  In this case, you'd still use ``test:resources.Resource`` as the context.
  But then you could use the ``path_info`` predicate to check that the
request path starts with ``/Welcome``.  Or you could pass in a
``custom_predicates`` with a single callable that will simply check to see
whether the context is the object you expect it to be.


However, I cannot use something like test:resources.Resource.Welcome
as Welcome is not
a member of the Resource class.

Can somebody point out what I should do get this simple case working.
I am having difficulties
in constructing a proper and well defined resource tree. Maybe I 

Re: Adventures in Pylons - Pyramid: WSGIController.__call__

2010-12-14 Thread Rob Miller

On 12/14/10 9:25 AM, Chris McDonough wrote:

In trying to think this through I've come up w/ a couple of ideas:

- I could write my own set of action decorators that implement the
desired functionality in addition to marking the wrapped functions as
exposed actions.  This would essentially be the same thing as stacking
multiple decorators around each of the functions, except that it avoids
having to stack multiple decorators around each of the functions.  ;)

- I could override the router itself, to allow me to keep the wrapped
functionality closer to the WSGI level.  Pyramid doesn't really provide
any hooks for this, however.  It'd be easy enough to change Pyramid to
fetch the router by interface rather than by class, making it possible
to supply an alternate router implementation, but there's a lot of code
in that __call__ method; I'm not terribly fond of copy/pasting large
blocks of code only to add a handful of additional lines to the middle
somewhere.

Does anyone have any other suggestions?  Opinions on the suggestions
I've made?  Has anybody out there thought about how to handle this
pattern in a Pyramid upgrade?


This is probably not a 100% solution, but have you seen
http://docs.pylonshq.com/pyramid/dev/narr/hooks.html#using-finished-callbacks ?


Yeah, I saw both the response and the finished callbacks, and am already 
using them for other purposes.  But, as you said, they don't handle all 
of the cases, especially not those where try: excepts are put around the 
entire WSGIController.__call__ invocation.


Right now I'm leaning towards using a custom @action decorator.  This 
decorator would call a method on the handler that would wrap the view 
callable before adding the view callable to the registry.  I'll let you 
know how it turns out.


-r

--
You received this message because you are subscribed to the Google Groups 
pylons-discuss group.
To post to this group, send email to pylons-disc...@googlegroups.com.
To unsubscribe from this group, send email to 
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.



Re: Adventures in Pylons - Pyramid: WSGIController.__call__

2010-12-14 Thread Rob Miller

On 12/14/10 11:24 AM, Chris McDonough wrote:

On Tue, 2010-12-14 at 10:36 -0800, Rob Miller wrote:

On 12/14/10 9:25 AM, Chris McDonough wrote:

In trying to think this through I've come up w/ a couple of ideas:

- I could write my own set of action decorators that implement the
desired functionality in addition to marking the wrapped functions as
exposed actions.  This would essentially be the same thing as stacking
multiple decorators around each of the functions, except that it avoids
having to stack multiple decorators around each of the functions.  ;)

- I could override the router itself, to allow me to keep the wrapped
functionality closer to the WSGI level.  Pyramid doesn't really provide
any hooks for this, however.  It'd be easy enough to change Pyramid to
fetch the router by interface rather than by class, making it possible
to supply an alternate router implementation, but there's a lot of code
in that __call__ method; I'm not terribly fond of copy/pasting large
blocks of code only to add a handful of additional lines to the middle
somewhere.

Does anyone have any other suggestions?  Opinions on the suggestions
I've made?  Has anybody out there thought about how to handle this
pattern in a Pyramid upgrade?


This is probably not a 100% solution, but have you seen
http://docs.pylonshq.com/pyramid/dev/narr/hooks.html#using-finished-callbacks ?


Yeah, I saw both the response and the finished callbacks, and am already
using them for other purposes.  But, as you said, they don't handle all
of the cases, especially not those where try: excepts are put around the
entire WSGIController.__call__ invocation.

Right now I'm leaning towards using a custom @action decorator.  This
decorator would call a method on the handler that would wrap the view
callable before adding the view callable to the registry.  I'll let you
know how it turns out.


I'd probably do it the other way around:

@view_config(...)
@mydecorator(...)
def aview(request):
 ...

or

class AHandler(object):
 def __init__(self, request):
 self.request = request

 @action()
 @mydecorator(...)
 def aview(self):

Both cases would add the *decorated* function / method to the registry,
which is probably what you want (the @action and @view_config
dectorators just attach attributes to the function / method, they don't
actually wrap the callable when it is called).


Yeah, that's essentially what I meant, sorry for being unclear.  I'm 
thinking a bit more syntactic sugar, though, something along the lines of:


class AHandler(object):
def __init__(self, request):
self.request = request

@classmethod
def _action_wrapper(klass, wrapped):
def action_method_wrapper(self, *args, **kw):
do stuff
ret = wrapped(self, *args, **kw)
do more stuff
return ret
return action_method_wrapper

@myaction(...)
def aview(self):
regular view code

Then the myaction decorator would call AHandler._action_wrapper(aview) 
to generate a wrapped view callable, which would then finally be 
registered.  This is only half-baked; I'm not even sure I can _get_ to 
the AHandler class from within the myaction decorator yet, but if I can 
then this would let me mirror the existing controller class hierarchy 
with a set of handler classes, moving the code from the older __call__ 
methods to the newer _action_wrapper class methods w/o too much of a 
conceptual leap.


does this seem like it would work?

-r

--
You received this message because you are subscribed to the Google Groups 
pylons-discuss group.
To post to this group, send email to pylons-disc...@googlegroups.com.
To unsubscribe from this group, send email to 
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.



Adventures in Pylons - Pyramid: WSGIController.__call__

2010-12-10 Thread Rob Miller

Hi all,

So I've started taking a look at what it would take to port a large 
suite of Pylons 0.9.6 apps to Pyramid.  Most of what needs to happen 
looks pretty straightforward; we'd need to convert all of the routes 
wiring to the new handler / action mechanisms, and make some superficial 
changes to the code within the action methods.  Maybe a bit painstaking 
and repetitive, but not particularly mind-bending.


There's one pattern in use that presents a bigger problem, however. 
These apps have a shared set of controller base classes, from which the 
actual controller implementations within the apps themselves inherit. 
Some of what happens in these controller base classes is just additional 
API stuff, fairly easily converted to a parallel set of handler base 
classes.


The tricky parts, though, are the cases where these controllers have 
overridden the __call__ method to effectively wrap the entire WSGI 
invocation to do such handy things as logging, caching, and error 
handling.  This isn't easy to replicate, because with Pyramid there's no 
way to get control of the outer layers of the request processing cycle 
like there is with Pylons (see 
http://docs.pylonshq.com/pyramid/dev/narr/router.html).


In trying to think this through I've come up w/ a couple of ideas:

- I could write my own set of action decorators that implement the 
desired functionality in addition to marking the wrapped functions as 
exposed actions.  This would essentially be the same thing as stacking 
multiple decorators around each of the functions, except that it avoids 
having to stack multiple decorators around each of the functions.  ;)


- I could override the router itself, to allow me to keep the wrapped 
functionality closer to the WSGI level.  Pyramid doesn't really provide 
any hooks for this, however.  It'd be easy enough to change Pyramid to 
fetch the router by interface rather than by class, making it possible 
to supply an alternate router implementation, but there's a lot of code 
in that __call__ method; I'm not terribly fond of copy/pasting large 
blocks of code only to add a handful of additional lines to the middle 
somewhere.


Does anyone have any other suggestions?  Opinions on the suggestions 
I've made?  Has anybody out there thought about how to handle this 
pattern in a Pyramid upgrade?


Thanks!

-r

--
You received this message because you are subscribed to the Google Groups 
pylons-discuss group.
To post to this group, send email to pylons-disc...@googlegroups.com.
To unsubscribe from this group, send email to 
pylons-discuss+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.