1import os 2import os.path 3import platform 4import sys 5from distutils.core import Command 6from glob import glob 7 8from setuptools import ( 9 Extension, 10 setup, 11) 12from setuptools.command.sdist import sdist 13 14 15def main(): 16 metadata = dict( 17 scripts=glob("scripts/*.py"), 18 cmdclass=command_classes) 19 20 if len(sys.argv) >= 2 and \ 21 ('--help' in sys.argv[1:] or sys.argv[1] in ('--help-commands', 'egg_info', '--version', 'clean')): 22 # For these actions, NumPy is not required. 23 # 24 # They are required to succeed without Numpy for example when 25 # pip is used to install when Numpy is not yet present in 26 # the system. 27 pass 28 else: 29 try: 30 import numpy 31 # Suppress numpy tests 32 numpy.test = None 33 except Exception as e: 34 raise Exception(f"numpy must be installed to build: {e}") 35 metadata['ext_modules'] = get_extension_modules(numpy_include=numpy.get_include()) 36 37 setup(**metadata) 38 39 40# ---- Commands ------------------------------------------------------------- 41 42# Use build_ext from Cython if found 43command_classes = {} 44try: 45 import Cython.Distutils 46 command_classes['build_ext'] = Cython.Distutils.build_ext 47 48 class build_ext_sdist(sdist): 49 def run(self): 50 # Make sure the compiled Cython files in the distribution are up-to-date 51 self.run_command("build_ext") 52 super().run() 53 54 command_classes['sdist'] = build_ext_sdist 55except ImportError: 56 pass 57 58# Use epydoc if found 59try: 60 import epydoc.cli 61 62 # Create command class to build API documentation 63 class BuildAPIDocs(Command): 64 user_options = [] 65 66 def initialize_options(self): 67 pass 68 69 def finalize_options(self): 70 pass 71 72 def run(self): 73 # Save working directory and args 74 old_argv = sys.argv 75 old_cwd = os.getcwd() 76 # Build command line for Epydoc 77 sys.argv = """epydoc.py bx --verbose --html --simple-term 78 --exclude=._ 79 --exclude=_tests 80 --docformat=reStructuredText 81 --output=../doc/docbuild/html/apidoc""".split() 82 # Make output directory 83 if not os.path.exists("./doc/docbuild/html/apidoc"): 84 os.mkdir("./doc/docbuild/html/apidoc") 85 # Move to lib directory (so bx package is in current directory) 86 os.chdir("./lib") 87 # Invoke epydoc 88 epydoc.cli.cli() 89 # Restore args and working directory 90 sys.argv = old_argv 91 os.chdir(old_cwd) 92 # Add to extra_commands 93 command_classes['build_apidocs'] = BuildAPIDocs 94except Exception: 95 pass 96 97# ---- Extension Modules ---------------------------------------------------- 98 99# # suppress C++ #warning, e.g., to silence NumPy deprecation warnings: 100# from functools import partial 101# _Extension = Extension 102# Extension = partial(_Extension, extra_compile_args=["-Wno-cpp"]) 103 104 105def get_extension_modules(numpy_include=None): 106 extensions = [] 107 # Bitsets 108 extensions.append(Extension("bx.bitset", 109 ["lib/bx/bitset.pyx", 110 "src/binBits.c", 111 "src/kent/bits.c", 112 "src/kent/common.c"], 113 include_dirs=["src/kent", "src"])) 114 # Interval intersection 115 extensions.append(Extension("bx.intervals.intersection", ["lib/bx/intervals/intersection.pyx"])) 116 # Alignment object speedups 117 extensions.append(Extension("bx.align._core", ["lib/bx/align/_core.pyx"])) 118 # NIB reading speedups 119 extensions.append(Extension("bx.seq._nib", ["lib/bx/seq/_nib.pyx"])) 120 # 2bit reading speedups 121 extensions.append(Extension("bx.seq._twobit", ["lib/bx/seq/_twobit.pyx"])) 122 # Translation if character / integer strings 123 extensions.append(Extension("bx._seqmapping", ["lib/bx/_seqmapping.pyx"])) 124 # BGZF 125 extensions.append(Extension("bx.misc.bgzf", 126 ["lib/bx/misc/bgzf.pyx", "src/samtools/bgzf.c"], 127 include_dirs=["src/samtools"], 128 libraries=['z'])) 129 130 # The following extensions won't (currently) compile on windows 131 if platform.system() not in ('Microsoft', 'Windows'): 132 # Interval clustering 133 extensions.append(Extension("bx.intervals.cluster", 134 ["lib/bx/intervals/cluster.pyx", 135 "src/cluster.c"], 136 include_dirs=["src"])) 137 # Position weight matrices 138 extensions.append(Extension("bx.pwm._position_weight_matrix", 139 ["lib/bx/pwm/_position_weight_matrix.pyx", "src/pwm_utils.c"], 140 include_dirs=["src"])) 141 142 extensions.append(Extension("bx.motif._pwm", ["lib/bx/motif/_pwm.pyx"], 143 include_dirs=[numpy_include])) 144 145 # Sparse arrays with summaries organized as trees on disk 146 extensions.append(Extension("bx.arrays.array_tree", ["lib/bx/arrays/array_tree.pyx"], include_dirs=[numpy_include])) 147 148 # Reading UCSC "big binary index" files 149 extensions.append(Extension("bx.bbi.bpt_file", ["lib/bx/bbi/bpt_file.pyx"])) 150 extensions.append(Extension("bx.bbi.cirtree_file", ["lib/bx/bbi/cirtree_file.pyx"])) 151 extensions.append(Extension("bx.bbi.bbi_file", ["lib/bx/bbi/bbi_file.pyx"], include_dirs=[numpy_include])) 152 extensions.append(Extension("bx.bbi.bigwig_file", ["lib/bx/bbi/bigwig_file.pyx"], include_dirs=[numpy_include])) 153 extensions.append(Extension("bx.bbi.bigbed_file", ["lib/bx/bbi/bigbed_file.pyx"], include_dirs=[numpy_include])) 154 155 # EPO and Chain arithmetics and IO speedups 156 extensions.append(Extension("bx.align._epo", ["lib/bx/align/_epo.pyx"], include_dirs=[numpy_include])) 157 158 # Reading UCSC bed and wiggle formats 159 extensions.append(Extension("bx.arrays.bed", ["lib/bx/arrays/bed.pyx"])) 160 extensions.append(Extension("bx.arrays.wiggle", ["lib/bx/arrays/wiggle.pyx"])) 161 162 # CpG masking 163 extensions.append(Extension("bx.align.sitemask._cpg", 164 ["lib/bx/align/sitemask/_cpg.pyx", 165 "lib/bx/align/sitemask/find_cpg.c"])) 166 167 # Counting n-grams in integer strings 168 extensions.append(Extension("bx.intseq.ngramcount", ["lib/bx/intseq/ngramcount.pyx"], 169 include_dirs=["src"])) 170 171 # Seekable access to bzip2 files 172 extensions.append(Extension("bx.misc._seekbzip2", 173 ["lib/bx/misc/_seekbzip2.pyx", 174 "src/bunzip/micro-bunzip.c"], 175 include_dirs=["src/bunzip"])) 176 return extensions 177 178 179if __name__ == "__main__": 180 main() 181