experchange > python

R.Wieser (11-18-19, 09:52 AM)
Hello all,

I'm trying to edit a binary extension to Python, and have a situation where
I would like to create method which adds a single argument, and than jumps
to / calls another method. Like this:

static PyObject *py_proc1(PyObject *self, PyObject *args)
{
.....
Py_RETURN_NONE
}

static PyObject *py_proc2(PyObject *self, PyObject *args)
{
// call py_proc1 to with "foo" prepended to "args"
}

I have no idea how I should do either the call or the adding of that
argument (and going to a few examples I've found googeling didn't show me
the answer either).

Than again, I'm not even sure if the "foo" needs to be prepended, or if that
"py_proc1" method can receive more than a single "args" argument ... Like
this perhaps:

static PyObject *py_proc1(PyObject *self, int MyNewArgument, PyObject *args)
{
.....
}

I've also tried to go the C way (just calling, from "py_proc2", a C function
containing "py_proc1"s code), but I got lots of errors, most of them in the
realm of the different returns not being of the same type (no idea why it
doesn't complain about it in the origional "py_proc1" code itself though).

tl;dr:
I could use some examples that show how to work withl PyObject subfunctions.

Regards,
Rudy Wieser

P.s.
Yes, this is related to my earlier questions and problems.
MRAB (11-18-19, 09:32 PM)
On 2019-11-18 07:52, R.Wieser wrote:
[..]
> Rudy Wieser
> P.s.
> Yes, this is related to my earlier questions and problems.

One possibility is to refactor the code so that py_proc1 and py_proc2
themselves just handle their arguments and then call the function that
does the actual work.

A clunkier way would be to make a new tuple that consists of the
prepended item and the items of args and pass that to py_proc1 as its
args. When py_proc1 returns its result object, DECREF the new tuple to
clean up and then return the result object.
R.Wieser (11-18-19, 10:15 PM)
MRAB,

> One possibility is to refactor the code so that py_proc1 and py_proc2
> themselves just handle their arguments and then call the function that
> does the actual work.


The thing is that the arguments of py_proc1 and py_proc2 are the same, but
for a single argument. Which means that letting both of them first parse
their own arguments means duplicated code. Which I do not really want and
thus try to evade

But yes, that is a possibility too. The "the function that does the actual
work" part is what I tried to describe with my second example.

> A clunkier way would be to make a new tuple that consists of the prepended
> item and the items of args and pass that to py_proc1 as its args.


That is what I tried to describe with my first example.

The thing is I have no clue about what the above calling should look like
(though I think I already found how to append my argument to the "args"
string-object).

In other words, do you have any idea of what either of those calling methods
should look like ? An example perhaps ? Having only encountered the
CPython API two days ago I'm still fumbling in the dark I'm afraid.

Regards,
Rudy Wieser
MRAB (11-18-19, 11:11 PM)
On 2019-11-18 20:15, R.Wieser wrote:
[..]
> In other words, do you have any idea of what either of those calling methods
> should look like ? An example perhaps ? Having only encountered the
> CPython API two days ago I'm still fumbling in the dark I'm afraid. It could be something like this:


static PyObject *py_proc2(PyObject *self, PyObject *args)
{
/*** TODO: Add error checking. ***/
PyObject* prepend_arg;
PyObject* prepend_tuple;
PyObject* new_args;
PyObject* result;

/* The object to be prepended. */
prepend_arg = PyUnicode_FromString("foo");

/* Make a tuple from the prepended object. */
prepend_tuple = BuildValue("(O)", prepend_arg);

/* No longer need prepend_arg. */
Py_DECREF(prepend_arg);

/* Make the new argument list. */
new_args = PySequence_Concat(prepend, args);

/* No longer need prepend_tuple. */
Py_DECREF(prepend_tuple);

/* Call the other method. */
result = py_proc1(self, new_args);

/* No longer need new_args. */
Py_DECREF(new_args);

return result;
}
Michael Torrie (11-19-19, 02:18 AM)
On 11/18/19 1:15 PM, R.Wieser wrote:
> The thing is that the arguments of py_proc1 and py_proc2 are the same, but
> for a single argument.


Does this have to be done in the C API? Depending on how this class is
used in your Python code, I would just create a new Python class that
extends this class defined in the C code. Then it's more a matter of:

import cmodule

class NewClass(cmodule.OldClass):

def my_proc2(self, *args):
b=3
self.my_proc1( *((b,) + args) ) #OldClass.my_proc1

Now any instance of NewClass has a method called my_proc2 which calls
the my_proc1 from the C API defined class with the extra argument prepended.

The "*" notation is to unpack the tuple, which is used when calling
another function that takes positional arguments.
R.Wieser (11-19-19, 10:09 AM)
Michael

> Does this have to be done in the C API?


As far as I can tell, yes. What I need to do is not exposed by the
extension itself, meaning that a wrapper class can't get access to it
either.

And its just a syntax problem. I currently simply have not enough knowledge
about the CPython API lanuages one to be able to even do a simple call ...
:-\

Regards,
Rudy Wieser
R.Wieser (11-19-19, 01:14 PM)
MRAB,

> It could be something like this: [snip example code]


Thank you very much. Your "Call the other method" line shows me that I've
been overthinking things. :-(

After that I decided to see if I could give the "py_proc1" function two
arguments, which worked. That means that the prepending of "foo" (to the
origional one) has been changed into transferring it on its own (much easier
for both the caller as well as the callee).

Regards,
Rudy Wieser
Michael Torrie (11-19-19, 06:00 PM)
On 11/19/19 1:09 AM, R.Wieser wrote:
> Michael
>> Does this have to be done in the C API?

> As far as I can tell, yes. What I need to do is not exposed by the
> extension itself, meaning that a wrapper class can't get access to it
> either.


Sure but the Python methods themselves are exposed and accessible and
according to your previous posts, all you want to do is add an argument
to a call to the existing method. If that's true, then you should be
able to do that part from pure Python. The beauty of the C API is that
anything you define there should be visible and accessible from pure
Python world.

I can understand that the pure C stuff is not accessible of course. But
the snippets you've shown so far don't show any of that.

> And its just a syntax problem. I currently simply have not enough knowledge
> about the CPython API lanuages one to be able to even do a simple call ...
> :-\


Are you able to post the C code, or at least enough of it that can
actually compile? It'd be much easier to help if we had something to
work with. We're working in the dark here so it's difficult to know
exactly where to direct you. It's always best on the list to work with
complete, standalone, minimal examples.

Looking at existing examples, as well as the C API documentation, are
how I figured out how to use it some years back when I needed to do a
small thing in C, although I've forgotten most of it now.
Michael Torrie (11-19-19, 06:06 PM)
On 11/19/19 9:00 AM, Michael Torrie wrote:
> Sure but the Python methods themselves are exposed and accessible and
> according to your previous posts,


I meant to say the class methods defined by the C code.
R.Wieser (11-19-19, 07:12 PM)
Michael,

> Sure but the Python methods* themselves are exposed and accessible
> and according to your previous posts, all you want to do is add an
> argument to a call to the existing method. If that's true, then you
> should be able to do that part from pure Python.


>* class methods defined by the C code


Feel free to post code showing that it can be done. The extension is
RPi.GPIO, the method is "output", and the extra argument is the pinnaming
scheme (BCM or BOARD). Success! :-p

> I can understand that the pure C stuff is not accessible of course.
> But the snippets you've shown so far don't show any of that.


Where did you think that "static PyObject *py_proc1(PyObject *self, PyObject
*args)" came from, or why I said "I've also tried to go the C way" ?
Besides that, the subject line should have been a dead giveaway by
itself ...

> We're working in the dark here


Are you sure ? MRAB didn't seem to have too much problems with both
recognising and understanding what I was busy with - he posted a spot-on
example, containing not more, but also not anything less than what I was
asking for.

> Looking at existing examples, as well as the C API documentation


I did not find any example that showed me what I needed to know - simply one
CPython function calling another one. And yes, I've found multiple
documentation pages, including the "Extending and Embedding the Python
Interpreter" ones. Alas, no dice.

Most of that documentation is only good when you already know what you are
looking for, and need to make sure of its exact usage. Not so much the
other way around, when you have no clue and are searching for what you need
to use to solve a particular problem (even one as stupid as just calling
another method)

By the way, the whole solution consists outof the following:

static PyObject *py_proc1(PyObject *self, int ExtraArg, PyObject *args)
{
.....
Py_RETURN_NONE
}

static PyObject *py_proc2(PyObject *self, PyObject *args)
{
return py_proc1(self, 42, args)
}

Regards,
Rudy Wieser
Luciano Ramalho (11-19-19, 10:13 PM)
Now that’s a novel approach to asking for free help: pretending to be
smarter than the people who are trying to help you.

On Tue, 19 Nov 2019 at 14:17 R.Wieser <address> wrote:
[..]
Luciano Ramalho (11-19-19, 10:20 PM)
I apologize to all but the intended recipient for this. I’d have given him
feedback in private if I knew his email.

I will take leave from the list now. Keep up the good work, friendly
responders.

On Tue, 19 Nov 2019 at 17:13 Luciano Ramalho <luciano> wrote:
[..]
Michael Torrie (11-19-19, 10:38 PM)
On 11/19/19 10:12 AM, R.Wieser wrote:
> Feel free to post code showing that it can be done. The extension is
> RPi.GPIO, the method is "output", and the extra argument is the pinnaming
> scheme (BCM or BOARD). Success! :-p


If you mentioned RPi.GPIO before, I apologize for my mistake. That's
very helpful to know.

As for posting code to show it can be done, If I knew what the pin
naming scheme was (how do you use it from python?), and if I knew how
you modified py_output_gpio to do something with that, I sure would give
it a shot.

>> We're working in the dark here

> Are you sure ?
> MRAB didn't seem to have too much problems with both
> recognising and understanding what I was busy with - he posted a spot-on
> example, containing not more, but also not anything less than what I was
> asking for.


MRAB understood and answered the specific question, yes.

But I thought, and remain convinced, that there were probably other ways
of solving it that didn't involve mucking with C code. Because forking
the RPi.GPIO code means that every time there's a change or update to it
you know have to redo everything each time.

You mentioned you're working with RPi.GPIO, so why not just use the real
function names in your questions? After grepping I've determined that
you are really wanting to work with the C function py_output_gpio().
Why not just say that? Doesn't take very much extra time but will get
more people willing to respond who might know.

> I did not find any example that showed me what I needed to know - simply one
> CPython function calling another one. And yes, I've found multiple
> documentation pages, including the "Extending and Embedding the Python
> Interpreter" ones. Alas, no dice. Fair enough.


> By the way, the whole solution consists outof the following:
> static PyObject *py_proc1(PyObject *self, int ExtraArg, PyObject *args)
> {
> ....
> Py_RETURN_NONE
> }
> static PyObject *py_proc2(PyObject *self, PyObject *args)
> {
> return py_proc1(self, 42, args)
> }


Glad it worked out for you. That "int ExtraArg" bit looks a bit
strange; I thought everything that was exposed to the Python side of
things had to be wrapped in PyObject. Guess I'm wrong?
Dennis Lee Bieber (11-20-19, 12:13 AM)
Going back in time...

On Mon, 18 Nov 2019 08:52:07 +0100, "R.Wieser" <address>
declaimed the following:

[..]
>I have no idea how I should do either the call or the adding of that
>argument (and going to a few examples I've found googeling didn't show me
>the answer either).



explains how to extract the individual arguments provided in the args
PyObject.


explains how to build an args PyObject from individual items.

So... extract the original args, then build a new args object with your
added argument, then call your new function with that...

{Personally, I still think you are looking for a solution to a problem that
doesn't exist. The only reason for trying to get RPi.GPIO to work with both
BCM and BOARD numbering schemes at the same time is that you are attempting
to provide some library module and have hard-coded pin numbers using one or
the other scheme and are attempting to adjust for an end-user of your
module possibly using the other scheme.
The proper way to handle this is to NOT hard-code any pin numbers in
your module, but instead provide an initialization/setup function which the
end-user calls, passing in pin numbers in their preferred scheme. Then it
doesn't matter which scheme they chose -- they provided the pins in that
scheme and your code doesn't have to worry about it.}
DL Neil (11-20-19, 01:04 AM)
On 20/11/19 9:20 AM, Luciano Ramalho wrote:
> I apologize to all but the intended recipient for this. I’d have given him
> feedback in private if I knew his email.
> I will take leave from the list now. Keep up the good work, friendly
> responders.


Please reconsider. Should your relationship with the 'good folks' be
governed by someone/anyone else?

There is no need to tell you that are many innocent reasons why we
misunderstand each other's motives or intent, particularly in a
multi-cultural context; just as there are folk who attempt to 'take
advantage'. Grossly generalised examples
- each academic year a new crop of PyStudents seems to crop-up, thinking
we'll *do* their 'homework' for them...
- some parts of British humor is impenetrable to those born south of Dover
- Dutch/German positivity can be interpreted as brusque or even
arrogant, in some parts of the world
- Kiwi/Aussie humor as often involves insult (which is not meant to be
taken seriously) as it does self-deprecation
- Self-deprecation is not 'the American way'...
- Monty Python humor is its own (lack of) explanation!

That said, I am asking (elsewhere, but please feel free...'here') if the
standards and conventions of the Python Foundation apply to this/these
list(s)? Such requires a balance between an individual's right to
privacy, and the open-ness with which we conduct Python-business, ie
without insult, derision, victimisation, etc, etc...