Split code into multiple modules

The following question has been asked on Telegram:

Hi, is it possible to split contracts into multiple modules and import them? I could keep them in single module but would like to split them and currently having issues with imports. I couldn’t find any examoles, only imports of utils module. Thanks in advance

Yes it is!

You can import modules within your file using the python import instruction.
For example, if your module a is in a file named module_a.py you can do

from module_a import a

In your test you need to add provide the full module list to the test scenario.

sc = sp.test_scenario([a, b, ...])

The list must be ordered based on the usage. For example, if module a is then used inside module b you provide [a, b].

You can then access the modules elements with module_name.element.

Here is a complete example with all modules in the same file. The only change if they are in multiple files is the import instruction.

import smartpy as sp

@sp.module
def a():
    t: type = sp.nat

    class Parent(sp.Contract):
        def __init__(self):
            pass

@sp.module
def b():
    class MyContract(a.Parent):
        def __init__(self, x):
            a.Parent.__init__(self)
            sp.cast(x, a.t)
            self.data.x = x

        @sp.entrypoint
        def ep(self):
            pass

if "main" in __name__:
    @sp.add_test(name="MyContract")
    def test():
        sc = sp.test_scenario([a, b])
        c1 = b.MyContract(5)
        sc += c1
        c1.ep()

Thanks for your reply Jordan.

I was trying that before and currently recreated your example and still having some issues with it. I have a folder named contracts. In this folder I have defined two files module_a.py and module_b.py.

module_a.py

import smartpy as sp

@sp.module
def a():
    t: type = sp.nat

    class Parent(sp.Contract):
        def __init__(self):
            pass

module_b.py

import smartpy as sp
from module_a import a

@sp.module
def b():
    class MyContract(a.Parent):
        def __init__(self, x):
            a.Parent.__init__(self)
            sp.cast(x, a.t)
            self.data.x = x

        @sp.entrypoint
        def ep(self):
            pass

if "main" in __name__:
    @sp.add_test(name="MyContract")
    def test():
        sc = sp.test_scenario([a, b])
        c1 = b.MyContract(5)
        sc += c1
        c1.ep()

When I try to test module_b.py using ./smartpy test contracts/module_b.py output I get an error ModuleNotFoundError: No module named 'module_a'. Am I missing something?

I’m able to replicate the error.
I’ll back to you when I have a fix.