Package: cython-dev-tools
Cython Dev Tools: toolkit for efficient Cython developmentKey featuresKeeping all development tools in one place with minimal effortsBuilt-in Cython debugger (including low-level cdef / C code, based on GDB)Cython code unit testing with coverage reportsCython code unit test with cdef class mocks / side-effectsLine-profilerEasy running .pyx files by entry-point functionsCython annotations and index file for all projectCython project boilerplateCython snippets for low-level C-code and debugging tricksMakefile for running command shortcuts, also don't let you forget to build changed files (for examplemake test,make test-debug p=path/to_test.py)RequirementsPython 3.6+ (including debug version for CyGDB)GDB 7+ (tested with ver 10 and 13)Cython 0.29Getting startedpipinstallcython-dev-tools# Create a new directory for a projectmkdirinit_projectcdinit_project# Initialize cython tools project filescytoolinitialize.--include-samples--include-boilerplate--boilerplate-name=cytoolz# The initialize commands will setup a simple package with core code and tests at ./cytools dir# also at `cy_tools_sample` directory you can find samplesInitialize commandCython tools require each project root to be initialized, the folder.cython_dev_toolswill be created at the project root. There you can find all temporary files, like annotations,
coverage data, debug files, etc.The main purpose of initialization also is keeping the all project paths relative to
its project root, because most of Cython utils are sensitive to relative paths, and
require appropriate project structure.To get more help run:cytoolinitialize--helpBuilding cython codeCython tools does the building automatically even if the module code doesn't use any
automaticpyximport, the compiled.csource and modules.so|.dllwill be placed
near each.pyxfile in the project.Building debug version of project is a mandatory for cython tools functions:cytool build --debugIMPORTANT:If you have thesetup.pythat somehow compiles Cython code thecytoolwill gracefully use it, but you will have to add new code/modules for compilation manually.DebuggingCython debugging is a hard fork of CyGDB, however I refactored its core to make it simply
work.Thecriticalrequirement for functioning of the debugger is having apython-dbgas
the interpreter, that runs/compiles cython. There is no Anaconda python version with
debug symbols, so I ended with Linux built-in Python 3.9dsudo apt-get install python-dbgand PipEnv.To figure out whether your modules compiled with debug info check thedin the file name,
like this: cy_memory_unsafe.cpython-39d-x86_64-linux-gnu.so, python interpreter should
be likepython3.6-dbgorpython3.6d.Launching debug session# cytool build --debug  (required)
#
# Both .py / .pyx entry points are suported 
#

# Can be called by file path relative to project root 
cytool debug cy_tools_samples/debugging/abort.pyx@main

# Also by package name with breakpoint at line 24 (only Cython!)
cytool debug cy_tools_samples.debugging.assertions@main:24

# Can contain default breakpoint at line 24 (only Cython!)
cytool debug cy_tools_samples/debugging/assertions.pyx@main:24

# Can break at segmentation fault too (at line 13 at the entry module)
cytool debug cy_tools_samples/debugging/segfault.pyx@main -b 13

# Can break at class method
cytool debug cy_tools_samples/cy_memory_unsafe.pyx@main:TestClass.hello_add

# Many breakpoints allowed
cytool debug cy_tools_samples/debugging/segfault.pyx@main -b 13 -b 21More helpcytool debug --helpCyGDB commandsCheck thecy_tools_samples/debugging/for more tricks on how to set breakpoints,
c-style (not python!) asserts and debug them.Troubleshooting the debuggerThis functionality is still under development, so expect bugs everywhere. However, there are some
common issues with the Cython debugger:Make sure that you are usingdebugversion of pythonMake sure that the current build is debug, try to force rebuildcytool build --debug --forceRamp up verbositycytool -vvvv debug cy_tools_samples/debugging/abort.pyx@main --cygdb-verbosity=3Don't hesitate to fill an issue on GitHub!Unit TestingRunning unit tests on Cython low-level cdef functions or even classes is also possible task, but requires some
code preparation.
To run unit tests on low-level code you must do the following steps:Implement unit test class intest_cython_.pyxfile:importunittest# cdef-classes require cimport and .pxd file!frombp_cython.bp_cython_classcimportSomeCythonClassclassCythonTestCase(unittest.TestCase):# IMPORTANT: in some reason, NoseTest doesn't recognize this module as a testdeftest_cytoolzz_class_init(self):cdefdouble*ptr=NULL# You can also use all low-level C-like stuffc=SomeCythonClass(4,3)# c.square() is cdef method and not accessible via Pythonself.assertEqual(12,c.square())Implement python file which includestest_cython_.pyx(don't usepyximport!) But it's literally 1 line!frommy_proj.tests.test_cython_import*Re-build project in debug mode and run test suite. Onlypytestworks for me, BUT you still have to writeunittest.TestCaseclasses,pytestfancy fixtures are not supported for Cython tests.> cytool build --debug 
> cytool tests .

# Or alternatively via make (no extra build step required)
> make testsSee Cython code with tests examplesUnit Test Mocks for Cython cdef classesSometimes it's crucial to have fast cdef code, but occasionally it could have undetermined functions like random or datetime.now(), so I found an approach
for implementing unit test mocks for Cython class methods. Unfortunately it's not so elegant as Python one, and require implementing special class. But in
some cases it's better than nothing.Cython UnitTest Mocks exampleCode coverageInstall the boilerplate projectcytool initialize --include-boilerplate, this package
contains unit-tests, so you can play with it.This command will run all tests in project root and open coverage report in the browser.# More help
# cytool cover --help
# cytool build --debug  (required)
cytool cover . --browserAnnotateFor developing high performance Cython code it's crucial to run annotations to see
potential bottlenecks. Cython tools provides this functionality, you can build one file or
all files in the folder/project.This command will run all tests in project root and open coverage report in the browser.# More help
# cytool annotate  --help
cytool annotate . --browser
cytool annotate cy_tools_samples/debugging/segfault.pyx --browserRunningA simple command for running the Cython code by entry point# More help
# cytool run --help
 
cytool run cy_tools_samples/debugging/segfault.pyx@main
cytool run cy_tools_samples.debugging.segfault@main
cytool run python/works/too.pyLine ProfilerLine profiler useshttps://github.com/pyutils/line_profilerproject, and uses the similar
logic as%lprunJupyter magic# More help
# cytool lprun --help
# cytool build --debug  (required)
 
# Profile approx_pi2"(10)" -- equals to launching this function as approx_pi2(n=10) 
cytool lprun cy_tools_samples/profiler/cy_module.pyx@approx_pi2"(10)"

# Profile extra functions in the entry-point module 
cytool lprun cy_tools_samples/profiler/cy_module.pyx@approx_pi2"(10)" -f recip_square2

# Profile class mehtod in entry-module
cytool lprun cy_tools_samples/profiler/py_module.py@approx_pi2"(10)" -f SQ.recip_square2

# Profile function in another module
cytool lprun cy_tools_samples/profiler/py_module.py@approx_pi2"(10)" -f cy_tools_samples/profiler/cy_module.pyx@recip_square2

# Profile entire module
cytool lprun cy_tools_samples/profiler/cy_module.pyx@approx_pi2"(10)" -m cy_tools_samples/profiler/cy_module.pyxCleanupCleanup all compilation junk# For more help
# cytool clean --help
cytool cleanTemplatesCreates Cython cdef module or class using boilerplate templates relative to project root.
Optionally it can include tests in new package directory.# For more help
# cytool template --help
cytool template subpkg.my_template