cython converts python code to C/C++ and creates compiled extensions. Generally this is used to speed up the execution, but one can also use it for protecting their python source code.

Code structure

package_tutorial
+- setup.py
+- README.md
+- my_pkg
   +- __init__.py
   +- module_one.pyx
   +- module_two.pyx
   +- utils.pyx
# __init__.py
from . import utils
from . import module_one
from . import module_two
# utils.py

def add(a, b):
    return a+b
# module_one.py
import utils

def func1():
    return utils.add(1, 2)      
# module_two.py
import utils

def func2():
    return utils.add('abc', 'xyz')      
# setup.py
import setuptools
from Cython.Build import cythonize
from glob import glob

with open("README.md", "r", encoding="utf-8") as fh:
    long_description = fh.read()

extensions = []
for x in glob('my_pkg/*pyx'):
    extensions.append(
        setuptools.Extension(x.replace('.pyx', '').replace('/', '.'),
                             sources=[x]))
setuptools.setup(
    name="My Package",
    version="0.0.1",
    author="",
    author_email="",
    description="",
    long_description=long_description,
    long_description_content_type="text/markdown",
    classifiers=[
        "Programming Language :: Python :: 3",
    ],
    packages=['my_pkg'],
    ext_modules=cythonize(extensions),
    python_requires=">=3.9",
) 

Building package

# Build .whl. Package will be created in dist directory
python setup.py bdist_wheel

Install package

pip install _whl_file_created_in_dist_directory_

Use package

>>> import my_pkg
>>> my_pkg.module_one.func1()
>>> my_pkg.module_two.func2()