Home > other >  Python error TypeError: __init__() missing 2 required positional arguments: and ctypes
Python error TypeError: __init__() missing 2 required positional arguments: and ctypes

Time:09-17

I have a DLL library in C, I managed to initialize the functions in python a receive and send data to it. Now I'm trying to reorganize the python code to have all my DLL python functions in one big class.

This is what I have in Visual Studio.

This is Hello.h

#pragma once
#include<stdio.h>
#include<stdint.h>

#ifdef SOME_API_EXPORTS
#define SOME_API __declspec(dllexport)
#else
#define SOME_API __declspec(dllimport)
#endif

SOME_API int sum(int a, int b);

SOME_API int mul(int a, int b);

SOME_API void message(void);

#define max_length 63U

typedef struct
{
    uint8_t param1;

    uint32_t param2;

    uint8_t param3;

    uint8_t param4[max_length];

} struct_1;

SOME_API void message_2(struct_1* request);

SOME_API int function_1(uint8_t param_1, uint8_t param_2);
SOME_API int function_2(uint8_t param_1, uint8_t param_2);

this is Hello.C

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include "Hello.h"
#include <inttypes.h>

 
int sum(int a, int b) {
        return a   b;
    }

int mul(int a, int b) {
    return a * b;
}

void message(void)
{
    puts("hello from dll\n");
}

SOME_API void message_2(struct_1* request)
{
    printf("data: request=[%d %d %d %s]\n", 
    request->param1, request->param2, request->param3, request->param4);
    //do some processing

}

SOME_API int function_1(uint8_t param_1, uint8_t param_2)
{
    int status;
    //do some processing
    printf("%u  , %u  \n", param_1, param_2);
    status = 1;
    return status;
}

SOME_API int function_2(uint8_t param_1, uint8_t param_2)
{
    int status;
    //do some processing
    printf("%u  , %u  \n", param_1, param_2);
    status = 0;
    return status;
}

this is my original python code without the class.

import ctypes

test = ctypes.WinDLL('Project.dll')

max_length = 63

class struct_1(ctypes.Structure):
    _fields_ = [("param1", ctypes.c_ubyte),
                ("param2", ctypes.c_uint32),
                ("param3", ctypes.c_ubyte),
                ("param4", ctypes.c_char * max_length)]

test.message()

##req = struct_1(1, 2 , 3,"test".encode('utf-8'))
##result = test.message_2(ctypes.byref(req))

py_function_1 = test.function_1
py_function_1.argtype = (ctypes.c_uint8,ctypes.c_uint8 )
py_function_1.restype = ctypes.c_int
py_function_1(255,255)

return_val = py_function_1()
print(return_val)

py_function_2 = test.function_2
py_function_2.argtype = (ctypes.c_uint8,ctypes.c_uint8 )
py_function_2.restype = ctypes.c_int
py_function_2(255,255)

return_val = py_function_2()

print(return_val)

and this is my python test code trying to implement the class that will contain all my dll function inits. I'm just testing with function_1 and function_2 for now. I will add other functions in the future.

import ctypes

test = ctypes.WinDLL('Project.dll')

max_length = 63

class struct_1(ctypes.Structure):
    _fields_ = [("param1", ctypes.c_ubyte),
                ("param2", ctypes.c_uint32),
                ("param3", ctypes.c_ubyte),
                ("param4", ctypes.c_char * max_length)]

class my_outer_class:

    def __init__(self,py_function_1,py_function_2):

        self.py_function_1 = test.function_1
        self.py_function_1.argtype = (ctypes.c_uint8,ctypes.c_uint8 )
        self.py_function_1.restype = ctypes.c_int

        self.py_function_2 = test.function_2
        self.py_function_2.argtype = (ctypes.c_uint8,ctypes.c_uint8 )
        self.py_function_2.restype = ctypes.c_int

myapi = my_outer_class()
            
result = myapi.py_function_1(255,255)
print(result)

result = myapi.py_function_2(255,255)
print(result)

The error I get is

Traceback (most recent call last):
  File "C:\Users\Dude\OneDrive\Desktop\Test.py", line 25, in <module>
    myapi = my_outer_class()
TypeError: __init__() missing 2 required positional arguments: 'py_function_1' and 'py_function_2'

I would appreciate any suggestions. Thanks.

CodePudding user response:

It is because you define the class's init to have py_function_1 and py_function_2 as the constructors. Thus, you should pass the test.function_1 and test.function_2 when initializing the object, i.e.

myapi = my_outer_class(test.function_1, test.function_2)

and then use it correctly in class' init, i.e.

class my_outer_class:

    def __init__(self, py_function_1, py_function_2):

        self.py_function_1 = py_function_1 # change this to use the constructor
        ... # other lines

        self.py_function_2 = py_function_2 # change this to use the constructor
        ... # other lines

The solution above means that the user has the ability to supply other callable in the constructor.

Another alternative is to restrict the user to use only the one from .dll. A possible solution would be the one mentioned in the comments section. However, I don't think this is the best practice because it uses the global scope to find the function. This will be an issue when you tried to scale your script, say, by separating the class in another file. You will need to include non-class code there.

Better solution if you want restrict the user to not altering the function_1 and function_2 is to load the .dll in the class' init instead of in the global scope.

class my_outer_class:

    def __init__(self):
        test = ctypes.WinDLL('Project.dll')
        self.py_function_1 = test.function_1

  • Related