profileapp.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. # encoding: utf-8
  2. """
  3. An application for managing IPython profiles.
  4. To be invoked as the `ipython profile` subcommand.
  5. Authors:
  6. * Min RK
  7. """
  8. from __future__ import print_function
  9. #-----------------------------------------------------------------------------
  10. # Copyright (C) 2008 The IPython Development Team
  11. #
  12. # Distributed under the terms of the BSD License. The full license is in
  13. # the file COPYING, distributed as part of this software.
  14. #-----------------------------------------------------------------------------
  15. #-----------------------------------------------------------------------------
  16. # Imports
  17. #-----------------------------------------------------------------------------
  18. import os
  19. from traitlets.config.application import Application
  20. from IPython.core.application import (
  21. BaseIPythonApplication, base_flags
  22. )
  23. from IPython.core.profiledir import ProfileDir
  24. from IPython.utils.importstring import import_item
  25. from IPython.paths import get_ipython_dir, get_ipython_package_dir
  26. from IPython.utils import py3compat
  27. from traitlets import Unicode, Bool, Dict, observe
  28. #-----------------------------------------------------------------------------
  29. # Constants
  30. #-----------------------------------------------------------------------------
  31. create_help = """Create an IPython profile by name
  32. Create an ipython profile directory by its name or
  33. profile directory path. Profile directories contain
  34. configuration, log and security related files and are named
  35. using the convention 'profile_<name>'. By default they are
  36. located in your ipython directory. Once created, you will
  37. can edit the configuration files in the profile
  38. directory to configure IPython. Most users will create a
  39. profile directory by name,
  40. `ipython profile create myprofile`, which will put the directory
  41. in `<ipython_dir>/profile_myprofile`.
  42. """
  43. list_help = """List available IPython profiles
  44. List all available profiles, by profile location, that can
  45. be found in the current working directly or in the ipython
  46. directory. Profile directories are named using the convention
  47. 'profile_<profile>'.
  48. """
  49. profile_help = """Manage IPython profiles
  50. Profile directories contain
  51. configuration, log and security related files and are named
  52. using the convention 'profile_<name>'. By default they are
  53. located in your ipython directory. You can create profiles
  54. with `ipython profile create <name>`, or see the profiles you
  55. already have with `ipython profile list`
  56. To get started configuring IPython, simply do:
  57. $> ipython profile create
  58. and IPython will create the default profile in <ipython_dir>/profile_default,
  59. where you can edit ipython_config.py to start configuring IPython.
  60. """
  61. _list_examples = "ipython profile list # list all profiles"
  62. _create_examples = """
  63. ipython profile create foo # create profile foo w/ default config files
  64. ipython profile create foo --reset # restage default config files over current
  65. ipython profile create foo --parallel # also stage parallel config files
  66. """
  67. _main_examples = """
  68. ipython profile create -h # show the help string for the create subcommand
  69. ipython profile list -h # show the help string for the list subcommand
  70. ipython locate profile foo # print the path to the directory for profile 'foo'
  71. """
  72. #-----------------------------------------------------------------------------
  73. # Profile Application Class (for `ipython profile` subcommand)
  74. #-----------------------------------------------------------------------------
  75. def list_profiles_in(path):
  76. """list profiles in a given root directory"""
  77. files = os.listdir(path)
  78. profiles = []
  79. for f in files:
  80. try:
  81. full_path = os.path.join(path, f)
  82. except UnicodeError:
  83. continue
  84. if os.path.isdir(full_path) and f.startswith('profile_'):
  85. profiles.append(f.split('_',1)[-1])
  86. return profiles
  87. def list_bundled_profiles():
  88. """list profiles that are bundled with IPython."""
  89. path = os.path.join(get_ipython_package_dir(), u'core', u'profile')
  90. files = os.listdir(path)
  91. profiles = []
  92. for profile in files:
  93. full_path = os.path.join(path, profile)
  94. if os.path.isdir(full_path) and profile != "__pycache__":
  95. profiles.append(profile)
  96. return profiles
  97. class ProfileLocate(BaseIPythonApplication):
  98. description = """print the path to an IPython profile dir"""
  99. def parse_command_line(self, argv=None):
  100. super(ProfileLocate, self).parse_command_line(argv)
  101. if self.extra_args:
  102. self.profile = self.extra_args[0]
  103. def start(self):
  104. print(self.profile_dir.location)
  105. class ProfileList(Application):
  106. name = u'ipython-profile'
  107. description = list_help
  108. examples = _list_examples
  109. aliases = Dict({
  110. 'ipython-dir' : 'ProfileList.ipython_dir',
  111. 'log-level' : 'Application.log_level',
  112. })
  113. flags = Dict(dict(
  114. debug = ({'Application' : {'log_level' : 0}},
  115. "Set Application.log_level to 0, maximizing log output."
  116. )
  117. ))
  118. ipython_dir = Unicode(get_ipython_dir(),
  119. help="""
  120. The name of the IPython directory. This directory is used for logging
  121. configuration (through profiles), history storage, etc. The default
  122. is usually $HOME/.ipython. This options can also be specified through
  123. the environment variable IPYTHONDIR.
  124. """
  125. ).tag(config=True)
  126. def _print_profiles(self, profiles):
  127. """print list of profiles, indented."""
  128. for profile in profiles:
  129. print(' %s' % profile)
  130. def list_profile_dirs(self):
  131. profiles = list_bundled_profiles()
  132. if profiles:
  133. print()
  134. print("Available profiles in IPython:")
  135. self._print_profiles(profiles)
  136. print()
  137. print(" The first request for a bundled profile will copy it")
  138. print(" into your IPython directory (%s)," % self.ipython_dir)
  139. print(" where you can customize it.")
  140. profiles = list_profiles_in(self.ipython_dir)
  141. if profiles:
  142. print()
  143. print("Available profiles in %s:" % self.ipython_dir)
  144. self._print_profiles(profiles)
  145. profiles = list_profiles_in(py3compat.getcwd())
  146. if profiles:
  147. print()
  148. print("Available profiles in current directory (%s):" % py3compat.getcwd())
  149. self._print_profiles(profiles)
  150. print()
  151. print("To use any of the above profiles, start IPython with:")
  152. print(" ipython --profile=<name>")
  153. print()
  154. def start(self):
  155. self.list_profile_dirs()
  156. create_flags = {}
  157. create_flags.update(base_flags)
  158. # don't include '--init' flag, which implies running profile create in other apps
  159. create_flags.pop('init')
  160. create_flags['reset'] = ({'ProfileCreate': {'overwrite' : True}},
  161. "reset config files in this profile to the defaults.")
  162. create_flags['parallel'] = ({'ProfileCreate': {'parallel' : True}},
  163. "Include the config files for parallel "
  164. "computing apps (ipengine, ipcontroller, etc.)")
  165. class ProfileCreate(BaseIPythonApplication):
  166. name = u'ipython-profile'
  167. description = create_help
  168. examples = _create_examples
  169. auto_create = Bool(True)
  170. def _log_format_default(self):
  171. return "[%(name)s] %(message)s"
  172. def _copy_config_files_default(self):
  173. return True
  174. parallel = Bool(False,
  175. help="whether to include parallel computing config files"
  176. ).tag(config=True)
  177. @observe('parallel')
  178. def _parallel_changed(self, change):
  179. parallel_files = [ 'ipcontroller_config.py',
  180. 'ipengine_config.py',
  181. 'ipcluster_config.py'
  182. ]
  183. if change['new']:
  184. for cf in parallel_files:
  185. self.config_files.append(cf)
  186. else:
  187. for cf in parallel_files:
  188. if cf in self.config_files:
  189. self.config_files.remove(cf)
  190. def parse_command_line(self, argv):
  191. super(ProfileCreate, self).parse_command_line(argv)
  192. # accept positional arg as profile name
  193. if self.extra_args:
  194. self.profile = self.extra_args[0]
  195. flags = Dict(create_flags)
  196. classes = [ProfileDir]
  197. def _import_app(self, app_path):
  198. """import an app class"""
  199. app = None
  200. name = app_path.rsplit('.', 1)[-1]
  201. try:
  202. app = import_item(app_path)
  203. except ImportError:
  204. self.log.info("Couldn't import %s, config file will be excluded", name)
  205. except Exception:
  206. self.log.warning('Unexpected error importing %s', name, exc_info=True)
  207. return app
  208. def init_config_files(self):
  209. super(ProfileCreate, self).init_config_files()
  210. # use local imports, since these classes may import from here
  211. from IPython.terminal.ipapp import TerminalIPythonApp
  212. apps = [TerminalIPythonApp]
  213. for app_path in (
  214. 'ipykernel.kernelapp.IPKernelApp',
  215. ):
  216. app = self._import_app(app_path)
  217. if app is not None:
  218. apps.append(app)
  219. if self.parallel:
  220. from ipyparallel.apps.ipcontrollerapp import IPControllerApp
  221. from ipyparallel.apps.ipengineapp import IPEngineApp
  222. from ipyparallel.apps.ipclusterapp import IPClusterStart
  223. apps.extend([
  224. IPControllerApp,
  225. IPEngineApp,
  226. IPClusterStart,
  227. ])
  228. for App in apps:
  229. app = App()
  230. app.config.update(self.config)
  231. app.log = self.log
  232. app.overwrite = self.overwrite
  233. app.copy_config_files=True
  234. app.ipython_dir=self.ipython_dir
  235. app.profile_dir=self.profile_dir
  236. app.init_config_files()
  237. def stage_default_config_file(self):
  238. pass
  239. class ProfileApp(Application):
  240. name = u'ipython profile'
  241. description = profile_help
  242. examples = _main_examples
  243. subcommands = Dict(dict(
  244. create = (ProfileCreate, ProfileCreate.description.splitlines()[0]),
  245. list = (ProfileList, ProfileList.description.splitlines()[0]),
  246. locate = (ProfileLocate, ProfileLocate.description.splitlines()[0]),
  247. ))
  248. def start(self):
  249. if self.subapp is None:
  250. print("No subcommand specified. Must specify one of: %s"%(self.subcommands.keys()))
  251. print()
  252. self.print_description()
  253. self.print_subcommands()
  254. self.exit(1)
  255. else:
  256. return self.subapp.start()