Re: [capi-sig] Constructing variable arg tuples
Todd Lyons <tlyons@ivenue.com> writes:
Obviously the scripts and your embedding module need to agree on an API;
Yes. I've set the following limitations:
- All args passed to a python function are converted to strings. It is up to the function to include an implicit cast
- No dicts, tuples, etc are passed. Just simple strings or numbers (which are converted to strings).
- Return from a function is always cast back to a string, which is what exim prefers.
This is subject to changes and additions.
Such an interface makes sense in Perl, where you can always treat numbers and strings in vice-versa, but might be somewhat inconvenient in Python, which is much more "strongly" typed (you can query for an object's type, and things like 1+"2" fail).
If my understanding is correct, you want exim configuration to define which Python functions will be called by exim, without an API defined upfront.
interface of the function is regulated by you, and it is you who prescribe how many and what kind of arguments it will accept.
I had to do a little work to figure out how many arguments the function is written to accept, and then double check that the call from the exim ACL's is using the correct number, and only then convert the variables and make the function call.
Why would you need to do that -- can't you just call the function and leave it to raise an exception if called with an incorrect argument count? Not only for EAFP, but because inspecting how many argument a function can fail. After all, the function could be imported from a module written in C or Boost.Python, or accept *args, which will likely confuse count detection.
The perl function count_headers() gets passed one variable: "from", stored in a variable named $header. The perl function is written to load the headers from the message (a big text blob), convert it to an array, then loop through the array looking for /^$header:/, counting how many it finds. Then it returns the number.
The "condition" line simply compares the returned value to 1, and if it's greater than one, it will set the fakereject and quarantine settings.
This will work and is easy to implement, but it does feel a bit more Perlish than Pythonic. If you want to go for a solution with a more native Python accent, I'd recommend passing the Python function some sort of context argument. Instead of a string, this would be an object with some methods that retrieve the message information, such as headers, and others to affect the response. This needn't be a complex framework -- if designed carefully, excellent functionality can be achieved with a very small number of methods.
On Mon, Jun 10, 2013 at 2:09 PM, Hrvoje Niksic <hniksic@xemacs.org> wrote:
If my understanding is correct, you want exim configuration to define which Python functions will be called by exim, without an API defined upfront.
Thank you for phrasing it properly, I was doing such a poor job. That is exactly what I am doing.
I had to do a little work to figure out how many arguments the function is written to accept, and then double check that the call from the exim ACL's is using the correct number, and only then convert the variables and make the function call. Why would you need to do that -- can't you just call the function and leave it to raise an exception if called with an incorrect argument count?
Because it segfaulted instead of raising an exception. If you remove lines 151-158 in python.c (http://git.exim.org/users/tlyons/exim.git/blob/4469a42e017cb6e44646d453b86e4...), then it will segfault when the function is called with the incorrect number of args.
This will work and is easy to implement, but it does feel a bit more Perlish than Pythonic. If you want to go for a solution with a more native Python accent, I'd recommend passing the Python function some sort of context argument. Instead of a string, this would be an object with some methods that retrieve the message information, such as headers, and others to affect the response. This needn't be a complex framework -- if designed carefully, excellent functionality can be achieved with a very small number of methods.
Noted, thanks for the input. That's good stuff.
...Todd
The total budget at all receivers for solving senders' problems is $0. If you want them to accept your mail and manage it the way you want, send it the way the spec says to. --John Levine
participants (2)
-
Hrvoje Niksic
-
Todd Lyons