1#! /usr/bin/env python
2# -*- coding: utf-8 -*-
3"""
4ObsPy - a Python framework for seismological observatories.
5
6ObsPy is an open-source project dedicated to provide a Python framework for
7processing seismological data. It provides parsers for common file formats,
8clients to access data centers and seismological signal processing routines
9which allow the manipulation of seismological time series (see Beyreuther et
10al. 2010, Megies et al. 2011).
11
12The goal of the ObsPy project is to facilitate rapid application development
13for seismology.
14
15For more information visit https://www.obspy.org.
16
17:copyright:
18    The ObsPy Development Team (devs@obspy.org)
19:license:
20    GNU Lesser General Public License, Version 3
21    (https://www.gnu.org/copyleft/lesser.html)
22"""
23# Importing setuptools monkeypatches some of distutils commands so things like
24# 'python setup.py develop' work. Wrap in try/except so it is not an actual
25# dependency. Inplace installation with pip works also without importing
26# setuptools.
27try:
28    import setuptools  # @UnusedImport # NOQA
29except ImportError:
30    pass
31
32try:
33    import numpy  # @UnusedImport # NOQA
34except ImportError:
35    msg = ("No module named numpy. "
36           "Please install numpy first, it is needed before installing ObsPy.")
37    raise ImportError(msg)
38
39import fnmatch
40import glob
41import inspect
42import os
43import sys
44import platform
45from distutils.util import change_root
46from distutils.errors import DistutilsSetupError
47
48from numpy.distutils.core import setup
49from numpy.distutils.ccompiler import get_default_compiler
50from numpy.distutils.command.build import build
51from numpy.distutils.command.install import install
52from numpy.distutils.exec_command import exec_command, find_executable
53from numpy.distutils.misc_util import Configuration
54
55
56# Directory of the current file in the (hopefully) most reliable way
57# possible, according to krischer
58SETUP_DIRECTORY = os.path.dirname(os.path.abspath(inspect.getfile(
59    inspect.currentframe())))
60
61# Import the version string.
62# Any .py files that are used at install time must be registered in
63# obspy.core.tests.test_util_misc.UtilMiscTestCase.test_no_obspy_imports!
64UTIL_PATH = os.path.join(SETUP_DIRECTORY, "obspy", "core", "util")
65sys.path.insert(0, UTIL_PATH)
66from version import get_git_version  # @UnresolvedImport
67from libnames import _get_lib_name  # @UnresolvedImport
68sys.path.pop(0)
69
70LOCAL_PATH = os.path.join(SETUP_DIRECTORY, "setup.py")
71DOCSTRING = __doc__.split("\n")
72
73# check for MSVC
74if platform.system() == "Windows" and (
75        'msvc' in sys.argv or
76        '-c' not in sys.argv and
77        get_default_compiler() == 'msvc'):
78    IS_MSVC = True
79else:
80    IS_MSVC = False
81
82# Use system libraries? Set later...
83EXTERNAL_EVALRESP = False
84EXTERNAL_LIBMSEED = False
85
86# package specific settings
87KEYWORDS = [
88    'ArcLink', 'array', 'array analysis', 'ASC', 'beachball',
89    'beamforming', 'cross correlation', 'database', 'dataless',
90    'Dataless SEED', 'DMX', 'earthquakes', 'Earthworm', 'EIDA',
91    'envelope', 'ESRI', 'events', 'FDSN', 'features', 'filter',
92    'focal mechanism', 'FOCMEC', 'GCF', 'GSE1', 'GSE2', 'hob', 'Tau-P',
93    'IASPEI', 'imaging', 'IMS', 'instrument correction',
94    'instrument simulation', 'IRIS', 'ISF', 'kinemetrics', 'KML', 'magnitude',
95    'MiniSEED', 'misfit', 'mopad', 'MSEED', 'NDK', 'NERA', 'NERIES',
96    'NonLinLoc', 'NLLOC', 'Nordic', 'NRL', 'observatory', 'ORFEUS', 'PDAS',
97    'picker', 'processing', 'PQLX', 'Q', 'real time', 'realtime', 'REFTEK',
98    'REFTEK130', 'RG-1.6', 'RT-130', 'RESP', 'response file', 'RT', 'SAC',
99    'scardec', 'sc3ml', 'SDS', 'SEED', 'SeedLink', 'SEG-2', 'SEG Y', 'SEISAN',
100    'SeisHub', 'Seismic Handler', 'seismology', 'seismogram', 'seismograms',
101    'shapefile', 'signal', 'slink', 'spectrogram', 'StationXML', 'taper',
102    'taup', 'travel time', 'trigger', 'VERCE', 'WAV', 'waveform', 'WaveServer',
103    'WaveServerV', 'WebDC', 'web service', 'WIN', 'Winston', 'XML-SEED',
104    'XSEED']
105
106# when bumping to numpy 1.9.0: replace bytes() in io.reftek with np.tobytes()
107# and in obspy/io/mseed/core.py change downcasting check to numpy.can_cast()
108# when bumping to numpy 1.7.0: get rid of if/else when loading npz file to PPSD
109# and get rid of helper function _np_copy_astype() in obspy/io/mseed/core.py
110INSTALL_REQUIRES = [
111    'future>=0.12.4',
112    'numpy>=1.6.1',
113    'scipy>=0.9.0',
114    'matplotlib>=1.1.0',
115    'lxml',
116    'setuptools',
117    'sqlalchemy',
118    'decorator',
119    'requests']
120EXTRAS_REQUIRE = {
121    'tests': ['flake8>=2', 'pyimgur', 'pyproj', 'pep8-naming'],
122    # arclink decryption also works with: pycrypto, m2crypto, pycryptodome
123    'arclink': ['cryptography'],
124    'io.shapefile': ['pyshp'],
125    }
126# PY2
127if sys.version_info[0] == 2:
128    EXTRAS_REQUIRE['tests'].append('mock')
129
130ENTRY_POINTS = {
131    'console_scripts': [
132        'obspy-flinn-engdahl = obspy.scripts.flinnengdahl:main',
133        'obspy-runtests = obspy.scripts.runtests:main',
134        'obspy-reftek-rescue = obspy.scripts.reftekrescue:main',
135        'obspy-print = obspy.scripts._print:main',
136        'obspy-sds-report = obspy.scripts.sds_html_report:main',
137        'obspy-indexer = obspy.db.scripts.indexer:main',
138        'obspy-scan = obspy.imaging.scripts.scan:main',
139        'obspy-plot = obspy.imaging.scripts.plot:main',
140        'obspy-mopad = obspy.imaging.scripts.mopad:main',
141        'obspy-mseed-recordanalyzer = '
142        'obspy.io.mseed.scripts.recordanalyzer:main',
143        'obspy-dataless2xseed = obspy.io.xseed.scripts.dataless2xseed:main',
144        'obspy-xseed2dataless = obspy.io.xseed.scripts.xseed2dataless:main',
145        'obspy-dataless2resp = obspy.io.xseed.scripts.dataless2resp:main',
146        ],
147    'obspy.plugin.waveform': [
148        'TSPAIR = obspy.io.ascii.core',
149        'SLIST = obspy.io.ascii.core',
150        'PICKLE = obspy.core.stream',
151        'CSS = obspy.io.css.core',
152        'WIN = obspy.io.win.core',
153        'KINEMETRICS_EVT = obspy.io.kinemetrics.core',
154        'GSE1 = obspy.io.gse2.core',
155        'GSE2 = obspy.io.gse2.core',
156        'MSEED = obspy.io.mseed.core',
157        'NNSA_KB_CORE = obspy.io.css.core',
158        'PDAS = obspy.io.pdas.core',
159        'SAC = obspy.io.sac.core',
160        'SACXY = obspy.io.sac.core',
161        'Y = obspy.io.y.core',
162        'SEG2 = obspy.io.seg2.seg2',
163        'SEGY = obspy.io.segy.core',
164        'SU = obspy.io.segy.core',
165        'SEISAN = obspy.io.seisan.core',
166        'Q = obspy.io.sh.core',
167        'SH_ASC = obspy.io.sh.core',
168        'WAV = obspy.io.wav.core',
169        'AH = obspy.io.ah.core',
170        'KNET = obspy.io.nied.knet',
171        'GCF = obspy.io.gcf.core',
172        'REFTEK130 = obspy.io.reftek.core',
173        'RG16 = obspy.io.rg16.core',
174        'DMX = obspy.io.dmx.core',
175        ],
176    'obspy.plugin.waveform.TSPAIR': [
177        'isFormat = obspy.io.ascii.core:_is_tspair',
178        'readFormat = obspy.io.ascii.core:_read_tspair',
179        'writeFormat = obspy.io.ascii.core:_write_tspair',
180        ],
181    'obspy.plugin.waveform.SLIST': [
182        'isFormat = obspy.io.ascii.core:_is_slist',
183        'readFormat = obspy.io.ascii.core:_read_slist',
184        'writeFormat = obspy.io.ascii.core:_write_slist',
185        ],
186    'obspy.plugin.waveform.PICKLE': [
187        'isFormat = obspy.core.stream:_is_pickle',
188        'readFormat = obspy.core.stream:_read_pickle',
189        'writeFormat = obspy.core.stream:_write_pickle',
190        ],
191    'obspy.plugin.waveform.CSS': [
192        'isFormat = obspy.io.css.core:_is_css',
193        'readFormat = obspy.io.css.core:_read_css',
194        ],
195    'obspy.plugin.waveform.NNSA_KB_CORE': [
196        'isFormat = obspy.io.css.core:_is_nnsa_kb_core',
197        'readFormat = obspy.io.css.core:_read_nnsa_kb_core',
198        ],
199    'obspy.plugin.waveform.WIN': [
200        'isFormat = obspy.io.win.core:_is_win',
201        'readFormat = obspy.io.win.core:_read_win',
202        ],
203    'obspy.plugin.waveform.KINEMETRICS_EVT': [
204        'isFormat = obspy.io.kinemetrics.core:is_evt',
205        'readFormat = obspy.io.kinemetrics.core:read_evt',
206        ],
207    'obspy.plugin.waveform.GSE1': [
208        'isFormat = obspy.io.gse2.core:_is_gse1',
209        'readFormat = obspy.io.gse2.core:_read_gse1',
210        ],
211    'obspy.plugin.waveform.GSE2': [
212        'isFormat = obspy.io.gse2.core:_is_gse2',
213        'readFormat = obspy.io.gse2.core:_read_gse2',
214        'writeFormat = obspy.io.gse2.core:_write_gse2',
215        ],
216    'obspy.plugin.waveform.MSEED': [
217        'isFormat = obspy.io.mseed.core:_is_mseed',
218        'readFormat = obspy.io.mseed.core:_read_mseed',
219        'writeFormat = obspy.io.mseed.core:_write_mseed',
220        ],
221    'obspy.plugin.waveform.PDAS': [
222        'isFormat = obspy.io.pdas.core:_is_pdas',
223        'readFormat = obspy.io.pdas.core:_read_pdas',
224        ],
225    'obspy.plugin.waveform.SAC': [
226        'isFormat = obspy.io.sac.core:_is_sac',
227        'readFormat = obspy.io.sac.core:_read_sac',
228        'writeFormat = obspy.io.sac.core:_write_sac',
229        ],
230    'obspy.plugin.waveform.SACXY': [
231        'isFormat = obspy.io.sac.core:_is_sac_xy',
232        'readFormat = obspy.io.sac.core:_read_sac_xy',
233        'writeFormat = obspy.io.sac.core:_write_sac_xy',
234        ],
235    'obspy.plugin.waveform.SEG2': [
236        'isFormat = obspy.io.seg2.seg2:_is_seg2',
237        'readFormat = obspy.io.seg2.seg2:_read_seg2',
238        ],
239    'obspy.plugin.waveform.SEGY': [
240        'isFormat = obspy.io.segy.core:_is_segy',
241        'readFormat = obspy.io.segy.core:_read_segy',
242        'writeFormat = obspy.io.segy.core:_write_segy',
243        ],
244    'obspy.plugin.waveform.SU': [
245        'isFormat = obspy.io.segy.core:_is_su',
246        'readFormat = obspy.io.segy.core:_read_su',
247        'writeFormat = obspy.io.segy.core:_write_su',
248        ],
249    'obspy.plugin.waveform.SEISAN': [
250        'isFormat = obspy.io.seisan.core:_is_seisan',
251        'readFormat = obspy.io.seisan.core:_read_seisan',
252        ],
253    'obspy.plugin.waveform.Q': [
254        'isFormat = obspy.io.sh.core:_is_q',
255        'readFormat = obspy.io.sh.core:_read_q',
256        'writeFormat = obspy.io.sh.core:_write_q',
257        ],
258    'obspy.plugin.waveform.SH_ASC': [
259        'isFormat = obspy.io.sh.core:_is_asc',
260        'readFormat = obspy.io.sh.core:_read_asc',
261        'writeFormat = obspy.io.sh.core:_write_asc',
262        ],
263    'obspy.plugin.waveform.WAV': [
264        'isFormat = obspy.io.wav.core:_is_wav',
265        'readFormat = obspy.io.wav.core:_read_wav',
266        'writeFormat = obspy.io.wav.core:_write_wav',
267        ],
268    'obspy.plugin.waveform.Y': [
269        'isFormat = obspy.io.y.core:_is_y',
270        'readFormat = obspy.io.y.core:_read_y',
271        ],
272    'obspy.plugin.waveform.AH': [
273        'isFormat = obspy.io.ah.core:_is_ah',
274        'readFormat = obspy.io.ah.core:_read_ah',
275        'writeFormat = obspy.io.ah.core:_write_ah1'
276        ],
277    'obspy.plugin.waveform.KNET': [
278        'isFormat = obspy.io.nied.knet:_is_knet_ascii',
279        'readFormat = obspy.io.nied.knet:_read_knet_ascii',
280        ],
281    'obspy.plugin.waveform.GCF': [
282        'isFormat = obspy.io.gcf.core:_is_gcf',
283        'readFormat = obspy.io.gcf.core:_read_gcf',
284        ],
285    'obspy.plugin.waveform.REFTEK130': [
286        'isFormat = obspy.io.reftek.core:_is_reftek130',
287        'readFormat = obspy.io.reftek.core:_read_reftek130',
288        ],
289    'obspy.plugin.waveform.RG16': [
290        'isFormat = obspy.io.rg16.core:_is_rg16',
291        'readFormat = obspy.io.rg16.core:_read_rg16',
292    ],
293    'obspy.plugin.waveform.DMX': [
294        'isFormat = obspy.io.dmx.core:_is_dmx',
295        'readFormat = obspy.io.dmx.core:_read_dmx',
296    ],
297    'obspy.plugin.event': [
298        'QUAKEML = obspy.io.quakeml.core',
299        'SC3ML = obspy.io.seiscomp.event',
300        'ZMAP = obspy.io.zmap.core',
301        'MCHEDR = obspy.io.pde.mchedr',
302        'JSON = obspy.io.json.core',
303        'NDK = obspy.io.ndk.core',
304        'NLLOC_HYP = obspy.io.nlloc.core',
305        'NLLOC_OBS = obspy.io.nlloc.core',
306        'NORDIC = obspy.io.nordic.core',
307        'CNV = obspy.io.cnv.core',
308        'CMTSOLUTION = obspy.io.cmtsolution.core',
309        'SCARDEC = obspy.io.scardec.core',
310        'SHAPEFILE = obspy.io.shapefile.core',
311        'KML = obspy.io.kml.core',
312        'FNETMT = obspy.io.nied.fnetmt',
313        'GSE2 = obspy.io.gse2.bulletin',
314        'IMS10BULLETIN = obspy.io.iaspei.core',
315        'EVT = obspy.io.sh.evt',
316        'FOCMEC = obspy.io.focmec.core',
317        'HYPODDPHA = obspy.io.hypodd.pha'
318        ],
319    'obspy.plugin.event.QUAKEML': [
320        'isFormat = obspy.io.quakeml.core:_is_quakeml',
321        'readFormat = obspy.io.quakeml.core:_read_quakeml',
322        'writeFormat = obspy.io.quakeml.core:_write_quakeml',
323        ],
324    'obspy.plugin.event.SC3ML': [
325        'isFormat = obspy.io.seiscomp.core:_is_sc3ml',
326        'readFormat = obspy.io.seiscomp.event:_read_sc3ml',
327        'writeFormat = obspy.io.seiscomp.event:_write_sc3ml',
328        ],
329    'obspy.plugin.event.MCHEDR': [
330        'isFormat = obspy.io.pde.mchedr:_is_mchedr',
331        'readFormat = obspy.io.pde.mchedr:_read_mchedr',
332        ],
333    'obspy.plugin.event.JSON': [
334        'writeFormat = obspy.io.json.core:_write_json',
335        ],
336    'obspy.plugin.event.ZMAP': [
337        'isFormat = obspy.io.zmap.core:_is_zmap',
338        'readFormat = obspy.io.zmap.core:_read_zmap',
339        'writeFormat = obspy.io.zmap.core:_write_zmap',
340        ],
341    'obspy.plugin.event.CNV': [
342        'writeFormat = obspy.io.cnv.core:_write_cnv',
343        ],
344    'obspy.plugin.event.NDK': [
345        'isFormat = obspy.io.ndk.core:_is_ndk',
346        'readFormat = obspy.io.ndk.core:_read_ndk',
347        ],
348    'obspy.plugin.event.NLLOC_HYP': [
349        'isFormat = obspy.io.nlloc.core:is_nlloc_hyp',
350        'readFormat = obspy.io.nlloc.core:read_nlloc_hyp',
351        ],
352    'obspy.plugin.event.NLLOC_OBS': [
353        'writeFormat = obspy.io.nlloc.core:write_nlloc_obs',
354        ],
355    'obspy.plugin.event.NORDIC': [
356        'writeFormat = obspy.io.nordic.core:write_select',
357        'readFormat = obspy.io.nordic.core:read_nordic',
358        'isFormat = obspy.io.nordic.core:_is_sfile'
359        ],
360    'obspy.plugin.event.CMTSOLUTION': [
361        'isFormat = obspy.io.cmtsolution.core:_is_cmtsolution',
362        'readFormat = obspy.io.cmtsolution.core:_read_cmtsolution',
363        'writeFormat = obspy.io.cmtsolution.core:_write_cmtsolution'
364        ],
365    'obspy.plugin.event.SCARDEC': [
366        'isFormat = obspy.io.scardec.core:_is_scardec',
367        'readFormat = obspy.io.scardec.core:_read_scardec',
368        'writeFormat = obspy.io.scardec.core:_write_scardec'
369        ],
370    'obspy.plugin.event.FNETMT': [
371        'isFormat = obspy.io.nied.fnetmt:_is_fnetmt_catalog',
372        'readFormat = obspy.io.nied.fnetmt:_read_fnetmt_catalog',
373        ],
374    'obspy.plugin.event.GSE2': [
375        'isFormat = obspy.io.gse2.bulletin:_is_gse2',
376        'readFormat = obspy.io.gse2.bulletin:_read_gse2',
377        ],
378    'obspy.plugin.event.SHAPEFILE': [
379        'writeFormat = obspy.io.shapefile.core:_write_shapefile',
380        ],
381    'obspy.plugin.event.KML': [
382        'writeFormat = obspy.io.kml.core:_write_kml',
383        ],
384    'obspy.plugin.event.IMS10BULLETIN': [
385        'isFormat = obspy.io.iaspei.core:_is_ims10_bulletin',
386        'readFormat = obspy.io.iaspei.core:_read_ims10_bulletin',
387        ],
388    'obspy.plugin.event.EVT': [
389        'isFormat = obspy.io.sh.evt:_is_evt',
390        'readFormat = obspy.io.sh.evt:_read_evt',
391        ],
392    'obspy.plugin.event.FOCMEC': [
393        'isFormat = obspy.io.focmec.core:_is_focmec',
394        'readFormat = obspy.io.focmec.core:_read_focmec',
395        ],
396    'obspy.plugin.event.HYPODDPHA': [
397        'isFormat = obspy.io.hypodd.pha:_is_pha',
398        'readFormat = obspy.io.hypodd.pha:_read_pha',
399        ],
400    'obspy.plugin.inventory': [
401        'STATIONXML = obspy.io.stationxml.core',
402        'INVENTORYXML = obspy.io.arclink.inventory',
403        'SC3ML = obspy.io.seiscomp.inventory',
404        'SACPZ = obspy.io.sac.sacpz',
405        'CSS = obspy.io.css.station',
406        'SHAPEFILE = obspy.io.shapefile.core',
407        'STATIONTXT = obspy.io.stationtxt.core',
408        'KML = obspy.io.kml.core',
409        'SEED = obspy.io.xseed.core',
410        'XSEED = obspy.io.xseed.core',
411        'RESP = obspy.io.xseed.core',
412        ],
413    'obspy.plugin.inventory.STATIONXML': [
414        'isFormat = obspy.io.stationxml.core:_is_stationxml',
415        'readFormat = obspy.io.stationxml.core:_read_stationxml',
416        'writeFormat = obspy.io.stationxml.core:_write_stationxml',
417        ],
418    'obspy.plugin.inventory.INVENTORYXML': [
419        'isFormat = obspy.io.arclink.inventory:_is_inventory_xml',
420        'readFormat = obspy.io.arclink.inventory:_read_inventory_xml',
421        ],
422    'obspy.plugin.inventory.SC3ML': [
423        'isFormat = obspy.io.seiscomp.core:_is_sc3ml',
424        'readFormat = obspy.io.seiscomp.inventory:_read_sc3ml',
425        ],
426    'obspy.plugin.inventory.SACPZ': [
427        'writeFormat = obspy.io.sac.sacpz:_write_sacpz',
428        ],
429    'obspy.plugin.inventory.CSS': [
430        'writeFormat = obspy.io.css.station:_write_css',
431        ],
432    'obspy.plugin.inventory.SHAPEFILE': [
433        'writeFormat = obspy.io.shapefile.core:_write_shapefile',
434        ],
435    'obspy.plugin.inventory.STATIONTXT': [
436        'isFormat = obspy.io.stationtxt.core:is_fdsn_station_text_file',
437        'readFormat = '
438        'obspy.io.stationtxt.core:read_fdsn_station_text_file',
439        'writeFormat = obspy.io.stationtxt.core:_write_stationtxt',
440        ],
441    'obspy.plugin.inventory.KML': [
442        'writeFormat = obspy.io.kml.core:_write_kml',
443        ],
444    'obspy.plugin.inventory.SEED': [
445        'isFormat = obspy.io.xseed.core:_is_seed',
446        'readFormat = obspy.io.xseed.core:_read_seed',
447    ],
448    'obspy.plugin.inventory.XSEED': [
449        'isFormat = obspy.io.xseed.core:_is_xseed',
450        'readFormat = obspy.io.xseed.core:_read_xseed',
451    ],
452    'obspy.plugin.inventory.RESP': [
453        'isFormat = obspy.io.xseed.core:_is_resp',
454        'readFormat = obspy.io.xseed.core:_read_resp',
455    ],
456    'obspy.plugin.detrend': [
457        'linear = scipy.signal:detrend',
458        'constant = scipy.signal:detrend',
459        'demean = scipy.signal:detrend',
460        'simple = obspy.signal.detrend:simple',
461        'polynomial = obspy.signal.detrend:polynomial',
462        'spline = obspy.signal.detrend:spline'
463        ],
464    'obspy.plugin.differentiate': [
465        'gradient = numpy:gradient',
466        ],
467    'obspy.plugin.integrate': [
468        'cumtrapz = '
469        'obspy.signal.differentiate_and_integrate:integrate_cumtrapz',
470        'spline = '
471        'obspy.signal.differentiate_and_integrate:integrate_spline',
472        ],
473    'obspy.plugin.filter': [
474        'bandpass = obspy.signal.filter:bandpass',
475        'bandstop = obspy.signal.filter:bandstop',
476        'lowpass = obspy.signal.filter:lowpass',
477        'highpass = obspy.signal.filter:highpass',
478        'lowpass_cheby_2 = obspy.signal.filter:lowpass_cheby_2',
479        'lowpass_fir = obspy.signal.filter:lowpass_FIR',
480        'remez_fir = obspy.signal.filter:remez_FIR',
481        ],
482    'obspy.plugin.interpolate': [
483        'interpolate_1d = obspy.signal.interpolation:interpolate_1d',
484        'weighted_average_slopes = '
485        'obspy.signal.interpolation:weighted_average_slopes',
486        'lanczos = obspy.signal.interpolation:lanczos_interpolation'
487        ],
488    'obspy.plugin.rotate': [
489        'rotate_ne_rt = obspy.signal.rotate:rotate_ne_rt',
490        'rotate_rt_ne = obspy.signal.rotate:rotate_rt_ne',
491        'rotate_zne_lqt = obspy.signal.rotate:rotate_zne_lqt',
492        'rotate_lqt_zne = obspy.signal.rotate:rotate_lqt_zne'
493        ],
494    'obspy.plugin.taper': [
495        'cosine = obspy.signal.invsim:cosine_taper',
496        'barthann = scipy.signal:barthann',
497        'bartlett = scipy.signal:bartlett',
498        'blackman = scipy.signal:blackman',
499        'blackmanharris = scipy.signal:blackmanharris',
500        'bohman = scipy.signal:bohman',
501        'boxcar = scipy.signal:boxcar',
502        'chebwin = scipy.signal:chebwin',
503        'flattop = scipy.signal:flattop',
504        'gaussian = scipy.signal:gaussian',
505        'general_gaussian = scipy.signal:general_gaussian',
506        'hamming = scipy.signal:hamming',
507        'hann = scipy.signal:hann',
508        'kaiser = scipy.signal:kaiser',
509        'nuttall = scipy.signal:nuttall',
510        'parzen = scipy.signal:parzen',
511        'slepian = scipy.signal:slepian',
512        'triang = scipy.signal:triang',
513        ],
514    'obspy.plugin.trigger': [
515        'recstalta = obspy.signal.trigger:recursive_sta_lta',
516        'carlstatrig = obspy.signal.trigger:carl_sta_trig',
517        'classicstalta = obspy.signal.trigger:classic_sta_lta',
518        'delayedstalta = obspy.signal.trigger:delayed_sta_lta',
519        'zdetect = obspy.signal.trigger:z_detect',
520        'recstaltapy = obspy.signal.trigger:recursive_sta_lta_py',
521        'classicstaltapy = obspy.signal.trigger:classic_sta_lta_py',
522        ],
523    'obspy.db.feature': [
524        'minmax_amplitude = obspy.db.feature:MinMaxAmplitudeFeature',
525        'bandpass_preview = obspy.db.feature:BandpassPreviewFeature',
526        ],
527    }
528
529
530def find_packages():
531    """
532    Simple function to find all modules under the current folder.
533    """
534    modules = []
535    for dirpath, _, filenames in os.walk(os.path.join(SETUP_DIRECTORY,
536                                                      "obspy")):
537        if "__init__.py" in filenames:
538            modules.append(os.path.relpath(dirpath, SETUP_DIRECTORY))
539    return [_i.replace(os.sep, ".") for _i in modules]
540
541
542# monkey patches for MS Visual Studio
543if IS_MSVC:
544    import distutils
545    from distutils.msvc9compiler import MSVCCompiler
546
547    # for Python 2.x only -> support library paths containing spaces
548    if distutils.__version__.startswith('2.'):
549        def _library_dir_option(self, dir):
550            return '/LIBPATH:"%s"' % (dir)
551
552        MSVCCompiler.library_dir_option = _library_dir_option
553
554    # remove 'init' entry in exported symbols
555    def _get_export_symbols(self, ext):
556        return ext.export_symbols
557    from distutils.command.build_ext import build_ext
558    build_ext.get_export_symbols = _get_export_symbols
559
560
561# helper function for collecting export symbols from .def files
562def export_symbols(*path):
563    lines = open(os.path.join(*path), 'r').readlines()[2:]
564    return [s.strip() for s in lines if s.strip() != '']
565
566
567# adds --with-system-libs command-line option if possible
568def add_features():
569    if 'setuptools' not in sys.modules or not hasattr(setuptools, 'Feature'):
570        return {}
571
572    class ExternalLibFeature(setuptools.Feature):
573        def __init__(self, *args, **kwargs):
574            self.name = kwargs['name']
575            setuptools.Feature.__init__(self, *args, **kwargs)
576
577        def include_in(self, dist):
578            globals()[self.name] = True
579
580        def exclude_from(self, dist):
581            globals()[self.name] = False
582
583    return {
584        'system-libs': setuptools.Feature(
585            'use of system C libraries',
586            standard=False,
587            require_features=('system-evalresp', 'system-libmseed')
588        ),
589        'system-evalresp': ExternalLibFeature(
590            'use of system evalresp library',
591            standard=False,
592            name='EXTERNAL_EVALRESP'
593        ),
594        'system-libmseed': ExternalLibFeature(
595            'use of system libmseed library',
596            standard=False,
597            name='EXTERNAL_LIBMSEED'
598        )
599    }
600
601
602def configuration(parent_package="", top_path=None):
603    """
604    Config function mainly used to compile C code.
605    """
606    config = Configuration("", parent_package, top_path)
607
608    # GSE2
609    path = os.path.join("obspy", "io", "gse2", "src", "GSE_UTI")
610    files = [os.path.join(path, "gse_functions.c")]
611    # compiler specific options
612    kwargs = {}
613    if IS_MSVC:
614        # get export symbols
615        kwargs['export_symbols'] = export_symbols(path, 'gse_functions.def')
616    config.add_extension(_get_lib_name("gse2", add_extension_suffix=False),
617                         files, **kwargs)
618
619    # LIBMSEED
620    path = os.path.join("obspy", "io", "mseed", "src")
621    files = [os.path.join(path, "obspy-readbuffer.c")]
622    if not EXTERNAL_LIBMSEED:
623        files += glob.glob(os.path.join(path, "libmseed", "*.c"))
624    # compiler specific options
625    kwargs = {}
626    if IS_MSVC:
627        # needed by libmseed lmplatform.h
628        kwargs['define_macros'] = [('WIN32', '1')]
629        # get export symbols
630        kwargs['export_symbols'] = \
631            export_symbols(path, 'libmseed', 'libmseed.def')
632        kwargs['export_symbols'] += \
633            export_symbols(path, 'obspy-readbuffer.def')
634    if EXTERNAL_LIBMSEED:
635        kwargs['libraries'] = ['mseed']
636    config.add_extension(_get_lib_name("mseed", add_extension_suffix=False),
637                         files, **kwargs)
638
639    # SEGY
640    path = os.path.join("obspy", "io", "segy", "src")
641    files = [os.path.join(path, "ibm2ieee.c")]
642    # compiler specific options
643    kwargs = {}
644    if IS_MSVC:
645        # get export symbols
646        kwargs['export_symbols'] = export_symbols(path, 'libsegy.def')
647    config.add_extension(_get_lib_name("segy", add_extension_suffix=False),
648                         files, **kwargs)
649
650    # SIGNAL
651    path = os.path.join("obspy", "signal", "src")
652    files = glob.glob(os.path.join(path, "*.c"))
653    # compiler specific options
654    kwargs = {}
655    if IS_MSVC:
656        # get export symbols
657        kwargs['export_symbols'] = export_symbols(path, 'libsignal.def')
658    config.add_extension(_get_lib_name("signal", add_extension_suffix=False),
659                         files, **kwargs)
660
661    # EVALRESP
662    path = os.path.join("obspy", "signal", "src")
663    if EXTERNAL_EVALRESP:
664        files = glob.glob(os.path.join(path, "evalresp", "_obspy*.c"))
665    else:
666        files = glob.glob(os.path.join(path, "evalresp", "*.c"))
667    # compiler specific options
668    kwargs = {}
669    if IS_MSVC:
670        # needed by evalresp evresp.h
671        kwargs['define_macros'] = [('WIN32', '1')]
672        # get export symbols
673        kwargs['export_symbols'] = export_symbols(path, 'libevresp.def')
674    if EXTERNAL_EVALRESP:
675        kwargs['libraries'] = ['evresp']
676    config.add_extension(_get_lib_name("evresp", add_extension_suffix=False),
677                         files, **kwargs)
678
679    # TAU
680    path = os.path.join("obspy", "taup", "src")
681    files = [os.path.join(path, "inner_tau_loops.c")]
682    # compiler specific options
683    kwargs = {}
684    if IS_MSVC:
685        # get export symbols
686        kwargs['export_symbols'] = export_symbols(path, 'libtau.def')
687    config.add_extension(_get_lib_name("tau", add_extension_suffix=False),
688                         files, **kwargs)
689
690    add_data_files(config)
691
692    return config
693
694
695def add_data_files(config):
696    """
697    Recursively include all non python files
698    """
699    # python files are included per default, we only include data files
700    # here
701    EXCLUDE_WILDCARDS = ['*.py', '*.pyc', '*.pyo', '*.pdf', '.git*']
702    EXCLUDE_DIRS = ['src', '__pycache__']
703    common_prefix = SETUP_DIRECTORY + os.path.sep
704    for root, dirs, files in os.walk(os.path.join(SETUP_DIRECTORY, 'obspy')):
705        root = root.replace(common_prefix, '')
706        for name in files:
707            if any(fnmatch.fnmatch(name, w) for w in EXCLUDE_WILDCARDS):
708                continue
709            config.add_data_files(os.path.join(root, name))
710        for folder in EXCLUDE_DIRS:
711            if folder in dirs:
712                dirs.remove(folder)
713
714    # Force include the contents of some directories.
715    FORCE_INCLUDE_DIRS = [
716        os.path.join(SETUP_DIRECTORY, 'obspy', 'io', 'mseed', 'src',
717                     'libmseed', 'test')]
718
719    for folder in FORCE_INCLUDE_DIRS:
720        for root, _, files in os.walk(folder):
721            for filename in files:
722                config.add_data_files(
723                    os.path.relpath(os.path.join(root, filename),
724                                    SETUP_DIRECTORY))
725
726
727# Auto-generate man pages from --help output
728class Help2ManBuild(build):
729    description = "Run help2man on scripts to produce man pages"
730
731    def finalize_options(self):
732        build.finalize_options(self)
733        self.help2man = find_executable('help2man')
734        if not self.help2man:
735            raise DistutilsSetupError('Building man pages requires help2man.')
736
737    def run(self):
738        mandir = os.path.join(self.build_base, 'man')
739        self.mkpath(mandir)
740
741        from pkg_resources import EntryPoint
742        for entrypoint in ENTRY_POINTS['console_scripts']:
743            ep = EntryPoint.parse(entrypoint)
744            if not ep.module_name.startswith('obspy'):
745                continue
746
747            output = os.path.join(mandir, ep.name + '.1')
748            print('Generating %s ...' % (output))
749            exec_command([self.help2man,
750                          '--no-info', '--no-discard-stderr',
751                          '--output', output,
752                          '"%s -m %s"' % (sys.executable,
753                                          ep.module_name)])
754
755
756class Help2ManInstall(install):
757    description = 'Install man pages generated by help2man'
758    user_options = install.user_options + [
759        ('manprefix=', None, 'MAN Prefix Path')
760    ]
761
762    def initialize_options(self):
763        self.manprefix = None
764        install.initialize_options(self)
765
766    def finalize_options(self):
767        if self.manprefix is None:
768            self.manprefix = os.path.join('share', 'man')
769        install.finalize_options(self)
770
771    def run(self):
772        if not self.skip_build:
773            self.run_command('build_man')
774
775        srcdir = os.path.join(self.build_base, 'man')
776        mandir = os.path.join(self.install_base, self.manprefix, 'man1')
777        if self.root is not None:
778            mandir = change_root(self.root, mandir)
779        self.mkpath(mandir)
780        self.copy_tree(srcdir, mandir)
781
782
783def setupPackage():
784    # setup package
785    setup(
786        name='obspy',
787        version=get_git_version(),
788        description=DOCSTRING[1],
789        long_description="\n".join(DOCSTRING[3:]),
790        url="https://www.obspy.org",
791        author='The ObsPy Development Team',
792        author_email='devs@obspy.org',
793        license='GNU Lesser General Public License, Version 3 (LGPLv3)',
794        platforms='OS Independent',
795        classifiers=[
796            'Development Status :: 5 - Production/Stable',
797            'Environment :: Console',
798            'Intended Audience :: Science/Research',
799            'Intended Audience :: Developers',
800            'License :: OSI Approved :: GNU Library or ' +
801                'Lesser General Public License (LGPL)',
802            'Operating System :: OS Independent',
803            'Programming Language :: Python',
804            'Programming Language :: Python :: 2',
805            'Programming Language :: Python :: 2.7',
806            'Programming Language :: Python :: 3',
807            'Programming Language :: Python :: 3.4',
808            'Programming Language :: Python :: 3.5',
809            'Programming Language :: Python :: 3.6',
810            'Programming Language :: Python :: 3.7',
811            'Programming Language :: Python :: 3.8',
812            'Topic :: Scientific/Engineering',
813            'Topic :: Scientific/Engineering :: Physics'],
814        keywords=KEYWORDS,
815        packages=find_packages(),
816        namespace_packages=[],
817        zip_safe=False,
818        install_requires=INSTALL_REQUIRES,
819        extras_require=EXTRAS_REQUIRE,
820        features=add_features(),
821        # this is needed for "easy_install obspy==dev"
822        download_url=("https://github.com/obspy/obspy/zipball/master"
823                      "#egg=obspy=dev"),
824        include_package_data=True,
825        entry_points=ENTRY_POINTS,
826        ext_package='obspy.lib',
827        cmdclass={
828            'build_man': Help2ManBuild,
829            'install_man': Help2ManInstall
830        },
831        configuration=configuration)
832
833
834if __name__ == '__main__':
835    # clean --all does not remove extensions automatically
836    if 'clean' in sys.argv and '--all' in sys.argv:
837        import shutil
838        # delete complete build directory
839        path = os.path.join(SETUP_DIRECTORY, 'build')
840        try:
841            shutil.rmtree(path)
842        except Exception:
843            pass
844        # delete all shared libs from lib directory
845        path = os.path.join(SETUP_DIRECTORY, 'obspy', 'lib')
846        for filename in glob.glob(path + os.sep + '*.pyd'):
847            try:
848                os.remove(filename)
849            except Exception:
850                pass
851        for filename in glob.glob(path + os.sep + '*.so'):
852            try:
853                os.remove(filename)
854            except Exception:
855                pass
856        path = os.path.join(SETUP_DIRECTORY, 'obspy', 'taup', 'data', 'models')
857        try:
858            shutil.rmtree(path)
859        except Exception:
860            pass
861    else:
862        setupPackage()
863