-
Notifications
You must be signed in to change notification settings - Fork 337
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[PROTO] Adding Cython framework for lite-functions (and more) #1416
base: cython
Are you sure you want to change the base?
Conversation
Codecov Report
@@ Coverage Diff @@
## cython #1416 +/- ##
=======================================
Coverage 97.15% 97.15%
=======================================
Files 77 77
Lines 7406 7406
=======================================
Hits 7195 7195
Misses 211 211 Continue to review full report at Codecov.
|
…p (isort will complain about this)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good! My suggested changes are all minor, and you're free to ignore them if you so choose.
The main thing I'm still wondering about, which I think we talked about yesterday, is on whether or not it specifically needs to be a numpy array as input, or if it could be a real or int. I think I remember you saying that yes, it does need to be a numpy array for the input.
If you're looking to eventually merge this prototype, we'd want to include the additional required steps in the contributor guide section on installing PlasmaPy for development.
Thank you for doing this!
Z = 1j * np.sqrt(np.pi) * wofz(zeta) | ||
|
||
return Z |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Z = 1j * np.sqrt(np.pi) * wofz(zeta) | |
return Z | |
return 1j * np.sqrt(np.pi) * wofz(zeta) |
[optional] This is a sort of refactoring I've often had pop up lately. Up to you.
setup.py
Outdated
from importlib.machinery import EXTENSION_SUFFIXES | ||
|
||
ext_suffixes = EXTENSION_SUFFIXES.copy() | ||
ext_suffixes.append(".c") | ||
|
||
cy_files = get_cython_files() | ||
for file in cy_files: | ||
for ext in ext_suffixes: | ||
ext_file = file.with_suffix(ext) | ||
if not ext_file.exists(): | ||
continue | ||
|
||
print(f"removing '{ext_file}'") | ||
|
||
if "--dry-run" in sys.argv: | ||
continue | ||
|
||
ext_file.unlink() # delete extension file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[optional] My inclination would be to put this into its own function that gets called here, so as to not have implementation details in the if __name__ == "main"
part. This goes along with the idea of having a main()
function that gets called in this section of code. In this case there isn't much else here, so I'd have no problem leaving it as is. Up to you.
|
||
def get_cython_files(): | ||
"""Find all cython files (*.pyx) in plasmapy.""" | ||
return list(Path().glob("plasmapy/**/*.pyx")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hadn't seen the **
before, so I had to look up on the World Wide Web™ to learn that it mean multiple directories here. Glad to learn new Python!
# def plasma_dispersion_func_deriv( | ||
# zeta: Union[complex, int, float, np.ndarray, u.Quantity] | ||
# ) -> Union[complex, float, np.ndarray, u.Quantity]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# def plasma_dispersion_func_deriv( | |
# zeta: Union[complex, int, float, np.ndarray, u.Quantity] | |
# ) -> Union[complex, float, np.ndarray, u.Quantity]: |
setup.py
Outdated
# by: | ||
# python setup.py build_ext --inplace | ||
# | ||
# this get executed with the command |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# this get executed with the command | |
# this gets executed with the command |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, one potential idea to make this introduce less code!
# this get executed with the command | ||
# python setup.py clean | ||
# | ||
if "clean" in sys.argv: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clean
is already a setup.py
command and I would be wary of reimplementing it. Have you tried playing around with https://stackoverflow.com/questions/30359216/compile-a-cython-project-and-clean and see whether the default python setup.py clean --all
does the trick?
People are generally moving away from setup.py
in the python space in general... but that's probably an issue for another day.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not overriding python setup.py clean
, this still runs as expected. I'm adding an additional setup after the clean
command is executed. The clean
command does not know about, and thus can not remove, --inplace
shared object files. All this is doing is seeing if the clean
command is specified, letting the normal clean
run, and then our setup.py
removes the --inplace
files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oooooh okay then, gotcha. 👍🏻
pip install --progress-bar off twine | ||
pip install --progress-bar off -r requirements/build.txt |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good cleanup! 👍🏻
… to annotate cycthonize during build
This pull request will be closed in 14 days due to a year of inactivity unless the stale label or comment is removed. |
This is currently a prototype to see how we can incorporate
Cython
intoplasmapy
. I'm particularly curious in how...cython
code. (Using lite-functions as the prototype)cython
code.cython
code.Using
cython
inplasmapy
means developers/contributors have an extra step to get off the ground, because, like c,cython
code needs to be compiled.Cython
looks very similar to Python and can be written in either.py
files or.pyx
files..pyx
files are specificallyCython
files. Once this is done, the code needs to be cythonized (i.e. built/compile). In this process c code is generated from the source code and then the c code is compiled into share object files. Python can then import directly from these shared object files. However, these shared object files are platform specific and this is why we can not package with pre-compiled code. Luckily, these shared object files are automatically generate withpip
installs, so there shouldn't be any extra steps for end users. For developers/contributors, we don't typicallypip
install so we have manually create the shared object files. This is done by...plasmapy
.python setup.py build_ext --inplace
This will create the shared object files in your repository. However, these are not under version control (i.e. excluded by
.gitignore
), so whenevercython
code is modified or you switch to a new branch you'll likely need to re-compile.To assist in cleaning up the compiled code I did modify the
setup.py
so that following commands will remove files generated bypython setup.py build_ext --inplace
.If you want to see what file are deleted before cleaning, then you can use...