#!/usr/bin/python def make_lifelib(autorun=True): ''' This script should be run from within the Python environment in which you would like to install or upgrade lifelib. It will do the following in turn: - ensure its own existence; - invoke the pip package manager to install/upgrade python-lifelib; - ensure the lifelib environment is correctly configured; - perform a rudimentary sanity check; - perform comprehensive tests. It can be invoked as a Python script or module, or run from within an interpreter (python, IPython, or Jupyter), or executed as a Golly script. ''' import sys import os from time import sleep print('Determining whether Golly exists...') try: import golly as g def pprint(x): print(x) g.show(x) g.update() sleep(0.5) golly_exists=True except ImportError: def pprint(x): print(x) golly_exists=False preposition = ('within' if golly_exists else 'outside') pprint('We are running %s Golly.' % preposition) pprint('Determining Python executable...') this_python = os.path.abspath(sys.executable) pprint('Determining script location...') try: this_script = os.path.abspath(__file__) if not os.path.exists(this_script): raise NameError("Script does not exist.") except NameError: # We may be running from stdin or the clipboard. Ensure the script # exists in a real location: pprint('Writing script to file...') this_script = 'lifelib_install.py' try: import inspect source = '#!/usr/bin/python\n\n' source += inspect.getsource(make_lifelib) source += '# run program\nmake_lifelib(False)\n' with open(this_script, 'w') as f: f.write(source) except: try: from urllib import urlretrieve except ImportError: from urllib.request import urlretrieve pprint("Downloading installation script over HTTPS...") script_path = 'https://gitlab.com/apgoucher/python-lifelib' script_path += '/raw/master/install/install.py' urlretrieve(script_path, this_script) def install_package(): pprint("Finding pip package manager...") try: import pip except ImportError: import ensurepip ensurepip.bootstrap() try: # Python 3.x: from pip._internal import main except ImportError: # Python 2.x: from pip import main pprint("Installing/upgrading lifelib...") rc = main(['install', '--user', '--upgrade', 'python-lifelib']) if rc and os.environ.get('VIRTUAL_ENV', None): pprint("Probably running in virtualenv so dropping --user...") rc = main(['install', '--upgrade', 'python-lifelib']) if rc: pprint("Failed to install or upgrade lifelib.") def post_install(): pprint("Checking lifelib is installed...") try: # This usually works, but not if this is the first time that # a --user package has been installed: import lifelib except ImportError: pprint("Updating sys.path...") # Find the updated sys.path which contains the newly-minted # python-lifelib installation: from subprocess import check_output sa = [this_python, '-c', 'import sys; print(sys.path)'] new_path = check_output(sa) # Python 3 returns a 'bytes' object which is incompatible # with the ast.literal_eval() function, so cast to str: if not isinstance(new_path, str): new_path = new_path.decode() # Safely decode the returned string: import ast new_path = ast.literal_eval(new_path) # In-place list concatenation: for n in new_path: sys.path.append(n) # Now that sys.path has been modified, we can import lifelib: import lifelib pprint("Lifelib version: %s" % lifelib.__version__) if (os.name == 'nt'): pprint("Installing Cygwin if necessary...") lifelib.install_cygwin() pprint("Creating session...") sess = lifelib.load_rules('b3s23', force_indirect=True) lt = sess.lifetree() lidka = lt.pattern("bo$obo$bo8$8bo$6bobo$5b2obo2$4b3o!", 'b3s23') lp = lidka.population l30kp = lidka[30000].population pprint("Initial population of Lidka: %d" % lp) pprint("Final population of Lidka: %d" % l30kp) if (lp != 13) or (l30kp != 1623): raise ValueError("Serious problem: populations do not match.") pprint("Checking numpy is installed...") import numpy as np pprint("Numpy version: %s" % np.__version__) pprint("Running comprehensive tests...") lifelib.run_tests() pprint("Everything completed successfully.") def install_sandboxed(): from subprocess import check_call pprint("Upgrading lifelib in separate process...") check_call([this_python, this_script, '*']) pprint("Lifelib upgraded; running post-install tasks...") sleep(1.0) post_install() if autorun or golly_exists: install_sandboxed() elif (__name__ == '__main__'): [install_sandboxed, install_package, post_install][len(sys.argv)-1]() pass # run program make_lifelib(False)