1#!/usr/bin/env python3
  2
  3"""Test there is a valid Python environment available.
  4
  5This is a standalone file that doesn't need any other CHART code and is used to test
  6interpreter installation."""
  7
  8import sys
  9import subprocess
 10from pathlib import Path
 11import warnings
 12
 13# disable matplotlib warnings about collections
 14# (this doesn't work)
 15# warnings.simplefilter('ignore')
 16# (this also doesn't work)
 17# warnings.filterwarnings('ignore', category=DeprecationWarning)
 18
 19def warn(*args, **kwargs):
 20    """Messy but functional way to disable pointless depreciation warnings from matplotlib."""
 21    pass
 22
 23warnings.warn = warn
 24
 25target = sys.stdout
 26
 27
 28def shell(command):
 29    """Run a command in a shell."""
 30    # print('>', command)
 31    subprocess.run(command.split(' '))
 32
 33
 34def test_interpreter():
 35    """Check for a recent Python interpreter."""
 36    import platform
 37    assert platform.python_version_tuple()[0] >= '3' and platform.python_version_tuple()[1] >= '6'
 38
 39# def prereq(package, version):
 40    # target.write('Found {package} {version}\n'.format(package=package, version=version))
 41# ;
 42
 43# def test_prereq():
 44    # """Test suitable prerequisites can be found.
 45
 46    # This list may not be definitive and the exact requirements depend on the project.
 47    # But it's useful to have some kind of standard list.
 48
 49    # Some of these are only needed for development."""
 50    # target.write('Searching for prerequisites...\n')
 51
 52    # import platform
 53    # prereq('python interpreter', platform.python_version())
 54
 55def test_prereq_expat():
 56    import xml.parsers.expat
 57    # prereq('expat', xml.parsers.expat.EXPAT_VERSION)
 58
 59
 60def test_prereq_pillow():
 61    import PIL
 62    # prereq('pillow', PIL.__version__)
 63
 64
 65def test_prereq_numpy():
 66    import numpy
 67    # prereq('numpy', numpy.version.version)
 68
 69
 70def test_prereq_matplotlib():
 71    import matplotlib
 72    # prereq('matplotlib', matplotlib.__version__)
 73
 74
 75def test_prereq_lxml():
 76    import lxml
 77    import lxml.etree
 78    # prereq('lxml', lxml.etree.__version__)
 79
 80
 81def test_prereq_django():
 82    import django
 83    import unslashed
 84    # prereq('django', django.__version__)
 85    # prereq('django_unslashed', unslashed.__version__)
 86
 87
 88def test_prereq_mysql():
 89    # Our code can use either
 90    try:
 91        import MySQLdb
 92    except ImportError:
 93        try:
 94            import pymysql
 95
 96        except ImportError:
 97            import mysql.connector
 98    # prereq('pymysql', pymysql.__version__)
 99
100
101def test_prereq_oracle():
102    import cx_Oracle
103    cx_Oracle.clientversion()
104    # prereq('cx_oracle', cx_Oracle.__version__)
105
106
107def test_prereq_supervisor():
108    shell('supervisord')
109    # import supervisor.options
110    # prereq('supervisord', supervisor.options.VERSION)
111
112
113def test_prereq_gunicorn():
114    # import gunicorn
115    # prereq('gunicorn', gunicorn.__version__)
116    shell('gunicorn')
117
118
119def test_prereq_docutils():
120    import docutils
121    # prereq('docutils', docutils.__version__)
122
123
124def test_prereq_pygments():
125    import pygments
126    # prereq('pygments', pygments.__version__)
127
128
129def test_prereq_slimit():
130    # import slimit
131    # prereq('slimit', 'unknown')
132    shell('slimit')
133
134
135def test_prereq_pytest():
136    try:
137        shell('pytest --version')
138    except FileNotFoundError:
139        # Ubuntu packages the python 3 pytest executable as pytest-3
140        shell('pytest --version')
141        # shell('pytest-3 --version')
142        # shell('pytest-3.6 --version')
143
144    import pytest
145    # prereq('pytest', pytest.__version__)
146
147
148def test_prereq_fabulous():
149    import fabulous
150    # prereq('fabulous', fabulous.__version__)
151
152
153def test_prereq_astor():
154    """This replaces codegen. Do not install or check for codegen.
155
156    The settings tool needs this."""
157    import astor
158    # prereq('astor', astor.__version__)
159
160
161def test_prereq_paramiko():
162    import paramiko
163    # prereq('paramiko', docutils.__version__)
164
165
166def test_prereq_xlrd():
167    """Excel library used by chartmsg."""
168    import xlrd
169    # prereq('xlrd', xlrd.__VERSION__)
170
171
172def test_prereq_matplotlib():
173    import matplotlib
174
175
176def test_prereq_fonts():
177    import matplotlib.font_manager
178    dejavu = [Path(i).name for i in matplotlib.font_manager.findSystemFonts(
179        fontpaths=None, fontext='ttf') if 'DejaVu' in i]
180    sans = [Path(i).name for i in matplotlib.font_manager.findSystemFonts(
181        fontpaths=None, fontext='ttf') if 'Sans' in i]
182    assert len(dejavu) > 0 or len(sans) > 0
183    # prereq('devavu fonts', len(dejavu))
184
185
186def test_prereq_cartopy():
187    try:
188        import cartopy
189
190    except ImportError:
191        from mpl_toolkits import basemap
192
193
194# def test_prereq_ucmclient():
195    # import ucmclient
196    # prereq('ucmclient', 'unknown')
197
198
199# aspell removed because it was only ever used to detect French text in CHART-EPS
200# parameter descriptions in order to auto-translate them, but that feature hasn't worked for a
201# long time and everyone is used to the original text by now anyway
202# def test_prereq_aspell():
203    # """Check installation of aspell."""
204    # aspell = subprocess.run(['aspell', '--version'], capture_output=True).stdout.decode(
205        # 'latin-1').strip()
206    # prereq('aspell', aspell)
207    # aspell_en = [i for i in subprocess.run(['aspell', '--help'], capture_output=True).stdout.decode(
208        # 'latin-1').split('\n') if i == '  en']
209    # prereq('aspell-en', len(aspell_en))
210    # shell('aspell')
211
212
213def test_prereq_trang():
214    # trang = subprocess.run(['trang'], capture_output=True).stdout.decode('latin-1').strip()
215    # prereq('trang', trang)
216    shell('trang')
217
218
219def test_prereq_rlwrap():
220    # rlwrap = subprocess.run(['rlwrap', '-v'], capture_output=True).stdout.decode('latin-1').strip()
221    # prereq('rlwrap', rlwrap)
222    shell('rlwrap')
223
224
225def test_prereq_postgres_psycopg2():
226    import psycopg2
227
228
229def test_prereq_postgres_psql():
230    shell('psql')
231
232
233def test_prereq_bugs():
234    """Over time we've hit various bugs in the compiler and libraries."""
235
236    # we once had an interpreter that returned "3155327:0000.0"
237    # due to some weird over-ambitious gcc optimisations
238    assert str(315532800000-0.0) == '315532800000.0'
239
240    # some versions of numpy compiled on older gcc versions cannot detect NaN values
241    import numpy
242    assert numpy.isnan(numpy.nan)
243
244    # struct decoding error that happened (gcc optimisation again I think)
245    import struct
246    assert struct.unpack('>f', b'\x00\x00\x00\x04')[0] == 5.605193857299268e-45
247
248    # struct decoding error after importing all of lxml (just a bad release of lxml)
249    from lxml import etree
250    assert struct.unpack('>f', b'\x00\x00\x00\x01')[0] == 1.401298464324817e-45
251
252    # Here, we could try to validate the build environment
253    # import sysconfig
254    # sysconfig.get_config_vars()['CFLAGS']
255    # sysconfig.get_config_vars()['CONFIGURE_CFLAGS']
256    # sysconfig.get_config_vars()['PY_CFLAGS']
257    # sysconfig.get_config_vars()['PY_CORE_CFLAGS']
258    # sysconfig.get_config_vars()['CONFIG_ARGS']
259    # sysconfig.get_config_vars()['OPT']
260
261
262if __name__ == '__main__':
263    here = __file__
264    test_interpreter()
265    try:
266        shell('pytest --version')
267    except FileNotFoundError:
268        # Ubuntu packages the python 3 pytest executable as pytest-3
269        # shell('pytest-3 --version')
270        shell('pytest --version')
271        # shell('pytest-3.6 --version')
272
273    import pytest
274    print('\nBasic test succeeded. Now run "pytest -v {here}" to run the full test'.format(here=here))