Jump to content
iqrf

TPythonModule - submodule

Recommended Posts

Hello,
is it possible to somehow create a submodule. Something like this

MainModule := TPythonModule.Create(nil);
MainModule.ModuleName := 'spam';

SubModule := TPythonModule.Create(nil);
SubModule.ModuleName := 'spam.test';

and call in Python

import spam
import spam.test

spam.function1()
spam.test.function2()

it reports an error

image.png.06eed4676710138e90f788dcbf02231c.png

if i do it like this it's fine

import spam
import spam.test as T

spam.function1()
T.function2()

Can it be solved somehow?
Thanks for the ideas.

Share this post


Link to post
16 hours ago, iqrf said:

Hello,
is it possible to somehow create a submodule. Something like this


MainModule := TPythonModule.Create(nil);
MainModule.ModuleName := 'spam';

SubModule := TPythonModule.Create(nil);
SubModule.ModuleName := 'spam.test';

and call in Python


import spam
import spam.test

spam.function1()
spam.test.function2()

it reports an error

image.png.06eed4676710138e90f788dcbf02231c.png

if i do it like this it's fine


import spam
import spam.test as T

spam.function1()
T.function2()

Can it be solved somehow?
Thanks for the ideas.

    PythonModule1 :=  TPythonModule.Create(nil);
    PythonModule1.Engine := GetPythonEngine ;
    PythonModule1.ModuleName := 'call';
    PythonModule1.AddDelphiMethod('preprocess',preprocess,'This function pre-processes data.');
    PythonModule1.MakeModule;

 

function Disassembler.preprocess(pself, args: PPyObject): PPyObject; cdecl;
var
  op_data, Dis_data: PPyObject;

  opcode_sequences, disasm_sequences, opcode_input_data, disasm_input_data: Variant;
begin
  with GetPythonEngine do
  begin
    if PyArg_ParseTuple(args, 'OO', @op_data, @Dis_data) <> 0 then
    begin


      var bm := BuiltinModule();

      var p_op_data := VarPythonCreate(op_data);
      var p_Dis_data:= VarPythonCreate(Dis_data);

      var b :=bm.type(opcode_tokenizer);

      // Preprocess data here as shown above
      opcode_sequences := opcode_tokenizer.texts_to_sequences(p_op_data);
      disasm_sequences := disasm_tokenizer.texts_to_sequences(p_Dis_data);

      opcode_input_data := t_tf.tf.keras.preprocessing.sequence.pad_sequences(opcode_sequences, maxlen:=Fopcode_seq_len) ;
      disasm_input_data := t_tf.tf.keras.preprocessing.sequence.pad_sequences(disasm_sequences, maxlen:=Fdisasm_seq_len) ;

      opcode_input_data := t_tf.tf.keras.utils.to_categorical(opcode_input_data, num_classes:=Finput_dim);
      disasm_input_data := t_tf.tf.keras.utils.to_categorical(disasm_input_data, num_classes:=Foutput_dim);

      Result := VariantAsPyObject( TPyEx.Tuple([opcode_input_data, disasm_input_data]) );
    end
    else
      Result := nil;
  end;
end;

Share this post


Link to post

Thanks, but understanding this code is beyond my abilities.

Share this post


Link to post

I'm afraid to add a submodule you have to go beyond Python4Delphi components and use Python C-API
try to study how the TPythonModule instance is created and act similarly

 

You will need to modify this approach someway to add the submodule entry to the dictionary for the supermodule: try use

PythonEngine.PyModule_GetDict(PythonModule.Module)

https://github.com/pyscripter/python4delphi/blob/1cd66211f586468d9fe3a1352344073759e64d8a/Source/PythonEngine.pas#L3655

 

Check also:

https://github.com/pyscripter/python4delphi/blob/master/Source/PythonEngine.pas#L3649

https://python.readthedocs.io/en/stable/c-api/import.html?highlight=pyimport_getmoduledict#c.PyImport_GetModuleDict

https://python.readthedocs.io/en/stable/c-api/import.html#c.PyImport_AddModuleObject

 

this will require some experimentation, but I hope you succeed

 

Share this post


Link to post

Hi,
I finally solved it at the Python level.

I have two TPython modules, one named main_module and the other sub_module.
Just add to the InitScript
import main_module
import sub_module
main_module.sub_module = sub_module

And you can use in Python main_module.sub_module.function1()
but of course, also sub_module.function1().

In this way, a pseudo-hierarchical structure of modules can be created.
Because this doesn't import main_module.sub_module as a test. main_module is not a package!

Share this post


Link to post

I finally found a way to make a package

import importlib
import types
import sys

# Package name
package_name = 'my_package'

# List of modules to be part of the package
module_names = ['module1', 'module2']

# Create an empty package
package = types.ModuleType(package_name)
package.__path__ = []

# Import and add individual modules to the package
for module_name in module_names:
    module = importlib.import_module(module_name)
    setattr(package, module_name, module)

# Set __all__ to the list of module names
package.__all__ = module_names

# Add the package to the list of imported modules
sys.modules[package_name] = package

Then it is possible

import my_package

from my_package import module1
from my_package import module2 as T

print(dir(module1))
print(dir(my_package.module1))
print(dir(T))

Only this import my_package.module1 as T is not possible. 

ModuleNotFoundError: No module named 'my_package.sub_module1'

Does anyone know why?

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×