提交 0f446def authored 作者: notoraptor's avatar notoraptor

Use the entry_points/console_scripts feature of setup.py

to make theano scripts installed when running pip install. These step are done to fix issue #5308. The bin folder containing the scripts is now importable from Python, with each script embedding its code into a main() function specified as the entry point of the script in `setup.py`. We also detect a Windows-specific error: the cache folder cannot be deleted because it contains shared libraries that are always loaded at theano importation and stay opened on Windows, which forbide the deletion of the shared library files in the cache. The workaround chosen is to unset theano config flag `cxx` only on Windows platform and only in theano-cache script. Doing that, Theano will not try to compile any C code, and will also not try to load compiled C codes that are in the cache, allowing these files to be deleted. To ensure this workaround does work, we also ensure that lazylinker module will be also ignored from cache when `cxx` is unset. Previously, if cxx was unset, Theano would not compile lazylinker but would look for an already compiled version of this module in the cache.
上级 fcdd8c77
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""IPython Test Suite Runner.
"""
from __future__ import print_function
# The tests can't even run if nose isn't available, so might as well give the
# user a civilized error message in that case.
try:
import nose
except ImportError:
error = """\
ERROR: The IPython test suite requires nose to run.
Please install nose on your system first and try again.
For information on installing nose, see:
http://nose.readthedocs.org/en/latest/
Exiting."""
import sys
print(error, file=sys.stderr)
else:
import theano
theano.test()
...@@ -4,6 +4,14 @@ import logging ...@@ -4,6 +4,14 @@ import logging
import os import os
import sys import sys
if sys.platform == 'win32':
config_cxx = 'cxx='
theano_flags = os.environ['THEANO_FLAGS'] if 'THEANO_FLAGS' in os.environ else ''
if theano_flags:
theano_flags += ','
theano_flags += config_cxx
os.environ['THEANO_FLAGS'] = theano_flags
import theano import theano
from theano import config from theano import config
import theano.gof.compiledir import theano.gof.compiledir
...@@ -32,54 +40,60 @@ def print_help(exit_status): ...@@ -32,54 +40,60 @@ def print_help(exit_status):
'that is, erase ALL cache directories') 'that is, erase ALL cache directories')
sys.exit(exit_status) sys.exit(exit_status)
if len(sys.argv) == 1:
print(config.compiledir)
elif len(sys.argv) == 2:
if sys.argv[1] == 'help':
print_help(exit_status=0)
if sys.argv[1] == 'clear':
# We skip the refresh on module cache creation because the refresh will
# be done when calling clear afterwards.
cache = get_module_cache(init_args=dict(do_refresh=False))
cache.clear(unversioned_min_age=-1, clear_base_files=True,
delete_if_problem=True)
# Print a warning if some cached modules were not removed, so that the def main():
# user knows he should manually delete them, or call if len(sys.argv) == 1:
# theano-cache purge, # to properly clear the cache. print(config.compiledir)
items = [item for item in sorted(os.listdir(cache.dirname)) elif len(sys.argv) == 2:
if item.startswith('tmp')] if sys.argv[1] == 'help':
if items: print_help(exit_status=0)
_logger.warning( if sys.argv[1] == 'clear':
'There remain elements in the cache dir that you may ' # We skip the refresh on module cache creation because the refresh will
'need to erase manually. The cache dir is:\n %s\n' # be done when calling clear afterwards.
'You can also call "theano-cache purge" to ' cache = get_module_cache(init_args=dict(do_refresh=False))
'remove everything from that directory.' % cache.clear(unversioned_min_age=-1, clear_base_files=True,
config.compiledir) delete_if_problem=True)
_logger.debug('Remaining elements (%s): %s' %
(len(items), ', '.join(items))) # Print a warning if some cached modules were not removed, so that the
elif sys.argv[1] == 'list': # user knows he should manually delete them, or call
theano.gof.compiledir.print_compiledir_content() # theano-cache purge, # to properly clear the cache.
elif sys.argv[1] == 'cleanup': items = [item for item in sorted(os.listdir(cache.dirname))
theano.gof.compiledir.cleanup() if item.startswith('tmp')]
cache = get_module_cache(init_args=dict(do_refresh=False)) if items:
cache.clear_old() _logger.warning(
elif sys.argv[1] == 'unlock': 'There remain elements in the cache dir that you may '
theano.gof.compilelock.force_unlock() 'need to erase manually. The cache dir is:\n %s\n'
print('Lock successfully removed!') 'You can also call "theano-cache purge" to '
elif sys.argv[1] == 'purge': 'remove everything from that directory.' %
theano.gof.compiledir.compiledir_purge() config.compiledir)
elif sys.argv[1] == 'basecompiledir': _logger.debug('Remaining elements (%s): %s' %
# Simply print the base_compiledir (len(items), ', '.join(items)))
print(theano.config.base_compiledir) elif sys.argv[1] == 'list':
else: theano.gof.compiledir.print_compiledir_content()
print_help(exit_status=1) elif sys.argv[1] == 'cleanup':
elif len(sys.argv) == 3 and sys.argv[1] == 'basecompiledir': theano.gof.compiledir.cleanup()
if sys.argv[2] == 'list': cache = get_module_cache(init_args=dict(do_refresh=False))
theano.gof.compiledir.basecompiledir_ls() cache.clear_old()
elif sys.argv[2] == 'purge': elif sys.argv[1] == 'unlock':
theano.gof.compiledir.basecompiledir_purge() theano.gof.compilelock.force_unlock()
print('Lock successfully removed!')
elif sys.argv[1] == 'purge':
theano.gof.compiledir.compiledir_purge()
elif sys.argv[1] == 'basecompiledir':
# Simply print the base_compiledir
print(theano.config.base_compiledir)
else:
print_help(exit_status=1)
elif len(sys.argv) == 3 and sys.argv[1] == 'basecompiledir':
if sys.argv[2] == 'list':
theano.gof.compiledir.basecompiledir_ls()
elif sys.argv[2] == 'purge':
theano.gof.compiledir.basecompiledir_purge()
else:
print_help(exit_status=1)
else: else:
print_help(exit_status=1) print_help(exit_status=1)
else:
print_help(exit_status=1)
if __name__ == '__main__':
main()
...@@ -25,7 +25,7 @@ import textwrap ...@@ -25,7 +25,7 @@ import textwrap
import sys import sys
from nose.plugins import Plugin from nose.plugins import Plugin
def main(): def main_function():
# Handle the --theano arguments # Handle the --theano arguments
if "--theano" in sys.argv: if "--theano" in sys.argv:
i = sys.argv.index("--theano") i = sys.argv.index("--theano")
...@@ -200,6 +200,14 @@ def help(): ...@@ -200,6 +200,14 @@ def help():
print(textwrap.dedent(help_msg)) print(textwrap.dedent(help_msg))
def main(args=None):
if '--help' in sys.argv or '-h' in sys.argv:
help()
else:
result = main_function()
sys.exit(result)
class DisabDocString(Plugin): class DisabDocString(Plugin):
""" """
...@@ -258,8 +266,4 @@ class DisabDocString(Plugin): ...@@ -258,8 +266,4 @@ class DisabDocString(Plugin):
return False return False
if __name__ == '__main__': if __name__ == '__main__':
if '--help' in sys.argv or '-h' in sys.argv: main()
help()
else:
result = main()
sys.exit(result)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""IPython Test Suite Runner.
"""
from __future__ import print_function
def main():
# The tests can't even run if nose isn't available, so might as well give the
# user a civilized error message in that case.
try:
import nose
except ImportError:
error = """\
ERROR: The IPython test suite requires nose to run.
Please install nose on your system first and try again.
For information on installing nose, see:
http://nose.readthedocs.org/en/latest/
Exiting."""
import sys
print(error, file=sys.stderr)
else:
import theano
theano.test()
if __name__ == "__main__":
main()
...@@ -173,7 +173,11 @@ def do_setup(): ...@@ -173,7 +173,11 @@ def do_setup():
'theano.misc': ['*.sh'], 'theano.misc': ['*.sh'],
'theano.d3viz' : ['html/*','css/*','js/*'] 'theano.d3viz' : ['html/*','css/*','js/*']
}, },
scripts=['bin/theano-cache', 'bin/theano-nose', 'bin/theano-test'], entry_points={
'console_scripts': ['theano-cache = bin.theano_cache:main',
'theano-nose = bin.theano_nose:main',
'theano-test = bin.theano_test:main']
},
keywords=' '.join([ keywords=' '.join([
'theano', 'math', 'numerical', 'symbolic', 'blas', 'theano', 'math', 'numerical', 'symbolic', 'blas',
'numpy', 'gpu', 'autodiff', 'differentiation' 'numpy', 'gpu', 'autodiff', 'differentiation'
......
...@@ -656,6 +656,8 @@ class Stack(VM): ...@@ -656,6 +656,8 @@ class Stack(VM):
try: try:
if not theano.config.cxx:
raise theano.gof.cmodule.MissingGXX('lazylinker will not be imported if theano.config.cxx is not set.')
from . import lazylinker_c from . import lazylinker_c
class CVM(lazylinker_c.CLazyLinker, VM): class CVM(lazylinker_c.CLazyLinker, VM):
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论