Re: [pylons-discuss] Question about creating routes

2024-03-14 Thread Laurent Daverio
Thank you so much Theron, this is spot-on!

So, it was lambda after all (although not Pyramid). You've solved my
problem, I can move on to the next 😅

Thanks again,

Laurent.

Le jeu. 14 mars 2024 à 06:57, Theron Luhn  a écrit :

> That’s a result of the lack of block scoping in Python.  `op` is going to
> resolve when the lambda first executes, which is always after the loop has
> finished, and scoped to the containing function so `op` will always be the
> final loop value.
>
> Easiest workaround is to just wrap the loop contents in a function, so you
> get a fresh scope for each permutation.
>
> def make_routes(config, cat, op):
> config.add_route…
>
> for cat in ('actes', 'constats'):
> for op in ('archive', 'unarchive’):
>make_routes(config, cat, op)
>
>
> — Theron
>
>
>
> On Mar 13, 2024, at 4:36 PM, Laurent Daverio  wrote:
>
> Thank you everybody, I'll try to set up a working example tomorrow.
>
> Actually you're right, my question was formulated incorrectly, it may not
> be a question of lambdas. Basically, I was trying to create a series of
> routes in a reasonably concise way, something like this : 2 types of
> objects (actes, constats), 2 operations (archive, unarchive), 2 variants
> (handle one object, or handle a list of ids):
>
> - /actes/{id}/archive
> - /actes/{id}/unarchive
> - /constats/{id}/archive
> - /constats/{id}/unarchive
> - /actes/-/archive_selection
> - /actes/-/unarchive_selection
> - /constats/-/archive_selection
> - /constats/-/unarchive_selection
>
> ```
>
>
> factories = {'actes':{'fact': acte_factory,
>   'rsrc': ActeResource},
>  'constats': {'fact': constat_factory,
>   'rsrc': ConstatResource}}
>
> functions = {'archive':   (_archive, _archive_multi),
>  'unarchive': (_unarchive, _unarchive_multi)}
>
> for cat in ('actes', 'constats'):
> for op in ('archive', 'unarchive'):
>
> route_name: str = f'api.{cat}.{op}'
>
> config.add_route(route_name, f'/{cat}/{{id}}/{op}', 
> factory=factories[cat]['fact'])
> config.add_view(functions[op][0], route_name=route_name, 
> request_method='GET', renderer='json')
>
> config.add_route(route_name + '_selection', 
> f'/{cat}/-/{op}_selection')
> config.add_view(
> lambda request: functions[op][1](request, factories[cat]['rsrc']),
> route_name=route_name + '_selection', request_method='POST', 
> renderer='json')
>
> ```
>
> The first 4 routes (those with "{id}" in them) worked fine, but last 4
> (those using lambdas) were all mapped to the same function
> (`_unarchive_multi`) in the end.
>
> In order to make them work, I had to unroll the loops and enumerate
> everything. Ugly :(
>
> ```
>
> config.add_route('api.actes.archive_selection', '/actes/-/archive_selection')
> config.add_route('api.constats.archive_selection', 
> '/constats/-/archive_selection')
> config.add_view(
> lambda request: _archive_multi(request, ActeResource),
> route_name='api.actes.archive_selection', request_method='POST', 
> renderer='json')
> config.add_view(
> lambda request: _archive_multi(request, ConstatResource),
> route_name='api.constats.archive_selection', request_method='POST', 
> renderer='json')
>
> config.add_route('api.actes.unarchive_selection', 
> '/actes/-/unarchive_selection')
> config.add_route('api.constats.unarchive_selection', 
> '/constats/-/unarchive_selection')
> config.add_view(
> lambda request: _unarchive_multi(request, ActeResource),
> route_name='api.actes.unarchive_selection', request_method='POST', 
> renderer='json')
> config.add_view(
> lambda request: _unarchive_multi(request, ConstatResource),
> route_name='api.constats.unarchive_selection', request_method='POST', 
> renderer='json')
>
> ```
>
> Laurent.
>
>
>
> --
> You received this message because you are subscribed to the Google Groups
> "pylons-discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/pylons-discuss/CAB7cU6wqp1fSXJ_6ngOBqOw2RSSTxzjAZwGoyYsoDa58OdJkPg%40mail.gmail.com
> 
> .
>
>
> --
> You received this message because you are subscribed to the Google Groups
> "pylons-discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/pylons-discuss/EFA14C22-E728-43D0-A25A-30157E698935%40luhn.com
> 
> .
>

-- 
You received this message because you are subscribed to 

Re: [pylons-discuss] Question about creating routes

2024-03-13 Thread Theron Luhn
That’s a result of the lack of block scoping in Python.  `op` is going to 
resolve when the lambda first executes, which is always after the loop has 
finished, and scoped to the containing function so `op` will always be the 
final loop value.

Easiest workaround is to just wrap the loop contents in a function, so you get 
a fresh scope for each permutation.

def make_routes(config, cat, op):
config.add_route…

for cat in ('actes', 'constats'):
for op in ('archive', 'unarchive’):
   make_routes(config, cat, op)


— Theron



> On Mar 13, 2024, at 4:36 PM, Laurent Daverio  wrote:
> 
> Thank you everybody, I'll try to set up a working example tomorrow.
> 
> Actually you're right, my question was formulated incorrectly, it may not be 
> a question of lambdas. Basically, I was trying to create a series of routes 
> in a reasonably concise way, something like this : 2 types of objects (actes, 
> constats), 2 operations (archive, unarchive), 2 variants (handle one object, 
> or handle a list of ids):
> 
> - /actes/{id}/archive
> - /actes/{id}/unarchive
> - /constats/{id}/archive
> - /constats/{id}/unarchive
> - /actes/-/archive_selection
> - /actes/-/unarchive_selection
> - /constats/-/archive_selection
> - /constats/-/unarchive_selection
> 
> ```
> 
> factories = {'actes':{'fact': acte_factory,
>   'rsrc': ActeResource},
>  'constats': {'fact': constat_factory,
>   'rsrc': ConstatResource}}
> 
> functions = {'archive':   (_archive, _archive_multi),
>  'unarchive': (_unarchive, _unarchive_multi)}
> 
> for cat in ('actes', 'constats'):
> for op in ('archive', 'unarchive'):
>  
> route_name: str = f'api.{cat}.{op}'
>  
> config.add_route(route_name, f'/{cat}/{{id}}/{op}', 
> factory=factories[cat]['fact'])
> config.add_view(functions[op][0], route_name=route_name, 
> request_method='GET', renderer='json')
> 
> config.add_route(route_name + '_selection', 
> f'/{cat}/-/{op}_selection')
> config.add_view(
> lambda request: functions[op][1](request, factories[cat]['rsrc']),
> route_name=route_name + '_selection', request_method='POST', 
> renderer='json')
> 
> ```
> 
> The first 4 routes (those with "{id}" in them) worked fine, but last 4 (those 
> using lambdas) were all mapped to the same function (`_unarchive_multi`) in 
> the end.
> 
> In order to make them work, I had to unroll the loops and enumerate 
> everything. Ugly :(
> 
> ```
> config.add_route('api.actes.archive_selection', '/actes/-/archive_selection')
> config.add_route('api.constats.archive_selection', 
> '/constats/-/archive_selection')
> config.add_view(
> lambda request: _archive_multi(request, ActeResource),
> route_name='api.actes.archive_selection', request_method='POST', 
> renderer='json')
> config.add_view(
> lambda request: _archive_multi(request, ConstatResource),
> route_name='api.constats.archive_selection', request_method='POST', 
> renderer='json')
> 
> config.add_route('api.actes.unarchive_selection', 
> '/actes/-/unarchive_selection')
> config.add_route('api.constats.unarchive_selection', 
> '/constats/-/unarchive_selection')
> config.add_view(
> lambda request: _unarchive_multi(request, ActeResource),
> route_name='api.actes.unarchive_selection', request_method='POST', 
> renderer='json')
> config.add_view(
> lambda request: _unarchive_multi(request, ConstatResource),
> route_name='api.constats.unarchive_selection', request_method='POST', 
> renderer='json')
> ```
> 
> Laurent.
> 
> 
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "pylons-discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to [email protected] 
> .
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/pylons-discuss/CAB7cU6wqp1fSXJ_6ngOBqOw2RSSTxzjAZwGoyYsoDa58OdJkPg%40mail.gmail.com
>  
> .

-- 
You received this message because you are subscribed to the Google Groups 
"pylons-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/pylons-discuss/EFA14C22-E728-43D0-A25A-30157E698935%40luhn.com.


Re: [pylons-discuss] Question about creating routes

2024-03-13 Thread Laurent Daverio
Thank you everybody, I'll try to set up a working example tomorrow.

Actually you're right, my question was formulated incorrectly, it may not
be a question of lambdas. Basically, I was trying to create a series of
routes in a reasonably concise way, something like this : 2 types of
objects (actes, constats), 2 operations (archive, unarchive), 2 variants
(handle one object, or handle a list of ids):

- /actes/{id}/archive
- /actes/{id}/unarchive
- /constats/{id}/archive
- /constats/{id}/unarchive
- /actes/-/archive_selection
- /actes/-/unarchive_selection
- /constats/-/archive_selection
- /constats/-/unarchive_selection

```


factories = {'actes':{'fact': acte_factory,
  'rsrc': ActeResource},
 'constats': {'fact': constat_factory,
  'rsrc': ConstatResource}}

functions = {'archive':   (_archive, _archive_multi),
 'unarchive': (_unarchive, _unarchive_multi)}

for cat in ('actes', 'constats'):
for op in ('archive', 'unarchive'):

route_name: str = f'api.{cat}.{op}'

config.add_route(route_name, f'/{cat}/{{id}}/{op}',
factory=factories[cat]['fact'])
config.add_view(functions[op][0], route_name=route_name,
request_method='GET', renderer='json')

config.add_route(route_name + '_selection', f'/{cat}/-/{op}_selection')
config.add_view(
lambda request: functions[op][1](request, factories[cat]['rsrc']),
route_name=route_name + '_selection',
request_method='POST', renderer='json')

```

The first 4 routes (those with "{id}" in them) worked fine, but last 4
(those using lambdas) were all mapped to the same function
(`_unarchive_multi`) in the end.

In order to make them work, I had to unroll the loops and enumerate
everything. Ugly :(

```

config.add_route('api.actes.archive_selection', '/actes/-/archive_selection')
config.add_route('api.constats.archive_selection',
'/constats/-/archive_selection')
config.add_view(
lambda request: _archive_multi(request, ActeResource),
route_name='api.actes.archive_selection', request_method='POST',
renderer='json')
config.add_view(
lambda request: _archive_multi(request, ConstatResource),
route_name='api.constats.archive_selection',
request_method='POST', renderer='json')

config.add_route('api.actes.unarchive_selection',
'/actes/-/unarchive_selection')
config.add_route('api.constats.unarchive_selection',
'/constats/-/unarchive_selection')
config.add_view(
lambda request: _unarchive_multi(request, ActeResource),
route_name='api.actes.unarchive_selection', request_method='POST',
renderer='json')
config.add_view(
lambda request: _unarchive_multi(request, ConstatResource),
route_name='api.constats.unarchive_selection',
request_method='POST', renderer='json')

```

Laurent.

-- 
You received this message because you are subscribed to the Google Groups 
"pylons-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/pylons-discuss/CAB7cU6wqp1fSXJ_6ngOBqOw2RSSTxzjAZwGoyYsoDa58OdJkPg%40mail.gmail.com.


Re: [pylons-discuss] Question about creating routes

2024-03-13 Thread Michael Merickel
Laurent, what error do you get? I'm not immediately aware of limitations
around using lambdas in Pyramid. This example below works fine with a
lambda as a view:

from pyramid.config import Configurator
from waitress import serve

config = Configurator()
config.add_route('foo', '/')
config.add_view(lambda req: 'foo', route_name='foo', renderer='string')
app = config.make_wsgi_app()
serve(app, listen='*:8080')

On Wed, Mar 13, 2024 at 2:26 PM Mike Orr  wrote:

> I'm not an expert in this, but I think the maybe-resolve functions
> only do lookups when the spec is a string, and pass non-strings
> through unchanged. As far as I know lambdas are regular functions, so
> I'd expect it to pass them through like view callable functions. Maybe
> another exception is occurring, and when Python tries to print the
> traceback, it can't find the lambda's source.
>
> I generally use regular functions instead of lambdas, but I realize
> this is a stylistic choice and some think otherwise. A partial might
> work in your use case:
> config.add_view( functools.partial(_delete_multi,
> arg2_keyword=Doc2Resource) , ...
>
> On Wed, Mar 13, 2024 at 10:50 AM Laurent Daverio 
> wrote:
> >
> > Hello list,
> >
> > it seems that Google is allowing me to post on here again. A couple of
> weeks ago, I was banned, both from emailing the list, AND from posting on
> the web group 💩
> >
> > I am trying to create a series of routes based on lambda functions,
> something like:
> >
> > ```
> > config.add_route('doc1.delete_selection', '/doc1/-/delete_selection')
> > config.add_route('doc2.delete_selection', '/doc2/-/delete_selection')
> > config.add_view(
> > lambda request: _delete_multi(request, Doc1Resource),
> > route_name='doc1.delete_selection', request_method='POST',
> renderer='json')
> > config.add_view(
> > lambda request: _delete_multi(request, Doc2Resource),
> > route_name='doc2.delete_selection', request_method='POST',
> renderer='json')
> > ```
> >
> > (I also have `archive_selection` and `unarchive_selection` routes)
> >
> > I'm under the impression that `config.add_view` can't take lambda
> functions as arguments, as it tries to resolve their names ("maybe_dotted",
> "maybe_resolve", etc.). All I can say it that the views seem to be calling
> the wrong functions. This prevents me from using for loops and lambda for
> generating the routes in a more concise way :/
> >
> > Could anyone confirm if I'm correct?
> >
> > Many thanks,
> >
> > Laurent.
> >
> > --
> > You received this message because you are subscribed to the Google
> Groups "pylons-discuss" group.
> > To unsubscribe from this group and stop receiving emails from it, send
> an email to [email protected].
> > To view this discussion on the web visit
> https://groups.google.com/d/msgid/pylons-discuss/CAB7cU6y56gx3fDEGsdx3qFJKTVPOM5yN1maohu8tEESRnY2ygQ%40mail.gmail.com
> .
>
>
>
> --
> Mike Orr 
>
> --
> You received this message because you are subscribed to the Google Groups
> "pylons-discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/pylons-discuss/CAH9f%3Duq3ENBFg13AfwbH%2BivU2yzP7zORkRAREJefS0Wg1MAJaQ%40mail.gmail.com
> .
>


-- 

Michael

-- 
You received this message because you are subscribed to the Google Groups 
"pylons-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/pylons-discuss/CAKdhhwECMJJyV1C9PcHET0%3DuGiQSbz09%2BP%2B8hyyPx4wL6W%3DUPg%40mail.gmail.com.


Re: [pylons-discuss] Question about creating routes

2024-03-13 Thread Mike Orr
I'm not an expert in this, but I think the maybe-resolve functions
only do lookups when the spec is a string, and pass non-strings
through unchanged. As far as I know lambdas are regular functions, so
I'd expect it to pass them through like view callable functions. Maybe
another exception is occurring, and when Python tries to print the
traceback, it can't find the lambda's source.

I generally use regular functions instead of lambdas, but I realize
this is a stylistic choice and some think otherwise. A partial might
work in your use case:
config.add_view( functools.partial(_delete_multi,
arg2_keyword=Doc2Resource) , ...

On Wed, Mar 13, 2024 at 10:50 AM Laurent Daverio  wrote:
>
> Hello list,
>
> it seems that Google is allowing me to post on here again. A couple of weeks 
> ago, I was banned, both from emailing the list, AND from posting on the web 
> group 💩
>
> I am trying to create a series of routes based on lambda functions, something 
> like:
>
> ```
> config.add_route('doc1.delete_selection', '/doc1/-/delete_selection')
> config.add_route('doc2.delete_selection', '/doc2/-/delete_selection')
> config.add_view(
> lambda request: _delete_multi(request, Doc1Resource),
> route_name='doc1.delete_selection', request_method='POST', 
> renderer='json')
> config.add_view(
> lambda request: _delete_multi(request, Doc2Resource),
> route_name='doc2.delete_selection', request_method='POST', 
> renderer='json')
> ```
>
> (I also have `archive_selection` and `unarchive_selection` routes)
>
> I'm under the impression that `config.add_view` can't take lambda functions 
> as arguments, as it tries to resolve their names ("maybe_dotted", 
> "maybe_resolve", etc.). All I can say it that the views seem to be calling 
> the wrong functions. This prevents me from using for loops and lambda for 
> generating the routes in a more concise way :/
>
> Could anyone confirm if I'm correct?
>
> Many thanks,
>
> Laurent.
>
> --
> You received this message because you are subscribed to the Google Groups 
> "pylons-discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to [email protected].
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/pylons-discuss/CAB7cU6y56gx3fDEGsdx3qFJKTVPOM5yN1maohu8tEESRnY2ygQ%40mail.gmail.com.



-- 
Mike Orr 

-- 
You received this message because you are subscribed to the Google Groups 
"pylons-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/pylons-discuss/CAH9f%3Duq3ENBFg13AfwbH%2BivU2yzP7zORkRAREJefS0Wg1MAJaQ%40mail.gmail.com.