Skip to content

Commit 8e5c9d0

Browse files
committed
Initial commit
0 parents  commit 8e5c9d0

File tree

10 files changed

+433
-0
lines changed

10 files changed

+433
-0
lines changed

.gitignore

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# VSCode
2+
.vscode/
3+
4+
# Byte-compiled / optimized / DLL files
5+
__pycache__/
6+
*.py[cod]
7+
*$py.class
8+
9+
# C extensions
10+
*.so
11+
12+
# Distribution / packaging
13+
.Python
14+
build/
15+
develop-eggs/
16+
dist/
17+
downloads/
18+
eggs/
19+
.eggs/
20+
lib/
21+
lib64/
22+
parts/
23+
sdist/
24+
var/
25+
wheels/
26+
pip-wheel-metadata/
27+
share/python-wheels/
28+
*.egg-info/
29+
.installed.cfg
30+
*.egg
31+
MANIFEST
32+
33+
# PyInstaller
34+
# Usually these files are written by a python script from a template
35+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
36+
*.manifest
37+
*.spec
38+
39+
# Installer logs
40+
pip-log.txt
41+
pip-delete-this-directory.txt
42+
43+
# Unit test / coverage reports
44+
htmlcov/
45+
.tox/
46+
.nox/
47+
.coverage
48+
.coverage.*
49+
.cache
50+
nosetests.xml
51+
coverage.xml
52+
*.cover
53+
*.py,cover
54+
.hypothesis/
55+
.pytest_cache/
56+
57+
# Translations
58+
*.mo
59+
*.pot
60+
61+
# Django stuff:
62+
*.log
63+
local_settings.py
64+
db.sqlite3
65+
db.sqlite3-journal
66+
67+
# Flask stuff:
68+
instance/
69+
.webassets-cache
70+
71+
# Scrapy stuff:
72+
.scrapy
73+
74+
# Sphinx documentation
75+
docs/_build/
76+
77+
# PyBuilder
78+
target/
79+
80+
# Jupyter Notebook
81+
.ipynb_checkpoints
82+
83+
# IPython
84+
profile_default/
85+
ipython_config.py
86+
87+
# pyenv
88+
.python-version
89+
90+
# pipenv
91+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
93+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
94+
# install all needed dependencies.
95+
#Pipfile.lock
96+
97+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
98+
__pypackages__/
99+
100+
# Celery stuff
101+
celerybeat-schedule
102+
celerybeat.pid
103+
104+
# SageMath parsed files
105+
*.sage.py
106+
107+
# Environments
108+
.env
109+
.venv
110+
env/
111+
venv/
112+
ENV/
113+
env.bak/
114+
venv.bak/
115+
116+
# Spyder project settings
117+
.spyderproject
118+
.spyproject
119+
120+
# Rope project settings
121+
.ropeproject
122+
123+
# mkdocs documentation
124+
/site
125+
126+
# mypy
127+
.mypy_cache/
128+
.dmypy.json
129+
dmypy.json
130+
131+
# Pyre type checker
132+
.pyre/

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
v1.2.0b1, 21-12-2020 -- Initial release.

LICENSE.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2020 TechLearners Inc.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

MANIFEST.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
include LICENSE.txt
2+
include CHANGES.txt
3+
include requirements.txt
4+
include README.rst

README.rst

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
==========
2+
cythonizer
3+
==========
4+
5+
*Cythonize one step faster*
6+
7+
.. image:: https://img.shields.io/badge/build-beta-brightgreen
8+
:target: https://github.com/TechLearnersInc/cythonizer
9+
10+
.. image:: https://img.shields.io/badge/license-MIT-green
11+
:target: LICENSE.txt
12+
13+
.. image:: https://img.shields.io/static/v1?label=Created%20with%20%E2%9D%A4%EF%B8%8F%20by&message=TechLearners&color=red
14+
:target: https://github.com/TechLearnersInc
15+
16+
Introduction
17+
------------
18+
19+
:code:`cythonizer.py` is a script that will attempt to
20+
automatically convert one or more :code:`.py` and :code:`.pyx` files into
21+
the corresponding compiled :code:`.pyd | .so` binary modules
22+
files. Example::
23+
24+
$ python cythonizer.py myext.pyx
25+
26+
:code:`pip install cythonizer` will automatically create an
27+
executable script in your :code:`Scripts/` folder, so you
28+
should be able to simply::
29+
30+
$ cythonizer myext.py
31+
32+
or even::
33+
34+
$ cythonizer *.pyx
35+
36+
You can type::
37+
38+
$ cythonizer -h
39+
40+
to obtain the following CLI::
41+
42+
usage: cythonizer.py [-h] [--annotation] [--numpy-includes]
43+
[--debugmode] filenames [filenames ...]
44+
45+
positional arguments:
46+
filenames .py and .pyx files only
47+
48+
optional arguments:
49+
-h, --help show this help message and exit
50+
--annotation (default: False)
51+
--numpy-includes (default: False)
52+
--debugmode (default: False)
53+
54+
55+
- :code:`--annotation` will create the HTML Cython annotation file.
56+
- :code:`--numpy-includes` will add the numpy headers to the build command.
57+
- Compiler flags :code:`-O2 -march=native` are automatically passed to the compiler.

cythonizer/__init__.py

Whitespace-only changes.

cythonizer/cythonizer.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import argparse
2+
import logging
3+
import os
4+
import pathlib
5+
import sys
6+
7+
# Always prefer setuptools over distutils
8+
from setuptools import Extension, setup
9+
import Cython.Compiler.Options
10+
from Cython.Build import cythonize
11+
from Cython.Distutils import build_ext
12+
13+
logging.basicConfig(level=logging.DEBUG, format="%(levelname)s: %(message)s")
14+
15+
16+
class cythonizer:
17+
def __init__(self) -> None:
18+
self.__extension: list = []
19+
self.__args = self.__Arguments()
20+
self.__Checking()
21+
self.__Compiling()
22+
# self.__Cleanup()
23+
24+
# Argumebts Parser ↓
25+
def __Arguments(self):
26+
parser = argparse.ArgumentParser(
27+
description="A script that will attempt to automatically convert one or more .py and .pyx files into the corresponding compiled .pyd or .so binary modules files."
28+
)
29+
30+
# Taking Files ↓
31+
parser.add_argument(
32+
"filenames", type=pathlib.Path, nargs="+", help=".py and .pyx files only"
33+
)
34+
35+
# Cython Annotation ↓
36+
parser.add_argument(
37+
"--annotation",
38+
default=False,
39+
action="store_true",
40+
help="(default: False)",
41+
)
42+
43+
# Numpy Includes ↓
44+
parser.add_argument(
45+
"--numpy-includes",
46+
default=False,
47+
action="store_true",
48+
help="(default: False)",
49+
)
50+
51+
# Cython Debugmode ↓
52+
parser.add_argument(
53+
"--debugmode",
54+
default=False,
55+
action="store_true",
56+
help="(default: False)",
57+
)
58+
59+
return parser.parse_args().__dict__
60+
61+
# Received File Checking ↓
62+
def __Checking(self):
63+
for file in self.__args.get("filenames"):
64+
if not os.path.exists(file):
65+
logging.error(f'"{file}" doesn\'t exist.')
66+
sys.exit(-1)
67+
if not os.path.isfile(file):
68+
logging.error(f'"{file}" is not a file')
69+
sys.exit(-1)
70+
if os.path.splitext(file)[-1] not in (".py", ".pyx"):
71+
logging.error(f'"{file}" is not a valid file')
72+
sys.exit(-1)
73+
74+
# Includes Directory ↓
75+
def __Includes_Dir(self):
76+
# Extra include folders. Mainly for numpy.
77+
if self.__args.get("numpy_includes"):
78+
try:
79+
import numpy as np
80+
81+
except ModuleNotFoundError:
82+
logging.error("Numpy is required, but not found. Please install it")
83+
sys.exit(-1)
84+
return [np.get_include()]
85+
else:
86+
return []
87+
88+
# Cython Compilation ↓
89+
def __Compiling(self):
90+
Cython.Compiler.Options.annotate = self.__args.get("annotation")
91+
92+
ext_modules: list = []
93+
for _ in self.__args.get("filenames"):
94+
file: str = str(_)
95+
# The name must be plain, no path
96+
module_name = os.path.basename(file)
97+
module_name = os.path.splitext(module_name)[0]
98+
ext_modules.append(
99+
Extension(
100+
module_name, [file], extra_compile_args=["-O2", "-march=native"]
101+
)
102+
)
103+
104+
sys.argv = [sys.argv[0], "build_ext", "--inplace"]
105+
106+
setup(
107+
cmdclass={"build_ext": build_ext},
108+
include_dirs=self.__Includes_Dir(),
109+
ext_modules=cythonize(module_list=ext_modules, language_level="3"),
110+
)
111+
112+
def __Cleanup(self):
113+
# Delete intermediate C files.
114+
for _ in self.__args.get("filenames"):
115+
filename = str(_)
116+
filename = f"{filename}.c"
117+
if os.path.exists(filename):
118+
os.remove(filename)
119+
120+
121+
def main():
122+
cythonizer()
123+
124+
125+
if __name__ == "__main__":
126+
main()

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Cython>=0.29.21
2+
numpy>=1.19.4

setup.cfg

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[bdist_wheel]
2+
universal=1

0 commit comments

Comments
 (0)