Use pip to install python packages.

This commit is contained in:
Christophe Buffenoir 2013-09-11 13:58:00 +02:00
parent c086fd3289
commit 13499f429e
125 changed files with 19 additions and 17208 deletions

View file

@ -1,25 +0,0 @@
#!/usr/bin/python
# vim:fileencoding=utf-8:noet
'''Powerline prompt and statusline script.'''
import sys
import os
try:
from powerline.shell import ShellPowerline, get_argparser
except ImportError:
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from powerline.shell import ShellPowerline, get_argparser # NOQA
if __name__ == '__main__':
args = get_argparser(description=__doc__).parse_args()
powerline = ShellPowerline(args, run_once=True)
rendered = powerline.render(
width=args.width,
side=args.side,
segment_info={'args': args, 'environ': os.environ},
)
try:
sys.stdout.write(rendered)
except UnicodeEncodeError:
sys.stdout.write(rendered.encode('utf-8'))

View file

@ -1,14 +0,0 @@
#!/usr/bin/python
# vim:fileencoding=utf-8:noet
'''Powerline configuration checker.'''
import argparse
from powerline.lint import check
import sys
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('-p', '--config_path', metavar='PATH')
if __name__ == '__main__':
args = parser.parse_args()
sys.exit(check(args.config_path))

View file

@ -1,325 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import subprocess
import sys
import re
import argparse
def warn(msg):
print '[powerline-zsh] ', msg
class Color:
# The following link is a pretty good resources for color values:
# http://www.calmar.ws/vim/color-output.png
PATH_BG = 237 # dark grey
PATH_FG = 250 # light grey
CWD_FG = 254 # nearly-white grey
SEPARATOR_FG = 244
REPO_CLEAN_BG = 148 # a light green color
REPO_CLEAN_FG = 0 # black
REPO_DIRTY_BG = 161 # pink/red
REPO_DIRTY_FG = 15 # white
CMD_PASSED_BG = 236
CMD_PASSED_FG = 15
CMD_FAILED_BG = 161
CMD_FAILED_FG = 15
SVN_CHANGES_BG = 148
SVN_CHANGES_FG = 22 # dark green
VIRTUAL_ENV_BG = 35 # a mid-tone green
VIRTUAL_ENV_FG = 22
class Powerline:
symbols = {
'compatible': {
'separator': u'\u25B6',
'separator_thin': u'\u276F'
},
'patched': {
'separator': u'\u2B80',
'separator_thin': u'\u2B81'
},
'default': {
'separator': '',
'separator_thin': ''
}
}
LSQESCRSQ = '\\[\\e%s\\]'
reset = ' %f%k'
def __init__(self, mode='default'):
self.separator = Powerline.symbols[mode]['separator']
self.separator_thin = Powerline.symbols[mode]['separator_thin']
self.segments = []
def color(self, prefix, code):
if prefix == '38':
return '%%F{%s}' % code
elif prefix == '48':
return '%%K{%s}' % code
def fgcolor(self, code):
return self.color('38', code)
def bgcolor(self, code):
return self.color('48', code)
def append(self, segment):
self.segments.append(segment)
def draw(self):
return (''.join((s[0].draw(self, s[1]) for s in zip(self.segments, self.segments[1:] + [None])))
+ self.reset)
class Segment:
def __init__(self, powerline, content, fg, bg, separator=None, separator_fg=None):
self.powerline = powerline
self.content = content
self.fg = fg
self.bg = bg
self.separator = separator or powerline.separator
self.separator_fg = separator_fg or bg
def draw(self, powerline, next_segment=None):
if next_segment:
separator_bg = powerline.bgcolor(next_segment.bg)
else:
separator_bg = powerline.reset
return ''.join((
powerline.fgcolor(self.fg),
powerline.bgcolor(self.bg),
self.content,
separator_bg,
powerline.fgcolor(self.separator_fg),
self.separator))
def add_cwd_segment(powerline, cwd, maxdepth, cwd_only=False):
#powerline.append(' \\w ', 15, 237)
home = os.getenv('HOME')
cwd = os.getenv('PWD')
if cwd.find(home) == 0:
cwd = cwd.replace(home, '~', 1)
if cwd[0] == '/':
cwd = cwd[1:]
names = cwd.split('/')
if len(names) > maxdepth:
names = names[:2] + [''] + names[2 - maxdepth:]
if not cwd_only:
for n in names[:-1]:
powerline.append(Segment(powerline, ' %s ' % n, Color.PATH_FG, Color.PATH_BG, powerline.separator_thin, Color.SEPARATOR_FG))
powerline.append(Segment(powerline, ' %s ' % names[-1], Color.CWD_FG, Color.PATH_BG))
def get_hg_status():
has_modified_files = False
has_untracked_files = False
has_missing_files = False
output = subprocess.Popen(['hg', 'status'], stdout=subprocess.PIPE).communicate()[0]
for line in output.split('\n'):
if line == '':
continue
elif line[0] == '?':
has_untracked_files = True
elif line[0] == '!':
has_missing_files = True
else:
has_modified_files = True
return has_modified_files, has_untracked_files, has_missing_files
def add_hg_segment(powerline, cwd):
branch = os.popen('hg branch 2> /dev/null').read().rstrip()
if len(branch) == 0:
return False
bg = Color.REPO_CLEAN_BG
fg = Color.REPO_CLEAN_FG
has_modified_files, has_untracked_files, has_missing_files = get_hg_status()
if has_modified_files or has_untracked_files or has_missing_files:
bg = Color.REPO_DIRTY_BG
fg = Color.REPO_DIRTY_FG
extra = ''
if has_untracked_files:
extra += '+'
if has_missing_files:
extra += '!'
branch += (' ' + extra if extra != '' else '')
powerline.append(Segment(powerline, ' %s ' % branch, fg, bg))
return True
def get_git_status():
has_pending_commits = True
has_untracked_files = False
detached_head = False
origin_position = ""
current_branch = ''
output = subprocess.Popen(['git', 'status', '-unormal'], stdout=subprocess.PIPE).communicate()[0]
for line in output.split('\n'):
origin_status = re.findall("Your branch is (ahead|behind).*?(\d+) comm", line)
if len(origin_status) > 0:
origin_position = " %d" % int(origin_status[0][1])
if origin_status[0][0] == 'behind':
origin_position += ''
if origin_status[0][0] == 'ahead':
origin_position += ''
if line.find('nothing to commit (working directory clean)') >= 0:
has_pending_commits = False
if line.find('Untracked files') >= 0:
has_untracked_files = True
if line.find('Not currently on any branch') >= 0:
detached_head = True
if line.find('On branch') >= 0:
current_branch = re.findall('On branch ([^ ]+)', line)[0]
return has_pending_commits, has_untracked_files, origin_position, detached_head, current_branch
def add_git_segment(powerline, cwd):
#cmd = "git branch 2> /dev/null | grep -e '\\*'"
p1 = subprocess.Popen(['git', 'branch'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p2 = subprocess.Popen(['grep', '-e', '\\*'], stdin=p1.stdout, stdout=subprocess.PIPE)
output = p2.communicate()[0].strip()
if len(output) == 0:
return False
has_pending_commits, has_untracked_files, origin_position, detached_head, current_branch = get_git_status()
if len(current_branch) > 0:
branch = current_branch
elif detached_head:
branch = subprocess.Popen(['git', 'describe', '--all', '--contains', '--abbrev=4', 'HEAD'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
branch = '((' + branch.communicate()[0].strip() + '))'
else:
return 'master'
branch += origin_position
if has_untracked_files:
branch += ' +'
bg = Color.REPO_CLEAN_BG
fg = Color.REPO_CLEAN_FG
if has_pending_commits:
bg = Color.REPO_DIRTY_BG
fg = Color.REPO_DIRTY_FG
powerline.append(Segment(powerline, ' %s ' % branch, fg, bg))
return True
def add_svn_segment(powerline, cwd):
if not os.path.exists(os.path.join(cwd, '.svn')):
return
'''svn info:
First column: Says if item was added, deleted, or otherwise changed
' ' no modifications
'A' Added
'C' Conflicted
'D' Deleted
'I' Ignored
'M' Modified
'R' Replaced
'X' an unversioned directory created by an externals definition
'?' item is not under version control
'!' item is missing (removed by non-svn command) or incomplete
'~' versioned item obstructed by some item of a different kind
'''
#TODO: Color segment based on above status codes
try:
#cmd = '"svn status | grep -c "^[ACDIMRX\\!\\~]"'
p1 = subprocess.Popen(['svn', 'status'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p2 = subprocess.Popen(['grep', '-c', '^[ACDIMRX\\!\\~]'], stdin=p1.stdout, stdout=subprocess.PIPE)
output = p2.communicate()[0].strip()
if len(output) > 0 and int(output) > 0:
changes = output.strip()
powerline.append(Segment(powerline, ' %s ' % changes, Color.SVN_CHANGES_FG, Color.SVN_CHANGES_BG))
except OSError:
return False
except subprocess.CalledProcessError:
return False
return True
def add_repo_segment(powerline, cwd):
for add_repo_segment in [add_git_segment, add_svn_segment, add_hg_segment]:
try:
if add_repo_segment(p, cwd):
return
except subprocess.CalledProcessError:
pass
except OSError:
pass
def add_virtual_env_segment(powerline, cwd):
env = os.getenv("VIRTUAL_ENV")
if env is None:
return False
env_name = os.path.basename(env)
bg = Color.VIRTUAL_ENV_BG
fg = Color.VIRTUAL_ENV_FG
powerline.append(Segment(powerline, ' %s ' % env_name, fg, bg))
return True
def add_root_indicator(powerline, error):
bg = Color.CMD_PASSED_BG
fg = Color.CMD_PASSED_FG
if int(error) != 0:
fg = Color.CMD_FAILED_FG
bg = Color.CMD_FAILED_BG
powerline.append(Segment(powerline, ' $ ', fg, bg))
def get_valid_cwd():
try:
cwd = os.getcwd()
except:
cwd = os.getenv('PWD') # This is where the OS thinks we are
parts = cwd.split(os.sep)
up = cwd
while parts and not os.path.exists(up):
parts.pop()
up = os.sep.join(parts)
try:
os.chdir(up)
except:
warn("Your current directory is invalid.")
sys.exit(1)
warn("Your current directory is invalid. Lowest valid directory: " + up)
return cwd
if __name__ == '__main__':
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument('--cwd-only', action="store_true")
arg_parser.add_argument('prev_error', nargs='?', default=0)
args = arg_parser.parse_args()
p = Powerline(mode='default')
cwd = get_valid_cwd()
add_virtual_env_segment(p, cwd)
#p.append(Segment(' \\u ', 250, 240))
#p.append(Segment(' \\h ', 250, 238))
add_cwd_segment(p, cwd, 5, args.cwd_only)
add_repo_segment(p, cwd)
add_root_indicator(p, args.prev_error)
sys.stdout.write(p.draw())
# vim: set expandtab:

View file

@ -1,63 +0,0 @@
Metadata-Version: 1.0
Name: Powerline
Version: beta
Summary: The ultimate statusline/prompt utility.
Home-page: https://github.com/Lokaltog/powerline
Author: Kim Silkebækken
Author-email: kim.silkebaekken+vim@gmail.com
License: UNKNOWN
Description: Powerline
=========
:Author: Kim Silkebækken (kim.silkebaekken+vim@gmail.com)
:Source: https://github.com/Lokaltog/powerline
:Version: beta
:Build status:
.. image:: https://api.travis-ci.org/Lokaltog/powerline.png?branch=develop
:target: `travis-build-status`_
:alt: Build status
This is the upcoming version of Powerline, implemented in Python. The
project is currently in a stable beta and almost ready for release.
* Consult the `documentation
<https://powerline.readthedocs.org/en/latest/>`_ for more information and
installation instructions.
* Check out `powerline-fonts <https://github.com/Lokaltog/powerline-fonts>`_
for pre-patched versions of popular coding fonts.
.. _travis-build-status: https://travis-ci.org/Lokaltog/powerline
Screenshots
-----------
Vim statusline
^^^^^^^^^^^^^^
**Mode-dependent highlighting**
* .. image:: https://raw.github.com/Lokaltog/powerline/develop/docs/source/_static/img/pl-mode-normal.png
:alt: Normal mode
* .. image:: https://raw.github.com/Lokaltog/powerline/develop/docs/source/_static/img/pl-mode-insert.png
:alt: Insert mode
* .. image:: https://raw.github.com/Lokaltog/powerline/develop/docs/source/_static/img/pl-mode-visual.png
:alt: Visual mode
* .. image:: https://raw.github.com/Lokaltog/powerline/develop/docs/source/_static/img/pl-mode-replace.png
:alt: Replace mode
**Automatic truncation of segments in small windows**
* .. image:: https://raw.github.com/Lokaltog/powerline/develop/docs/source/_static/img/pl-truncate1.png
:alt: Truncation illustration
* .. image:: https://raw.github.com/Lokaltog/powerline/develop/docs/source/_static/img/pl-truncate2.png
:alt: Truncation illustration
* .. image:: https://raw.github.com/Lokaltog/powerline/develop/docs/source/_static/img/pl-truncate3.png
:alt: Truncation illustration
----
The font in the screenshots is `Pragmata Pro`_ by Fabrizio Schiavi.
.. _`Pragmata Pro`: http://www.fsd.it/fonts/pragmatapro.htm
Platform: UNKNOWN

View file

@ -1,98 +0,0 @@
MANIFEST.in
README.rst
Powerline.egg-info/PKG-INFO
Powerline.egg-info/SOURCES.txt
Powerline.egg-info/dependency_links.txt
Powerline.egg-info/not-zip-safe
Powerline.egg-info/requires.txt
Powerline.egg-info/top_level.txt
powerline/__init__.py
powerline/colorscheme.py
powerline/ipython.py
powerline/matcher.py
powerline/renderer.py
powerline/segment.py
powerline/shell.py
powerline/theme.py
powerline/vim.py
powerline/bindings/__init__.py
powerline/bindings/awesome/powerline-awesome.py
powerline/bindings/awesome/powerline.lua
powerline/bindings/bash/powerline.sh
powerline/bindings/ipython/__init__.py
powerline/bindings/ipython/post_0_11.py
powerline/bindings/ipython/pre_0_11.py
powerline/bindings/qtile/__init__.py
powerline/bindings/qtile/widget.py
powerline/bindings/tmux/powerline.conf
powerline/bindings/vim/__init__.py
powerline/bindings/vim/plugin/powerline.vim
powerline/bindings/zsh/__init__.py
powerline/bindings/zsh/powerline.zsh
powerline/config_files/colors.json
powerline/config_files/config.json
powerline/config_files/colorschemes/ipython/default.json
powerline/config_files/colorschemes/shell/default.json
powerline/config_files/colorschemes/shell/solarized.json
powerline/config_files/colorschemes/tmux/default.json
powerline/config_files/colorschemes/vim/default.json
powerline/config_files/colorschemes/vim/solarized.json
powerline/config_files/colorschemes/wm/default.json
powerline/config_files/themes/ipython/in.json
powerline/config_files/themes/ipython/in2.json
powerline/config_files/themes/ipython/out.json
powerline/config_files/themes/ipython/rewrite.json
powerline/config_files/themes/shell/default.json
powerline/config_files/themes/shell/default_leftonly.json
powerline/config_files/themes/tmux/default.json
powerline/config_files/themes/vim/cmdwin.json
powerline/config_files/themes/vim/default.json
powerline/config_files/themes/vim/help.json
powerline/config_files/themes/vim/quickfix.json
powerline/config_files/themes/wm/default.json
powerline/lib/__init__.py
powerline/lib/config.py
powerline/lib/file_watcher.py
powerline/lib/humanize_bytes.py
powerline/lib/inotify.py
powerline/lib/memoize.py
powerline/lib/monotonic.py
powerline/lib/threaded.py
powerline/lib/tree_watcher.py
powerline/lib/url.py
powerline/lib/vcs/__init__.py
powerline/lib/vcs/bzr.py
powerline/lib/vcs/git.py
powerline/lib/vcs/mercurial.py
powerline/lint/__init__.py
powerline/lint/inspect.py
powerline/lint/markedjson/__init__.py
powerline/lint/markedjson/composer.py
powerline/lint/markedjson/constructor.py
powerline/lint/markedjson/error.py
powerline/lint/markedjson/events.py
powerline/lint/markedjson/loader.py
powerline/lint/markedjson/markedvalue.py
powerline/lint/markedjson/nodes.py
powerline/lint/markedjson/parser.py
powerline/lint/markedjson/reader.py
powerline/lint/markedjson/resolver.py
powerline/lint/markedjson/scanner.py
powerline/lint/markedjson/tokens.py
powerline/matchers/__init__.py
powerline/matchers/vim.py
powerline/renderers/__init__.py
powerline/renderers/bash_prompt.py
powerline/renderers/ipython.py
powerline/renderers/pango_markup.py
powerline/renderers/shell.py
powerline/renderers/tmux.py
powerline/renderers/vim.py
powerline/renderers/zsh_prompt.py
powerline/segments/__init__.py
powerline/segments/common.py
powerline/segments/ipython.py
powerline/segments/shell.py
powerline/segments/vim.py
scripts/powerline
scripts/powerline-lint

View file

@ -1,159 +0,0 @@
../powerline/shell.py
../powerline/colorscheme.py
../powerline/ipython.py
../powerline/theme.py
../powerline/vim.py
../powerline/__init__.py
../powerline/matcher.py
../powerline/renderer.py
../powerline/segment.py
../powerline/matchers/vim.py
../powerline/matchers/__init__.py
../powerline/bindings/__init__.py
../powerline/lint/__init__.py
../powerline/lint/inspect.py
../powerline/segments/shell.py
../powerline/segments/ipython.py
../powerline/segments/common.py
../powerline/segments/vim.py
../powerline/segments/__init__.py
../powerline/renderers/shell.py
../powerline/renderers/ipython.py
../powerline/renderers/bash_prompt.py
../powerline/renderers/zsh_prompt.py
../powerline/renderers/vim.py
../powerline/renderers/__init__.py
../powerline/renderers/pango_markup.py
../powerline/renderers/tmux.py
../powerline/lib/memoize.py
../powerline/lib/monotonic.py
../powerline/lib/config.py
../powerline/lib/humanize_bytes.py
../powerline/lib/__init__.py
../powerline/lib/inotify.py
../powerline/lib/url.py
../powerline/lib/threaded.py
../powerline/lib/file_watcher.py
../powerline/lib/tree_watcher.py
../powerline/bindings/ipython/post_0_11.py
../powerline/bindings/ipython/pre_0_11.py
../powerline/bindings/ipython/__init__.py
../powerline/bindings/qtile/__init__.py
../powerline/bindings/qtile/widget.py
../powerline/bindings/vim/__init__.py
../powerline/bindings/zsh/__init__.py
../powerline/lint/markedjson/composer.py
../powerline/lint/markedjson/constructor.py
../powerline/lint/markedjson/loader.py
../powerline/lint/markedjson/nodes.py
../powerline/lint/markedjson/resolver.py
../powerline/lint/markedjson/scanner.py
../powerline/lint/markedjson/reader.py
../powerline/lint/markedjson/__init__.py
../powerline/lint/markedjson/parser.py
../powerline/lint/markedjson/markedvalue.py
../powerline/lint/markedjson/events.py
../powerline/lint/markedjson/tokens.py
../powerline/lint/markedjson/error.py
../powerline/lib/vcs/git.py
../powerline/lib/vcs/mercurial.py
../powerline/lib/vcs/__init__.py
../powerline/lib/vcs/bzr.py
../powerline/config_files/colors.json
../powerline/config_files/config.json
../powerline/config_files/colorschemes/ipython/default.json
../powerline/config_files/colorschemes/shell/default.json
../powerline/config_files/colorschemes/shell/solarized.json
../powerline/config_files/colorschemes/tmux/default.json
../powerline/config_files/colorschemes/vim/default.json
../powerline/config_files/colorschemes/vim/solarized.json
../powerline/config_files/colorschemes/wm/default.json
../powerline/config_files/themes/ipython/in.json
../powerline/config_files/themes/ipython/in2.json
../powerline/config_files/themes/ipython/out.json
../powerline/config_files/themes/ipython/rewrite.json
../powerline/config_files/themes/shell/default.json
../powerline/config_files/themes/shell/default_leftonly.json
../powerline/config_files/themes/tmux/default.json
../powerline/config_files/themes/vim/cmdwin.json
../powerline/config_files/themes/vim/default.json
../powerline/config_files/themes/vim/help.json
../powerline/config_files/themes/vim/quickfix.json
../powerline/config_files/themes/wm/default.json
../powerline/bindings/awesome/powerline-awesome.py
../powerline/bindings/awesome/powerline.lua
../powerline/bindings/bash/powerline.sh
../powerline/bindings/tmux/powerline.conf
../powerline/bindings/vim/plugin/powerline.vim
../powerline/bindings/zsh/powerline.zsh
../powerline/shell.pyc
../powerline/colorscheme.pyc
../powerline/ipython.pyc
../powerline/theme.pyc
../powerline/vim.pyc
../powerline/__init__.pyc
../powerline/matcher.pyc
../powerline/renderer.pyc
../powerline/segment.pyc
../powerline/matchers/vim.pyc
../powerline/matchers/__init__.pyc
../powerline/bindings/__init__.pyc
../powerline/lint/__init__.pyc
../powerline/lint/inspect.pyc
../powerline/segments/shell.pyc
../powerline/segments/ipython.pyc
../powerline/segments/common.pyc
../powerline/segments/vim.pyc
../powerline/segments/__init__.pyc
../powerline/renderers/shell.pyc
../powerline/renderers/ipython.pyc
../powerline/renderers/bash_prompt.pyc
../powerline/renderers/zsh_prompt.pyc
../powerline/renderers/vim.pyc
../powerline/renderers/__init__.pyc
../powerline/renderers/pango_markup.pyc
../powerline/renderers/tmux.pyc
../powerline/lib/memoize.pyc
../powerline/lib/monotonic.pyc
../powerline/lib/config.pyc
../powerline/lib/humanize_bytes.pyc
../powerline/lib/__init__.pyc
../powerline/lib/inotify.pyc
../powerline/lib/url.pyc
../powerline/lib/threaded.pyc
../powerline/lib/file_watcher.pyc
../powerline/lib/tree_watcher.pyc
../powerline/bindings/ipython/post_0_11.pyc
../powerline/bindings/ipython/pre_0_11.pyc
../powerline/bindings/ipython/__init__.pyc
../powerline/bindings/qtile/__init__.pyc
../powerline/bindings/qtile/widget.pyc
../powerline/bindings/vim/__init__.pyc
../powerline/bindings/zsh/__init__.pyc
../powerline/lint/markedjson/composer.pyc
../powerline/lint/markedjson/constructor.pyc
../powerline/lint/markedjson/loader.pyc
../powerline/lint/markedjson/nodes.pyc
../powerline/lint/markedjson/resolver.pyc
../powerline/lint/markedjson/scanner.pyc
../powerline/lint/markedjson/reader.pyc
../powerline/lint/markedjson/__init__.pyc
../powerline/lint/markedjson/parser.pyc
../powerline/lint/markedjson/markedvalue.pyc
../powerline/lint/markedjson/events.pyc
../powerline/lint/markedjson/tokens.pyc
../powerline/lint/markedjson/error.pyc
../powerline/lib/vcs/git.pyc
../powerline/lib/vcs/mercurial.pyc
../powerline/lib/vcs/__init__.pyc
../powerline/lib/vcs/bzr.pyc
../powerline/bindings/awesome/powerline-awesome.pyc
./
SOURCES.txt
PKG-INFO
not-zip-safe
dependency_links.txt
top_level.txt
requires.txt
../../../../bin/powerline
../../../../bin/powerline-lint

View file

@ -1,282 +0,0 @@
Metadata-Version: 1.1
Name: jedi
Version: 0.5b5
Summary: An autocompletion tool for Python that can be used for text editors.
Home-page: https://github.com/davidhalter/jedi
Author: David Halter
Author-email: davidhalter88@gmail.com
License: LGPLv3
Description: ########################################
Jedi - an awesome Python auto-completion
########################################
.. image:: https://secure.travis-ci.org/davidhalter/jedi.png?branch=master
:target: http://travis-ci.org/davidhalter/jedi
:alt: Travis-CI build status
**beta testing**
*If you have any comments or feature requests, please tell me! I really want to
know, what you think about Jedi.*
Jedi is an autocompletion tool for Python. It works. With and without syntax
errors. Sometimes it sucks, but that's normal in dynamic languages. But it
sucks less than other tools. It understands almost all of the basic Python
syntax elements including many builtins.
Jedi suports two different goto functions and has support for renaming.
Probably it will also have some support for refactoring in the future.
Jedi uses a very simple interface to connect with IDE's. As an reference, there
is a VIM implementation, which uses Jedi's autocompletion. However, I encourage
you to use Jedi in your IDEs. Start writing plugins! If there are problems with
licensing, just contact me.
At the moment Jedi can be used as a
`VIM-Plugin <http://github.com/davidhalter/jedi-vim>`_. So, if you want to test
Jedi for now, you'll have to use VIM. But there are new plugins emerging:
- `Emacs-Plugin <https://github.com/tkf/emacs-jedi>`_
- `Sublime-Plugin <https://github.com/svaiter/SublimeJEDI>`_ **Under construction**
Here are some pictures:
.. image:: https://github.com/davidhalter/jedi/raw/master/screenshot_complete.png
Completion for almost anything (Ctrl+Space).
.. image:: https://github.com/davidhalter/jedi/raw/master/screenshot_function.png
Display of function/class bodies, docstrings.
.. image:: https://github.com/davidhalter/jedi/raw/master/screenshot_pydoc.png
Pydoc support (with highlighting, Shift+k).
There is also support for goto and renaming.
Get the latest from `github <http://github.com/davidhalter/jedi>`_.
Installation
============
You can either include Jedi as a submodule in your text editor plugin (like
jedi-vim_ does it by default), or you
can install Jedi systemwide.
The preferred way to install the Jedi library into your system is by using
pip_::
sudo pip install jedi
If you want to install the current development version::
sudo pip install -e git://github.com/davidhalter/jedi.git#egg=jedi
Note: This just installs the Jedi library, not the editor plugins. For
information about how to make it work with your editor, refer to the
corresponding documentation.
Support
=======
Jedi supports Python 2.5 up to 3.x. There is just one code base, for both
Python 2 and 3.
Jedi supports many of the widely used Python features:
- builtin functions/classes support
- complex module / function / class structures
- ignores syntax and indentation errors
- multiple returns / yields
- tuple assignments / array indexing / dictionary indexing
- exceptions / with-statement
- \*args / \*\*kwargs
- decorators
- descriptors -> property / staticmethod / classmethod
- closures
- generators (yield statement) / iterators
- support for some magic methods: ``__call__``, ``__iter__``, ``__next__``,
``__get__``, ``__getitem__``, ``__init__``
- support for list.append, set.add, list.extend, etc.
- (nested) list comprehensions / ternary expressions
- relative imports
- ``getattr()`` / ``__getattr__`` / ``__getattribute__``
- function annotations (py3k feature, are ignored right now, but being parsed.
I don't know what to do with them.)
- class decorators (py3k feature, are being ignored too, until I find a use
case, that doesn't work with Jedi)
- simple/usual ``sys.path`` modifications
- ``isinstance`` checks for if/while/assert
- virtualenv support
- infer function arguments with sphinx (and other) docstrings
However, it does not yet support (and probably will in future versions, because
they are on my todo list):
- manipulations of instances outside the instance variables, without using
functions
It does not support (and most probably will not in future versions):
- metaclasses (how could an auto-completion ever support this)
- ``setattr()``, ``__import__()``
- Writing to some dicts: ``globals()``, ``locals()``, ``object.__dict__``
- evaluate ``if`` / ``while``
Caveats
=======
This framework should work for both Python 2/3. However, some things were just
not as *pythonic* in Python 2 as things should be. To keep things simple, some
things have been held back:
- Classes: Always Python 3 like, therefore all classes inherit from ``object``.
- Generators: No ``next`` method. The ``__next__`` method is used instead.
- Exceptions are only looked at in the form of ``Exception as e``, no comma!
Syntax errors and other strange stuff, that is defined differently in the
Python language, may lead to undefined behaviour of the completion. Jedi is
**NOT** a Python compiler, that tries to correct you. It is a tool that wants
to help you. But **YOU** have to know Python, not Jedi.
Importing ``numpy`` can be quite slow sometimes, as well as loading the builtins
the first time. If you want to speed it up, you could write import hooks in
jedi, which preloads this stuff. However, once loaded, this is not a problem
anymore. The same is true for huge modules like ``PySide``, ``wx``, etc.
Security is an important issue for Jedi. Therefore no Python code is executed.
As long as you write pure python, everything is evaluated statically. But: If
you use builtin modules (`c_builtin`) there is no other option than to execute
those modules. However: Execute isn't that critical (as e.g. in pythoncomplete,
which used to execute *every* import!), because it means one import and no
more. So basically the only dangerous thing is using the import itself. If your
`c_builtin` uses some strange initializations, it might be dangerous. But if it
does you're screwed anyways, because eventualy you're going to execute your
code, which executes the import.
A little history
================
The Star Wars Jedi are awesome. My Jedi software tries to imitate a little bit
of the precognition the Jedi have. There is even an awesome `scene
<http://www.youtube.com/watch?v=5BDO3pyavOY>`_ of Monty Python Jedi's :-).
But actually the name hasn't so much to do with Star Wars. It's part of my
second name.
After I explained Guido van Rossum, how some parts of my auto-completion work,
he said (we drank a beer or two):
*Oh, that worries me*
When it's finished, I hope he'll like it :-)
I actually started Jedi, because there were no good solutions available for
VIM. Most auto-completions just didn't work well. The only good solution was
PyCharm. I just like my good old VIM. Rope was never really intended to be an
auto-completion (and also I really hate project folders for my Python scripts).
It's more of a refactoring suite. So I decided to do my own version of a
completion, which would execute non-dangerous code. But I soon realized, that
this wouldn't work. So I built an extremely recursive thing which understands
many of Python's key features.
By the way, I really tried to program it as understandable as possible. But I
think understanding it might need quite some time, because of its recursive
nature.
API-Design for IDEs
===================
If you want to set up an IDE with Jedi, you need to ``import jedi``. You should
have the following objects available:
::
Script(source, line, column, source_path)
``source`` would be the source of your python file/script, separated by new
lines. ``line`` is the current line you want to perform actions on (starting
with line #1 as the first line). ``column`` represents the current
column/indent of the cursor (starting with zero). ``source_path`` should be the
path of your file in the file system.
It returns a script object that contains the relevant information for the other
functions to work without params.
::
Script().complete
Returns ``api.Completion`` objects. Those objects have got
informations about the completions. More than just names.
::
Script().goto
Similar to complete. The returned ``api.Definition`` objects contain
information about the definitions found.
::
Script().get_definition
Mostly used for tests. Like goto, but follows statements and imports and
doesn't break there. You probably don't want to use this function. It's
mostly for testing.
::
Script().related_names
Returns all names that point to the definition of the name under the
cursor. This is also very useful for refactoring (renaming).
::
Script().get_in_function_call
Get the ``Function`` object of the call you're currently in, e.g.: ``abs(``
with the cursor at the end would return the builtin ``abs`` function.
::
NotFoundError
If you use the goto function and no valid identifier (name) is at the
place of the cursor (position). It will raise this exception.
::
set_debug_function
Sets a callback function for ``debug.py``. This function is called with
multiple text objects, in python 3 you could insert ``print``.
::
settings
Access to the ``settings.py`` module. The settings are described there.
.. _jedi-vim: http://github.com/davidhalter/jedi-vim
.. _pip: http://www.pip-installer.org/
Keywords: python completion refactoring vim
Platform: any
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Plugins
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Text Editors :: Integrated Development Environments (IDE)
Classifier: Topic :: Utilities

View file

@ -1,31 +0,0 @@
AUTHORS.txt
LICENSE.txt
MANIFEST.in
README.rst
setup.cfg
setup.py
jedi/__init__.py
jedi/_compatibility.py
jedi/api.py
jedi/api_classes.py
jedi/builtin.py
jedi/debug.py
jedi/docstrings.py
jedi/dynamic.py
jedi/evaluate.py
jedi/helpers.py
jedi/imports.py
jedi/keywords.py
jedi/modules.py
jedi/parsing.py
jedi/settings.py
jedi.egg-info/PKG-INFO
jedi.egg-info/SOURCES.txt
jedi.egg-info/dependency_links.txt
jedi.egg-info/top_level.txt
jedi/mixin/_functools.pym
jedi/mixin/_sre.pym
jedi/mixin/_weakref.pym
jedi/mixin/builtins.pym
jedi/mixin/datetime.pym
jedi/mixin/posix.pym

View file

@ -1,41 +0,0 @@
../jedi/builtin.py
../jedi/evaluate.py
../jedi/debug.py
../jedi/helpers.py
../jedi/settings.py
../jedi/keywords.py
../jedi/api_classes.py
../jedi/api.py
../jedi/modules.py
../jedi/__init__.py
../jedi/parsing.py
../jedi/docstrings.py
../jedi/_compatibility.py
../jedi/imports.py
../jedi/dynamic.py
../jedi/mixin/builtins.pym
../jedi/mixin/posix.pym
../jedi/mixin/_functools.pym
../jedi/mixin/_weakref.pym
../jedi/mixin/_sre.pym
../jedi/mixin/datetime.pym
../jedi/builtin.pyc
../jedi/evaluate.pyc
../jedi/debug.pyc
../jedi/helpers.pyc
../jedi/settings.pyc
../jedi/keywords.pyc
../jedi/api_classes.pyc
../jedi/api.pyc
../jedi/modules.pyc
../jedi/__init__.pyc
../jedi/parsing.pyc
../jedi/docstrings.pyc
../jedi/_compatibility.pyc
../jedi/imports.pyc
../jedi/dynamic.pyc
./
SOURCES.txt
PKG-INFO
dependency_links.txt
top_level.txt

View file

@ -1,16 +0,0 @@
import sys
# python imports are hell sometimes. Especially the combination of relative
# imports and circular imports... Just avoid it:
sys.path.insert(0, __path__[0])
from .api import Script, NotFoundError, set_debug_function
from . import settings
from . import api
__doc__ = api.__doc__
del api
sys.path.pop(0)

View file

@ -1,169 +0,0 @@
"""
This is a compatibility module, to make it possible to use jedi also with older
python versions.
"""
import sys
is_py3k = sys.hexversion >= 0x03000000
is_py25 = sys.hexversion < 0x02060000
# next was defined in python 2.6, in python 3 obj.next won't be possible
# anymore
try:
next = next
except NameError:
_raiseStopIteration = object()
def next(iterator, default=_raiseStopIteration):
if not hasattr(iterator, 'next'):
raise TypeError("not an iterator")
try:
return iterator.next()
except StopIteration:
if default is _raiseStopIteration:
raise
else:
return default
# ast module was defined in python 2.6
try:
from ast import literal_eval
except ImportError:
literal_eval = eval
# properties in 2.5
try:
property.setter
except AttributeError:
class property(property):
def __init__(self, fget, *args, **kwargs):
self.__doc__ = fget.__doc__
super(property, self).__init__(fget, *args, **kwargs)
def setter(self, fset):
cls_ns = sys._getframe(1).f_locals
for k, v in cls_ns.iteritems():
if v == self:
propname = k
break
cls_ns[propname] = property(self.fget, fset,
self.fdel, self.__doc__)
return cls_ns[propname]
else:
property = property
# unicode function
try:
unicode = unicode
except NameError:
unicode = str
if is_py3k:
utf8 = lambda s: s
else:
utf8 = lambda s: s.decode('utf-8')
utf8.__doc__ = """
Decode a raw string into unicode object. Do nothing in Python 3.
"""
# exec function
if is_py3k:
def exec_function(source, global_map):
exec(source, global_map)
else:
eval(compile("""def exec_function(source, global_map):
exec source in global_map """, 'blub', 'exec'))
# StringIO (Python 2.5 has no io module), so use io only for py3k
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
# hasattr function used because python
if is_py3k:
hasattr = hasattr
else:
def hasattr(obj, name):
try:
getattr(obj, name)
return True
except AttributeError:
return False
class Python3Method(object):
def __init__(self, func):
self.func = func
def __get__(self, obj, objtype):
if obj is None:
return lambda *args, **kwargs: self.func(*args, **kwargs)
else:
return lambda *args, **kwargs: self.func(obj, *args, **kwargs)
try:
# the python3 way
from functools import reduce
except ImportError:
reduce = reduce
def use_metaclass(meta, *bases):
""" Create a class with a metaclass. """
if not bases:
bases = (object,)
return meta("HackClass", bases, {})
try:
from inspect import cleandoc
except ImportError:
# python 2.5 doesn't have this method
import string
def cleandoc(doc):
"""Clean up indentation from docstrings.
Any whitespace that can be uniformly removed from the second line
onwards is removed."""
try:
lines = string.split(string.expandtabs(doc), '\n')
except UnicodeError:
return None
else:
# Find minimum indentation of any non-blank lines after first line.
margin = sys.maxint
for line in lines[1:]:
content = len(string.lstrip(line))
if content:
indent = len(line) - content
margin = min(margin, indent)
# Remove indentation.
if lines:
lines[0] = lines[0].lstrip()
if margin < sys.maxint:
for i in range(1, len(lines)):
lines[i] = lines[i][margin:]
# Remove any trailing or leading blank lines.
while lines and not lines[-1]:
lines.pop()
while lines and not lines[0]:
lines.pop(0)
return string.join(lines, '\n')
if is_py25:
# adds the `itertools.chain.from_iterable` constructor
import itertools
class chain(itertools.chain):
@staticmethod
def from_iterable(iterables):
# chain.from_iterable(['ABC', 'DEF']) --> A B C D E F
for it in iterables:
for element in it:
yield element
itertools.chain = chain
del chain

View file

@ -1,457 +0,0 @@
"""
Jedi is an autocompletion library for Python. It offers additonal
services such as goto / get_definition / pydoc support /
get_in_function_call / related names.
To give you a simple exmple how you can use the jedi library,
here is an exmple for the autocompletion feature:
>>> import jedi
>>> source = '''import json; json.l'''
>>> script = jedi.Script(source, 1, 19, '')
>>> script
<jedi.api.Script at 0x7f6d40f3db90>
>>> completions = script.complete()
>>> completions
[<Completion: load>, <Completion: loads>]
>>> completions[0].complete
'oad'
>>> completions[0].word
'load'
As you see Jedi is pretty simple and allows you to concentrate
writing a good text editor, while still having very good IDE features
for Python.
"""
from __future__ import with_statement
__all__ = ['Script', 'NotFoundError', 'set_debug_function']
import re
import parsing
import dynamic
import imports
import evaluate
import modules
import debug
import settings
import keywords
import helpers
import builtin
import api_classes
from _compatibility import next, unicode
class NotFoundError(Exception):
""" A custom error to avoid catching the wrong exceptions """
pass
class Script(object):
"""
A Script is the base for a completion, goto or whatever call.
:param source: The source code of the current file
:type source: string
:param line: The line to complete in.
:type line: int
:param col: The column to complete in.
:type col: int
:param source_path: The path in the os, the current module is in.
:type source_path: string or None
:param source_encoding: encoding for decoding `source`, when it
is not a `unicode` object.
:type source_encoding: string
"""
def __init__(self, source, line, column, source_path,
source_encoding='utf-8'):
debug.reset_time()
try:
source = unicode(source, source_encoding, 'replace')
# Use 'replace' over 'ignore' to hold code structure.
except TypeError: # `source` is already a unicode object
pass
self.pos = line, column
self.module = modules.ModuleWithCursor(source_path, source=source,
position=self.pos)
self.source_path = source_path
debug.speed('init')
@property
def parser(self):
""" The lazy parser """
return self.module.parser
def complete(self):
"""
An auto completer for python files.
:return: list of Completion objects, sorted by name and __ comes last.
:rtype: list
"""
def follow_imports_if_possible(name):
# TODO remove this, or move to another place (not used)
par = name.parent
if isinstance(par, parsing.Import) and not \
isinstance(self.parser.user_stmt, parsing.Import):
new = imports.ImportPath(par).follow(is_goto=True)
# Only remove the old entry if a new one has been found.
#print par, new, par.parent
if new:
try:
return new
except AttributeError: # .name undefined
pass
return [name]
debug.speed('complete start')
path = self.module.get_path_until_cursor()
path, dot, like = self._get_completion_parts(path)
try:
scopes = list(self._prepare_goto(path, True))
except NotFoundError:
scopes = []
scope_generator = evaluate.get_names_for_scope(
self.parser.user_scope, self.pos)
completions = []
for scope, name_list in scope_generator:
for c in name_list:
completions.append((c, scope))
else:
completions = []
debug.dbg('possible scopes', scopes)
for s in scopes:
if s.isinstance(evaluate.Function):
names = s.get_magic_method_names()
else:
if isinstance(s, imports.ImportPath):
if like == 'import':
l = self.module.get_line(self.pos[0])[:self.pos[1]]
if not l.endswith('import import'):
continue
names = s.get_defined_names(on_import_stmt=True)
else:
names = s.get_defined_names()
for c in names:
completions.append((c, s))
if not dot: # named_params have no dots
call_def = self.get_in_function_call()
if call_def:
if not call_def.module.is_builtin():
for p in call_def.params:
completions.append((p.get_name(), p))
# Do the completion if there is no path before and no import stmt.
if (not scopes or not isinstance(scopes[0], imports.ImportPath)) \
and not path:
# add keywords
bs = builtin.Builtin.scope
completions += ((k, bs) for k in keywords.get_keywords(
all=True))
needs_dot = not dot and path
comps = []
for c, s in set(completions):
n = c.names[-1]
if settings.case_insensitive_completion \
and n.lower().startswith(like.lower()) \
or n.startswith(like):
if not evaluate.filter_private_variable(s,
self.parser.user_stmt, n):
new = api_classes.Completion(c, needs_dot,
len(like), s)
comps.append(new)
debug.speed('complete end')
return sorted(comps, key=lambda x: (x.word.startswith('__'),
x.word.startswith('_'),
x.word.lower()))
def _prepare_goto(self, goto_path, is_like_search=False):
""" Base for complete, goto and get_definition. Basically it returns
the resolved scopes under cursor. """
debug.dbg('start: %s in %s' % (goto_path, self.parser.scope))
user_stmt = self.parser.user_stmt
debug.speed('parsed')
if not user_stmt and len(goto_path.split('\n')) > 1:
# If the user_stmt is not defined and the goto_path is multi line,
# something's strange. Most probably the backwards tokenizer
# matched to much.
return []
if isinstance(user_stmt, parsing.Import):
scopes = [self._get_on_import_stmt(is_like_search)[0]]
else:
# just parse one statement, take it and evaluate it
stmt = self._get_under_cursor_stmt(goto_path)
scopes = evaluate.follow_statement(stmt)
return scopes
def _get_under_cursor_stmt(self, cursor_txt):
r = parsing.PyFuzzyParser(cursor_txt, self.source_path, no_docstr=True)
try:
stmt = r.module.statements[0]
except IndexError:
raise NotFoundError()
stmt.start_pos = self.pos
stmt.parent = self.parser.user_scope
return stmt
def get_definition(self):
"""
Returns the definitions of a the path under the cursor. This is
not a goto function! This follows complicated paths and returns the
end, not the first definition.
The big difference of goto and get_definition is that goto doesn't
follow imports and statements.
Multiple objects may be returned, because Python itself is a dynamic
language, which means depending on an option you can have two different
versions of a function.
:return: list of Definition objects, which are basically scopes.
:rtype: list
"""
def resolve_import_paths(scopes):
for s in scopes.copy():
if isinstance(s, imports.ImportPath):
scopes.remove(s)
scopes.update(resolve_import_paths(set(s.follow())))
return scopes
goto_path = self.module.get_path_under_cursor()
context = self.module.get_context()
if next(context) in ('class', 'def'):
scopes = set([self.module.parser.user_scope])
elif not goto_path:
op = self.module.get_operator_under_cursor()
scopes = set([keywords.get_operator(op, self.pos)] if op else [])
else:
scopes = set(self._prepare_goto(goto_path))
scopes = resolve_import_paths(scopes)
# add keywords
scopes |= keywords.get_keywords(string=goto_path, pos=self.pos)
d = set([api_classes.Definition(s) for s in scopes
if not isinstance(s, imports.ImportPath._GlobalNamespace)])
return sorted(d, key=lambda x: (x.module_path, x.start_pos))
def goto(self):
"""
Returns the first definition found by goto. This means: It doesn't
follow imports and statements.
Multiple objects may be returned, because Python itself is a dynamic
language, which means depending on an option you can have two different
versions of a function.
:return: list of Definition objects, which are basically scopes.
"""
d = [api_classes.Definition(d) for d in set(self._goto()[0])]
return sorted(d, key=lambda x: (x.module_path, x.start_pos))
def _goto(self, add_import_name=False):
"""
Used for goto and related_names.
:param add_import_name: TODO add description
"""
def follow_inexistent_imports(defs):
""" Imports can be generated, e.g. following
`multiprocessing.dummy` generates an import dummy in the
multiprocessing module. The Import doesn't exist -> follow.
"""
definitions = set(defs)
for d in defs:
if isinstance(d.parent, parsing.Import) \
and d.start_pos == (0, 0):
i = imports.ImportPath(d.parent).follow(is_goto=True)
definitions.remove(d)
definitions |= follow_inexistent_imports(i)
return definitions
goto_path = self.module.get_path_under_cursor()
context = self.module.get_context()
if next(context) in ('class', 'def'):
user_scope = self.parser.user_scope
definitions = set([user_scope.name])
search_name = str(user_scope.name)
elif isinstance(self.parser.user_stmt, parsing.Import):
s, name_part = self._get_on_import_stmt()
try:
definitions = [s.follow(is_goto=True)[0]]
except IndexError:
definitions = []
search_name = str(name_part)
if add_import_name:
import_name = self.parser.user_stmt.get_defined_names()
# imports have only one name
if name_part == import_name[0].names[-1]:
definitions.append(import_name[0])
else:
stmt = self._get_under_cursor_stmt(goto_path)
defs, search_name = evaluate.goto(stmt)
definitions = follow_inexistent_imports(defs)
return definitions, search_name
def related_names(self, additional_module_paths=[]):
"""
Returns `dynamic.RelatedName` objects, which contain all names, that
are defined by the same variable, function, class or import.
This function can be used either to show all the usages of a variable
or for renaming purposes.
TODO implement additional_module_paths
"""
user_stmt = self.parser.user_stmt
definitions, search_name = self._goto(add_import_name=True)
if isinstance(user_stmt, parsing.Statement) \
and self.pos < user_stmt.get_assignment_calls().start_pos:
# the search_name might be before `=`
definitions = [v for v in user_stmt.set_vars
if str(v) == search_name]
if not isinstance(user_stmt, parsing.Import):
# import case is looked at with add_import_name option
definitions = dynamic.related_name_add_import_modules(definitions,
search_name)
module = set([d.get_parent_until() for d in definitions])
module.add(self.parser.module)
names = dynamic.related_names(definitions, search_name, module)
for d in set(definitions):
if isinstance(d, parsing.Module):
names.append(api_classes.RelatedName(d, d))
else:
names.append(api_classes.RelatedName(d.names[0], d))
return sorted(set(names), key=lambda x: (x.module_path, x.start_pos),
reverse=True)
def get_in_function_call(self):
"""
Return the function, that the cursor is in, e.g.:
>>> isinstance(| # | <-- cursor is here
This would return the `isinstance` function. In contrary:
>>> isinstance()| # | <-- cursor is here
This would return `None`.
"""
def check_user_stmt(user_stmt):
if user_stmt is None \
or not isinstance(user_stmt, parsing.Statement):
return None, 0
ass = helpers.fast_parent_copy(user_stmt.get_assignment_calls())
call, index, stop = helpers.scan_array_for_pos(ass, self.pos)
return call, index
def check_cache():
""" Do the parsing with a part parser, therefore reduce ressource
costs.
TODO this is not working with multi-line docstrings, improve.
"""
if self.source_path is None:
return None, 0
try:
timestamp, parser = builtin.CachedModule.cache[
self.source_path]
except KeyError:
return None, 0
part_parser = self.module.get_part_parser()
user_stmt = part_parser.user_stmt
call, index = check_user_stmt(user_stmt)
if call:
old_stmt = parser.module.get_statement_for_position(self.pos)
if old_stmt is None:
return None, 0
old_call, old_index = check_user_stmt(old_stmt)
if old_call:
# compare repr because that should definitely be the same.
# Otherwise the whole thing is out of sync.
if repr(old_call) == repr(call):
# return the index of the part_parser
return old_call, index
return None, 0
else:
raise NotFoundError()
debug.speed('func_call start')
try:
call, index = check_cache()
except NotFoundError:
return None
debug.speed('func_call parsed')
if call is None:
# This is a backup, if the above is not successful.
user_stmt = self.parser.user_stmt
call, index = check_user_stmt(user_stmt)
if call is None:
return None
debug.speed('func_call user_stmt')
with helpers.scale_speed_settings(settings.scale_get_in_function_call):
origins = evaluate.follow_call(call)
debug.speed('func_call followed')
if len(origins) == 0:
return None
# just take entry zero, because we need just one.
executable = origins[0]
return api_classes.CallDef(executable, index, call)
def _get_on_import_stmt(self, is_like_search=False):
""" Resolve the user statement, if it is an import. Only resolve the
parts until the user position. """
user_stmt = self.parser.user_stmt
import_names = user_stmt.get_all_import_names()
kill_count = -1
cur_name_part = None
for i in import_names:
if user_stmt.alias == i:
continue
for name_part in i.names:
if name_part.end_pos >= self.pos:
if not cur_name_part:
cur_name_part = name_part
kill_count += 1
i = imports.ImportPath(user_stmt, is_like_search,
kill_count=kill_count, direct_resolve=True)
return i, cur_name_part
def _get_completion_parts(self, path):
"""
Returns the parts for the completion
:return: tuple - (path, dot, like)
"""
match = re.match(r'^(.*?)(\.|)(\w?[\w\d]*)$', path, flags=re.S)
return match.groups()
def __del__(self):
evaluate.clear_caches()
def set_debug_function(func_cb=debug.print_to_stdout, warnings=True,
notices=True, speed=True):
"""
You can define a callback debug function to get all the debug messages.
:param func_cb: The callback function for debug messages, with n params.
"""
debug.debug_function = func_cb
debug.enable_warning = warnings
debug.enable_notice = notices
debug.enable_speed = speed

View file

@ -1,311 +0,0 @@
""" The classes returned by the api """
import re
import os
import settings
import evaluate
import imports
import parsing
import keywords
class BaseDefinition(object):
_mapping = {'posixpath': 'os.path',
'riscospath': 'os.path',
'ntpath': 'os.path',
'os2emxpath': 'os.path',
'macpath': 'os.path',
'genericpath': 'os.path',
'_io': 'io',
'__builtin__': '',
'builtins': '',
}
_tuple_mapping = dict((tuple(k.split('.')), v) for (k, v) in {
'argparse._ActionsContainer': 'argparse.ArgumentParser',
'_sre.SRE_Match': 're.MatchObject',
'_sre.SRE_Pattern': 're.RegexObject',
}.items())
def __init__(self, definition, start_pos):
self.start_pos = start_pos
self.definition = definition
self.is_keyword = isinstance(definition, keywords.Keyword)
# generate a path to the definition
self.module_path = str(definition.get_parent_until().path)
@property
def type(self):
# generate the type
stripped = self.definition
if isinstance(self.definition, evaluate.InstanceElement):
stripped = self.definition.var
return type(stripped).__name__
@property
def path(self):
path = []
if not isinstance(self.definition, keywords.Keyword):
par = self.definition
while par is not None:
try:
path.insert(0, par.name)
except AttributeError:
pass
par = par.parent
return path
@property
def module_name(self):
path = self.module_path
sep = os.path.sep
p = re.sub(r'^.*?([\w\d]+)(%s__init__)?.py$' % sep, r'\1', path)
return p
def in_builtin_module(self):
return not self.module_path.endswith('.py')
@property
def line_nr(self):
return self.start_pos[0]
@property
def column(self):
return self.start_pos[1]
@property
def doc(self):
""" Return a document string for this completion object. """
try:
return self.definition.doc
except AttributeError:
return self.raw_doc
@property
def raw_doc(self):
""" Returns the raw docstring `__doc__` for any object """
try:
return str(self.definition.docstr)
except AttributeError:
return ''
@property
def description(self):
return str(self.definition)
@property
def full_name(self):
"""
Returns the path to a certain class/function, see #61.
"""
path = [str(p) for p in self.path]
# TODO add further checks, the mapping should only occur on stdlib.
try:
path[0] = self._mapping[path[0]]
except KeyError:
pass
for key, repl in self._tuple_mapping.items():
if tuple(path[:len(key)]) == key:
path = [repl] + path[len(key):]
return '.'.join(path if path[0] else path[1:])
def __repr__(self):
return "<%s %s>" % (type(self).__name__, self.description)
class Completion(BaseDefinition):
""" `Completion` objects are returned from `Script.complete`. Providing
some useful functions for IDE's. """
def __init__(self, name, needs_dot, like_name_length, base):
super(Completion, self).__init__(name.parent, name.start_pos)
self.name = name
self.needs_dot = needs_dot
self.like_name_length = like_name_length
self.base = base
self._followed_definitions = None
@property
def complete(self):
""" Delievers the rest of the word, e.g. completing `isinstance`
>>> isinstan
would return the string 'ce'. It also adds additional stuff, depending
on your `settings.py`
"""
dot = '.' if self.needs_dot else ''
append = ''
if settings.add_bracket_after_function \
and self.type == 'Function':
append = '('
if settings.add_dot_after_module:
if isinstance(self.base, parsing.Module):
append += '.'
if isinstance(self.base, parsing.Param):
append += '='
return dot + self.name.names[-1][self.like_name_length:] + append
@property
def word(self):
""" In contrary to `complete` returns the whole word, e.g.
>>> isinstan
would return 'isinstance'.
"""
return str(self.name.names[-1])
@property
def description(self):
""" Provides a description of the completion object
TODO return value is just __repr__ of some objects, improve! """
parent = self.name.parent
if parent is None:
return ''
t = self.type
if t == 'Statement' or t == 'Import':
desc = self.definition.get_code(False)
else:
desc = '.'.join(str(p) for p in self.path)
line_nr = '' if self.in_builtin_module else '@%s' % self.line_nr
return '%s: %s%s' % (t, desc, line_nr)
def follow_definition(self):
""" Returns you the original definitions. I strongly recommend not
using it for your completions, because it might slow down Jedi. If you
want to read only a few objects (<=20). I think it might be useful,
especially to get the original docstrings.
The basic problem of this function is that it follows all results. This
means with 1000 completions (e.g. numpy), it's just PITA slow.
"""
if self._followed_definitions is None:
if self.definition.isinstance(parsing.Statement):
defs = evaluate.follow_statement(self.definition)
elif self.definition.isinstance(parsing.Import):
defs = imports.strip_imports([self.definition])
else:
return [self]
self._followed_definitions = \
[BaseDefinition(d, d.start_pos) for d in defs]
evaluate.clear_caches()
return self._followed_definitions
def __repr__(self):
return '<%s: %s>' % (type(self).__name__, self.name)
class Definition(BaseDefinition):
""" These are the objects returned by either `Script.goto` or
`Script.get_definition`. """
def __init__(self, definition):
super(Definition, self).__init__(definition, definition.start_pos)
@property
def description(self):
""" A description of the Definition object, which is heavily used in
testing. e.g. for `isinstance` it returns 'def isinstance' """
d = self.definition
if isinstance(d, evaluate.InstanceElement):
d = d.var
if isinstance(d, evaluate.parsing.Name):
d = d.parent
if isinstance(d, evaluate.Array):
d = 'class ' + d.type
elif isinstance(d, (parsing.Class, evaluate.Class, evaluate.Instance)):
d = 'class ' + str(d.name)
elif isinstance(d, (evaluate.Function, evaluate.parsing.Function)):
d = 'def ' + str(d.name)
elif isinstance(d, evaluate.parsing.Module):
# only show module name
d = 'module %s' % self.module_name
elif self.is_keyword:
d = 'keyword %s' % d.name
else:
d = d.get_code().replace('\n', '')
return d
@property
def desc_with_module(self):
""" In addition to the Definition, it also returns the module. Don't
use it yet, its behaviour may change. If you really need it, talk to me
TODO add full path. This function is should return a
module.class.function path. """
if self.module_path.endswith('.py') \
and not isinstance(self.definition, parsing.Module):
position = '@%s' % (self.line_nr)
else:
# is a builtin or module
position = ''
return "%s:%s%s" % (self.module_name, self.description, position)
class RelatedName(BaseDefinition):
def __init__(self, name_part, scope):
super(RelatedName, self).__init__(scope, name_part.start_pos)
self.name_part = name_part
self.text = str(name_part)
self.end_pos = name_part.end_pos
@property
def description(self):
return "%s@%s,%s" % (self.text, self.start_pos[0], self.start_pos[1])
def __eq__(self, other):
return self.start_pos == other.start_pos \
and self.module_path == other.module_path
def __hash__(self):
return hash((self.start_pos, self.module_path))
class CallDef(object):
""" `CallDef` objects is the return value of `Script.get_in_function_call`.
It knows what functions you are currently in. e.g. `isinstance(` would
return the `isinstance` function. without `(` it would return nothing."""
def __init__(self, executable, index, call):
self.executable = executable
self.index = index
self.call = call
@property
def params(self):
if self.executable.isinstance(evaluate.Function):
if isinstance(self.executable, evaluate.InstanceElement):
return self.executable.params[1:]
return self.executable.params
else:
try:
sub = self.executable.get_subscope_by_name('__init__')
return sub.params[1:] # ignore self
except KeyError:
return []
@property
def bracket_start(self):
""" The indent of the bracket that is responsible for the last function
call. """
c = self.call
while c.next is not None:
c = c.next
return c.name.end_pos
@property
def call_name(self):
""" The name (e.g. 'isinstance') as a string. """
return str(self.executable.name)
@property
def module(self):
return self.executable.get_parent_until()
def __repr__(self):
return '<%s: %s index %s>' % (type(self).__name__, self.executable,
self.index)

View file

@ -1,472 +0,0 @@
from __future__ import with_statement
from _compatibility import exec_function, is_py3k
import re
import sys
import os
if is_py3k:
import io
import types
import inspect
import debug
import parsing
import imports
import evaluate
def get_sys_path():
def check_virtual_env(sys_path):
""" Add virtualenv's site-packages to the `sys.path`."""
venv = os.getenv('VIRTUAL_ENV')
if not venv:
return
venv = os.path.abspath(venv)
p = os.path.join(
venv, 'lib', 'python%d.%d' % sys.version_info[:2], 'site-packages')
sys_path.insert(0, p)
p = sys.path[1:]
check_virtual_env(p)
return p
class CachedModule(object):
"""
The base type for all modules, which is not to be confused with
`parsing.Module`. Caching happens here.
"""
cache = {}
def __init__(self, path=None, name=None):
self.path = path and os.path.abspath(path)
self.name = name
self._parser = None
@property
def parser(self):
""" get the parser lazy """
if not self._parser:
try:
timestamp, parser = self.cache[self.path or self.name]
if not self.path or os.path.getmtime(self.path) <= timestamp:
self._parser = parser
else:
# In case there is already a module cached and this module
# has to be reparsed, we also need to invalidate the import
# caches.
imports.invalidate_star_import_cache(parser.module)
raise KeyError()
except KeyError:
self._load_module()
return self._parser
def _get_source(self):
raise NotImplementedError()
def _load_module(self):
source = self._get_source()
self._parser = parsing.PyFuzzyParser(source, self.path or self.name)
p_time = None if not self.path else os.path.getmtime(self.path)
if self.path or self.name:
self.cache[self.path or self.name] = p_time, self._parser
class Parser(CachedModule):
"""
This module is a parser for all builtin modules, which are programmed in
C/C++. It should also work on third party modules.
It can be instantiated with either a path or a name of the module. The path
is important for third party modules.
:param name: The name of the module.
:param path: The path of the module.
:param sys_path: The sys.path, which is can be customizable.
"""
map_types = {
'floating point number': '0.0',
'string': '""',
'str': '""',
'character': '"a"',
'integer': '0',
'int': '0',
'dictionary': '{}',
'list': '[]',
'file object': 'file("")',
# TODO things like dbg: ('not working', 'tuple of integers')
}
if is_py3k:
map_types['file object'] = 'import io; return io.TextIOWrapper()'
module_cache = {}
def __init__(self, path=None, name=None, sys_path=None):
if sys_path is None:
sys_path = get_sys_path()
if not name:
name = os.path.basename(path)
name = name.rpartition('.')[0] # cut file type (normally .so)
super(Parser, self).__init__(path=path, name=name)
self.sys_path = list(sys_path)
self._module = None
@property
def module(self):
def load_module(name, path):
if path:
self.sys_path.insert(0, path)
temp, sys.path = sys.path, self.sys_path
content = {}
try:
exec_function('import %s as module' % name, content)
self._module = content['module']
except AttributeError:
# use sys.modules, because you cannot access some modules
# directly. -> #59
self._module = sys.modules[name]
sys.path = temp
if path:
self.sys_path.pop(0)
# module might already be defined
if not self._module:
path = self.path
name = self.name
if self.path:
dot_path = []
p = self.path
# search for the builtin with the correct path
while p and p not in sys.path:
p, sep, mod = p.rpartition(os.path.sep)
dot_path.append(mod.partition('.')[0])
if p:
name = ".".join(reversed(dot_path))
path = p
else:
path = os.path.dirname(self.path)
load_module(name, path)
return self._module
def _get_source(self):
""" Override this abstract method """
return _generate_code(self.module, self._load_mixins())
def _load_mixins(self):
"""
Load functions that are mixed in to the standard library.
E.g. builtins are written in C (binaries), but my autocompletion only
understands Python code. By mixing in Python code, the autocompletion
should work much better for builtins.
"""
regex = r'^(def|class)\s+([\w\d]+)'
def process_code(code, depth=0):
funcs = {}
matches = list(re.finditer(regex, code, re.MULTILINE))
positions = [m.start() for m in matches]
for i, pos in enumerate(positions):
try:
code_block = code[pos:positions[i + 1]]
except IndexError:
code_block = code[pos:len(code)]
structure_name = matches[i].group(1)
name = matches[i].group(2)
if structure_name == 'def':
funcs[name] = code_block
elif structure_name == 'class':
if depth > 0:
raise NotImplementedError()
# remove class line
c = re.sub(r'^[^\n]+', '', code_block)
# remove whitespace
c = re.compile(r'^[ ]{4}', re.MULTILINE).sub('', c)
funcs[name] = process_code(c)
else:
raise NotImplementedError()
return funcs
try:
name = self.name
if name == '__builtin__' and not is_py3k:
name = 'builtins'
path = os.path.dirname(os.path.abspath(__file__))
with open(os.path.sep.join([path, 'mixin', name]) + '.pym') as f:
s = f.read()
except IOError:
return {}
else:
mixin_dct = process_code(s)
if is_py3k and self.name == Builtin.name:
# in the case of Py3k xrange is now range
mixin_dct['range'] = mixin_dct['xrange']
return mixin_dct
def _generate_code(scope, mixin_funcs={}, depth=0):
"""
Generate a string, which uses python syntax as an input to the
PyFuzzyParser.
"""
def get_doc(obj, indent=False):
doc = inspect.getdoc(obj)
if doc:
doc = ('r"""\n%s\n"""\n' % doc)
if indent:
doc = parsing.indent_block(doc)
return doc
return ''
def is_in_base_classes(cls, name, comparison):
""" Base classes may contain the exact same object """
if name in mixin_funcs:
return False
try:
mro = cls.mro()
except TypeError:
# this happens, if cls == type
return False
for base in mro[1:]:
try:
attr = getattr(base, name)
except AttributeError:
continue
if attr == comparison:
return True
return False
def get_scope_objects(names):
"""
Looks for the names defined with dir() in an objects and divides
them into different object types.
"""
classes = {}
funcs = {}
stmts = {}
members = {}
for n in names:
try:
# this has a builtin_function_or_method
exe = getattr(scope, n)
except AttributeError:
# happens e.g. in properties of
# PyQt4.QtGui.QStyleOptionComboBox.currentText
# -> just set it to None
members[n] = None
else:
if inspect.isclass(scope):
if is_in_base_classes(scope, n, exe):
continue
if inspect.isbuiltin(exe) or inspect.ismethod(exe) \
or inspect.ismethoddescriptor(exe):
funcs[n] = exe
elif inspect.isclass(exe):
classes[n] = exe
elif inspect.ismemberdescriptor(exe):
members[n] = exe
else:
stmts[n] = exe
return classes, funcs, stmts, members
code = ''
if inspect.ismodule(scope): # generate comment where the code's from.
try:
path = scope.__file__
except AttributeError:
path = '?'
code += '# Generated module %s from %s\n' % (scope.__name__, path)
code += get_doc(scope)
names = set(dir(scope)) - set(['__file__', '__name__', '__doc__',
'__path__', '__package__']) \
| set(['mro'])
classes, funcs, stmts, members = get_scope_objects(names)
# classes
for name, cl in classes.items():
bases = (c.__name__ for c in cl.__bases__)
code += 'class %s(%s):\n' % (name, ','.join(bases))
if depth == 0:
try:
mixin = mixin_funcs[name]
except KeyError:
mixin = {}
cl_code = _generate_code(cl, mixin, depth + 1)
code += parsing.indent_block(cl_code)
code += '\n'
# functions
for name, func in funcs.items():
params, ret = parse_function_doc(func)
if depth > 0:
params = 'self, ' + params
doc_str = get_doc(func, indent=True)
try:
mixin = mixin_funcs[name]
except KeyError:
# normal code generation
code += 'def %s(%s):\n' % (name, params)
code += doc_str
code += parsing.indent_block('%s\n\n' % ret)
else:
# generation of code with mixins
# the parser only supports basic functions with a newline after
# the double dots
# find doc_str place
pos = re.search(r'\):\s*\n', mixin).end()
if pos is None:
raise Exception("Builtin function not parsed correctly")
code += mixin[:pos] + doc_str + mixin[pos:]
# class members (functions) properties?
for name, func in members.items():
# recursion problem in properties TODO remove
if name in ['fget', 'fset', 'fdel']:
continue
ret = 'pass'
code += '@property\ndef %s(self):\n' % (name)
code += parsing.indent_block(get_doc(func) + '%s\n\n' % ret)
# variables
for name, value in stmts.items():
if is_py3k:
file_type = io.TextIOWrapper
else:
file_type = types.FileType
if type(value) == file_type:
value = 'open()'
elif name == 'None':
value = ''
elif type(value).__name__ in ['int', 'bool', 'float',
'dict', 'list', 'tuple']:
value = repr(value)
else:
# get the type, if the type is not simple.
mod = type(value).__module__
value = type(value).__name__ + '()'
if mod != '__builtin__':
value = '%s.%s' % (mod, value)
code += '%s = %s\n' % (name, value)
if depth == 0:
#with open('writeout.py', 'w') as f:
# f.write(code)
#import sys
#sys.stdout.write(code)
#exit()
pass
return code
def parse_function_doc(func):
"""
Takes a function and returns the params and return value as a tuple.
This is nothing more than a docstring parser.
"""
# TODO: things like utime(path, (atime, mtime)) and a(b [, b]) -> None
doc = inspect.getdoc(func)
# get full string, parse round parentheses: def func(a, (b,c))
try:
count = 0
debug.dbg(func, func.__name__, doc)
start = doc.index('(')
for i, s in enumerate(doc[start:]):
if s == '(':
count += 1
elif s == ')':
count -= 1
if count == 0:
end = start + i
break
param_str = doc[start + 1:end]
# remove square brackets, that show an optional param ( = None)
def change_options(m):
args = m.group(1).split(',')
for i, a in enumerate(args):
if a and '=' not in a:
args[i] += '=None'
return ','.join(args)
while True:
param_str, changes = re.subn(r' ?\[([^\[\]]+)\]',
change_options, param_str)
if changes == 0:
break
except (ValueError, AttributeError):
debug.dbg('no brackets found - no param')
end = 0
param_str = ''
param_str = param_str.replace('-', '_') # see: isinstance.__doc__
if doc is not None:
r = re.search('-[>-]* ', doc[end:end + 7])
if doc is None or r is None:
ret = 'pass'
else:
index = end + r.end()
# get result type, which can contain newlines
pattern = re.compile(r'(,\n|[^\n-])+')
ret_str = pattern.match(doc, index).group(0).strip()
# New object -> object()
ret_str = re.sub(r'[nN]ew (.*)', r'\1()', ret_str)
ret = Parser.map_types.get(ret_str, ret_str)
if ret == ret_str and ret not in ['None', 'object', 'tuple', 'set']:
debug.dbg('not working', ret_str)
if ret != 'pass':
ret = ('return ' if 'return' not in ret else '') + ret
return param_str, ret
class Builtin(object):
""" The builtin scope / module """
# Python 3 compatibility
if is_py3k:
name = 'builtins'
else:
name = '__builtin__'
_builtin = None
@property
def builtin(self):
if self._builtin is None:
self._builtin = Parser(name=self.name)
return self._builtin
@property
def scope(self):
return self.builtin.parser.module
@property
def magic_function_scope(self):
try:
return self._magic_function_scope
except AttributeError:
# depth = 1 because this is not a module
class Container(object):
FunctionType = types.FunctionType
source = _generate_code(Container, depth=0)
parser = parsing.PyFuzzyParser(source, None)
module = parser.module
module.parent = self.scope
typ = evaluate.follow_path(iter(['FunctionType']), module, module)
s = self._magic_function_scope = typ.pop()
return s
Builtin = Builtin()

View file

@ -1,64 +0,0 @@
import inspect
import time
try:
# Use colorama for nicer console output.
from colorama import Fore, init
init()
except ImportError:
class Fore(object):
RED = ''
GREEN = ''
YELLOW = ''
RESET = ''
NOTICE = object()
WARNING = object()
SPEED = object()
enable_speed = False
enable_warning = False
enable_notice = False
# callback, interface: level, str
debug_function = None
ignored_modules = ['parsing', 'builtin', 'jedi.builtin', 'jedi.parsing']
def reset_time():
global start_time
start_time = time.time()
def dbg(*args):
""" Looks at the stack, to see if a debug message should be printed. """
if debug_function and enable_notice:
frm = inspect.stack()[1]
mod = inspect.getmodule(frm[0])
if not (mod.__name__ in ignored_modules):
debug_function(NOTICE, 'dbg: ' + ', '.join(str(a) for a in args))
def warning(*args):
if debug_function and enable_warning:
debug_function(WARNING, 'warning: ' + ', '.join(str(a) for a in args))
def speed(name):
if debug_function and enable_speed:
now = time.time()
debug_function(SPEED, 'speed: ' + '%s %s' % (name, now - start_time))
def print_to_stdout(level, str_out):
""" The default debug function """
if level == NOTICE:
col = Fore.GREEN
elif level == WARNING:
col = Fore.RED
else:
col = Fore.YELLOW
print(col + str_out + Fore.RESET)
#debug_function = print_to_stdout

View file

@ -1,34 +0,0 @@
""" Processing of docstrings, which means parsing for types. """
import re
import evaluate
#@evaluate.memoize_default() # TODO add
def follow_param(param):
func = param.parent_function
#print func, param, param.parent_function
param_str = search_param_in_docstr(func.docstr, str(param.get_name()))
if param_str is not None:
scope = func.get_parent_until()
return evaluate.get_scopes_for_name(scope, param_str,
search_global=True)
return []
def search_param_in_docstr(docstr, param_str):
lines = docstr.split('\n')
# look at #40 to see definitions of those params
sphinx_comp = ':type %s:' % param_str
googley_comp = re.compile('\s*%s\s+\(([^()]+)\)' % re.escape(param_str))
for l in lines:
if l.startswith(sphinx_comp):
return l.replace(sphinx_comp, '', 1).strip()
r = re.match(googley_comp, l)
if r is not None:
return r.group(1)
return None

View file

@ -1,507 +0,0 @@
"""
For dynamic completion.
Sorry to everyone who is reading this code. Especially the array parts are
really cryptic and not understandable. It's just a hack, that turned out to be
working quite good.
"""
from __future__ import with_statement
import os
import parsing
import modules
import evaluate
import helpers
import settings
import debug
import builtin
import imports
import api_classes
# This is something like the sys.path, but only for searching params. It means
# that this is the order in which Jedi searches params.
search_param_modules = ['.']
search_param_cache = {}
def get_directory_modules_for_name(mods, name):
"""
Search a name in the directories of modules.
"""
def check_python_file(path):
try:
return builtin.CachedModule.cache[path][1].module
except KeyError:
try:
return check_fs(path)
except IOError:
return None
def check_fs(path):
with open(path) as f:
source = f.read()
if name in source:
return modules.Module(path, source).parser.module
# skip non python modules
mods = set(m for m in mods if m.path.endswith('.py'))
mod_paths = set()
for m in mods:
mod_paths.add(m.path)
yield m
if settings.dynamic_params_for_other_modules:
paths = set(settings.additional_dynamic_modules)
for p in mod_paths:
d = os.path.dirname(p)
for entry in os.listdir(d):
if entry not in mod_paths:
if entry.endswith('.py'):
paths.add(d + os.path.sep + entry)
for p in paths:
c = check_python_file(p)
if c is not None and c not in mods:
yield c
def search_param_memoize(func):
"""
Is only good for search params memoize, respectively the closure,
because it just caches the input, not the func, like normal memoize does.
"""
def wrapper(*args, **kwargs):
key = (args, frozenset(kwargs.items()))
if key in search_param_cache:
return search_param_cache[key]
else:
rv = func(*args, **kwargs)
search_param_cache[key] = rv
return rv
return wrapper
class ParamListener(object):
"""
This listener is used to get the params for a function.
"""
def __init__(self):
self.param_possibilities = []
def execute(self, params):
self.param_possibilities.append(params)
@evaluate.memoize_default([])
def search_params(param):
"""
This is a dynamic search for params. If you try to complete a type:
>>> def func(foo):
>>> # here is the completion
>>> foo
>>> func(1)
>>> func("")
It is not known what the type is, because it cannot be guessed with
recursive madness. Therefore one has to analyse the statements that are
calling the function, as well as analyzing the incoming params.
"""
if not settings.dynamic_params:
return []
def get_params_for_module(module):
"""
Returns the values of a param, or an empty array.
"""
@search_param_memoize
def get_posibilities(module, func_name):
try:
possible_stmts = module.used_names[func_name]
except KeyError:
return []
for stmt in possible_stmts:
if not isinstance(stmt, parsing.Import):
calls = _scan_array(stmt.get_assignment_calls(), func_name)
for c in calls:
# no execution means that params cannot be set
call_path = c.generate_call_path()
pos = c.start_pos
scope = stmt.parent
evaluate.follow_call_path(call_path, scope, pos)
return listener.param_possibilities
result = []
for params in get_posibilities(module, func_name):
for p in params:
if str(p) == param_name:
result += evaluate.follow_statement(p.parent)
return result
func = param.get_parent_until(parsing.Function)
current_module = param.get_parent_until()
func_name = str(func.name)
if func_name == '__init__' and isinstance(func.parent, parsing.Class):
func_name = str(func.parent.name)
# get the param name
if param.assignment_details:
arr = param.assignment_details[0][1]
else:
arr = param.get_assignment_calls()
offset = 1 if arr[0][0] in ['*', '**'] else 0
param_name = str(arr[0][offset].name)
# add the listener
listener = ParamListener()
func.listeners.add(listener)
result = []
# This is like backtracking: Get the first possible result.
for mod in get_directory_modules_for_name([current_module], func_name):
result = get_params_for_module(mod)
if result:
break
# cleanup: remove the listener; important: should not stick.
func.listeners.remove(listener)
return result
def check_array_additions(array):
""" Just a mapper function for the internal _check_array_additions """
if array._array.type not in ['list', 'set']:
# TODO also check for dict updates
return []
is_list = array._array.type == 'list'
current_module = array._array.parent_stmt.get_parent_until()
res = _check_array_additions(array, current_module, is_list)
return res
def _scan_array(arr, search_name):
""" Returns the function Call that match search_name in an Array. """
result = []
for sub in arr:
for s in sub:
if isinstance(s, parsing.Array):
result += _scan_array(s, search_name)
elif isinstance(s, parsing.Call):
s_new = s
while s_new is not None:
n = s_new.name
if isinstance(n, parsing.Name) and search_name in n.names:
result.append(s)
if s_new.execution is not None:
result += _scan_array(s_new.execution, search_name)
s_new = s_new.next
return result
counter = 0
def dec(func):
""" TODO delete this """
def wrapper(*args, **kwargs):
global counter
element = args[0]
if isinstance(element, evaluate.Array):
stmt = element._array.parent_stmt
else:
# must be instance
stmt = element.var_args.parent_stmt
print(' ' * counter + 'recursion,', stmt)
counter += 1
res = func(*args, **kwargs)
counter -= 1
#print ' '*counter + 'end,'
return res
return wrapper
#@dec
@evaluate.memoize_default([])
def _check_array_additions(compare_array, module, is_list):
"""
Checks if a `parsing.Array` has "add" statements:
>>> a = [""]
>>> a.append(1)
"""
if not settings.dynamic_array_additions or module.is_builtin():
return []
def check_calls(calls, add_name):
"""
Calls are processed here. The part before the call is searched and
compared with the original Array.
"""
result = []
for c in calls:
call_path = list(c.generate_call_path())
separate_index = call_path.index(add_name)
if add_name == call_path[-1] or separate_index == 0:
# this means that there is no execution -> [].append
# or the keyword is at the start -> append()
continue
backtrack_path = iter(call_path[:separate_index])
position = c.start_pos
scope = c.parent_stmt.parent
found = evaluate.follow_call_path(backtrack_path, scope, position)
if not compare_array in found:
continue
params = call_path[separate_index + 1]
if not params.values:
continue # no params: just ignore it
if add_name in ['append', 'add']:
result += evaluate.follow_call_list(params)
elif add_name in ['insert']:
try:
second_param = params[1]
except IndexError:
continue
else:
result += evaluate.follow_call_list([second_param])
elif add_name in ['extend', 'update']:
iterators = evaluate.follow_call_list(params)
result += evaluate.get_iterator_types(iterators)
return result
def get_execution_parent(element, *stop_classes):
""" Used to get an Instance/Execution parent """
if isinstance(element, evaluate.Array):
stmt = element._array.parent_stmt
else:
# must be instance
stmt = element.var_args.parent_stmt
if isinstance(stmt, evaluate.InstanceElement):
stop_classes = list(stop_classes) + [evaluate.Function]
return stmt.get_parent_until(stop_classes)
temp_param_add = settings.dynamic_params_for_other_modules
settings.dynamic_params_for_other_modules = False
search_names = ['append', 'extend', 'insert'] if is_list else \
['add', 'update']
comp_arr_parent = get_execution_parent(compare_array, evaluate.Execution)
possible_stmts = []
res = []
for n in search_names:
try:
possible_stmts += module.used_names[n]
except KeyError:
continue
for stmt in possible_stmts:
# Check if the original scope is an execution. If it is, one
# can search for the same statement, that is in the module
# dict. Executions are somewhat special in jedi, since they
# literally copy the contents of a function.
if isinstance(comp_arr_parent, evaluate.Execution):
stmt = comp_arr_parent. \
get_statement_for_position(stmt.start_pos)
if stmt is None:
continue
# InstanceElements are special, because they don't get copied,
# but have this wrapper around them.
if isinstance(comp_arr_parent, evaluate.InstanceElement):
stmt = evaluate.InstanceElement(comp_arr_parent.instance, stmt)
if evaluate.follow_statement.push_stmt(stmt):
# check recursion
continue
res += check_calls(_scan_array(stmt.get_assignment_calls(), n), n)
evaluate.follow_statement.pop_stmt()
# reset settings
settings.dynamic_params_for_other_modules = temp_param_add
return res
def check_array_instances(instance):
""" Used for set() and list() instances. """
if not settings.dynamic_arrays_instances:
return instance.var_args
ai = ArrayInstance(instance)
return helpers.generate_param_array([ai], instance.var_args.parent_stmt)
class ArrayInstance(parsing.Base):
"""
Used for the usage of set() and list().
This is definitely a hack, but a good one :-)
It makes it possible to use set/list conversions.
"""
def __init__(self, instance):
self.instance = instance
self.var_args = instance.var_args
def iter_content(self):
"""
The index is here just ignored, because of all the appends, etc.
lists/sets are too complicated too handle that.
"""
items = []
for array in evaluate.follow_call_list(self.var_args):
if isinstance(array, evaluate.Instance) and len(array.var_args):
temp = array.var_args[0][0]
if isinstance(temp, ArrayInstance):
# prevent recursions
# TODO compare Modules
if self.var_args.start_pos != temp.var_args.start_pos:
items += temp.iter_content()
else:
debug.warning('ArrayInstance recursion', self.var_args)
continue
items += evaluate.get_iterator_types([array])
if self.var_args.parent_stmt is None:
return [] # generated var_args should not be checked for arrays
module = self.var_args.parent_stmt.get_parent_until()
is_list = str(self.instance.name) == 'list'
items += _check_array_additions(self.instance, module, is_list)
return items
def related_names(definitions, search_name, mods):
def check_call(call):
result = []
follow = [] # There might be multiple search_name's in one call_path
call_path = list(call.generate_call_path())
for i, name in enumerate(call_path):
# name is `parsing.NamePart`.
if name == search_name:
follow.append(call_path[:i + 1])
for f in follow:
follow_res, search = evaluate.goto(call.parent_stmt, f)
follow_res = related_name_add_import_modules(follow_res, search)
#print follow_res, [d.parent for d in follow_res]
# compare to see if they match
if any(r in definitions for r in follow_res):
scope = call.parent_stmt
result.append(api_classes.RelatedName(search, scope))
return result
if not definitions:
return set()
def is_definition(arr):
try:
for a in arr:
assert len(a) == 1
a = a[0]
if a.isinstance(parsing.Array):
assert is_definition(a)
elif a.isinstance(parsing.Call):
assert a.execution is None
return True
except AssertionError:
return False
mods |= set([d.get_parent_until() for d in definitions])
names = []
for m in get_directory_modules_for_name(mods, search_name):
try:
stmts = m.used_names[search_name]
except KeyError:
continue
for stmt in stmts:
if isinstance(stmt, parsing.Import):
count = 0
imps = []
for i in stmt.get_all_import_names():
for name_part in i.names:
count += 1
if name_part == search_name:
imps.append((count, name_part))
for used_count, name_part in imps:
i = imports.ImportPath(stmt, kill_count=count - used_count,
direct_resolve=True)
f = i.follow(is_goto=True)
if set(f) & set(definitions):
names.append(api_classes.RelatedName(name_part, stmt))
else:
calls = _scan_array(stmt.get_assignment_calls(), search_name)
for d in stmt.assignment_details:
if not is_definition(d[1]):
calls += _scan_array(d[1], search_name)
for call in calls:
names += check_call(call)
return names
def related_name_add_import_modules(definitions, search_name):
""" Adds the modules of the imports """
new = set()
for d in definitions:
if isinstance(d.parent, parsing.Import):
s = imports.ImportPath(d.parent, direct_resolve=True)
try:
new.add(s.follow(is_goto=True)[0])
except IndexError:
pass
return set(definitions) | new
def check_flow_information(flow, search_name, pos):
""" Try to find out the type of a variable just with the information that
is given by the flows: e.g. It is also responsible for assert checks.
>>> if isinstance(k, str):
>>> k. # <- completion here
ensures that `k` is a string.
"""
result = []
if isinstance(flow, parsing.Scope) and not result:
for ass in reversed(flow.asserts):
if pos is None or ass.start_pos > pos:
continue
result = check_statement_information(ass, search_name)
if result:
break
if isinstance(flow, parsing.Flow) and not result:
if flow.command in ['if', 'while'] and len(flow.inits) == 1:
result = check_statement_information(flow.inits[0], search_name)
return result
def check_statement_information(stmt, search_name):
try:
ass = stmt.get_assignment_calls()
try:
call = ass.get_only_subelement()
except AttributeError:
assert False
assert type(call) == parsing.Call and str(call.name) == 'isinstance'
assert bool(call.execution)
# isinstance check
isinst = call.execution.values
assert len(isinst) == 2 # has two params
assert len(isinst[0]) == 1
assert len(isinst[1]) == 1
assert isinstance(isinst[0][0], parsing.Call)
# names fit?
assert str(isinst[0][0].name) == search_name
classes_call = isinst[1][0] # class_or_type_or_tuple
assert isinstance(classes_call, parsing.Call)
result = []
for c in evaluate.follow_call(classes_call):
if isinstance(c, evaluate.Array):
result += c.get_index_types()
else:
result.append(c)
for i, c in enumerate(result):
result[i] = evaluate.Instance(c)
return result
except AssertionError:
return []

File diff suppressed because it is too large Load diff

View file

@ -1,266 +0,0 @@
import copy
import contextlib
import parsing
import evaluate
import debug
import builtin
import settings
class RecursionDecorator(object):
"""
A decorator to detect recursions in statements. In a recursion a statement
at the same place, in the same module may not be executed two times.
"""
def __init__(self, func):
self.func = func
self.reset()
def __call__(self, stmt, *args, **kwargs):
#print stmt, len(self.node_statements())
if self.push_stmt(stmt):
return []
else:
result = self.func(stmt, *args, **kwargs)
self.pop_stmt()
return result
def push_stmt(self, stmt):
self.current = RecursionNode(stmt, self.current)
if self._check_recursion():
debug.warning('catched recursion', stmt)
self.pop_stmt()
return True
return False
def pop_stmt(self):
if self.current is not None:
# I don't know how current can be None, but sometimes it happens
# with Python3.
self.current = self.current.parent
def _check_recursion(self):
test = self.current
while True:
test = test.parent
if self.current == test:
return True
if not test:
return False
def reset(self):
self.top = None
self.current = None
def node_statements(self):
result = []
n = self.current
while n:
result.insert(0, n.stmt)
n = n.parent
return result
class RecursionNode(object):
""" A node of the RecursionDecorator. """
def __init__(self, stmt, parent):
self.script = stmt.get_parent_until()
self.position = stmt.start_pos
self.parent = parent
self.stmt = stmt
# Don't check param instances, they are not causing recursions
# The same's true for the builtins, because the builtins are really
# simple.
self.is_ignored = isinstance(stmt, parsing.Param) \
or (self.script == builtin.Builtin.scope)
def __eq__(self, other):
if not other:
return None
return self.script == other.script \
and self.position == other.position \
and not self.is_ignored and not other.is_ignored
class ExecutionRecursionDecorator(object):
"""
Catches recursions of executions.
It is designed like a Singelton. Only one instance should exist.
"""
def __init__(self, func):
self.func = func
self.reset()
def __call__(self, execution, evaluate_generator=False):
debug.dbg('Execution recursions: %s' % execution, self.recursion_level,
self.execution_count, len(self.execution_funcs))
if self.check_recursion(execution, evaluate_generator):
result = []
else:
result = self.func(execution, evaluate_generator)
self.cleanup()
return result
@classmethod
def cleanup(cls):
cls.parent_execution_funcs.pop()
cls.recursion_level -= 1
@classmethod
def check_recursion(cls, execution, evaluate_generator):
in_par_execution_funcs = execution.base in cls.parent_execution_funcs
in_execution_funcs = execution.base in cls.execution_funcs
cls.recursion_level += 1
cls.execution_count += 1
cls.execution_funcs.add(execution.base)
cls.parent_execution_funcs.append(execution.base)
if cls.execution_count > settings.max_executions:
return True
if isinstance(execution.base, (evaluate.Generator, evaluate.Array)):
return False
module = execution.get_parent_until()
if evaluate_generator or module == builtin.Builtin.scope:
return False
if in_par_execution_funcs:
if cls.recursion_level > settings.max_function_recursion_level:
return True
if in_execution_funcs and \
len(cls.execution_funcs) > settings.max_until_execution_unique:
return True
if cls.execution_count > settings.max_executions_without_builtins:
return True
return False
@classmethod
def reset(cls):
cls.recursion_level = 0
cls.parent_execution_funcs = []
cls.execution_funcs = set()
cls.execution_count = 0
def fast_parent_copy(obj):
"""
Much, much faster than copy.deepcopy, but just for certain elements.
"""
new_elements = {}
def recursion(obj):
new_obj = copy.copy(obj)
new_elements[obj] = new_obj
items = new_obj.__dict__.items()
for key, value in items:
# replace parent (first try _parent and then parent)
if key in ['parent', '_parent', '_parent_stmt'] \
and value is not None:
if key == 'parent' and '_parent' in items:
# parent can be a property
continue
try:
setattr(new_obj, key, new_elements[value])
except KeyError:
pass
elif key in ['parent_stmt', 'parent_function']:
continue
elif isinstance(value, list):
setattr(new_obj, key, list_rec(value))
elif isinstance(value, (parsing.Simple, parsing.Call)):
setattr(new_obj, key, recursion(value))
return new_obj
def list_rec(list_obj):
copied_list = list_obj[:] # lists, tuples, strings, unicode
for i, el in enumerate(copied_list):
if isinstance(el, (parsing.Simple, parsing.Call)):
copied_list[i] = recursion(el)
elif isinstance(el, list):
copied_list[i] = list_rec(el)
return copied_list
return recursion(obj)
def generate_param_array(args_tuple, parent_stmt=None):
""" This generates an array, that can be used as a param. """
values = []
for arg in args_tuple:
if arg is None:
values.append([])
else:
values.append([arg])
pos = None
arr = parsing.Array(pos, parsing.Array.TUPLE, parent_stmt, values=values)
evaluate.faked_scopes.append(arr)
return arr
def scan_array_for_pos(arr, pos):
"""
Returns the function Call that match search_name in an Array.
Makes changes to arr!
"""
def check_arr_index():
positions = arr.arr_el_pos
for index, comma_pos in enumerate(positions):
if pos < comma_pos:
return index
return len(positions)
call = None
stop = False
for sub in arr.values:
call = None
for s in sub:
if isinstance(s, parsing.Array):
new = scan_array_for_pos(s, pos)
if new[0] is not None:
call, index, stop = new
if stop:
return call, index, stop
elif isinstance(s, parsing.Call):
start_s = s
# check parts of calls
while s is not None:
if s.start_pos >= pos:
return call, check_arr_index(), stop
elif s.execution is not None:
end = s.execution.end_pos
if s.execution.start_pos < pos and \
(end is None or pos < end):
c, index, stop = scan_array_for_pos(
s.execution, pos)
if stop:
return c, index, stop
# call should return without execution and
# next
reset = c or s
if reset.execution.type not in \
[parsing.Array.TUPLE,
parsing.Array.NOARRAY]:
return start_s, index, False
reset.execution = None
reset.next = None
return c or start_s, index, True
s = s.next
# The third return is just necessary for recursion inside, because
# it needs to know when to stop iterating.
return call, check_arr_index(), stop
@contextlib.contextmanager
def scale_speed_settings(factor):
a = settings.max_executions
b = settings.max_until_execution_unique
settings.max_executions *= factor
settings.max_until_execution_unique *= factor
yield
settings.max_executions = a
settings.max_until_execution_unique = b

View file

@ -1,332 +0,0 @@
from __future__ import with_statement
import os
import pkgutil
import imp
import sys
import time
import builtin
import modules
import debug
import parsing
import evaluate
import itertools
import settings
# for debugging purposes only
imports_processed = 0
star_import_cache = {}
class ModuleNotFound(Exception):
pass
class ImportPath(parsing.Base):
"""
An ImportPath is the path of a `parsing.Import` object.
"""
class _GlobalNamespace(object):
def get_defined_names(self):
return []
def get_imports(self):
return []
@property
def start_pos(self):
return (0, 0)
def get_parent_until(self):
return None
GlobalNamespace = _GlobalNamespace()
def __init__(self, import_stmt, is_like_search=False, kill_count=0,
direct_resolve=False):
self.import_stmt = import_stmt
self.is_like_search = is_like_search
self.direct_resolve = direct_resolve
self.is_partial_import = bool(kill_count)
path = import_stmt.get_parent_until().path
self.file_path = os.path.dirname(path) if path is not None else None
# rest is import_path resolution
self.import_path = []
if import_stmt.from_ns:
self.import_path += import_stmt.from_ns.names
if import_stmt.namespace:
if self.is_nested_import() and not direct_resolve:
self.import_path.append(import_stmt.namespace.names[0])
else:
self.import_path += import_stmt.namespace.names
for i in range(kill_count + int(is_like_search)):
self.import_path.pop()
def __repr__(self):
return '<%s: %s>' % (type(self).__name__, self.import_stmt)
def is_nested_import(self):
"""
This checks for the special case of nested imports, without aliases and
from statement:
>>> import foo.bar
"""
return not self.import_stmt.alias and not self.import_stmt.from_ns \
and len(self.import_stmt.namespace.names) > 1 \
and not self.direct_resolve
def get_nested_import(self, parent):
"""
See documentation of `self.is_nested_import`.
Generates an Import statement, that can be used to fake nested imports.
"""
i = self.import_stmt
# This is not an existing Import statement. Therefore, set position to
# 0 (0 is not a valid line number).
zero = (0, 0)
n = parsing.Name(i.namespace.names[1:], zero, zero, self.import_stmt)
new = parsing.Import(zero, zero, n)
new.parent = parent
evaluate.faked_scopes.append(new)
debug.dbg('Generated a nested import: %s' % new)
return new
def get_defined_names(self, on_import_stmt=False):
names = []
for scope in self.follow():
if scope is ImportPath.GlobalNamespace:
if self.import_stmt.relative_count == 0:
names += self.get_module_names()
if self.file_path is not None:
path = os.path.abspath(self.file_path)
for i in range(self.import_stmt.relative_count - 1):
path = os.path.dirname(path)
names += self.get_module_names([path])
else:
if on_import_stmt and isinstance(scope, parsing.Module) \
and scope.path.endswith('__init__.py'):
pkg_path = os.path.dirname(scope.path)
names += self.get_module_names([pkg_path])
for s, scope_names in evaluate.get_names_for_scope(scope,
include_builtin=False):
for n in scope_names:
if self.import_stmt.from_ns is None \
or self.is_partial_import:
# from_ns must be defined to access module
# values plus a partial import means that there
# is something after the import, which
# automatically implies that there must not be
# any non-module scope.
continue
names.append(n)
return names
def get_module_names(self, search_path=None):
"""
Get the names of all modules in the search_path. This means file names
and not names defined in the files.
"""
if not search_path:
search_path = self.sys_path_with_modifications()
names = []
for module_loader, name, is_pkg in pkgutil.iter_modules(search_path):
inf_pos = (float('inf'), float('inf'))
names.append(parsing.Name([(name, inf_pos)], inf_pos, inf_pos,
self.import_stmt))
return names
def sys_path_with_modifications(self):
module = self.import_stmt.get_parent_until()
return modules.sys_path_with_modifications(module)
def follow(self, is_goto=False):
"""
Returns the imported modules.
"""
if evaluate.follow_statement.push_stmt(self.import_stmt):
# check recursion
return []
if self.import_path:
try:
scope, rest = self._follow_file_system()
except ModuleNotFound:
debug.warning('Module not found: ' + str(self.import_stmt))
evaluate.follow_statement.pop_stmt()
return []
scopes = [scope]
scopes += itertools.chain.from_iterable(
remove_star_imports(s) for s in scopes)
# follow the rest of the import (not FS -> classes, functions)
if len(rest) > 1 or rest and self.is_like_search:
scopes = []
elif rest:
if is_goto:
scopes = itertools.chain.from_iterable(
evaluate.get_scopes_for_name(s, rest[0], is_goto=True)
for s in scopes)
else:
scopes = itertools.chain.from_iterable(
evaluate.follow_path(iter(rest), s, s)
for s in scopes)
scopes = list(scopes)
if self.is_nested_import():
scopes.append(self.get_nested_import(scope))
else:
scopes = [ImportPath.GlobalNamespace]
debug.dbg('after import', scopes)
evaluate.follow_statement.pop_stmt()
return scopes
def _follow_file_system(self):
"""
Find a module with a path (of the module, like usb.backend.libusb10).
"""
def follow_str(ns, string):
debug.dbg('follow_module', ns, string)
path = None
if ns:
path = ns[1]
elif self.import_stmt.relative_count:
module = self.import_stmt.get_parent_until()
path = os.path.abspath(module.path)
for i in range(self.import_stmt.relative_count):
path = os.path.dirname(path)
global imports_processed
imports_processed += 1
if path is not None:
return imp.find_module(string, [path])
else:
debug.dbg('search_module', string, self.file_path)
# Override the sys.path. It works only good that way.
# Injecting the path directly into `find_module` did not work.
sys.path, temp = sys_path_mod, sys.path
try:
i = imp.find_module(string)
except ImportError:
sys.path = temp
raise
sys.path = temp
return i
if self.file_path:
sys_path_mod = list(self.sys_path_with_modifications())
sys_path_mod.insert(0, self.file_path)
else:
sys_path_mod = list(builtin.get_sys_path())
current_namespace = None
# now execute those paths
rest = []
for i, s in enumerate(self.import_path):
try:
current_namespace = follow_str(current_namespace, s)
except ImportError:
if current_namespace:
rest = self.import_path[i:]
else:
raise ModuleNotFound(
'The module you searched has not been found')
sys_path_mod.pop(0) # TODO why is this here?
path = current_namespace[1]
is_package_directory = current_namespace[2][2] == imp.PKG_DIRECTORY
f = None
if is_package_directory or current_namespace[0]:
# is a directory module
if is_package_directory:
path += '/__init__.py'
with open(path) as f:
source = f.read()
else:
source = current_namespace[0].read()
current_namespace[0].close()
if path.endswith('.py'):
f = modules.Module(path, source)
else:
f = builtin.Parser(path=path)
else:
f = builtin.Parser(name=path)
return f.parser.module, rest
def strip_imports(scopes):
"""
Here we strip the imports - they don't get resolved necessarily.
Really used anymore? Merge with remove_star_imports?
"""
result = []
for s in scopes:
if isinstance(s, parsing.Import):
result += ImportPath(s).follow()
else:
result.append(s)
return result
def cache_star_import(func):
def wrapper(scope, *args, **kwargs):
try:
mods = star_import_cache[scope]
if mods[0] + settings.star_import_cache_validity > time.time():
return mods[1]
except KeyError:
pass
# cache is too old and therefore invalid or not available
invalidate_star_import_cache(scope)
mods = func(scope, *args, **kwargs)
star_import_cache[scope] = time.time(), mods
return mods
return wrapper
def invalidate_star_import_cache(module, only_main=False):
""" Important if some new modules are being reparsed """
try:
t, mods = star_import_cache[module]
del star_import_cache[module]
for m in mods:
invalidate_star_import_cache(m, only_main=True)
except KeyError:
pass
if not only_main:
# We need a list here because otherwise the list is being changed
# during the iteration in py3k: iteritems -> items.
for key, (t, mods) in list(star_import_cache.items()):
if module in mods:
invalidate_star_import_cache(key)
@cache_star_import
def remove_star_imports(scope, ignored_modules=[]):
"""
Check a module for star imports:
>>> from module import *
and follow these modules.
"""
modules = strip_imports(i for i in scope.get_imports() if i.star)
new = []
for m in modules:
if m not in ignored_modules:
new += remove_star_imports(m, modules)
modules += new
# Filter duplicate modules.
return set(modules)

View file

@ -1,86 +0,0 @@
import keyword
from _compatibility import is_py3k
import builtin
import pydoc
try:
from pydoc_data import topics as pydoc_topics
except ImportError:
# Python 2.6
try:
import pydoc_topics
except ImportError:
# Python 2.5
pydoc_topics = None
if is_py3k:
keys = keyword.kwlist
else:
keys = keyword.kwlist + ['None', 'False', 'True']
def get_keywords(string='', pos=(0, 0), all=False):
if all:
return set([Keyword(k, pos) for k in keys])
if string in keys:
return set([Keyword(string, pos)])
return set()
def get_operator(string, pos):
return Keyword(string, pos)
class Keyword(object):
def __init__(self, name, pos):
self.name = name
self.start_pos = pos
self.parent = builtin.Builtin.scope
def get_parent_until(self):
return self.parent
@property
def names(self):
""" For a `parsing.Name` like comparision """
return [self.name]
@property
def docstr(self):
return imitate_pydoc(self.name)
def __repr__(self):
return '<%s: %s>' % (type(self).__name__, self.name)
def imitate_pydoc(string):
"""
It's not possible to get the pydoc's without starting the annoying pager
stuff.
"""
# str needed because of possible unicode stuff in py2k (pydoc doesn't work
# with unicode strings)
string = str(string)
h = pydoc.help
try:
# try to access symbols
string = h.symbols[string]
string, _, related = string.partition(' ')
except KeyError:
pass
get_target = lambda s: h.topics.get(s, h.keywords.get(s))
while isinstance(string, str):
string = get_target(string)
try:
# is a tuple now
label, related = string
except TypeError:
return ''
try:
return pydoc_topics.topics[label] if pydoc_topics else ''
except KeyError:
return ''

View file

@ -1,9 +0,0 @@
class partial():
def __init__(self, func, *args, **keywords):
self.__func = func
self.__args = args
self.__keywords = keywords
def __call__(self, *args, **kwargs):
# I know this doesn't work in Python, but Jedi can this ;-)
return self.__func(*self.__args, *args, **self.keywords, **kwargs)

View file

@ -1,99 +0,0 @@
def compile():
class SRE_Match():
endpos = 1
lastgroup = 0
lastindex = 1
pos = 0
string = 'a'
regs = ((0, 1),)
def __init__(self, pattern):
self.re = pattern
def start(self):
return 0
def end(self):
return 1
def span(self):
return 0, 1
def expand(self):
return ''
def group(self):
return ''
def groupdict(self):
return {'a', 'a'}
def groups(self):
return ('a',)
class SRE_Pattern():
flags = 0
groupindex = {}
groups = 0
pattern = 'a'
def findall(self):
"""
findall(string[, pos[, endpos]]) --> list.
Return a list of all non-overlapping matches of pattern in string.
"""
return ['a']
def finditer(self):
"""
finditer(string[, pos[, endpos]]) --> iterator.
Return an iterator over all non-overlapping matches for the
RE pattern in string. For each match, the iterator returns a
match object.
"""
yield SRE_Match(self)
def match(self):
"""
match(string[, pos[, endpos]]) --> match object or None.
Matches zero or more characters at the beginning of the string
pattern
"""
return SRE_Match(self)
def scanner(self):
pass
def search(self):
"""
search(string[, pos[, endpos]]) --> match object or None.
Scan through string looking for a match, and return a corresponding
MatchObject instance. Return None if no position in the string matches.
"""
return SRE_Match(self)
def split(self):
"""
split(string[, maxsplit = 0]) --> list.
Split string by the occurrences of pattern.
"""
return ['a']
def sub(self):
"""
sub(repl, string[, count = 0]) --> newstring
Return the string obtained by replacing the leftmost non-overlapping
occurrences of pattern in string by the replacement repl.
"""
return ''
def subn(self):
"""
subn(repl, string[, count = 0]) --> (newstring, number of subs)
Return the tuple (new_string, number_of_subs_made) found by replacing
the leftmost non-overlapping occurrences of pattern with the
replacement repl.
"""
return ('', 1)
return SRE_Pattern()

View file

@ -1,8 +0,0 @@
def proxy(object, callback=None):
return object
class ref():
def __init__(self, object, callback=None):
self.__object = object
def __call__(self):
return self.__object

View file

@ -1,218 +0,0 @@
"""
Pure Python implementation of some builtins.
This code is not going to be executed anywhere.
These implementations are not always correct, but should work as good as
possible for the auto completion.
"""
def next(iterator, default=None):
if hasattr("next"):
return iterator.next()
else:
return iterator.__next__()
return default
def iter(collection, sentinel=None):
if sentinel:
yield collection()
else:
for c in collection:
yield c
def range(start, stop=None, step=1):
return [0]
class xrange():
# Attention: this function doesn't exist in Py3k (there it is range).
def __iter__(self):
yield 1
def count(self):
return 1
def index(self):
return 1
#--------------------------------------------------------
# descriptors
#--------------------------------------------------------
class property():
def __init__(self, fget, fset=None, fdel=None, doc=None):
self.fget = fget
self.fset = fset
self.fdel = fdel
self.__doc__ = doc
def __get__(self, obj, cls):
return self.fget(obj)
def __set__(self, obj, value):
self.fset(obj, value)
def __delete__(self, obj):
self.fdel(obj)
def setter(self, func):
self.fset = func
return self
def getter(self, func):
self.fget = func
return self
def deleter(self, func):
self.fdel = func
return self
class staticmethod():
def __init__(self, func):
self.__func = func
def __get__(self, obj, cls):
return self.__func
class classmethod():
def __init__(self, func):
self.__func = func
def __get__(self, obj, cls):
def _method(*args, **kwargs):
return self.__func(cls, *args, **kwargs)
return _method
#--------------------------------------------------------
# array stuff
#--------------------------------------------------------
class list():
def __init__(self, iterable=[]):
self.__iterable = []
for i in iterable:
self.__iterable += [i]
def __iter__(self):
for i in self.__iterable:
yield i
def __getitem__(self, y):
return self.__iterable[y]
def pop(self):
return self.__iterable[-1]
class tuple():
def __init__(self, iterable=[]):
self.__iterable = []
for i in iterable:
self.__iterable += [i]
def __iter__(self):
for i in self.__iterable:
yield i
def __getitem__(self, y):
return self.__iterable[y]
def index(self):
return 1
def count(self):
return 1
class set():
def __init__(self, iterable=[]):
self.__iterable = iterable
def __iter__(self):
for i in self.__iterable:
yield i
def pop(self):
return self.__iterable.pop()
def copy(self):
return self
def difference(self, other):
return self - other
def intersection(self, other):
return self & other
def symmetric_difference(self, other):
return self ^ other
def union(self, other):
return self | other
class frozenset():
def __init__(self, iterable=[]):
self.__iterable = iterable
def __iter__(self):
for i in self.__iterable:
yield i
def copy(self):
return self
class dict():
def __init__(self, **elements):
self.__elements = elements
def clear(self):
# has a strange docstr
pass
def get(self, k, d=None):
# TODO implement
try:
#return self.__elements[k]
pass
except KeyError:
return d
class reversed():
def __init__(self, sequence):
self.__sequence = sequence
def __iter__(self):
for i in self.__sequence:
yield i
def __next__(self):
return next(self.__iter__())
def next(self):
return self.__next__()
#--------------------------------------------------------
# basic types
#--------------------------------------------------------
class int():
def __init__(self, x, base=None):
pass
class str():
def __init__(self, obj):
pass
class object():
def mro():
""" mro() -> list
return a type's method resolution order """
return [object]

View file

@ -1,4 +0,0 @@
class datetime():
@staticmethod
def now():
return datetime()

View file

@ -1,5 +0,0 @@
def getcwd():
return ''
def getcwdu():
return ''

View file

@ -1,312 +0,0 @@
from __future__ import with_statement
from _compatibility import exec_function
import re
import tokenize
import sys
import os
import time
import parsing
import builtin
import debug
import evaluate
import settings
import imports
class Module(builtin.CachedModule):
"""
Manages all files, that are parsed and caches them.
:param path: The module path of the file.
:param source: The source code of the file.
"""
def __init__(self, path, source):
super(Module, self).__init__(path=path)
self.source = source
self._line_cache = None
def _get_source(self):
""" Just one time """
s = self.source
del self.source # memory efficiency
return s
class ModuleWithCursor(Module):
"""
Manages all files, that are parsed and caches them.
Important are the params source and path, one of them has to
be there.
:param source: The source code of the file.
:param path: The module path of the file or None.
:param position: The position, the user is currently in. Only important \
for the main file.
"""
def __init__(self, path, source, position):
super(ModuleWithCursor, self).__init__(path, source)
self.position = position
# this two are only used, because there is no nonlocal in Python 2
self._line_temp = None
self._relevant_temp = None
self.source = source
self._part_parser = None
@property
def parser(self):
""" get the parser lazy """
if not self._parser:
try:
ts, parser = builtin.CachedModule.cache[self.path]
imports.invalidate_star_import_cache(parser.module)
del builtin.CachedModule.cache[self.path]
except KeyError:
pass
# Call the parser already here, because it will be used anyways.
# Also, the position is here important (which will not be used by
# default), therefore fill the cache here.
self._parser = parsing.PyFuzzyParser(self.source, self.path,
self.position)
if self.path is not None:
builtin.CachedModule.cache[self.path] = time.time(), \
self._parser
return self._parser
def get_path_until_cursor(self):
""" Get the path under the cursor. """
result = self._get_path_until_cursor()
self._start_cursor_pos = self._line_temp + 1, self._column_temp
return result
def _get_path_until_cursor(self, start_pos=None):
def fetch_line():
line = self.get_line(self._line_temp)
if self._is_first:
self._is_first = False
self._line_length = self._column_temp
line = line[:self._column_temp]
else:
self._line_length = len(line)
line = line + '\n'
# add lines with a backslash at the end
while 1:
self._line_temp -= 1
last_line = self.get_line(self._line_temp)
if last_line and last_line[-1] == '\\':
line = last_line[:-1] + ' ' + line
else:
break
return line[::-1]
self._is_first = True
if start_pos is None:
self._line_temp = self.position[0]
self._column_temp = self.position[1]
else:
self._line_temp, self._column_temp = start_pos
open_brackets = ['(', '[', '{']
close_brackets = [')', ']', '}']
gen = tokenize.generate_tokens(fetch_line)
string = ''
level = 0
force_point = False
try:
for token_type, tok, start, end, line in gen:
#print 'tok', token_type, tok, force_point
if level > 0:
if tok in close_brackets:
level += 1
if tok in open_brackets:
level -= 1
elif tok == '.':
force_point = False
elif force_point:
# it is reversed, therefore a number is getting recognized
# as a floating point number
if token_type == tokenize.NUMBER and tok[0] == '.':
force_point = False
else:
break
elif tok in close_brackets:
level += 1
elif token_type in [tokenize.NAME, tokenize.STRING]:
force_point = True
elif token_type == tokenize.NUMBER:
pass
else:
break
self._column_temp = self._line_length - end[1]
string += tok
except tokenize.TokenError:
debug.warning("Tokenize couldn't finish", sys.exc_info)
return string[::-1]
def get_path_under_cursor(self):
"""
Return the path under the cursor. If there is a rest of the path left,
it will be added to the stuff before it.
"""
line = self.get_line(self.position[0])
after = re.search("[\w\d]*", line[self.position[1]:]).group(0)
return self.get_path_until_cursor() + after
def get_operator_under_cursor(self):
line = self.get_line(self.position[0])
after = re.match("[^\w\s]+", line[self.position[1]:])
before = re.match("[^\w\s]+", line[:self.position[1]][::-1])
return (before.group(0) if before is not None else '') \
+ (after.group(0) if after is not None else '')
def get_context(self):
pos = self._start_cursor_pos
while pos > (1, 0):
# remove non important white space
line = self.get_line(pos[0])
while pos[1] > 0 and line[pos[1] - 1].isspace():
pos = pos[0], pos[1] - 1
try:
yield self._get_path_until_cursor(start_pos=pos)
except StopIteration:
yield ''
pos = self._line_temp, self._column_temp
while True:
yield ''
def get_line(self, line_nr):
if not self._line_cache:
self._line_cache = self.source.split('\n')
if line_nr == 0:
# This is a fix for the zeroth line. We need a newline there, for
# the backwards parser.
return ''
if line_nr < 0:
raise StopIteration()
try:
return self._line_cache[line_nr - 1]
except IndexError:
raise StopIteration()
def get_part_parser(self):
""" Returns a parser that contains only part of the source code. This
exists only because of performance reasons.
"""
if self._part_parser:
return self._part_parser
# TODO check for docstrings
length = settings.part_line_length
offset = max(self.position[0] - length, 0)
s = '\n'.join(self.source.split('\n')[offset:offset + length])
self._part_parser = parsing.PyFuzzyParser(s, self.path, self.position,
line_offset=offset)
return self._part_parser
@evaluate.memoize_default([])
def sys_path_with_modifications(module):
def execute_code(code):
c = "import os; from os.path import *; result=%s"
variables = {'__file__': module.path}
try:
exec_function(c % code, variables)
except Exception:
debug.warning('sys path detected, but failed to evaluate')
return None
try:
res = variables['result']
if isinstance(res, str):
return os.path.abspath(res)
else:
return None
except KeyError:
return None
def check_module(module):
try:
possible_stmts = module.used_names['path']
except KeyError:
return builtin.get_sys_path()
sys_path = list(builtin.get_sys_path()) # copy
for p in possible_stmts:
try:
call = p.get_assignment_calls().get_only_subelement()
except AttributeError:
continue
n = call.name
if not isinstance(n, parsing.Name) or len(n.names) != 3:
continue
if n.names[:2] != ('sys', 'path'):
continue
array_cmd = n.names[2]
if call.execution is None:
continue
exe = call.execution
if not (array_cmd == 'insert' and len(exe) == 2
or array_cmd == 'append' and len(exe) == 1):
continue
if array_cmd == 'insert':
exe_type, exe.type = exe.type, parsing.Array.NOARRAY
exe_pop = exe.values.pop(0)
res = execute_code(exe.get_code())
if res is not None:
sys_path.insert(0, res)
debug.dbg('sys path inserted: %s' % res)
exe.type = exe_type
exe.values.insert(0, exe_pop)
elif array_cmd == 'append':
res = execute_code(exe.get_code())
if res is not None:
sys_path.append(res)
debug.dbg('sys path added: %s' % res)
return sys_path
if module.path is None:
return [] # support for modules without a path is intentionally bad.
curdir = os.path.abspath(os.curdir)
try:
os.chdir(os.path.dirname(module.path))
except OSError:
pass
result = check_module(module)
result += detect_django_path(module.path)
# cleanup, back to old directory
os.chdir(curdir)
return result
def detect_django_path(module_path):
""" Detects the path of the very well known Django library (if used) """
result = []
while True:
new = os.path.dirname(module_path)
# If the module_path doesn't change anymore, we're finished -> /
if new == module_path:
break
else:
module_path = new
try:
with open(module_path + os.path.sep + 'manage.py'):
debug.dbg('Found django path: %s' % module_path)
result.append(module_path)
except IOError:
pass
return result

File diff suppressed because it is too large Load diff

View file

@ -1,87 +0,0 @@
# ----------------
# completion output settings
# ----------------
# The completion is by default case insensitive.
case_insensitive_completion = True
# Adds a dot after a module, because a module that is not accessed this way is
# definitely not the normal case. However, in VIM this doesn't work, that's why
# it isn't used at the moment.
add_dot_after_module = False
# Adds an opening bracket after a function, because that's normal behaviour.
# Removed it again, because in VIM that is not very practical.
add_bracket_after_function = False
# ----------------
# dynamic stuff
# ----------------
# check for `append`, etc. on array instances like list()
dynamic_arrays_instances = True
# check for `append`, etc. on arrays: [], {}, ()
dynamic_array_additions = True
# A dynamic param completion, finds the callees of the function, which define
# the params of a function.
dynamic_params = True
# Do the same for other modules.
dynamic_params_for_other_modules = True
# Additional modules in which Jedi checks if statements are to be found. This
# is practical for IDE's, that want to administrate their modules themselves.
additional_dynamic_modules = []
# ----------------
# recursions
# ----------------
# Recursion settings are important if you don't want extremly recursive python
# code to go absolutely crazy. First of there is a global limit
# `max_executions`. This limit is important, to set a maximum amount of time,
# the completion may use.
#
# The `max_until_execution_unique` limit is probably the most important one,
# because if that limit is passed, functions can only be one time executed. So
# new functions will be executed, complex recursions with the same functions
# again and again, are ignored.
#
# `max_function_recursion_level` is more about whether the recursions are
# stopped in deepth or in width. The ratio beetween this and
# `max_until_execution_unique` is important here. It stops a recursion (after
# the number of function calls in the recursion), if it was already used
# earlier.
#
# The values are based on my experimental tries, used on the jedi library. But
# I don't think there's any other Python library, that uses recursion in a
# similar (extreme) way. This makes the completion definitely worse in some
# cases. But a completion should also be fast.
max_function_recursion_level = 5
max_until_execution_unique = 50
max_executions_without_builtins = 200
max_executions = 250
# Because get_in_function_call is normally used on every single key hit, it has
# to be faster than a normal completion. This is the factor that is used to
# scale `max_executions` and `max_until_execution_unique`:
scale_get_in_function_call = 0.1
# ----------------
# various
# ----------------
# Size of the current code part, which is used to speed up parsing.
part_line_length = 20
# ----------------
# star import caching
# ----------------
# In huge packages like numpy, checking all star imports on every completion
# might be slow, therefore we do a star import caching, that lasts a certain
# time span (in seconds).
star_import_cache_validity = 60.0

View file

@ -1,409 +0,0 @@
# vim:fileencoding=utf-8:noet
from __future__ import absolute_import
import os
import sys
import logging
from powerline.colorscheme import Colorscheme
from powerline.lib.config import ConfigLoader
from threading import Lock, Event
DEFAULT_SYSTEM_CONFIG_DIR = None
def find_config_file(search_paths, config_file):
config_file += '.json'
for path in search_paths:
config_file_path = os.path.join(path, config_file)
if os.path.isfile(config_file_path):
return config_file_path
raise IOError('Config file not found in search path: {0}'.format(config_file))
class PowerlineLogger(object):
def __init__(self, use_daemon_threads, logger, ext):
self.logger = logger
self.ext = ext
self.use_daemon_threads = use_daemon_threads
self.prefix = ''
self.last_msgs = {}
def _log(self, attr, msg, *args, **kwargs):
prefix = kwargs.get('prefix') or self.prefix
prefix = self.ext + ((':' + prefix) if prefix else '')
if args or kwargs:
msg = msg.format(*args, **kwargs)
msg = prefix + ':' + msg
key = attr + ':' + prefix
if msg != self.last_msgs.get(key):
getattr(self.logger, attr)(msg)
self.last_msgs[key] = msg
def critical(self, msg, *args, **kwargs):
self._log('critical', msg, *args, **kwargs)
def exception(self, msg, *args, **kwargs):
self._log('exception', msg, *args, **kwargs)
def info(self, msg, *args, **kwargs):
self._log('info', msg, *args, **kwargs)
def error(self, msg, *args, **kwargs):
self._log('error', msg, *args, **kwargs)
def warn(self, msg, *args, **kwargs):
self._log('warning', msg, *args, **kwargs)
def debug(self, msg, *args, **kwargs):
self._log('debug', msg, *args, **kwargs)
class Powerline(object):
'''Main powerline class, entrance point for all powerline uses. Sets
powerline up and loads the configuration.
:param str ext:
extension used. Determines where configuration files will
searched and what renderer module will be used. Affected: used ``ext``
dictionary from :file:`powerline/config.json`, location of themes and
colorschemes, render module (``powerline.renders.{ext}``).
:param str renderer_module:
Overrides renderer module (defaults to ``ext``). Should be the name of
the package imported like this: ``powerline.renders.{render_module}``.
If this parameter contains a dot, ``powerline.renderers.`` is not
prepended. There is also a special case for renderers defined in
toplevel modules: ``foo.`` (note: dot at the end) tries to get renderer
from module ``foo`` (because ``foo`` (without dot) tries to get renderer
from module ``powerline.renderers.foo``).
:param bool run_once:
Determines whether .renderer.render() method will be run only once
during python session.
:param Logger logger:
If present, no new logger will be created and this logger will be used.
:param bool use_daemon_threads:
Use daemon threads for.
:param Event shutdown_event:
Use this Event as shutdown_event.
:param ConfigLoader config_loader:
Class that manages (re)loading of configuration.
'''
def __init__(self,
ext,
renderer_module=None,
run_once=False,
logger=None,
use_daemon_threads=True,
shutdown_event=None,
config_loader=None):
self.ext = ext
self.renderer_module = renderer_module or ext
self.run_once = run_once
self.logger = logger
self.use_daemon_threads = use_daemon_threads
if '.' not in self.renderer_module:
self.renderer_module = 'powerline.renderers.' + self.renderer_module
elif self.renderer_module[-1] == '.':
self.renderer_module = self.renderer_module[:-1]
config_paths = self.get_config_paths()
self.find_config_file = lambda cfg_path: find_config_file(config_paths, cfg_path)
self.cr_kwargs_lock = Lock()
self.create_renderer_kwargs = {
'load_main': True,
'load_colors': True,
'load_colorscheme': True,
'load_theme': True,
}
self.shutdown_event = shutdown_event or Event()
self.config_loader = config_loader or ConfigLoader(shutdown_event=self.shutdown_event)
self.run_loader_update = False
self.renderer_options = {}
self.prev_common_config = None
self.prev_ext_config = None
self.pl = None
def create_renderer(self, load_main=False, load_colors=False, load_colorscheme=False, load_theme=False):
'''(Re)create renderer object. Can be used after Powerline object was
successfully initialized. If any of the below parameters except
``load_main`` is True renderer object will be recreated.
:param bool load_main:
Determines whether main configuration file (:file:`config.json`)
should be loaded. If appropriate configuration changes implies
``load_colorscheme`` and ``load_theme`` and recreation of renderer
object. Wont trigger recreation if only unrelated configuration
changed.
:param bool load_colors:
Determines whether colors configuration from :file:`colors.json`
should be (re)loaded.
:param bool load_colorscheme:
Determines whether colorscheme configuration should be (re)loaded.
:param bool load_theme:
Determines whether theme configuration should be reloaded.
'''
common_config_differs = False
ext_config_differs = False
if load_main:
self._purge_configs('main')
config = self.load_main_config()
self.common_config = config['common']
if self.common_config != self.prev_common_config:
common_config_differs = True
self.prev_common_config = self.common_config
self.common_config['paths'] = [os.path.expanduser(path) for path in self.common_config.get('paths', [])]
self.import_paths = self.common_config['paths']
if not self.logger:
log_format = self.common_config.get('log_format', '%(asctime)s:%(levelname)s:%(message)s')
formatter = logging.Formatter(log_format)
level = getattr(logging, self.common_config.get('log_level', 'WARNING'))
handler = self.get_log_handler()
handler.setLevel(level)
handler.setFormatter(formatter)
self.logger = logging.getLogger('powerline')
self.logger.setLevel(level)
self.logger.addHandler(handler)
if not self.pl:
self.pl = PowerlineLogger(self.use_daemon_threads, self.logger, self.ext)
if not self.config_loader.pl:
self.config_loader.pl = self.pl
self.renderer_options.update(
pl=self.pl,
term_truecolor=self.common_config.get('term_truecolor', False),
ambiwidth=self.common_config.get('ambiwidth', 1),
tmux_escape=self.common_config.get('additional_escapes') == 'tmux',
screen_escape=self.common_config.get('additional_escapes') == 'screen',
theme_kwargs={
'ext': self.ext,
'common_config': self.common_config,
'run_once': self.run_once,
'shutdown_event': self.shutdown_event,
},
)
if not self.run_once and self.common_config.get('reload_config', True):
interval = self.common_config.get('interval', None)
self.config_loader.set_interval(interval)
self.run_loader_update = (interval is None)
if interval is not None and not self.config_loader.is_alive():
self.config_loader.start()
self.ext_config = config['ext'][self.ext]
if self.ext_config != self.prev_ext_config:
ext_config_differs = True
if not self.prev_ext_config or self.ext_config.get('local_themes') != self.prev_ext_config.get('local_themes'):
self.renderer_options['local_themes'] = self.get_local_themes(self.ext_config.get('local_themes'))
load_colorscheme = (load_colorscheme
or not self.prev_ext_config
or self.prev_ext_config['colorscheme'] != self.ext_config['colorscheme'])
load_theme = (load_theme
or not self.prev_ext_config
or self.prev_ext_config['theme'] != self.ext_config['theme'])
self.prev_ext_config = self.ext_config
create_renderer = load_colors or load_colorscheme or load_theme or common_config_differs or ext_config_differs
if load_colors:
self._purge_configs('colors')
self.colors_config = self.load_colors_config()
if load_colorscheme or load_colors:
self._purge_configs('colorscheme')
if load_colorscheme:
self.colorscheme_config = self.load_colorscheme_config(self.ext_config['colorscheme'])
self.renderer_options['colorscheme'] = Colorscheme(self.colorscheme_config, self.colors_config)
if load_theme:
self._purge_configs('theme')
self.renderer_options['theme_config'] = self.load_theme_config(self.ext_config.get('theme', 'default'))
if create_renderer:
try:
Renderer = __import__(self.renderer_module, fromlist=['renderer']).renderer
except Exception as e:
self.pl.exception('Failed to import renderer module: {0}', str(e))
sys.exit(1)
# Renderer updates configuration file via segments .startup thus it
# should be locked to prevent state when configuration was updated,
# but .render still uses old renderer.
try:
renderer = Renderer(**self.renderer_options)
except Exception as e:
self.pl.exception('Failed to construct renderer object: {0}', str(e))
if not hasattr(self, 'renderer'):
raise
else:
self.renderer = renderer
def get_log_handler(self):
'''Get log handler.
:param dict common_config:
Common configuration.
:return: logging.Handler subclass.
'''
log_file = self.common_config.get('log_file', None)
if log_file:
log_file = os.path.expanduser(log_file)
log_dir = os.path.dirname(log_file)
if not os.path.isdir(log_dir):
os.mkdir(log_dir)
return logging.FileHandler(log_file)
else:
return logging.StreamHandler()
@staticmethod
def get_config_paths():
'''Get configuration paths.
:return: list of paths
'''
config_home = os.environ.get('XDG_CONFIG_HOME', os.path.join(os.path.expanduser('~'), '.config'))
config_path = os.path.join(config_home, 'powerline')
config_paths = [config_path]
config_dirs = os.environ.get('XDG_CONFIG_DIRS', DEFAULT_SYSTEM_CONFIG_DIR)
if config_dirs is not None:
config_paths.extend([os.path.join(d, 'powerline') for d in config_dirs.split(':')])
plugin_path = os.path.join(os.path.realpath(os.path.dirname(__file__)), 'config_files')
config_paths.append(plugin_path)
return config_paths
def _load_config(self, cfg_path, type):
'''Load configuration and setup watches.'''
function = getattr(self, 'on_' + type + '_change')
try:
path = self.find_config_file(cfg_path)
except IOError:
self.config_loader.register_missing(self.find_config_file, function, cfg_path)
raise
self.config_loader.register(function, path)
return self.config_loader.load(path)
def _purge_configs(self, type):
function = getattr(self, 'on_' + type + '_change')
self.config_loader.unregister_functions(set((function,)))
self.config_loader.unregister_missing(set(((self.find_config_file, function),)))
def load_theme_config(self, name):
'''Get theme configuration.
:param str name:
Name of the theme to load.
:return: dictionary with :ref:`theme configuration <config-themes>`
'''
return self._load_config(os.path.join('themes', self.ext, name), 'theme')
def load_main_config(self):
'''Get top-level configuration.
:return: dictionary with :ref:`top-level configuration <config-main>`.
'''
return self._load_config('config', 'main')
def load_colorscheme_config(self, name):
'''Get colorscheme.
:param str name:
Name of the colorscheme to load.
:return: dictionary with :ref:`colorscheme configuration <config-colorschemes>`.
'''
return self._load_config(os.path.join('colorschemes', self.ext, name), 'colorscheme')
def load_colors_config(self):
'''Get colorscheme.
:return: dictionary with :ref:`colors configuration <config-colors>`.
'''
return self._load_config('colors', 'colors')
@staticmethod
def get_local_themes(local_themes):
'''Get local themes. No-op here, to be overridden in subclasses if
required.
:param dict local_themes:
Usually accepts ``{matcher_name : theme_name}``. May also receive
None in case there is no local_themes configuration.
:return:
anything accepted by ``self.renderer.get_theme`` and processable by
``self.renderer.add_local_theme``. Renderer module is determined by
``__init__`` arguments, refer to its documentation.
'''
return None
def update_renderer(self):
'''Updates/creates a renderer if needed.'''
if self.run_loader_update:
self.config_loader.update()
create_renderer_kwargs = None
with self.cr_kwargs_lock:
if self.create_renderer_kwargs:
create_renderer_kwargs = self.create_renderer_kwargs.copy()
if create_renderer_kwargs:
try:
self.create_renderer(**create_renderer_kwargs)
except Exception as e:
self.pl.exception('Failed to create renderer: {0}', str(e))
finally:
self.create_renderer_kwargs.clear()
def render(self, *args, **kwargs):
'''Update/create renderer if needed and pass all arguments further to
``self.renderer.render()``.
'''
self.update_renderer()
return self.renderer.render(*args, **kwargs)
def shutdown(self):
'''Shut down all background threads. Must be run only prior to exiting
current application.
'''
self.shutdown_event.set()
self.renderer.shutdown()
functions = (
self.on_main_change,
self.on_colors_change,
self.on_colorscheme_change,
self.on_theme_change,
)
self.config_loader.unregister_functions(set(functions))
self.config_loader.unregister_missing(set(((find_config_file, function) for function in functions)))
def on_main_change(self, path):
with self.cr_kwargs_lock:
self.create_renderer_kwargs['load_main'] = True
def on_colors_change(self, path):
with self.cr_kwargs_lock:
self.create_renderer_kwargs['load_colors'] = True
def on_colorscheme_change(self, path):
with self.cr_kwargs_lock:
self.create_renderer_kwargs['load_colorscheme'] = True
def on_theme_change(self, path):
with self.cr_kwargs_lock:
self.create_renderer_kwargs['load_theme'] = True
def __enter__(self):
return self
def __exit__(self, *args):
self.shutdown()

View file

@ -1,38 +0,0 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8:noet
from powerline import Powerline
import sys
from time import sleep
from powerline.lib.monotonic import monotonic
from subprocess import Popen, PIPE
powerline = Powerline('wm', renderer_module='pango_markup')
powerline.update_renderer()
try:
interval = float(sys.argv[1])
except IndexError:
interval = 2
def read_to_log(pl, client):
for line in client.stdout:
if line:
pl.info(line, prefix='awesome-client')
for line in client.stderr:
if line:
pl.error(line, prefix='awesome-client')
if client.wait():
pl.error('Client exited with {0}', client.returncode, prefix='awesome')
while True:
start_time = monotonic()
s = powerline.render(side='right')
request = "powerline_widget:set_markup('" + s.replace('\\', '\\\\').replace("'", "\\'") + "')\n"
client = Popen(['awesome-client'], shell=False, stdout=PIPE, stderr=PIPE, stdin=PIPE)
client.stdin.write(request.encode('utf-8'))
client.stdin.close()
read_to_log(powerline.pl, client)
sleep(max(interval - (monotonic() - start_time), 0.1))

View file

@ -1,11 +0,0 @@
local wibox = require('wibox')
local awful = require('awful')
powerline_widget = wibox.widget.textbox()
powerline_widget:set_align('right')
function powerline(mode, widget) end
bindings_path = string.gsub(debug.getinfo(1).source:match('@(.*)$'), '/[^/]+$', '')
powerline_cmd = bindings_path .. '/powerline-awesome.py'
awful.util.spawn_with_shell('ps -C powerline-awesome.py || ' .. powerline_cmd)

View file

@ -1,28 +0,0 @@
_powerline_tmux_setenv() {
if [[ -n "$TMUX" ]]; then
tmux setenv TMUX_"$1"_$(tmux display -p "#D" | tr -d %) "$2"
fi
}
_powerline_tmux_set_pwd() {
_powerline_tmux_setenv PWD "$PWD"
}
_powerline_tmux_set_columns() {
_powerline_tmux_setenv COLUMNS "$COLUMNS"
}
_powerline_prompt() {
local last_exit_code=$?
[[ -z "$POWERLINE_OLD_PROMPT_COMMAND" ]] ||
eval $POWERLINE_OLD_PROMPT_COMMAND
PS1="$(powerline shell left -r bash_prompt --last_exit_code=$last_exit_code)"
_powerline_tmux_set_pwd
}
trap "_powerline_tmux_set_columns" SIGWINCH
_powerline_tmux_set_columns
[[ "$PROMPT_COMMAND" == "_powerline_prompt" ]] ||
POWERLINE_OLD_PROMPT_COMMAND="$PROMPT_COMMAND"
export PROMPT_COMMAND="_powerline_prompt"

View file

@ -1,61 +0,0 @@
# vim:fileencoding=utf-8:noet
from powerline.ipython import IpythonPowerline
from IPython.core.prompts import PromptManager
from IPython.core.hooks import TryNext
class IpythonInfo(object):
def __init__(self, shell):
self._shell = shell
@property
def prompt_count(self):
return self._shell.execution_count
class PowerlinePromptManager(PromptManager):
powerline = None
def __init__(self, powerline, shell):
self.powerline = powerline
self.powerline_segment_info = IpythonInfo(shell)
self.shell = shell
def render(self, name, color=True, *args, **kwargs):
width = None if name == 'in' else self.width
res, res_nocolor = self.powerline.render(output_raw=True, width=width, matcher_info=name, segment_info=self.powerline_segment_info)
self.txtwidth = len(res_nocolor)
self.width = self.txtwidth
return res if color else res_nocolor
class ConfigurableIpythonPowerline(IpythonPowerline):
def __init__(self, ip):
config = ip.config.Powerline
self.config_overrides = config.get('config_overrides')
self.theme_overrides = config.get('theme_overrides', {})
self.path = config.get('path')
super(ConfigurableIpythonPowerline, self).__init__()
old_prompt_manager = None
def load_ipython_extension(ip):
global old_prompt_manager
old_prompt_manager = ip.prompt_manager
powerline = ConfigurableIpythonPowerline(ip)
ip.prompt_manager = PowerlinePromptManager(powerline=powerline, shell=ip.prompt_manager.shell)
def shutdown_hook():
powerline.shutdown()
raise TryNext()
ip.hooks.shutdown_hook.add(shutdown_hook)
def unload_ipython_extension(ip):
ip.prompt_manager = old_prompt_manager

View file

@ -1,135 +0,0 @@
# vim:fileencoding=utf-8:noet
from powerline.ipython import IpythonPowerline
from IPython.Prompts import BasePrompt
from IPython.ipapi import get as get_ipython
from IPython.ipapi import TryNext
import re
def string(s):
if type(s) is not str:
return s.encode('utf-8')
else:
return s
# HACK: ipython tries to only leave us with plain ASCII
class RewriteResult(object):
def __init__(self, prompt):
self.prompt = string(prompt)
def __str__(self):
return self.prompt
def __add__(self, s):
if type(s) is not str:
try:
s = s.encode('utf-8')
except AttributeError:
raise NotImplementedError
return RewriteResult(self.prompt + s)
class IpythonInfo(object):
def __init__(self, cache):
self._cache = cache
@property
def prompt_count(self):
return self._cache.prompt_count
class PowerlinePrompt(BasePrompt):
def __init__(self, powerline, powerline_last_in, old_prompt):
self.powerline = powerline
self.powerline_last_in = powerline_last_in
self.powerline_segment_info = IpythonInfo(old_prompt.cache)
self.cache = old_prompt.cache
if hasattr(old_prompt, 'sep'):
self.sep = old_prompt.sep
self.pad_left = False
def __str__(self):
self.set_p_str()
return string(self.p_str)
def set_p_str(self, width=None):
self.p_str, self.p_str_nocolor = (
self.powerline.render(output_raw=True,
segment_info=self.powerline_segment_info,
matcher_info=self.powerline_prompt_type,
width=width)
)
@staticmethod
def set_colors():
pass
class PowerlinePrompt1(PowerlinePrompt):
powerline_prompt_type = 'in'
rspace = re.compile(r'(\s*)$')
def __str__(self):
self.cache.prompt_count += 1
self.set_p_str()
self.cache.last_prompt = self.p_str_nocolor.split('\n')[-1]
return string(self.p_str)
def set_p_str(self):
super(PowerlinePrompt1, self).set_p_str()
self.nrspaces = len(self.rspace.search(self.p_str_nocolor).group())
self.prompt_text_len = len(self.p_str_nocolor) - self.nrspaces
self.powerline_last_in['nrspaces'] = self.nrspaces
self.powerline_last_in['prompt_text_len'] = self.prompt_text_len
def auto_rewrite(self):
return RewriteResult(self.powerline.render(matcher_info='rewrite', width=self.prompt_text_len, segment_info=self.powerline_segment_info)
+ (' ' * self.nrspaces))
class PowerlinePromptOut(PowerlinePrompt):
powerline_prompt_type = 'out'
def set_p_str(self):
super(PowerlinePromptOut, self).set_p_str(width=self.powerline_last_in['prompt_text_len'])
spaces = ' ' * self.powerline_last_in['nrspaces']
self.p_str += spaces
self.p_str_nocolor += spaces
class PowerlinePrompt2(PowerlinePromptOut):
powerline_prompt_type = 'in2'
class ConfigurableIpythonPowerline(IpythonPowerline):
def __init__(self, config_overrides=None, theme_overrides={}, path=None):
self.config_overrides = config_overrides
self.theme_overrides = theme_overrides
self.path = path
super(ConfigurableIpythonPowerline, self).__init__()
def setup(**kwargs):
ip = get_ipython()
powerline = ConfigurableIpythonPowerline(**kwargs)
def late_startup_hook():
last_in = {'nrspaces': 0, 'prompt_text_len': None}
for attr, prompt_class in (
('prompt1', PowerlinePrompt1),
('prompt2', PowerlinePrompt2),
('prompt_out', PowerlinePromptOut)
):
old_prompt = getattr(ip.IP.outputcache, attr)
setattr(ip.IP.outputcache, attr, prompt_class(powerline, last_in, old_prompt))
raise TryNext()
def shutdown_hook():
powerline.shutdown()
raise TryNext()
ip.IP.hooks.late_startup_hook.add(late_startup_hook)
ip.IP.hooks.shutdown_hook.add(shutdown_hook)

View file

@ -1,36 +0,0 @@
# vim:fileencoding=utf-8:noet
from libqtile import bar
from libqtile.widget import base
from powerline import Powerline as PowerlineCore
class Powerline(base._TextBox):
def __init__(self, timeout=2, text=" ", width=bar.CALCULATED, **config):
base._TextBox.__init__(self, text, width, **config)
self.timeout_add(timeout, self.update)
self.powerline = PowerlineCore(ext='wm', renderer_module='pango_markup')
def update(self):
if not self.configured:
return True
self.text = self.powerline.render(side='right')
self.bar.draw()
return True
def cmd_update(self, text):
self.update(text)
def cmd_get(self):
return self.text
def _configure(self, qtile, bar):
base._TextBox._configure(self, qtile, bar)
self.layout = self.drawer.textlayout(
self.text,
self.foreground,
self.font,
self.fontsize,
self.fontshadow,
markup=True)

View file

@ -1,11 +0,0 @@
set -g status on
set -g status-utf8 on
set -g status-interval 2
set -g status-fg colour231
set -g status-bg colour234
set -g status-left-length 20
set -g status-left '#[fg=colour16,bg=colour254,bold] #S #[fg=colour254,bg=colour234,nobold]#(powerline tmux left)'
set -g status-right '#(powerline tmux right)'
set -g status-right-length 150
set -g window-status-format "#[fg=colour244,bg=colour234]#I #[fg=colour240] #[fg=colour249]#W "
set -g window-status-current-format "#[fg=colour234,bg=colour31]#[fg=colour117,bg=colour31] #I  #[fg=colour231,bold]#W #[fg=colour31,bg=colour234,nobold]"

View file

@ -1,64 +0,0 @@
# vim:fileencoding=utf-8:noet
import sys
try:
import vim
except ImportError:
vim = {}
try:
_vim_globals = vim.bindeval('g:')
def vim_set_global_var(var, val):
'''Set a global var in vim using bindeval().'''
_vim_globals[var] = val
def vim_get_func(f, rettype=None):
'''Return a vim function binding.'''
try:
func = vim.bindeval('function("' + f + '")')
if sys.version_info >= (3,) and rettype is str:
return (lambda *args, **kwargs: func(*args, **kwargs).decode('utf-8', errors='replace'))
return func
except vim.error:
return None
except AttributeError:
import json
def vim_set_global_var(var, val): # NOQA
'''Set a global var in vim using vim.command().
This is a fallback function for older vim versions.
'''
vim.command('let g:{0}={1}'.format(var, json.dumps(val)))
class VimFunc(object):
'''Evaluate a vim function using vim.eval().
This is a fallback class for older vim versions.
'''
__slots__ = ('f', 'rettype')
def __init__(self, f, rettype=None):
self.f = f
self.rettype = rettype
def __call__(self, *args):
r = vim.eval(self.f + '(' + json.dumps(args)[1:-1] + ')')
if self.rettype:
return self.rettype(r)
return r
vim_get_func = VimFunc
if sys.version_info < (3,) or not hasattr(vim, 'bindeval'):
getbufvar = vim_get_func('getbufvar')
else:
_getbufvar = vim_get_func('getbufvar')
def getbufvar(*args):
r = _getbufvar(*args)
if type(r) is bytes:
return r.decode('utf-8')
return r

View file

@ -1,95 +0,0 @@
if exists('g:powerline_loaded')
finish
endif
let g:powerline_loaded = 1
function! s:CriticalError(message)
echohl ErrorMsg
echomsg a:message
echohl None
endfunction
if ! has('python') && ! has('python3')
call s:CriticalError('You need vim compiled with Python 2.6+ or 3.2+ support
\ for Powerline to work. Please consult the documentation for more details.')
finish
endif
let s:powerline_pycmd = substitute(get(g:, 'powerline_pycmd', has('python') ? 'py' : 'py3'),
\'\v^(py)%[thon](3?)$', '\1\2', '')
let s:powerline_pyeval = get(g:, 'powerline_pyeval', s:powerline_pycmd.'eval')
let s:import_cmd = 'from powerline.vim import VimPowerline'
try
exec s:powerline_pycmd "try:\n"
\ ." ".s:import_cmd."\n"
\ ."except ImportError:\n"
\ ." import sys, vim\n"
\ ." sys.path.append(vim.eval('expand(\"<sfile>:h:h:h:h:h\")'))\n"
\ ." ".s:import_cmd
let s:launched = 1
finally
if !exists('s:launched')
call s:CriticalError('An error occurred while importing the Powerline package.
\ This could be caused by an invalid sys.path setting, or by an incompatible
\ Python version (Powerline requires Python 2.6+ or 3.2+ to work). Please consult
\ the troubleshooting section in the documentation for possible solutions.')
finish
else
unlet s:launched
endif
endtry
if !get(g:, 'powerline_debugging_pyeval') && exists('*'. s:powerline_pyeval)
let s:pyeval = function(s:powerline_pyeval)
else
exec s:powerline_pycmd 'import json, vim'
exec "function! s:pyeval(e)\n".
\ s:powerline_pycmd." vim.command('return ' + json.dumps(eval(vim.eval('a:e'))))\n".
\"endfunction"
endif
let s:last_window_id = 0
function! s:GetWinID(winnr)
let r = getwinvar(a:winnr, 'window_id')
if empty(r)
let r = s:last_window_id
let s:last_window_id += 1
call setwinvar(a:winnr, 'window_id', r)
endif
" Without this condition it triggers unneeded statusline redraw
if getwinvar(a:winnr, '&statusline') isnot# '%!Powerline('.r.')'
call setwinvar(a:winnr, '&statusline', '%!Powerline('.r.')')
endif
return r
endfunction
function! Powerline(window_id)
let winidx = index(map(range(1, winnr('$')), 's:GetWinID(v:val)'), a:window_id)
let current = w:window_id is# a:window_id
return s:pyeval('powerline.render('. a:window_id .', '. winidx .', '. current .')')
endfunction
function! PowerlineNew()
call map(range(1, winnr('$')), 's:GetWinID(v:val)')
endfunction
function! PowerlineRegisterCachePurgerEvent(event)
exec s:powerline_pycmd 'from powerline.segments.vim import launchevent as powerline_launchevent'
augroup Powerline
exec 'autocmd' a:event '*' s:powerline_pycmd.' powerline_launchevent("'.a:event.'")'
augroup END
endfunction
augroup Powerline
autocmd! ColorScheme * :exec s:powerline_pycmd 'powerline.reset_highlight()'
autocmd! VimEnter * :redrawstatus!
autocmd! VimLeavePre * :exec s:powerline_pycmd 'powerline.shutdown()'
augroup END
exec s:powerline_pycmd 'powerline = VimPowerline()'
exec s:powerline_pycmd 'del VimPowerline'
" Is immediately changed when PowerlineNew() function is run. Good for global
" value.
set statusline=%!PowerlineNew()
call PowerlineNew()

View file

@ -1,128 +0,0 @@
# vim:fileencoding=utf-8:noet
import zsh
import atexit
from powerline.shell import ShellPowerline
from powerline.lib import parsedotval
used_powerlines = []
def shutdown():
for powerline in used_powerlines:
powerline.shutdown()
def get_var_config(var):
try:
return [parsedotval(i) for i in zsh.getvalue(var).items()]
except:
return None
class Args(object):
ext = ['shell']
renderer_module = 'zsh_prompt'
@property
def last_exit_code(self):
return zsh.last_exit_code()
@property
def last_pipe_status(self):
return zsh.pipestatus()
@property
def config(self):
try:
return get_var_config('POWERLINE_CONFIG')
except IndexError:
return None
@property
def theme_option(self):
try:
return get_var_config('POWERLINE_THEME_CONFIG')
except IndexError:
return None
@property
def config_path(self):
try:
return zsh.getvalue('POWERLINE_CONFIG_PATH')
except IndexError:
return None
def string(s):
if type(s) is bytes:
return s.decode('utf-8', errors='replace')
else:
return str(s)
class Environment(object):
@staticmethod
def __getitem__(key):
try:
return string(zsh.getvalue(key))
except IndexError as e:
raise KeyError(*e.args)
@staticmethod
def get(key, default=None):
try:
return string(zsh.getvalue(key))
except IndexError:
return default
environ = Environment()
class Prompt(object):
__slots__ = ('powerline', 'side', 'savedpsvar', 'savedps', 'args')
def __init__(self, powerline, side, savedpsvar=None, savedps=None):
self.powerline = powerline
self.side = side
self.savedpsvar = savedpsvar
self.savedps = savedps
self.args = powerline.args
def __str__(self):
r = self.powerline.render(
width=zsh.columns(),
side=self.side,
segment_info={'args': self.args, 'environ': environ}
)
if type(r) is not str:
if type(r) is bytes:
return r.decode('utf-8')
else:
return r.encode('utf-8')
return r
def __del__(self):
if self.savedps:
zsh.setvalue(self.savedpsvar, self.savedps)
used_powerlines.remove(self.powerline)
if self.powerline not in used_powerlines:
self.powerline.shutdown()
def set_prompt(powerline, psvar, side):
savedps = zsh.getvalue(psvar)
zpyvar = 'ZPYTHON_POWERLINE_' + psvar
prompt = Prompt(powerline, side, psvar, savedps)
zsh.set_special_string(zpyvar, prompt)
zsh.setvalue(psvar, '${' + zpyvar + '}')
def setup():
powerline = ShellPowerline(Args())
used_powerlines.append(powerline)
used_powerlines.append(powerline)
set_prompt(powerline, 'PS1', 'left')
set_prompt(powerline, 'RPS1', 'right')
atexit.register(shutdown)

View file

@ -1,39 +0,0 @@
_powerline_tmux_setenv() {
emulate -L zsh
if [[ -n "$TMUX" ]]; then
tmux setenv TMUX_"$1"_$(tmux display -p "#D" | tr -d %) "$2"
fi
}
_powerline_tmux_set_pwd() {
_powerline_tmux_setenv PWD "$PWD"
}
_powerline_tmux_set_columns() {
_powerline_tmux_setenv COLUMNS "$COLUMNS"
}
_powerline_install_precmd() {
emulate zsh
for f in "${precmd_functions[@]}"; do
if [[ "$f" = "_powerline_precmd" ]]; then
return
fi
done
chpwd_functions+=( _powerline_tmux_set_pwd )
setopt promptpercent
setopt promptsubst
if zmodload zsh/zpython &>/dev/null ; then
zpython 'from powerline.bindings.zsh import setup as powerline_setup'
zpython 'powerline_setup()'
zpython 'del powerline_setup'
else
PS1='$(powerline shell left -r zsh_prompt --last_exit_code=$? --last_pipe_status="$pipestatus")'
RPS1='$(powerline shell right -r zsh_prompt --last_exit_code=$? --last_pipe_status="$pipestatus")'
fi
}
trap "_powerline_tmux_set_columns" SIGWINCH
_powerline_tmux_set_columns
_powerline_install_precmd

View file

@ -1,143 +0,0 @@
# vim:fileencoding=utf-8:noet
from copy import copy
DEFAULT_MODE_KEY = None
ATTR_BOLD = 1
ATTR_ITALIC = 2
ATTR_UNDERLINE = 4
def get_attr_flag(attributes):
'''Convert an attribute array to a renderer flag.'''
attr_flag = 0
if 'bold' in attributes:
attr_flag |= ATTR_BOLD
if 'italic' in attributes:
attr_flag |= ATTR_ITALIC
if 'underline' in attributes:
attr_flag |= ATTR_UNDERLINE
return attr_flag
def pick_gradient_value(grad_list, gradient_level):
'''Given a list of colors and gradient percent, return a color that should be used.
Note: gradient level is not checked for being inside [0, 100] interval.
'''
return grad_list[int(round(gradient_level * (len(grad_list) - 1) / 100))]
def hl_iter(value):
if type(value) is list:
for v in value:
yield v
else:
yield value
class Colorscheme(object):
def __init__(self, colorscheme_config, colors_config):
'''Initialize a colorscheme.'''
self.colors = {}
self.gradients = {}
self.groups = colorscheme_config['groups']
self.translations = colorscheme_config.get('mode_translations', {})
# Create a dict of color tuples with both a cterm and hex value
for color_name, color in colors_config['colors'].items():
try:
self.colors[color_name] = (color[0], int(color[1], 16))
except TypeError:
self.colors[color_name] = (color, cterm_to_hex[color])
# Create a dict of gradient names with two lists: for cterm and hex
# values. Two lists in place of one list of pairs were chosen because
# true colors allow more precise gradients.
for gradient_name, gradient in colors_config['gradients'].items():
if len(gradient) == 2:
self.gradients[gradient_name] = (
(gradient[0], [int(color, 16) for color in gradient[1]]))
else:
self.gradients[gradient_name] = (
(gradient[0], [cterm_to_hex[color] for color in gradient[0]]))
def get_gradient(self, gradient, gradient_level):
if gradient in self.gradients:
return tuple((pick_gradient_value(grad_list, gradient_level) for grad_list in self.gradients[gradient]))
else:
return self.colors[gradient]
def get_highlighting(self, groups, mode, gradient_level=None):
trans = self.translations.get(mode, {})
for group in hl_iter(groups):
if 'groups' in trans and group in trans['groups']:
try:
group_props = trans['groups'][group]
except KeyError:
continue
break
else:
try:
group_props = copy(self.groups[group])
except KeyError:
continue
try:
ctrans = trans['colors']
for key in ('fg', 'bg'):
try:
group_props[key] = ctrans[group_props[key]]
except KeyError:
pass
except KeyError:
pass
break
else:
raise KeyError('Highlighting groups not found in colorscheme: ' + ', '.join(hl_iter(groups)))
if gradient_level is None:
pick_color = self.colors.__getitem__
else:
pick_color = lambda gradient: self.get_gradient(gradient, gradient_level)
return {
'fg': pick_color(group_props['fg']),
'bg': pick_color(group_props['bg']),
'attr': get_attr_flag(group_props.get('attr', [])),
}
# 0 1 2 3 4 5 6 7 8 9
cterm_to_hex = (
0x000000, 0xc00000, 0x008000, 0x804000, 0x0000c0, 0xc000c0, 0x008080, 0xc0c0c0, 0x808080, 0xff6060, # 0
0x00ff00, 0xffff00, 0x8080ff, 0xff40ff, 0x00ffff, 0xffffff, 0x000000, 0x00005f, 0x000087, 0x0000af, # 1
0x0000d7, 0x0000ff, 0x005f00, 0x005f5f, 0x005f87, 0x005faf, 0x005fd7, 0x005fff, 0x008700, 0x00875f, # 2
0x008787, 0x0087af, 0x0087d7, 0x0087ff, 0x00af00, 0x00af5f, 0x00af87, 0x00afaf, 0x00afd7, 0x00afff, # 3
0x00d700, 0x00d75f, 0x00d787, 0x00d7af, 0x00d7d7, 0x00d7ff, 0x00ff00, 0x00ff5f, 0x00ff87, 0x00ffaf, # 4
0x00ffd7, 0x00ffff, 0x5f0000, 0x5f005f, 0x5f0087, 0x5f00af, 0x5f00d7, 0x5f00ff, 0x5f5f00, 0x5f5f5f, # 5
0x5f5f87, 0x5f5faf, 0x5f5fd7, 0x5f5fff, 0x5f8700, 0x5f875f, 0x5f8787, 0x5f87af, 0x5f87d7, 0x5f87ff, # 6
0x5faf00, 0x5faf5f, 0x5faf87, 0x5fafaf, 0x5fafd7, 0x5fafff, 0x5fd700, 0x5fd75f, 0x5fd787, 0x5fd7af, # 7
0x5fd7d7, 0x5fd7ff, 0x5fff00, 0x5fff5f, 0x5fff87, 0x5fffaf, 0x5fffd7, 0x5fffff, 0x870000, 0x87005f, # 8
0x870087, 0x8700af, 0x8700d7, 0x8700ff, 0x875f00, 0x875f5f, 0x875f87, 0x875faf, 0x875fd7, 0x875fff, # 9
0x878700, 0x87875f, 0x878787, 0x8787af, 0x8787d7, 0x8787ff, 0x87af00, 0x87af5f, 0x87af87, 0x87afaf, # 10
0x87afd7, 0x87afff, 0x87d700, 0x87d75f, 0x87d787, 0x87d7af, 0x87d7d7, 0x87d7ff, 0x87ff00, 0x87ff5f, # 11
0x87ff87, 0x87ffaf, 0x87ffd7, 0x87ffff, 0xaf0000, 0xaf005f, 0xaf0087, 0xaf00af, 0xaf00d7, 0xaf00ff, # 12
0xaf5f00, 0xaf5f5f, 0xaf5f87, 0xaf5faf, 0xaf5fd7, 0xaf5fff, 0xaf8700, 0xaf875f, 0xaf8787, 0xaf87af, # 13
0xaf87d7, 0xaf87ff, 0xafaf00, 0xafaf5f, 0xafaf87, 0xafafaf, 0xafafd7, 0xafafff, 0xafd700, 0xafd75f, # 14
0xafd787, 0xafd7af, 0xafd7d7, 0xafd7ff, 0xafff00, 0xafff5f, 0xafff87, 0xafffaf, 0xafffd7, 0xafffff, # 15
0xd70000, 0xd7005f, 0xd70087, 0xd700af, 0xd700d7, 0xd700ff, 0xd75f00, 0xd75f5f, 0xd75f87, 0xd75faf, # 16
0xd75fd7, 0xd75fff, 0xd78700, 0xd7875f, 0xd78787, 0xd787af, 0xd787d7, 0xd787ff, 0xd7af00, 0xd7af5f, # 17
0xd7af87, 0xd7afaf, 0xd7afd7, 0xd7afff, 0xd7d700, 0xd7d75f, 0xd7d787, 0xd7d7af, 0xd7d7d7, 0xd7d7ff, # 18
0xd7ff00, 0xd7ff5f, 0xd7ff87, 0xd7ffaf, 0xd7ffd7, 0xd7ffff, 0xff0000, 0xff005f, 0xff0087, 0xff00af, # 19
0xff00d7, 0xff00ff, 0xff5f00, 0xff5f5f, 0xff5f87, 0xff5faf, 0xff5fd7, 0xff5fff, 0xff8700, 0xff875f, # 20
0xff8787, 0xff87af, 0xff87d7, 0xff87ff, 0xffaf00, 0xffaf5f, 0xffaf87, 0xffafaf, 0xffafd7, 0xffafff, # 21
0xffd700, 0xffd75f, 0xffd787, 0xffd7af, 0xffd7d7, 0xffd7ff, 0xffff00, 0xffff5f, 0xffff87, 0xffffaf, # 22
0xffffd7, 0xffffff, 0x080808, 0x121212, 0x1c1c1c, 0x262626, 0x303030, 0x3a3a3a, 0x444444, 0x4e4e4e, # 23
0x585858, 0x626262, 0x6c6c6c, 0x767676, 0x808080, 0x8a8a8a, 0x949494, 0x9e9e9e, 0xa8a8a8, 0xb2b2b2, # 24
0xbcbcbc, 0xc6c6c6, 0xd0d0d0, 0xdadada, 0xe4e4e4, 0xeeeeee # 25
)

View file

@ -1,106 +0,0 @@
{
"colors": {
"black": 16,
"white": 231,
"darkestgreen": 22,
"darkgreen": 28,
"mediumgreen": 70,
"brightgreen": 148,
"darkestcyan": 23,
"darkcyan": 74,
"mediumcyan": 117,
"brightcyan": 159,
"darkestblue": 24,
"darkblue": 31,
"darkestred": 52,
"darkred": 88,
"mediumred": 124,
"brightred": 160,
"brightestred": 196,
"darkestpurple": 55,
"mediumpurple": 98,
"brightpurple": 189,
"darkorange": 94,
"mediumorange": 166,
"brightorange": 208,
"brightestorange": 214,
"brightyellow": 220,
"gray0": 233,
"gray1": 235,
"gray2": 236,
"gray3": 239,
"gray4": 240,
"gray5": 241,
"gray6": 244,
"gray7": 245,
"gray8": 247,
"gray9": 250,
"gray10": 252,
"gray61": [14, "93a1a1"],
"gray13": [8, "002b36"],
"royalblue5": [0, "073642"],
"darkgreencopper": [10, "586e75"],
"lightskyblue4": [11, "657b83"],
"azure4": [12, "839496"],
"lightyellow": [7, "eee8d5"],
"oldlace": [15, "fdf6e3"],
"green": [2, "719e07"],
"cyan": [6, "2aa198"],
"blue": [4, "268bd2"],
"red": [1, "dc322f"],
"magenta": [5, "d33682"],
"violet": [13, "6c71c4"],
"orange": [9, "cb4b16"],
"yellow": [3, "b58900"],
"lightyellowgreen": 106,
"gold3": 178,
"orangered": 202,
"steelblue": 67,
"darkorange3": 166,
"skyblue1": 117,
"khaki1": 228
},
"gradients": {
"dark_GREEN_Orange_red": [
[22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 94, 94, 94, 94, 94, 94, 94, 52],
["005f00", "015f00", "025f00", "035f00", "045f00", "055f00", "065f00", "075f00", "085f00", "095f00", "0b5f00", "0c5f00", "0d5f00", "0e5f00", "0f5f00", "105f00", "115f00", "125f00", "135f00", "145f00", "165f00", "175f00", "185f00", "195f00", "1a5f00", "1b5f00", "1c5f00", "1d5f00", "1e5f00", "1f5f00", "215f00", "225f00", "235f00", "245f00", "255f00", "265f00", "275f00", "285f00", "295f00", "2a5f00", "2c5f00", "2d5f00", "2e5f00", "2f5f00", "305f00", "315f00", "325f00", "335f00", "345f00", "355f00", "375f00", "385f00", "395f00", "3a5f00", "3b5f00", "3c5f00", "3d5f00", "3e5f00", "3f5f00", "415f00", "425f00", "435f00", "445f00", "455f00", "465f00", "475f00", "485f00", "495f00", "4a5f00", "4c5f00", "4d5f00", "4e5f00", "4f5f00", "505f00", "515f00", "525f00", "535f00", "545f00", "555f00", "575f00", "585f00", "595f00", "5a5f00", "5b5f00", "5c5f00", "5d5f00", "5e5f00", "615f00", "655f00", "685f00", "6c5f00", "6f5f00", "735f00", "765f00", "7a5f00", "7d5f00", "815f00", "845f00", "815200", "702900"]
],
"GREEN_Orange_red": [
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1],
["005f00", "015f00", "025f00", "035f00", "045f00", "055f00", "065f00", "075f00", "085f00", "095f00", "0b5f00", "0c5f00", "0d5f00", "0e5f00", "0f5f00", "105f00", "115f00", "125f00", "135f00", "145f00", "165f00", "175f00", "185f00", "195f00", "1a5f00", "1b5f00", "1c5f00", "1d5f00", "1e5f00", "1f5f00", "215f00", "225f00", "235f00", "245f00", "255f00", "265f00", "275f00", "285f00", "295f00", "2a5f00", "2c5f00", "2d5f00", "2e5f00", "2f5f00", "305f00", "315f00", "325f00", "335f00", "345f00", "355f00", "375f00", "385f00", "395f00", "3a5f00", "3b5f00", "3c5f00", "3d5f00", "3e5f00", "3f5f00", "415f00", "425f00", "435f00", "445f00", "455f00", "465f00", "475f00", "485f00", "495f00", "4a5f00", "4c5f00", "4d5f00", "4e5f00", "4f5f00", "505f00", "515f00", "525f00", "535f00", "545f00", "555f00", "575f00", "585f00", "595f00", "5a5f00", "5b5f00", "5c5f00", "5d5f00", "5e5f00", "615f00", "655f00", "685f00", "6c5f00", "6f5f00", "735f00", "765f00", "7a5f00", "7d5f00", "815f00", "845f00", "815200", "702900"]
],
"green_yellow_red": [
[190, 184, 178, 172, 166, 160],
["8ae71c", "8ce71c", "8fe71c", "92e71c", "95e71d", "98e71d", "9ae71d", "9de71d", "a0e71e", "a3e71e", "a6e71e", "a8e71e", "abe71f", "aee71f", "b1e71f", "b4e71f", "b6e720", "b9e720", "bce720", "bfe720", "c2e821", "c3e721", "c5e621", "c7e521", "c9e522", "cbe422", "cde322", "cfe222", "d1e223", "d3e123", "d5e023", "d7df23", "d9df24", "dbde24", "dddd24", "dfdc24", "e1dc25", "e3db25", "e5da25", "e7d925", "e9d926", "e9d626", "e9d426", "e9d126", "e9cf27", "e9cc27", "e9ca27", "e9c727", "e9c528", "e9c228", "e9c028", "e9bd28", "e9bb29", "e9b829", "e9b629", "e9b329", "e9b12a", "e9ae2a", "e9ac2a", "e9a92a", "eaa72b", "eaa42b", "eaa22b", "ea9f2b", "ea9d2c", "ea9b2c", "ea982c", "ea962c", "ea942d", "ea912d", "ea8f2d", "ea8d2d", "ea8a2e", "ea882e", "ea862e", "ea832e", "ea812f", "ea7f2f", "ea7c2f", "ea7a2f", "eb7830", "eb7530", "eb7330", "eb7130", "eb6f31", "eb6c31", "eb6a31", "eb6831", "eb6632", "eb6332", "eb6132", "eb5f32", "eb5d33", "eb5a33", "eb5833", "eb5633", "eb5434", "eb5134", "eb4f34", "eb4d34", "ec4b35"]
],
"green_yellow_orange_red": [
[2, 3, 9, 1],
["719e07", "739d06", "759c06", "779c06", "799b06", "7b9a05", "7d9a05", "7f9905", "819805", "839805", "859704", "879704", "899604", "8b9504", "8d9504", "8f9403", "919303", "949303", "969203", "989102", "9a9102", "9c9002", "9e9002", "a08f02", "a28e01", "a48e01", "a68d01", "a88c01", "aa8c01", "ac8b00", "ae8a00", "b08a00", "b28900", "b58900", "b58700", "b68501", "b78302", "b78102", "b87f03", "b97d04", "b97b04", "ba7905", "bb7806", "bb7606", "bc7407", "bd7208", "bd7008", "be6e09", "bf6c0a", "bf6a0a", "c0690b", "c1670c", "c1650c", "c2630d", "c3610e", "c35f0e", "c45d0f", "c55b10", "c55a10", "c65811", "c75612", "c75412", "c85213", "c95014", "c94e14", "ca4c15", "cb4b16", "cb4a16", "cc4917", "cc4818", "cd4719", "cd4719", "ce461a", "ce451b", "cf441c", "cf441c", "d0431d", "d0421e", "d1411f", "d1411f", "d24020", "d23f21", "d33e22", "d33e22", "d43d23", "d43c24", "d53b25", "d53b25", "d63a26", "d63927", "d73828", "d73828", "d83729", "d8362a", "d9352b", "d9352b", "da342c", "da332d", "db322e", "dc322f"]
],
"yellow_red": [
[220, 178, 172, 166, 160],
["ffd700", "fdd500", "fbd300", "fad200", "f8d000", "f7cf00", "f5cd00", "f3cb00", "f2ca00", "f0c800", "efc700", "edc500", "ebc300", "eac200", "e8c000", "e7bf00", "e5bd00", "e3bb00", "e2ba00", "e0b800", "dfb700", "ddb500", "dbb300", "dab200", "d8b000", "d7af00", "d7ad00", "d7ab00", "d7aa00", "d7a800", "d7a700", "d7a500", "d7a300", "d7a200", "d7a000", "d79f00", "d79d00", "d79b00", "d79a00", "d79800", "d79700", "d79500", "d79300", "d79200", "d79000", "d78f00", "d78d00", "d78b00", "d78a00", "d78800", "d78700", "d78500", "d78300", "d78200", "d78000", "d77f00", "d77d00", "d77b00", "d77a00", "d77800", "d77700", "d77500", "d77300", "d77200", "d77000", "d76f00", "d76d00", "d76b00", "d76a00", "d76800", "d76700", "d76500", "d76300", "d76200", "d76000", "d75f00", "d75b00", "d75700", "d75300", "d74f00", "d74c00", "d74800", "d74400", "d74000", "d73c00", "d73900", "d73500", "d73100", "d72d00", "d72900", "d72600", "d72200", "d71e00", "d71a00", "d71600", "d71300", "d70f00", "d70b00", "d70700"]
],
"yellow_orange_red": [
[3, 9, 1],
["b58900", "b58700", "b58600", "b68501", "b68401", "b78202", "b78102", "b88003", "b87f03", "b87d03", "b97c04", "b97b04", "ba7a05", "ba7805", "bb7706", "bb7606", "bc7507", "bc7307", "bc7207", "bd7108", "bd7008", "be6e09", "be6d09", "bf6c0a", "bf6b0a", "c06a0b", "c0680b", "c0670b", "c1660c", "c1650c", "c2630d", "c2620d", "c3610e", "c3600e", "c35e0e", "c45d0f", "c45c0f", "c55b10", "c55910", "c65811", "c65711", "c75612", "c75412", "c75312", "c85213", "c85113", "c94f14", "c94e14", "ca4d15", "ca4c15", "cb4b16", "cb4a16", "cb4a17", "cc4917", "cc4918", "cc4818", "cd4819", "cd4719", "cd471a", "ce461a", "ce461b", "ce451b", "cf451c", "cf441c", "cf441d", "d0431d", "d0431e", "d0421e", "d1421f", "d1411f", "d14120", "d24020", "d24021", "d23f21", "d33f22", "d33e22", "d33e23", "d43d23", "d43d24", "d43c24", "d53c25", "d53b25", "d53b26", "d63a26", "d63a27", "d63927", "d73928", "d73828", "d73829", "d83729", "d8372a", "d8362a", "d9362b", "d9352b", "d9352c", "da342c", "da342d", "da332d", "db332e"]
],
"blue_red": [
[39, 74, 68, 67, 103, 97, 96, 132, 131, 167, 203, 197],
["19b4fe", "1bb2fc", "1db1fa", "1faff8", "22aef6", "24adf4", "26abf2", "29aaf0", "2ba9ee", "2da7ec", "30a6ea", "32a5e8", "34a3e6", "36a2e4", "39a0e2", "3b9fe1", "3d9edf", "409cdd", "429bdb", "449ad9", "4798d7", "4997d5", "4b96d3", "4d94d1", "5093cf", "5292cd", "5490cb", "578fc9", "598dc7", "5b8cc6", "5e8bc4", "6089c2", "6288c0", "6487be", "6785bc", "6984ba", "6b83b8", "6e81b6", "7080b4", "727eb2", "757db0", "777cae", "797aac", "7b79ab", "7e78a9", "8076a7", "8275a5", "8574a3", "8772a1", "89719f", "8c709d", "8e6e9b", "906d99", "926b97", "956a95", "976993", "996791", "9c668f", "9e658e", "a0638c", "a3628a", "a56188", "a75f86", "a95e84", "ac5c82", "ae5b80", "b05a7e", "b3587c", "b5577a", "b75678", "ba5476", "bc5374", "be5273", "c05071", "c34f6f", "c54e6d", "c74c6b", "ca4b69", "cc4967", "ce4865", "d14763", "d34561", "d5445f", "d7435d", "da415b", "dc4059", "de3f58", "e13d56", "e33c54", "e53a52", "e83950", "ea384e", "ec364c", "ee354a", "f13448", "f33246", "f53144", "f83042", "fa2e40"]
]
}
}

View file

@ -1,8 +0,0 @@
{
"name": "Default color scheme for IPython prompt",
"groups": {
"virtualenv": { "fg": "white", "bg": "darkcyan" },
"prompt": { "fg": "gray9", "bg": "gray4" },
"prompt_count": { "fg": "white", "bg": "gray4" }
}
}

View file

@ -1,17 +0,0 @@
{
"name": "Default color scheme for shell prompts",
"groups": {
"user": { "fg": "white", "bg": "darkblue", "attr": ["bold"] },
"superuser": { "fg": "white", "bg": "brightred", "attr": ["bold"] },
"virtualenv": { "fg": "white", "bg": "darkcyan" },
"branch": { "fg": "gray9", "bg": "gray2" },
"branch_dirty": { "fg": "brightyellow", "bg": "gray2" },
"branch_clean": { "fg": "gray9", "bg": "gray2" },
"cwd": { "fg": "gray9", "bg": "gray4" },
"cwd:current_folder": { "fg": "gray10", "bg": "gray4", "attr": ["bold"] },
"cwd:divider": { "fg": "gray7", "bg": "gray4" },
"hostname": { "fg": "brightyellow", "bg": "mediumorange" },
"exit_fail": { "fg": "white", "bg": "darkestred" },
"exit_success": { "fg": "white", "bg": "darkestgreen" }
}
}

View file

@ -1,17 +0,0 @@
{
"name": "Solarized Dark",
"groups": {
"user": { "fg": "oldlace", "bg": "blue", "attr": ["bold"] },
"superuser": { "fg": "oldlace", "bg": "red", "attr": ["bold"] },
"virtualenv": { "fg": "oldlace", "bg": "green" },
"branch": { "fg": "gray61", "bg": "royalblue5" },
"branch_dirty": { "fg": "yellow", "bg": "royalblue5" },
"branch_clean": { "fg": "gray61", "bg": "royalblue5" },
"cwd": { "fg": "lightyellow", "bg": "darkgreencopper" },
"cwd:current_folder": { "fg": "oldlace", "bg": "darkgreencopper", "attr": ["bold"] },
"cwd:divider": { "fg": "gray61", "bg": "darkgreencopper" },
"hostname": { "fg": "oldlace", "bg": "darkgreencopper" },
"exit_fail": { "fg": "oldlace", "bg": "red" },
"exit_success": { "fg": "oldlace", "bg": "green" }
}
}

View file

@ -1,24 +0,0 @@
{
"name": "Default color scheme for terminal prompts",
"groups": {
"background:divider": { "fg": "gray5", "bg": "gray0" },
"session": { "fg": "black", "bg": "gray10", "attr": ["bold"] },
"date": { "fg": "gray8", "bg": "gray2" },
"time": { "fg": "gray10", "bg": "gray2", "attr": ["bold"] },
"time:divider": { "fg": "gray5", "bg": "gray2" },
"email_alert": { "fg": "white", "bg": "brightred", "attr": ["bold"] },
"email_alert_gradient": { "fg": "white", "bg": "yellow_orange_red", "attr": ["bold"] },
"hostname": { "fg": "black", "bg": "gray10", "attr": ["bold"] },
"weather": { "fg": "gray8", "bg": "gray0" },
"weather_temp_gradient": { "fg": "blue_red", "bg": "gray0" },
"weather_condition_hot": { "fg": "khaki1", "bg": "gray0" },
"weather_condition_snowy": { "fg": "skyblue1", "bg": "gray0" },
"weather_condition_rainy": { "fg": "skyblue1", "bg": "gray0" },
"uptime": { "fg": "gray8", "bg": "gray0" },
"external_ip": { "fg": "gray8", "bg": "gray0" },
"network_load": { "fg": "gray8", "bg": "gray0" },
"network_load_gradient": { "fg": "green_yellow_orange_red", "bg": "gray0" },
"system_load": { "fg": "gray8", "bg": "gray0" },
"system_load_gradient": { "fg": "green_yellow_orange_red", "bg": "gray0" }
}
}

View file

@ -1,95 +0,0 @@
{
"name": "Default color scheme",
"groups": {
"background": { "fg": "white", "bg": "gray2" },
"background:divider": { "fg": "gray6", "bg": "gray2" },
"mode": { "fg": "darkestgreen", "bg": "brightgreen", "attr": ["bold"] },
"modified_indicator": { "fg": "brightyellow", "bg": "gray4", "attr": ["bold"] },
"paste_indicator": { "fg": "white", "bg": "mediumorange", "attr": ["bold"] },
"readonly_indicator": { "fg": "brightestred", "bg": "gray4" },
"branch": { "fg": "gray9", "bg": "gray4" },
"branch_dirty": { "fg": "brightyellow", "bg": "gray4" },
"branch_clean": { "fg": "gray9", "bg": "gray4" },
"branch:divider": { "fg": "gray7", "bg": "gray4" },
"file_directory": { "fg": "gray9", "bg": "gray4" },
"file_name": { "fg": "white", "bg": "gray4", "attr": ["bold"] },
"file_size": { "fg": "gray8", "bg": "gray2" },
"file_name_no_file": { "fg": "gray9", "bg": "gray4", "attr": ["bold"] },
"file_name_empty": { "fg": "gray9", "bg": "gray4" },
"file_format": { "fg": "gray8", "bg": "gray2" },
"file_encoding": { "fg": "gray8", "bg": "gray2" },
"file_type": { "fg": "gray8", "bg": "gray2" },
"file_vcs_status": { "fg": "brightestred", "bg": "gray4" },
"file_vcs_status_M": { "fg": "brightyellow", "bg": "gray4" },
"file_vcs_status_A": { "fg": "brightgreen", "bg": "gray4" },
"line_percent": { "fg": "gray9", "bg": "gray4" },
"line_percent_gradient": { "fg": "green_yellow_red", "bg": "gray4" },
"line_current": { "fg": "gray1", "bg": "gray10", "attr": ["bold"] },
"line_current_symbol": { "fg": "gray1", "bg": "gray10" },
"virtcol_current_gradient": { "fg": "dark_GREEN_Orange_red", "bg": "gray10" },
"col_current": { "fg": "gray6", "bg": "gray10" },
"modified_buffers": { "fg": "brightyellow", "bg": "gray2" }
},
"mode_translations": {
"nc": {
"colors": {
"brightyellow": "darkorange",
"brightestred": "darkred",
"gray0": "gray0",
"gray1": "gray0",
"gray2": "gray0",
"gray3": "gray1",
"gray4": "gray1",
"gray5": "gray1",
"gray6": "gray1",
"gray7": "gray4",
"gray8": "gray4",
"gray9": "gray4",
"gray10": "gray5",
"white": "gray6",
"green_yellow_red": "gray5"
}
},
"i": {
"colors": {
"gray0": "darkestblue",
"gray1": "darkestblue",
"gray2": "darkestblue",
"gray3": "darkblue",
"gray4": "darkblue",
"gray5": "darkestcyan",
"gray6": "darkestcyan",
"gray7": "darkestcyan",
"gray8": "mediumcyan",
"gray9": "mediumcyan",
"gray10": "mediumcyan",
"green_yellow_red": "gray5"
},
"groups": {
"mode": { "fg": "darkestcyan", "bg": "white", "attr": ["bold"] },
"background:divider": { "fg": "darkcyan", "bg": "darkestblue" },
"branch:divider": { "fg": "darkcyan", "bg": "darkblue" }
}
},
"v": {
"groups": {
"mode": { "fg": "darkorange", "bg": "brightestorange", "attr": ["bold"] }
}
},
"V": {
"groups": {
"mode": { "fg": "darkorange", "bg": "brightestorange", "attr": ["bold"] }
}
},
"^V": {
"groups": {
"mode": { "fg": "darkorange", "bg": "brightestorange", "attr": ["bold"] }
}
},
"R": {
"groups": {
"mode": { "fg": "white", "bg": "brightred", "attr": ["bold"] }
}
}
}
}

View file

@ -1,92 +0,0 @@
{
"name": "Solarized Dark",
"groups": {
"background": { "fg": "oldlace", "bg": "royalblue5" },
"background:divider": { "fg": "lightskyblue4", "bg": "royalblue5" },
"mode": { "fg": "oldlace", "bg": "green", "attr": ["bold"] },
"modified_indicator": { "fg": "yellow", "bg": "darkgreencopper", "attr": ["bold"] },
"paste_indicator": { "fg": "oldlace", "bg": "orange", "attr": ["bold"] },
"readonly_indicator": { "fg": "red", "bg": "darkgreencopper" },
"branch": { "fg": "lightyellow", "bg": "darkgreencopper" },
"branch_dirty": { "fg": "yellow", "bg": "darkgreencopper" },
"branch_clean": { "fg": "lightyellow", "bg": "darkgreencopper" },
"branch:divider": { "fg": "gray61", "bg": "darkgreencopper" },
"file_directory": { "fg": "lightyellow", "bg": "darkgreencopper" },
"file_name": { "fg": "oldlace", "bg": "darkgreencopper", "attr": ["bold"] },
"file_size": { "fg": "oldlace", "bg": "darkgreencopper" },
"file_name_no_file": { "fg": "oldlace", "bg": "darkgreencopper", "attr": ["bold"] },
"file_name_empty": { "fg": "oldlace", "bg": "darkgreencopper" },
"file_format": { "fg": "gray61", "bg": "royalblue5" },
"file_encoding": { "fg": "gray61", "bg": "royalblue5" },
"file_type": { "fg": "gray61", "bg": "royalblue5" },
"file_vcs_status": { "fg": "red", "bg": "darkgreencopper" },
"file_vcs_status_M": { "fg": "yellow", "bg": "darkgreencopper" },
"file_vcs_status_A": { "fg": "green", "bg": "darkgreencopper" },
"line_percent": { "fg": "oldlace", "bg": "lightskyblue4" },
"line_percent_gradient": { "fg": "green_yellow_orange_red", "bg": "lightskyblue4" },
"line_current": { "fg": "gray13", "bg": "lightyellow", "attr": ["bold"] },
"line_current_symbol": { "fg": "gray13", "bg": "lightyellow" },
"virtcol_current_gradient": { "fg": "GREEN_Orange_red", "bg": "gray10" },
"col_current": { "fg": "azure4", "bg": "lightyellow" }
},
"mode_translations": {
"nc": {
"colors": {
"darkgreencopper": "royalblue5",
"lightskyblue4": "royalblue5",
"azure4": "darkgreencopper",
"gray61": "lightskyblue4",
"lightyellow": "azure4",
"oldlace": "gray61"
}
},
"i": {
"groups": {
"background": { "fg": "oldlace", "bg": "darkgreencopper" },
"background:divider": { "fg": "lightyellow", "bg": "darkgreencopper" },
"mode": { "fg": "oldlace", "bg": "blue", "attr": ["bold"] },
"modified_indicator": { "fg": "yellow", "bg": "lightyellow", "attr": ["bold"] },
"paste_indicator": { "fg": "oldlace", "bg": "orange", "attr": ["bold"] },
"readonly_indicator": { "fg": "red", "bg": "lightyellow" },
"branch": { "fg": "darkgreencopper", "bg": "lightyellow" },
"branch:divider": { "fg": "lightskyblue4", "bg": "lightyellow" },
"file_directory": { "fg": "darkgreencopper", "bg": "lightyellow" },
"file_name": { "fg": "royalblue5", "bg": "lightyellow", "attr": ["bold"] },
"file_size": { "fg": "royalblue5", "bg": "lightyellow" },
"file_name_no_file": { "fg": "royalblue5", "bg": "lightyellow", "attr": ["bold"] },
"file_name_empty": { "fg": "royalblue5", "bg": "lightyellow" },
"file_format": { "fg": "lightyellow", "bg": "darkgreencopper" },
"file_encoding": { "fg": "lightyellow", "bg": "darkgreencopper" },
"file_type": { "fg": "lightyellow", "bg": "darkgreencopper" },
"file_vcs_status": { "fg": "red", "bg": "lightyellow" },
"file_vcs_status_M": { "fg": "yellow", "bg": "lightyellow" },
"file_vcs_status_A": { "fg": "green", "bg": "lightyellow" },
"line_percent": { "fg": "oldlace", "bg": "gray61" },
"line_percent_gradient": { "fg": "oldlace", "bg": "gray61" },
"line_current": { "fg": "gray13", "bg": "oldlace", "attr": ["bold"] },
"line_current_symbol": { "fg": "gray13", "bg": "oldlace" },
"col_current": { "fg": "azure4", "bg": "oldlace" }
}
},
"v": {
"groups": {
"mode": { "fg": "oldlace", "bg": "orange", "attr": ["bold"] }
}
},
"V": {
"groups": {
"mode": { "fg": "oldlace", "bg": "orange", "attr": ["bold"] }
}
},
"^V": {
"groups": {
"mode": { "fg": "oldlace", "bg": "orange", "attr": ["bold"] }
}
},
"R": {
"groups": {
"mode": { "fg": "oldlace", "bg": "red", "attr": ["bold"] }
}
}
}
}

View file

@ -1,25 +0,0 @@
{
"name": "Default color scheme for window managers",
"groups": {
"background:divider": { "fg": "gray5", "bg": "gray0" },
"session": { "fg": "black", "bg": "gray10", "attr": ["bold"] },
"date": { "fg": "gray8", "bg": "gray2" },
"time": { "fg": "gray10", "bg": "gray2", "attr": ["bold"] },
"time:divider": { "fg": "gray5", "bg": "gray2" },
"email_alert": { "fg": "white", "bg": "brightred", "attr": ["bold"] },
"email_alert_gradient": { "fg": "white", "bg": "yellow_orange_red", "attr": ["bold"] },
"hostname": { "fg": "black", "bg": "gray10", "attr": ["bold"] },
"weather": { "fg": "gray8", "bg": "gray0" },
"weather_temp_gradient": { "fg": "blue_red", "bg": "gray0" },
"weather_condition_hot": { "fg": "khaki1", "bg": "gray0" },
"weather_condition_snowy": { "fg": "skyblue1", "bg": "gray0" },
"weather_condition_rainy": { "fg": "skyblue1", "bg": "gray0" },
"uptime": { "fg": "gray8", "bg": "gray0" },
"external_ip": { "fg": "gray8", "bg": "gray0" },
"network_load": { "fg": "gray8", "bg": "gray0" },
"system_load": { "fg": "gray8", "bg": "gray0" },
"system_load_good": { "fg": "lightyellowgreen", "bg": "gray0" },
"system_load_bad": { "fg": "gold3", "bg": "gray0" },
"system_load_ugly": { "fg": "orangered", "bg": "gray0" }
}
}

View file

@ -1,48 +0,0 @@
{
"common": {
"term_truecolor": false,
"dividers": {
"left": {
"hard": " ",
"soft": " "
},
"right": {
"hard": " ",
"soft": " "
}
},
"spaces": 1
},
"ext": {
"ipython": {
"colorscheme": "default",
"theme": "in",
"local_themes": {
"rewrite": "rewrite",
"out": "out",
"in2": "in2"
}
},
"shell": {
"colorscheme": "default",
"theme": "default"
},
"tmux": {
"colorscheme": "default",
"theme": "default"
},
"vim": {
"colorscheme": "default",
"theme": "default",
"local_themes": {
"cmdwin": "cmdwin",
"help": "help",
"quickfix": "quickfix"
}
},
"wm": {
"colorscheme": "default",
"theme": "default"
}
}
}

View file

@ -1,26 +0,0 @@
{
"default_module": "powerline.segments.common",
"segments": {
"left": [
{
"name": "virtualenv"
},
{
"type": "string",
"contents": "In[",
"draw_soft_divider": false,
"highlight_group": ["prompt"]
},
{
"name": "prompt_count",
"module": "powerline.segments.ipython",
"draw_soft_divider": false
},
{
"type": "string",
"contents": "]",
"highlight_group": ["prompt"]
}
]
}
}

View file

@ -1,13 +0,0 @@
{
"default_module": "powerline.segments.common",
"segments": {
"left": [
{
"type": "string",
"contents": "",
"width": "auto",
"highlight_group": ["prompt"]
}
]
}
}

View file

@ -1,25 +0,0 @@
{
"default_module": "powerline.segments.common",
"segments": {
"left": [
{
"type": "string",
"contents": "Out[",
"draw_soft_divider": false,
"width": "auto",
"align": "r",
"highlight_group": ["prompt"]
},
{
"name": "prompt_count",
"module": "powerline.segments.ipython",
"draw_soft_divider": false
},
{
"type": "string",
"contents": "]",
"highlight_group": ["prompt"]
}
]
}
}

View file

@ -1,23 +0,0 @@
{
"segments": {
"left": [
{
"type": "string",
"contents": "",
"draw_soft_divider": false,
"width": "auto",
"highlight_group": ["prompt"]
},
{
"name": "prompt_count",
"module": "powerline.segments.ipython",
"draw_soft_divider": false
},
{
"type": "string",
"contents": ">",
"highlight_group": ["prompt"]
}
]
}
}

View file

@ -1,45 +0,0 @@
{
"default_module": "powerline.segments.common",
"segment_data": {
"hostname": {
"before": " ",
"args": {
"only_if_ssh": true
}
},
"virtualenv": {
"before": "ⓔ "
},
"branch": {
"before": " "
}
},
"segments": {
"left": [
{
"name": "hostname"
},
{
"name": "user"
},
{
"name": "virtualenv"
},
{
"name": "cwd",
"args": {
"dir_limit_depth": 3
}
}
],
"right": [
{
"module": "powerline.segments.shell",
"name": "last_pipe_status"
},
{
"name": "branch"
}
]
}
}

View file

@ -1,43 +0,0 @@
{
"default_module": "powerline.segments.common",
"segment_data": {
"hostname": {
"before": " ",
"args": {
"only_if_ssh": true
}
},
"virtualenv": {
"before": "ⓔ "
},
"branch": {
"before": " "
}
},
"segments": {
"left": [
{
"name": "hostname"
},
{
"name": "user"
},
{
"name": "virtualenv"
},
{
"name": "branch"
},
{
"name": "cwd",
"args": {
"dir_limit_depth": 3
}
},
{
"name": "last_status",
"module": "powerline.segments.shell"
}
]
}
}

View file

@ -1,62 +0,0 @@
{
"default_module": "powerline.segments.common",
"segment_data": {
"uptime": {
"before": "⇑ "
},
"external_ip": {
"before": "ⓦ "
},
"date": {
"before": "⌚ "
},
"email_imap_alert": {
"before": "✉ ",
"args": {
"username": "",
"password": ""
}
}
},
"segments": {
"right": [
{
"name": "uptime",
"priority": 50
},
{
"name": "external_ip",
"priority": 50
},
{
"name": "network_load",
"priority": 50
},
{
"name": "system_load",
"priority": 50
},
{
"name": "weather",
"priority": 50
},
{
"name": "date"
},
{
"name": "date",
"args": {
"format": "%H:%M",
"istime": true
}
},
{
"name": "email_imap_alert",
"priority": 10
},
{
"name": "hostname"
}
]
}
}

View file

@ -1,18 +0,0 @@
{
"segments": {
"left": [
{
"type": "string",
"contents": "Command Line",
"highlight_group": ["file_name"]
},
{
"type": "string",
"highlight_group": ["background"],
"draw_soft_divider": false,
"draw_hard_divider": false,
"width": "auto"
}
]
}
}

View file

@ -1,108 +0,0 @@
{
"segment_data": {
"branch": {
"before": " "
},
"modified_indicator": {
"args": { "text": "+" }
},
"line_percent": {
"args": { "gradient": true },
"after": "%"
},
"line_current_symbol": {
"contents": " "
}
},
"segments": {
"left": [
{
"name": "mode",
"exclude_modes": ["nc"]
},
{
"name": "paste_indicator",
"exclude_modes": ["nc"],
"priority": 10
},
{
"name": "branch",
"exclude_modes": ["nc"],
"priority": 30
},
{
"name": "readonly_indicator",
"draw_soft_divider": false,
"after": " "
},
{
"name": "file_directory",
"priority": 40,
"draw_soft_divider": false
},
{
"name": "file_name",
"draw_soft_divider": false
},
{
"name": "file_vcs_status",
"before": " ",
"draw_soft_divider": false
},
{
"name": "modified_indicator",
"before": " "
},
{
"type": "string",
"highlight_group": ["background"],
"draw_soft_divider": false,
"draw_hard_divider": false,
"width": "auto"
}
],
"right": [
{
"name": "file_format",
"draw_soft_divider": false,
"exclude_modes": ["nc"],
"priority": 60
},
{
"name": "file_encoding",
"exclude_modes": ["nc"],
"priority": 60
},
{
"name": "file_type",
"exclude_modes": ["nc"],
"priority": 60
},
{
"name": "line_percent",
"priority": 50,
"width": 4,
"align": "r"
},
{
"type": "string",
"name": "line_current_symbol",
"highlight_group": ["line_current_symbol", "line_current"]
},
{
"name": "line_current",
"draw_soft_divider": false,
"width": 3,
"align": "r"
},
{
"name": "virtcol_current",
"draw_soft_divider": false,
"priority": 20,
"before": ":",
"width": 3,
"align": "l"
}
]
}
}

View file

@ -1,36 +0,0 @@
{
"segments": {
"left": [
{
"name": "file_name",
"draw_soft_divider": false
},
{
"type": "string",
"highlight_group": ["background"],
"draw_soft_divider": false,
"draw_hard_divider": false,
"width": "auto"
}
],
"right": [
{
"name": "line_percent",
"priority": 30,
"width": 4,
"align": "r"
},
{
"type": "string",
"name": "line_current_symbol",
"highlight_group": ["line_current_symbol", "line_current"]
},
{
"name": "line_current",
"draw_soft_divider": false,
"width": 3,
"align": "r"
}
]
}
}

View file

@ -1,37 +0,0 @@
{
"segment_data": {
"buffer_name": {
"contents": "Location List"
}
},
"segments": {
"left": [
{
"type": "string",
"name": "buffer_name",
"highlight_group": ["file_name"],
"draw_soft_divider": false
},
{
"type": "string",
"highlight_group": ["background"],
"draw_soft_divider": false,
"draw_hard_divider": false,
"width": "auto"
}
],
"right": [
{
"type": "string",
"name": "line_current_symbol",
"highlight_group": ["line_current_symbol", "line_current"]
},
{
"name": "line_current",
"draw_soft_divider": false,
"width": 3,
"align": "r"
}
]
}
}

View file

@ -1,31 +0,0 @@
{
"default_module": "powerline.segments.common",
"segments": {
"right": [
{
"name": "weather",
"priority": 50
},
{
"name": "date"
},
{
"name": "date",
"args": {
"format": "%H:%M",
"istime": true
},
"before": "⌚ "
},
{
"name": "email_imap_alert",
"before": "✉ ",
"priority": 10,
"args": {
"username": "",
"password": ""
}
}
]
}
}

View file

@ -1,30 +0,0 @@
# vim:fileencoding=utf-8:noet
from powerline import Powerline
from powerline.lib import mergedicts
class IpythonPowerline(Powerline):
def __init__(self):
super(IpythonPowerline, self).__init__('ipython', use_daemon_threads=True)
def get_config_paths(self):
if self.path:
return [self.path]
else:
return super(IpythonPowerline, self).get_config_paths()
def get_local_themes(self, local_themes):
return dict(((type, {'config': self.load_theme_config(name)}) for type, name in local_themes.items()))
def load_main_config(self):
r = super(IpythonPowerline, self).load_main_config()
if self.config_overrides:
mergedicts(r, self.config_overrides)
return r
def load_theme_config(self, name):
r = super(IpythonPowerline, self).load_theme_config(name)
if name in self.theme_overrides:
mergedicts(r, self.theme_overrides[name])
return r

View file

@ -1,67 +0,0 @@
# vim:fileencoding=utf-8:noet
from functools import wraps
import json
def wraps_saveargs(wrapped):
def dec(wrapper):
r = wraps(wrapped)(wrapper)
r.powerline_origin = getattr(wrapped, 'powerline_origin', wrapped)
return r
return dec
def mergedicts(d1, d2):
'''Recursively merge two dictionaries. First dictionary is modified in-place.
'''
for k in d2:
if k in d1 and type(d1[k]) is dict and type(d2[k]) is dict:
mergedicts(d1[k], d2[k])
else:
d1[k] = d2[k]
def add_divider_highlight_group(highlight_group):
def dec(func):
@wraps_saveargs(func)
def f(**kwargs):
r = func(**kwargs)
if r:
return [{
'contents': r,
'divider_highlight_group': highlight_group,
}]
else:
return None
return f
return dec
def keyvaluesplit(s):
if '=' not in s:
raise TypeError('Option must look like option=json_value')
if s[0] == '_':
raise ValueError('Option names must not start with `_\'')
idx = s.index('=')
o = s[:idx]
val = json.loads(s[idx + 1:])
return (o, val)
def parsedotval(s):
if type(s) is tuple:
o, val = s
else:
o, val = keyvaluesplit(s)
keys = o.split('.')
if len(keys) > 1:
r = (keys[0], {})
rcur = r[1]
for key in keys[1:-1]:
rcur[key] = {}
rcur = rcur[key]
rcur[keys[-1]] = val
return r
else:
return (o, val)

View file

@ -1,156 +0,0 @@
# vim:fileencoding=utf-8:noet
from powerline.lib.threaded import MultiRunnedThread
from powerline.lib.file_watcher import create_file_watcher
from threading import Event, Lock
from collections import defaultdict
import json
def open_file(path):
return open(path, 'r')
def load_json_config(config_file_path, load=json.load, open_file=open_file):
with open_file(config_file_path) as config_file_fp:
return load(config_file_fp)
class ConfigLoader(MultiRunnedThread):
def __init__(self, shutdown_event=None, watcher=None, load=load_json_config):
super(ConfigLoader, self).__init__()
self.shutdown_event = shutdown_event or Event()
self.watcher = watcher or create_file_watcher()
self._load = load
self.pl = None
self.interval = None
self.lock = Lock()
self.watched = defaultdict(set)
self.missing = defaultdict(set)
self.loaded = {}
def set_pl(self, pl):
self.pl = pl
def set_interval(self, interval):
self.interval = interval
def register(self, function, path):
'''Register function that will be run when file changes.
:param function function:
Function that will be called when file at the given path changes.
:param str path:
Path that will be watched for.
'''
with self.lock:
self.watched[path].add(function)
self.watcher.watch(path)
def register_missing(self, condition_function, function, key):
'''Register any function that will be called with given key each
interval seconds (interval is defined at __init__). Its result is then
passed to ``function``, but only if the result is true.
:param function condition_function:
Function which will be called each ``interval`` seconds. All
exceptions from it will be ignored.
:param function function:
Function which will be called if condition_function returns
something that is true. Accepts result of condition_function as an
argument.
:param str key:
Any value, it will be passed to condition_function on each call.
Note: registered functions will be automatically removed if
condition_function results in something true.
'''
with self.lock:
self.missing[key].add((condition_function, function))
def unregister_functions(self, removed_functions):
'''Unregister files handled by these functions.
:param set removed_functions:
Set of functions previously passed to ``.register()`` method.
'''
with self.lock:
for path, functions in list(self.watched.items()):
functions -= removed_functions
if not functions:
self.watched.pop(path)
self.loaded.pop(path, None)
def unregister_missing(self, removed_functions):
'''Unregister files handled by these functions.
:param set removed_functions:
Set of pairs (2-tuples) representing ``(condition_function,
function)`` function pairs previously passed as an arguments to
``.register_missing()`` method.
'''
with self.lock:
for key, functions in list(self.missing.items()):
functions -= removed_functions
if not functions:
self.missing.pop(key)
def load(self, path):
try:
# No locks: GIL does what we need
return self.loaded[path]
except KeyError:
r = self._load(path)
self.loaded[path] = r
return r
def update(self):
toload = []
with self.lock:
for path, functions in self.watched.items():
for function in functions:
try:
modified = self.watcher(path)
except OSError as e:
modified = True
self.exception('Error while running watcher for path {0}: {1}', path, str(e))
else:
if modified:
toload.append(path)
if modified:
function(path)
with self.lock:
for key, functions in list(self.missing.items()):
for condition_function, function in list(functions):
try:
path = condition_function(key)
except Exception as e:
self.exception('Error while running condition function for key {0}: {1}', key, str(e))
else:
if path:
toload.append(path)
function(path)
functions.remove((condition_function, function))
if not functions:
self.missing.pop(key)
for path in toload:
try:
self.loaded[path] = self._load(path)
except Exception as e:
self.exception('Error while loading {0}: {1}', path, str(e))
def run(self):
while self.interval is not None and not self.shutdown_event.is_set():
self.update()
self.shutdown_event.wait(self.interval)
def exception(self, msg, *args, **kwargs):
if self.pl:
self.pl.exception(msg, prefix='config_loader', *args, **kwargs)
else:
raise

View file

@ -1,181 +0,0 @@
# vim:fileencoding=utf-8:noet
from __future__ import unicode_literals, absolute_import
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import os
import sys
from time import sleep
from threading import RLock
from powerline.lib.monotonic import monotonic
from powerline.lib.inotify import INotify, INotifyError
class INotifyWatch(INotify):
is_stat_based = False
def __init__(self, expire_time=10):
super(INotifyWatch, self).__init__()
self.watches = {}
self.modified = {}
self.last_query = {}
self.lock = RLock()
self.expire_time = expire_time * 60
def expire_watches(self):
now = monotonic()
for path, last_query in tuple(self.last_query.items()):
if last_query - now > self.expire_time:
self.unwatch(path)
def process_event(self, wd, mask, cookie, name):
if wd == -1 and (mask & self.Q_OVERFLOW):
# We missed some INOTIFY events, so we dont
# know the state of any tracked files.
for path in tuple(self.modified):
if os.path.exists(path):
self.modified[path] = True
else:
self.watches.pop(path, None)
self.modified.pop(path, None)
self.last_query.pop(path, None)
return
for path, num in tuple(self.watches.items()):
if num == wd:
if mask & self.IGNORED:
self.watches.pop(path, None)
self.modified.pop(path, None)
self.last_query.pop(path, None)
else:
self.modified[path] = True
def unwatch(self, path):
''' Remove the watch for path. Raises an OSError if removing the watch
fails for some reason. '''
path = self.os.path.abspath(path)
with self.lock:
self.modified.pop(path, None)
self.last_query.pop(path, None)
wd = self.watches.pop(path, None)
if wd is not None:
if self._rm_watch(self._inotify_fd, wd) != 0:
self.handle_error()
def watch(self, path):
''' Register a watch for the file named path. Raises an OSError if path
does not exist. '''
import ctypes
path = self.os.path.abspath(path)
with self.lock:
if path not in self.watches:
bpath = path if isinstance(path, bytes) else path.encode(self.fenc)
wd = self._add_watch(self._inotify_fd, ctypes.c_char_p(bpath),
self.MODIFY | self.ATTRIB | self.MOVE_SELF | self.DELETE_SELF)
if wd == -1:
self.handle_error()
self.watches[path] = wd
self.modified[path] = False
def __call__(self, path):
''' Return True if path has been modified since the last call. Can
raise OSError if the path does not exist. '''
path = self.os.path.abspath(path)
with self.lock:
self.last_query[path] = monotonic()
self.expire_watches()
if path not in self.watches:
# Try to re-add the watch, it will fail if the file does not
# exist/you dont have permission
self.watch(path)
return True
self.read(get_name=False)
if path not in self.modified:
# An ignored event was received which means the path has been
# automatically unwatched
return True
ans = self.modified[path]
if ans:
self.modified[path] = False
return ans
def close(self):
with self.lock:
for path in tuple(self.watches):
try:
self.unwatch(path)
except OSError:
pass
super(INotifyWatch, self).close()
class StatWatch(object):
is_stat_based = True
def __init__(self):
self.watches = {}
self.lock = RLock()
def watch(self, path):
path = os.path.abspath(path)
with self.lock:
self.watches[path] = os.path.getmtime(path)
def unwatch(self, path):
path = os.path.abspath(path)
with self.lock:
self.watches.pop(path, None)
def __call__(self, path):
path = os.path.abspath(path)
with self.lock:
if path not in self.watches:
self.watches[path] = os.path.getmtime(path)
return True
mtime = os.path.getmtime(path)
if mtime != self.watches[path]:
self.watches[path] = mtime
return True
return False
def close(self):
with self.lock:
self.watches.clear()
def create_file_watcher(use_stat=False, expire_time=10):
'''
Create an object that can watch for changes to specified files. To use:
watcher = create_file_watcher()
watcher(path1) # Will return True if path1 has changed since the last time this was called. Always returns True the first time.
watcher.unwatch(path1)
Uses inotify if available, otherwise tracks mtimes. expire_time is the
number of minutes after the last query for a given path for the inotify
watch for that path to be automatically removed. This conserves kernel
resources.
'''
if use_stat:
return StatWatch()
try:
return INotifyWatch(expire_time=expire_time)
except INotifyError:
pass
return StatWatch()
if __name__ == '__main__':
watcher = create_file_watcher()
print ('Using watcher: %s' % watcher.__class__.__name__)
print ('Watching %s, press Ctrl-C to quit' % sys.argv[-1])
watcher.watch(sys.argv[-1])
try:
while True:
if watcher(sys.argv[-1]):
print ('%s has changed' % sys.argv[-1])
sleep(1)
except KeyboardInterrupt:
pass
watcher.close()

View file

@ -1,22 +0,0 @@
# vim:fileencoding=utf-8:noet
from math import log
unit_list = tuple(zip(['', 'k', 'M', 'G', 'T', 'P'], [0, 0, 1, 2, 2, 2]))
def humanize_bytes(num, suffix='B', si_prefix=False):
'''Return a human friendly byte representation.
Modified version from http://stackoverflow.com/questions/1094841
'''
if num == 0:
return '0 ' + suffix
div = 1000 if si_prefix else 1024
exponent = min(int(log(num, div)) if num else 0, len(unit_list) - 1)
quotient = float(num) / div ** exponent
unit, decimals = unit_list[exponent]
if unit and not si_prefix:
unit = unit.upper() + 'i'
return '{{quotient:.{decimals}f}} {{unit}}{{suffix}}'\
.format(decimals=decimals)\
.format(quotient=quotient, unit=unit, suffix=suffix)

View file

@ -1,178 +0,0 @@
# vim:fileencoding=utf-8:noet
from __future__ import unicode_literals, absolute_import
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import sys
import os
import errno
class INotifyError(Exception):
pass
_inotify = None
def load_inotify():
''' Initialize the inotify library '''
global _inotify
if _inotify is None:
if hasattr(sys, 'getwindowsversion'):
# On windows abort before loading the C library. Windows has
# multiple, incompatible C runtimes, and we have no way of knowing
# if the one chosen by ctypes is compatible with the currently
# loaded one.
raise INotifyError('INotify not available on windows')
import ctypes
if not hasattr(ctypes, 'c_ssize_t'):
raise INotifyError('You need python >= 2.7 to use inotify')
from ctypes.util import find_library
name = find_library('c')
if not name:
raise INotifyError('Cannot find C library')
libc = ctypes.CDLL(name, use_errno=True)
for function in ("inotify_add_watch", "inotify_init1", "inotify_rm_watch"):
if not hasattr(libc, function):
raise INotifyError('libc is too old')
# inotify_init1()
prototype = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, use_errno=True)
init1 = prototype(('inotify_init1', libc), ((1, "flags", 0),))
# inotify_add_watch()
prototype = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_char_p, ctypes.c_uint32, use_errno=True)
add_watch = prototype(('inotify_add_watch', libc), (
(1, "fd"), (1, "pathname"), (1, "mask")), use_errno=True)
# inotify_rm_watch()
prototype = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_int, use_errno=True)
rm_watch = prototype(('inotify_rm_watch', libc), (
(1, "fd"), (1, "wd")), use_errno=True)
# read()
prototype = ctypes.CFUNCTYPE(ctypes.c_ssize_t, ctypes.c_int, ctypes.c_void_p, ctypes.c_size_t, use_errno=True)
read = prototype(('read', libc), (
(1, "fd"), (1, "buf"), (1, "count")), use_errno=True)
_inotify = (init1, add_watch, rm_watch, read)
return _inotify
class INotify(object):
# See <sys/inotify.h> for the flags defined below
# Supported events suitable for MASK parameter of INOTIFY_ADD_WATCH.
ACCESS = 0x00000001 # File was accessed.
MODIFY = 0x00000002 # File was modified.
ATTRIB = 0x00000004 # Metadata changed.
CLOSE_WRITE = 0x00000008 # Writtable file was closed.
CLOSE_NOWRITE = 0x00000010 # Unwrittable file closed.
OPEN = 0x00000020 # File was opened.
MOVED_FROM = 0x00000040 # File was moved from X.
MOVED_TO = 0x00000080 # File was moved to Y.
CREATE = 0x00000100 # Subfile was created.
DELETE = 0x00000200 # Subfile was deleted.
DELETE_SELF = 0x00000400 # Self was deleted.
MOVE_SELF = 0x00000800 # Self was moved.
# Events sent by the kernel.
UNMOUNT = 0x00002000 # Backing fs was unmounted.
Q_OVERFLOW = 0x00004000 # Event queued overflowed.
IGNORED = 0x00008000 # File was ignored.
# Helper events.
CLOSE = (CLOSE_WRITE | CLOSE_NOWRITE) # Close.
MOVE = (MOVED_FROM | MOVED_TO) # Moves.
# Special flags.
ONLYDIR = 0x01000000 # Only watch the path if it is a directory.
DONT_FOLLOW = 0x02000000 # Do not follow a sym link.
EXCL_UNLINK = 0x04000000 # Exclude events on unlinked objects.
MASK_ADD = 0x20000000 # Add to the mask of an already existing watch.
ISDIR = 0x40000000 # Event occurred against dir.
ONESHOT = 0x80000000 # Only send event once.
# All events which a program can wait on.
ALL_EVENTS = (ACCESS | MODIFY | ATTRIB | CLOSE_WRITE | CLOSE_NOWRITE |
OPEN | MOVED_FROM | MOVED_TO | CREATE | DELETE |
DELETE_SELF | MOVE_SELF)
# See <bits/inotify.h>
CLOEXEC = 0x80000
NONBLOCK = 0x800
def __init__(self, cloexec=True, nonblock=True):
import ctypes
import struct
self._init1, self._add_watch, self._rm_watch, self._read = load_inotify()
flags = 0
if cloexec:
flags |= self.CLOEXEC
if nonblock:
flags |= self.NONBLOCK
self._inotify_fd = self._init1(flags)
if self._inotify_fd == -1:
raise INotifyError(os.strerror(ctypes.get_errno()))
self._buf = ctypes.create_string_buffer(5000)
self.fenc = sys.getfilesystemencoding() or 'utf-8'
self.hdr = struct.Struct(b'iIII')
if self.fenc == 'ascii':
self.fenc = 'utf-8'
# We keep a reference to os to prevent it from being deleted
# during interpreter shutdown, which would lead to errors in the
# __del__ method
self.os = os
def handle_error(self):
import ctypes
eno = ctypes.get_errno()
raise OSError(eno, self.os.strerror(eno))
def __del__(self):
# This method can be called during interpreter shutdown, which means we
# must do the absolute minimum here. Note that there could be running
# daemon threads that are trying to call other methods on this object.
try:
self.os.close(self._inotify_fd)
except (AttributeError, TypeError):
pass
def close(self):
if hasattr(self, '_inotify_fd'):
self.os.close(self._inotify_fd)
del self.os
del self._add_watch
del self._rm_watch
del self._inotify_fd
def read(self, get_name=True):
import ctypes
buf = []
while True:
num = self._read(self._inotify_fd, self._buf, len(self._buf))
if num == 0:
break
if num < 0:
en = ctypes.get_errno()
if en == errno.EAGAIN:
break # No more data
if en == errno.EINTR:
continue # Interrupted, try again
raise OSError(en, self.os.strerror(en))
buf.append(self._buf.raw[:num])
raw = b''.join(buf)
pos = 0
lraw = len(raw)
while lraw - pos >= self.hdr.size:
wd, mask, cookie, name_len = self.hdr.unpack_from(raw, pos)
pos += self.hdr.size
name = None
if get_name:
name = raw[pos:pos + name_len].rstrip(b'\0').decode(self.fenc)
pos += name_len
self.process_event(wd, mask, cookie, name)
def process_event(self, *args):
raise NotImplementedError()

View file

@ -1,40 +0,0 @@
# vim:fileencoding=utf-8:noet
from functools import wraps
from powerline.lib.monotonic import monotonic
def default_cache_key(**kwargs):
return frozenset(kwargs.items())
class memoize(object):
'''Memoization decorator with timeout.'''
def __init__(self, timeout, cache_key=default_cache_key, cache_reg_func=None):
self.timeout = timeout
self.cache_key = cache_key
self.cache = {}
self.cache_reg_func = cache_reg_func
def __call__(self, func):
@wraps(func)
def decorated_function(**kwargs):
if self.cache_reg_func:
self.cache_reg_func(self.cache)
self.cache_reg_func = None
key = self.cache_key(**kwargs)
try:
cached = self.cache.get(key, None)
except TypeError:
return func(**kwargs)
# Handle case when time() appears to be less then cached['time'] due
# to clock updates. Not applicable for monotonic clock, but this
# case is currently rare.
if cached is None or not (cached['time'] < monotonic() < cached['time'] + self.timeout):
cached = self.cache[key] = {
'result': func(**kwargs),
'time': monotonic(),
}
return cached['result']
return decorated_function

View file

@ -1,103 +0,0 @@
# vim:fileencoding=utf-8:noet
from __future__ import division, absolute_import
try:
try:
# >=python-3.3, Unix
from time import clock_gettime
try:
# >={kernel}-sources-2.6.28
from time import CLOCK_MONOTONIC_RAW as CLOCK_ID
except ImportError:
from time import CLOCK_MONOTONIC as CLOCK_ID # NOQA
monotonic = lambda: clock_gettime(CLOCK_ID)
except ImportError:
# >=python-3.3
from time import monotonic # NOQA
except ImportError:
import ctypes
import sys
try:
if sys.platform == 'win32':
# Windows only
GetTickCount64 = ctypes.windll.kernel32.GetTickCount64
GetTickCount64.restype = ctypes.c_ulonglong
def monotonic(): # NOQA
return GetTickCount64() / 1000
elif sys.platform == 'darwin':
# Mac OS X
from ctypes.util import find_library
libc_name = find_library('c')
if not libc_name:
raise OSError
libc = ctypes.CDLL(libc_name, use_errno=True)
mach_absolute_time = libc.mach_absolute_time
mach_absolute_time.argtypes = ()
mach_absolute_time.restype = ctypes.c_uint64
class mach_timebase_info_data_t(ctypes.Structure):
_fields_ = (
('numer', ctypes.c_uint32),
('denom', ctypes.c_uint32),
)
mach_timebase_info_data_p = ctypes.POINTER(mach_timebase_info_data_t)
_mach_timebase_info = libc.mach_timebase_info
_mach_timebase_info.argtypes = (mach_timebase_info_data_p,)
_mach_timebase_info.restype = ctypes.c_int
def mach_timebase_info():
timebase = mach_timebase_info_data_t()
_mach_timebase_info(ctypes.byref(timebase))
return (timebase.numer, timebase.denom)
timebase = mach_timebase_info()
factor = timebase[0] / timebase[1] * 1e-9
def monotonic(): # NOQA
return mach_absolute_time() * factor
else:
# linux only (no librt on OS X)
import os
# See <bits/time.h>
CLOCK_MONOTONIC = 1
CLOCK_MONOTONIC_RAW = 4
class timespec(ctypes.Structure):
_fields_ = (
('tv_sec', ctypes.c_long),
('tv_nsec', ctypes.c_long)
)
tspec = timespec()
librt = ctypes.CDLL('librt.so.1', use_errno=True)
clock_gettime = librt.clock_gettime
clock_gettime.argtypes = [ctypes.c_int, ctypes.POINTER(timespec)]
if clock_gettime(CLOCK_MONOTONIC_RAW, ctypes.pointer(tspec)) == 0:
# >={kernel}-sources-2.6.28
clock_id = CLOCK_MONOTONIC_RAW
elif clock_gettime(CLOCK_MONOTONIC, ctypes.pointer(tspec)) == 0:
clock_id = CLOCK_MONOTONIC
else:
raise OSError
def monotonic(): # NOQA
if clock_gettime(CLOCK_MONOTONIC, ctypes.pointer(tspec)) != 0:
errno_ = ctypes.get_errno()
raise OSError(errno_, os.strerror(errno_))
return tspec.tv_sec + tspec.tv_nsec / 1e9
except:
from time import time as monotonic # NOQA

View file

@ -1,204 +0,0 @@
# vim:fileencoding=utf-8:noet
from __future__ import absolute_import
from powerline.lib.monotonic import monotonic
from threading import Thread, Lock, Event
class MultiRunnedThread(object):
daemon = True
def __init__(self):
self.thread = None
def is_alive(self):
return self.thread and self.thread.is_alive()
def start(self):
self.shutdown_event.clear()
self.thread = Thread(target=self.run)
self.thread.daemon = self.daemon
self.thread.start()
def join(self, *args, **kwargs):
if self.thread:
return self.thread.join(*args, **kwargs)
return None
class ThreadedSegment(MultiRunnedThread):
min_sleep_time = 0.1
update_first = True
interval = 1
daemon = False
def __init__(self):
super(ThreadedSegment, self).__init__()
self.run_once = True
self.skip = False
self.crashed_value = None
self.update_value = None
self.updated = False
def __call__(self, pl, update_first=True, **kwargs):
if self.run_once:
self.pl = pl
self.set_state(**kwargs)
update_value = self.get_update_value(True)
elif not self.is_alive():
# Without this we will not have to wait long until receiving bug “I
# opened vim, but branch information is only shown after I move
# cursor”.
#
# If running once .update() is called in __call__.
update_value = self.get_update_value(update_first and self.update_first)
self.start()
elif not self.updated:
update_value = self.get_update_value(True)
self.updated = True
else:
update_value = self.update_value
if self.skip:
return self.crashed_value
return self.render(update_value, update_first=update_first, pl=pl, **kwargs)
def get_update_value(self, update=False):
if update:
self.update_value = self.update(self.update_value)
return self.update_value
def run(self):
while not self.shutdown_event.is_set():
start_time = monotonic()
try:
self.update_value = self.update(self.update_value)
except Exception as e:
self.exception('Exception while updating: {0}', str(e))
self.skip = True
except KeyboardInterrupt:
self.warn('Caught keyboard interrupt while updating')
self.skip = True
else:
self.skip = False
self.shutdown_event.wait(max(self.interval - (monotonic() - start_time), self.min_sleep_time))
def shutdown(self):
self.shutdown_event.set()
if self.daemon and self.is_alive():
# Give the worker thread a chance to shutdown, but don't block for
# too long
self.join(0.01)
def set_interval(self, interval=None):
# Allowing “interval” keyword in configuration.
# Note: Here **kwargs is needed to support foreign data, in subclasses
# it can be seen in a number of places in order to support
# .set_interval().
interval = interval or getattr(self, 'interval')
self.interval = interval
def set_state(self, interval=None, update_first=True, shutdown_event=None, **kwargs):
self.set_interval(interval)
self.shutdown_event = shutdown_event or Event()
self.updated = self.updated or (not (update_first and self.update_first))
def startup(self, pl, **kwargs):
self.run_once = False
self.pl = pl
self.daemon = pl.use_daemon_threads
self.set_state(**kwargs)
if not self.is_alive():
self.start()
def critical(self, *args, **kwargs):
self.pl.critical(prefix=self.__class__.__name__, *args, **kwargs)
def exception(self, *args, **kwargs):
self.pl.exception(prefix=self.__class__.__name__, *args, **kwargs)
def info(self, *args, **kwargs):
self.pl.info(prefix=self.__class__.__name__, *args, **kwargs)
def error(self, *args, **kwargs):
self.pl.error(prefix=self.__class__.__name__, *args, **kwargs)
def warn(self, *args, **kwargs):
self.pl.warn(prefix=self.__class__.__name__, *args, **kwargs)
def debug(self, *args, **kwargs):
self.pl.debug(prefix=self.__class__.__name__, *args, **kwargs)
class KwThreadedSegment(ThreadedSegment):
drop_interval = 10 * 60
update_first = True
def __init__(self):
super(KwThreadedSegment, self).__init__()
self.updated = True
self.update_value = ({}, set())
self.write_lock = Lock()
self.new_queries = {}
@staticmethod
def key(**kwargs):
return frozenset(kwargs.items())
def render(self, update_value, update_first, **kwargs):
queries, crashed = update_value
key = self.key(**kwargs)
if key in crashed:
return self.crashed_value
try:
update_state = queries[key][1]
except KeyError:
# Allow only to forbid to compute missing values: in either user
# configuration or in subclasses.
update_state = self.compute_state(key) if ((update_first and self.update_first) or self.run_once) else None
with self.write_lock:
self.new_queries[key] = (monotonic(), update_state)
return self.render_one(update_state, **kwargs)
def update(self, old_update_value):
updates = {}
crashed = set()
update_value = (updates, crashed)
queries = old_update_value[0]
with self.write_lock:
if self.new_queries:
queries.update(self.new_queries)
self.new_queries.clear()
for key, (last_query_time, state) in queries.items():
if last_query_time < monotonic() < last_query_time + self.drop_interval:
try:
updates[key] = (last_query_time, self.compute_state(key))
except Exception as e:
self.exception('Exception while computing state for {0!r}: {1}', key, str(e))
crashed.add(key)
except KeyboardInterrupt:
self.warn('Interrupt while computing state for {0!r}', key)
crashed.add(key)
return update_value
def set_state(self, interval=None, shutdown_event=None, **kwargs):
self.set_interval(interval)
self.shutdown_event = shutdown_event or Event()
@staticmethod
def render_one(update_state, **kwargs):
return update_state
def with_docstring(instance, doc):
instance.__doc__ = doc
return instance

View file

@ -1,199 +0,0 @@
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, absolute_import, print_function)
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import sys
import os
import errno
from time import sleep
from powerline.lib.monotonic import monotonic
from powerline.lib.inotify import INotify, INotifyError
class NoSuchDir(ValueError):
pass
class DirTooLarge(ValueError):
def __init__(self, bdir):
ValueError.__init__(self, 'The directory {0} is too large to monitor. Try increasing the value in /proc/sys/fs/inotify/max_user_watches'.format(bdir))
class INotifyTreeWatcher(INotify):
is_dummy = False
def __init__(self, basedir):
super(INotifyTreeWatcher, self).__init__()
self.basedir = os.path.abspath(basedir)
self.watch_tree()
self.modified = True
def watch_tree(self):
self.watched_dirs = {}
self.watched_rmap = {}
try:
self.add_watches(self.basedir)
except OSError as e:
if e.errno == errno.ENOSPC:
raise DirTooLarge(self.basedir)
def add_watches(self, base, top_level=True):
''' Add watches for this directory and all its descendant directories,
recursively. '''
base = os.path.abspath(base)
try:
is_dir = self.add_watch(base)
except OSError as e:
if e.errno == errno.ENOENT:
# The entry could have been deleted between listdir() and
# add_watch().
if top_level:
raise NoSuchDir('The dir {0} does not exist'.format(base))
return
if e.errno == errno.EACCES:
# We silently ignore entries for which we dont have permission,
# unless they are the top level dir
if top_level:
raise NoSuchDir('You do not have permission to monitor {0}'.format(base))
return
raise
else:
if is_dir:
try:
files = os.listdir(base)
except OSError as e:
if e.errno in (errno.ENOTDIR, errno.ENOENT):
# The dir was deleted/replaced between the add_watch()
# and listdir()
if top_level:
raise NoSuchDir('The dir {0} does not exist'.format(base))
return
raise
for x in files:
self.add_watches(os.path.join(base, x), top_level=False)
elif top_level:
# The top level dir is a file, not good.
raise NoSuchDir('The dir {0} does not exist'.format(base))
def add_watch(self, path):
import ctypes
bpath = path if isinstance(path, bytes) else path.encode(self.fenc)
wd = self._add_watch(self._inotify_fd, ctypes.c_char_p(bpath),
# Ignore symlinks and watch only directories
self.DONT_FOLLOW | self.ONLYDIR |
self.MODIFY | self.CREATE | self.DELETE |
self.MOVE_SELF | self.MOVED_FROM | self.MOVED_TO |
self.ATTRIB | self.MOVE_SELF | self.DELETE_SELF)
if wd == -1:
eno = ctypes.get_errno()
if eno == errno.ENOTDIR:
return False
raise OSError(eno, 'Failed to add watch for: {0}: {1}'.format(path, self.os.strerror(eno)))
self.watched_dirs[path] = wd
self.watched_rmap[wd] = path
return True
def process_event(self, wd, mask, cookie, name):
if wd == -1 and (mask & self.Q_OVERFLOW):
# We missed some INOTIFY events, so we dont
# know the state of any tracked dirs.
self.watch_tree()
self.modified = True
return
path = self.watched_rmap.get(wd, None)
if path is not None:
self.modified = True
if mask & self.CREATE:
# A new sub-directory might have been created, monitor it.
try:
self.add_watch(os.path.join(path, name))
except OSError as e:
if e.errno == errno.ENOENT:
# Deleted before add_watch()
pass
elif e.errno == errno.ENOSPC:
raise DirTooLarge(self.basedir)
else:
raise
def __call__(self):
self.read()
ret = self.modified
self.modified = False
return ret
class DummyTreeWatcher(object):
is_dummy = True
def __init__(self, basedir):
self.basedir = os.path.abspath(basedir)
def __call__(self):
return False
class TreeWatcher(object):
def __init__(self, expire_time=10):
self.watches = {}
self.last_query_times = {}
self.expire_time = expire_time * 60
def watch(self, path, logger=None):
path = os.path.abspath(path)
try:
w = INotifyTreeWatcher(path)
except (INotifyError, DirTooLarge) as e:
if logger is not None:
logger.warn('Failed to watch path: {0} with error: {1}'.format(path, e))
w = DummyTreeWatcher(path)
self.watches[path] = w
return w
def is_actually_watched(self, path):
w = self.watches.get(path, None)
return not getattr(w, 'is_dummy', True)
def expire_old_queries(self):
pop = []
now = monotonic()
for path, lt in self.last_query_times.items():
if now - lt > self.expire_time:
pop.append(path)
for path in pop:
del self.last_query_times[path]
def __call__(self, path, logger=None):
path = os.path.abspath(path)
self.expire_old_queries()
self.last_query_times[path] = monotonic()
w = self.watches.get(path, None)
if w is None:
try:
self.watch(path)
except NoSuchDir:
pass
return True
try:
return w()
except DirTooLarge as e:
if logger is not None:
logger.warn(str(e))
self.watches[path] = DummyTreeWatcher(path)
return False
if __name__ == '__main__':
w = INotifyTreeWatcher(sys.argv[-1])
w()
print ('Monitoring', sys.argv[-1], 'press Ctrl-C to stop')
try:
while True:
if w():
print (sys.argv[-1], 'changed')
sleep(1)
except KeyboardInterrupt:
raise SystemExit(0)

View file

@ -1,16 +0,0 @@
# vim:fileencoding=utf-8:noet
try:
from urllib.error import HTTPError
from urllib.request import urlopen
from urllib.parse import urlencode as urllib_urlencode # NOQA
except ImportError:
from urllib2 import urlopen, HTTPError # NOQA
from urllib import urlencode as urllib_urlencode # NOQA
def urllib_read(url):
try:
return urlopen(url, timeout=10).read().decode('utf-8')
except HTTPError:
return

View file

@ -1,33 +0,0 @@
# vim:fileencoding=utf-8:noet
from __future__ import absolute_import
import os
vcs_props = (
('git', '.git', os.path.exists),
('mercurial', '.hg', os.path.isdir),
('bzr', '.bzr', os.path.isdir),
)
def generate_directories(path):
yield path
while True:
old_path = path
path = os.path.dirname(path)
if path == old_path or not path:
break
yield path
def guess(path):
for directory in generate_directories(path):
for vcs, vcs_dir, check in vcs_props:
if check(os.path.join(directory, vcs_dir)):
try:
if vcs not in globals():
globals()[vcs] = getattr(__import__('powerline.lib.vcs', fromlist=[vcs]), vcs)
return globals()[vcs].Repository(directory)
except:
pass
return None

View file

@ -1,64 +0,0 @@
# vim:fileencoding=utf-8:noet
from __future__ import absolute_import, unicode_literals, division, print_function
import sys
from io import StringIO
from bzrlib import (branch, workingtree, status, library_state, trace, ui)
class CoerceIO(StringIO):
def write(self, arg):
if isinstance(arg, bytes):
arg = arg.decode('utf-8', 'replace')
return super(CoerceIO, self).write(arg)
class Repository(object):
def __init__(self, directory):
if isinstance(directory, bytes):
directory = directory.decode(sys.getfilesystemencoding() or sys.getdefaultencoding() or 'utf-8')
self.directory = directory
self.state = library_state.BzrLibraryState(ui=ui.SilentUIFactory, trace=trace.DefaultConfig())
def status(self, path=None):
'''Return status of repository or file.
Without file argument: returns status of the repository:
:"D?": dirty (tracked modified files: added, removed, deleted, modified),
:"?U": untracked-dirty (added, but not tracked files)
:None: clean (status is empty)
With file argument: returns status of this file: The status codes are
those returned by bzr status -S
'''
try:
return self._status(path)
except:
pass
def _status(self, path):
buf = CoerceIO()
w = workingtree.WorkingTree.open(self.directory)
status.show_tree_status(w, specific_files=[path] if path else None, to_file=buf, short=True)
raw = buf.getvalue()
if not raw.strip():
return
if path:
return raw[:2]
dirtied = untracked = ' '
for line in raw.splitlines():
if len(line) > 1 and line[1] in 'ACDMRIN':
dirtied = 'D'
elif line and line[0] == '?':
untracked = 'U'
ans = dirtied + untracked
return ans if ans.strip() else None
def branch(self):
try:
b = branch.Branch.open(self.directory)
return b._get_nick(local=True) or None
except:
pass

View file

@ -1,143 +0,0 @@
# vim:fileencoding=utf-8:noet
try:
import pygit2 as git
class Repository(object):
__slots__ = ('directory')
def __init__(self, directory):
self.directory = directory
def _repo(self):
return git.Repository(self.directory)
def status(self, path=None):
'''Return status of repository or file.
Without file argument: returns status of the repository:
:First column: working directory status (D: dirty / space)
:Second column: index status (I: index dirty / space)
:Third column: presense of untracked files (U: untracked files / space)
:None: repository clean
With file argument: returns status of this file. Output is
equivalent to the first two columns of "git status --porcelain"
(except for merge statuses as they are not supported by libgit2).
'''
if path:
try:
status = self._repo().status_file(path)
except (KeyError, ValueError):
return None
if status == git.GIT_STATUS_CURRENT:
return None
else:
if status & git.GIT_STATUS_WT_NEW:
return '??'
if status & git.GIT_STATUS_IGNORED:
return '!!'
if status & git.GIT_STATUS_INDEX_NEW:
index_status = 'A'
elif status & git.GIT_STATUS_INDEX_DELETED:
index_status = 'D'
elif status & git.GIT_STATUS_INDEX_MODIFIED:
index_status = 'M'
else:
index_status = ' '
if status & git.GIT_STATUS_WT_DELETED:
wt_status = 'D'
elif status & git.GIT_STATUS_WT_MODIFIED:
wt_status = 'M'
else:
wt_status = ' '
return index_status + wt_status
else:
wt_column = ' '
index_column = ' '
untracked_column = ' '
for status in self._repo().status().values():
if status & git.GIT_STATUS_WT_NEW:
untracked_column = 'U'
continue
if status & (git.GIT_STATUS_WT_DELETED
| git.GIT_STATUS_WT_MODIFIED):
wt_column = 'D'
if status & (git.GIT_STATUS_INDEX_NEW
| git.GIT_STATUS_INDEX_MODIFIED
| git.GIT_STATUS_INDEX_DELETED):
index_column = 'I'
r = wt_column + index_column + untracked_column
return r if r != ' ' else None
def branch(self):
try:
ref = self._repo().lookup_reference('HEAD')
except KeyError:
return None
try:
target = ref.target
except ValueError:
return '[DETACHED HEAD]'
if target.startswith('refs/heads/'):
return target[11:]
else:
return '[DETACHED HEAD]'
except ImportError:
from subprocess import Popen, PIPE
def readlines(cmd, cwd):
p = Popen(cmd, shell=False, stdout=PIPE, stderr=PIPE, cwd=cwd)
p.stderr.close()
with p.stdout:
for line in p.stdout:
yield line[:-1].decode('utf-8')
class Repository(object):
__slots__ = ('directory',)
def __init__(self, directory):
self.directory = directory
def _gitcmd(self, *args):
return readlines(('git',) + args, self.directory)
def status(self, path=None):
if path:
try:
return next(self._gitcmd('status', '--porcelain', '--ignored', '--', path))[:2]
except StopIteration:
return None
else:
wt_column = ' '
index_column = ' '
untracked_column = ' '
for line in self._gitcmd('status', '--porcelain'):
if line[0] == '?':
untracked_column = 'U'
continue
elif line[0] == '!':
continue
if line[0] != ' ':
index_column = 'I'
if line[1] != ' ':
wt_column = 'D'
r = wt_column + index_column + untracked_column
return r if r != ' ' else None
def branch(self):
for line in self._gitcmd('branch', '-l'):
if line[0] == '*':
return line[2:]
return None

View file

@ -1,51 +0,0 @@
# vim:fileencoding=utf-8:noet
from __future__ import absolute_import
from mercurial import hg, ui, match
class Repository(object):
__slots__ = ('directory', 'ui')
statuses = 'MARDUI'
repo_statuses = (1, 1, 1, 1, 2)
repo_statuses_str = (None, 'D ', ' U', 'DU')
def __init__(self, directory):
self.directory = directory
self.ui = ui.ui()
def _repo(self):
# Cannot create this object once and use always: when repository updates
# functions emit invalid results
return hg.repository(self.ui, self.directory)
def status(self, path=None):
'''Return status of repository or file.
Without file argument: returns status of the repository:
:"D?": dirty (tracked modified files: added, removed, deleted, modified),
:"?U": untracked-dirty (added, but not tracked files)
:None: clean (status is empty)
With file argument: returns status of this file: "M"odified, "A"dded,
"R"emoved, "D"eleted (removed from filesystem, but still tracked),
"U"nknown, "I"gnored, (None)Clean.
'''
repo = self._repo()
if path:
m = match.match(None, None, [path], exact=True)
statuses = repo.status(match=m, unknown=True, ignored=True)
for status, paths in zip(self.statuses, statuses):
if paths:
return status
return None
else:
resulting_status = 0
for status, paths in zip(self.repo_statuses, repo.status(unknown=True)):
if paths:
resulting_status |= status
return self.repo_statuses_str[resulting_status]
def branch(self):
return self._repo().dirstate.branch()

View file

@ -1,59 +0,0 @@
# vim:fileencoding=utf-8:noet
from __future__ import absolute_import
from inspect import ArgSpec, getargspec
from powerline.lib.threaded import ThreadedSegment, KwThreadedSegment
from itertools import count
def getconfigargspec(obj):
if isinstance(obj, ThreadedSegment):
args = ['interval']
defaults = [getattr(obj, 'interval', 1)]
if obj.update_first:
args.append('update_first')
defaults.append(True)
methods = ['render', 'set_state']
if isinstance(obj, KwThreadedSegment):
methods += ['key', 'render_one']
for method in methods:
if hasattr(obj, method):
# Note: on <python-2.6 it may return simple tuple, not
# ArgSpec instance.
argspec = getargspec(getattr(obj, method))
for i, arg in zip(count(1), reversed(argspec.args)):
if (arg == 'self' or
(arg == 'segment_info' and
getattr(obj, 'powerline_requires_segment_info', None)) or
(arg == 'pl') or
(method.startswith('render') and (1 if argspec.args[0] == 'self' else 0) + i == len(argspec.args)) or
arg in args):
continue
if argspec.defaults and len(argspec.defaults) >= i:
default = argspec.defaults[-i]
defaults.append(default)
args.append(arg)
else:
args.insert(0, arg)
argspec = ArgSpec(args=args, varargs=None, keywords=None, defaults=tuple(defaults))
else:
if hasattr(obj, 'powerline_origin'):
obj = obj.powerline_origin
else:
obj = obj
argspec = getargspec(obj)
args = []
defaults = []
for i, arg in zip(count(1), reversed(argspec.args)):
if ((arg == 'segment_info' and getattr(obj, 'powerline_requires_segment_info', None)) or
arg == 'pl'):
continue
if argspec.defaults and len(argspec.defaults) >= i:
default = argspec.defaults[-i]
defaults.append(default)
args.append(arg)
else:
args.insert(0, arg)
argspec = ArgSpec(args=args, varargs=argspec.varargs, keywords=argspec.keywords, defaults=tuple(defaults))
return argspec

View file

@ -1,17 +0,0 @@
__version__ = '3.10'
from .loader import Loader
def load(stream, Loader=Loader):
"""
Parse the first YAML document in a stream
and produce the corresponding Python object.
"""
loader = Loader(stream)
try:
r = loader.get_single_data()
return r, loader.haserrors
finally:
loader.dispose()

View file

@ -1,117 +0,0 @@
__all__ = ['Composer', 'ComposerError']
from .error import MarkedError
from .events import * # NOQA
from .nodes import * # NOQA
class ComposerError(MarkedError):
pass
class Composer:
def __init__(self):
pass
def check_node(self):
# Drop the STREAM-START event.
if self.check_event(StreamStartEvent):
self.get_event()
# If there are more documents available?
return not self.check_event(StreamEndEvent)
def get_node(self):
# Get the root node of the next document.
if not self.check_event(StreamEndEvent):
return self.compose_document()
def get_single_node(self):
# Drop the STREAM-START event.
self.get_event()
# Compose a document if the stream is not empty.
document = None
if not self.check_event(StreamEndEvent):
document = self.compose_document()
# Ensure that the stream contains no more documents.
if not self.check_event(StreamEndEvent):
event = self.get_event()
raise ComposerError("expected a single document in the stream",
document.start_mark, "but found another document",
event.start_mark)
# Drop the STREAM-END event.
self.get_event()
return document
def compose_document(self):
# Drop the DOCUMENT-START event.
self.get_event()
# Compose the root node.
node = self.compose_node(None, None)
# Drop the DOCUMENT-END event.
self.get_event()
return node
def compose_node(self, parent, index):
self.descend_resolver(parent, index)
if self.check_event(ScalarEvent):
node = self.compose_scalar_node()
elif self.check_event(SequenceStartEvent):
node = self.compose_sequence_node()
elif self.check_event(MappingStartEvent):
node = self.compose_mapping_node()
self.ascend_resolver()
return node
def compose_scalar_node(self):
event = self.get_event()
tag = event.tag
if tag is None or tag == '!':
tag = self.resolve(ScalarNode, event.value, event.implicit, event.start_mark)
node = ScalarNode(tag, event.value,
event.start_mark, event.end_mark, style=event.style)
return node
def compose_sequence_node(self):
start_event = self.get_event()
tag = start_event.tag
if tag is None or tag == '!':
tag = self.resolve(SequenceNode, None, start_event.implicit)
node = SequenceNode(tag, [],
start_event.start_mark, None,
flow_style=start_event.flow_style)
index = 0
while not self.check_event(SequenceEndEvent):
node.value.append(self.compose_node(node, index))
index += 1
end_event = self.get_event()
node.end_mark = end_event.end_mark
return node
def compose_mapping_node(self):
start_event = self.get_event()
tag = start_event.tag
if tag is None or tag == '!':
tag = self.resolve(MappingNode, None, start_event.implicit)
node = MappingNode(tag, [],
start_event.start_mark, None,
flow_style=start_event.flow_style)
while not self.check_event(MappingEndEvent):
#key_event = self.peek_event()
item_key = self.compose_node(node, None)
#if item_key in node.value:
# raise ComposerError("while composing a mapping", start_event.start_mark,
# "found duplicate key", key_event.start_mark)
item_value = self.compose_node(node, item_key)
#node.value[item_key] = item_value
node.value.append((item_key, item_value))
end_event = self.get_event()
node.end_mark = end_event.end_mark
return node

View file

@ -1,274 +0,0 @@
__all__ = ['BaseConstructor', 'Constructor', 'ConstructorError']
from .error import MarkedError
from .nodes import * # NOQA
from .markedvalue import gen_marked_value
import collections
import types
from functools import wraps
try:
from __builtin__ import unicode
except ImportError:
unicode = str # NOQA
def marked(func):
@wraps(func)
def f(self, node, *args, **kwargs):
return gen_marked_value(func(self, node, *args, **kwargs), node.start_mark)
return f
class ConstructorError(MarkedError):
pass
class BaseConstructor:
yaml_constructors = {}
def __init__(self):
self.constructed_objects = {}
self.state_generators = []
self.deep_construct = False
def check_data(self):
# If there are more documents available?
return self.check_node()
def get_data(self):
# Construct and return the next document.
if self.check_node():
return self.construct_document(self.get_node())
def get_single_data(self):
# Ensure that the stream contains a single document and construct it.
node = self.get_single_node()
if node is not None:
return self.construct_document(node)
return None
def construct_document(self, node):
data = self.construct_object(node)
while self.state_generators:
state_generators = self.state_generators
self.state_generators = []
for generator in state_generators:
for dummy in generator:
pass
self.constructed_objects = {}
self.deep_construct = False
return data
def construct_object(self, node, deep=False):
if node in self.constructed_objects:
return self.constructed_objects[node]
if deep:
old_deep = self.deep_construct
self.deep_construct = True
constructor = None
tag_suffix = None
if node.tag in self.yaml_constructors:
constructor = self.yaml_constructors[node.tag]
else:
raise ConstructorError(None, None, 'no constructor for tag %s' % node.tag)
if tag_suffix is None:
data = constructor(self, node)
else:
data = constructor(self, tag_suffix, node)
if isinstance(data, types.GeneratorType):
generator = data
data = next(generator)
if self.deep_construct:
for dummy in generator:
pass
else:
self.state_generators.append(generator)
self.constructed_objects[node] = data
if deep:
self.deep_construct = old_deep
return data
@marked
def construct_scalar(self, node):
if not isinstance(node, ScalarNode):
raise ConstructorError(None, None,
"expected a scalar node, but found %s" % node.id,
node.start_mark)
return node.value
def construct_sequence(self, node, deep=False):
if not isinstance(node, SequenceNode):
raise ConstructorError(None, None,
"expected a sequence node, but found %s" % node.id,
node.start_mark)
return [self.construct_object(child, deep=deep)
for child in node.value]
@marked
def construct_mapping(self, node, deep=False):
if not isinstance(node, MappingNode):
raise ConstructorError(None, None,
"expected a mapping node, but found %s" % node.id,
node.start_mark)
mapping = {}
for key_node, value_node in node.value:
key = self.construct_object(key_node, deep=deep)
if not isinstance(key, collections.Hashable):
self.echoerr('While constructing a mapping', node.start_mark,
'found unhashable key', key_node.start_mark)
continue
elif type(key.value) != unicode:
self.echoerr('Error while constructing a mapping', node.start_mark,
'found key that is not a string', key_node.start_mark)
continue
elif key in mapping:
self.echoerr('Error while constructing a mapping', node.start_mark,
'found duplicate key', key_node.start_mark)
continue
value = self.construct_object(value_node, deep=deep)
mapping[key] = value
return mapping
@classmethod
def add_constructor(cls, tag, constructor):
if not 'yaml_constructors' in cls.__dict__:
cls.yaml_constructors = cls.yaml_constructors.copy()
cls.yaml_constructors[tag] = constructor
class Constructor(BaseConstructor):
def construct_scalar(self, node):
if isinstance(node, MappingNode):
for key_node, value_node in node.value:
if key_node.tag == 'tag:yaml.org,2002:value':
return self.construct_scalar(value_node)
return BaseConstructor.construct_scalar(self, node)
def flatten_mapping(self, node):
merge = []
index = 0
while index < len(node.value):
key_node, value_node = node.value[index]
if key_node.tag == 'tag:yaml.org,2002:merge':
del node.value[index]
if isinstance(value_node, MappingNode):
self.flatten_mapping(value_node)
merge.extend(value_node.value)
elif isinstance(value_node, SequenceNode):
submerge = []
for subnode in value_node.value:
if not isinstance(subnode, MappingNode):
raise ConstructorError("while constructing a mapping",
node.start_mark,
"expected a mapping for merging, but found %s"
% subnode.id, subnode.start_mark)
self.flatten_mapping(subnode)
submerge.append(subnode.value)
submerge.reverse()
for value in submerge:
merge.extend(value)
else:
raise ConstructorError("while constructing a mapping", node.start_mark,
"expected a mapping or list of mappings for merging, but found %s"
% value_node.id, value_node.start_mark)
elif key_node.tag == 'tag:yaml.org,2002:value':
key_node.tag = 'tag:yaml.org,2002:str'
index += 1
else:
index += 1
if merge:
node.value = merge + node.value
def construct_mapping(self, node, deep=False):
if isinstance(node, MappingNode):
self.flatten_mapping(node)
return BaseConstructor.construct_mapping(self, node, deep=deep)
@marked
def construct_yaml_null(self, node):
self.construct_scalar(node)
return None
@marked
def construct_yaml_bool(self, node):
value = self.construct_scalar(node).value
return bool(value)
@marked
def construct_yaml_int(self, node):
value = self.construct_scalar(node).value
sign = +1
if value[0] == '-':
sign = -1
if value[0] in '+-':
value = value[1:]
if value == '0':
return 0
else:
return sign * int(value)
@marked
def construct_yaml_float(self, node):
value = self.construct_scalar(node).value
sign = +1
if value[0] == '-':
sign = -1
if value[0] in '+-':
value = value[1:]
else:
return sign * float(value)
def construct_yaml_str(self, node):
return self.construct_scalar(node)
def construct_yaml_seq(self, node):
data = gen_marked_value([], node.start_mark)
yield data
data.extend(self.construct_sequence(node))
def construct_yaml_map(self, node):
data = gen_marked_value({}, node.start_mark)
yield data
value = self.construct_mapping(node)
data.update(value)
def construct_undefined(self, node):
raise ConstructorError(None, None,
"could not determine a constructor for the tag %r" % node.tag,
node.start_mark)
Constructor.add_constructor(
'tag:yaml.org,2002:null',
Constructor.construct_yaml_null)
Constructor.add_constructor(
'tag:yaml.org,2002:bool',
Constructor.construct_yaml_bool)
Constructor.add_constructor(
'tag:yaml.org,2002:int',
Constructor.construct_yaml_int)
Constructor.add_constructor(
'tag:yaml.org,2002:float',
Constructor.construct_yaml_float)
Constructor.add_constructor(
'tag:yaml.org,2002:str',
Constructor.construct_yaml_str)
Constructor.add_constructor(
'tag:yaml.org,2002:seq',
Constructor.construct_yaml_seq)
Constructor.add_constructor(
'tag:yaml.org,2002:map',
Constructor.construct_yaml_map)
Constructor.add_constructor(None,
Constructor.construct_undefined)

View file

@ -1,99 +0,0 @@
__all__ = ['Mark', 'MarkedError', 'echoerr', 'NON_PRINTABLE']
import sys
import re
try:
from __builtin__ import unichr
except ImportError:
unichr = chr # NOQA
NON_PRINTABLE = re.compile('[^\t\n\x20-\x7E' + unichr(0x85) + (unichr(0xA0) + '-' + unichr(0xD7FF)) + (unichr(0xE000) + '-' + unichr(0xFFFD)) + ']')
def repl(s):
return '<x%04x>' % ord(s.group())
def strtrans(s):
return NON_PRINTABLE.sub(repl, s.replace('\t', '>---'))
class Mark:
def __init__(self, name, line, column, buffer, pointer):
self.name = name
self.line = line
self.column = column
self.buffer = buffer
self.pointer = pointer
def copy(self):
return Mark(self.name, self.line, self.column, self.buffer, self.pointer)
def get_snippet(self, indent=4, max_length=75):
if self.buffer is None:
return None
head = ''
start = self.pointer
while start > 0 and self.buffer[start - 1] not in '\0\n':
start -= 1
if self.pointer - start > max_length / 2 - 1:
head = ' ... '
start += 5
break
tail = ''
end = self.pointer
while end < len(self.buffer) and self.buffer[end] not in '\0\n':
end += 1
if end - self.pointer > max_length / 2 - 1:
tail = ' ... '
end -= 5
break
snippet = [self.buffer[start:self.pointer], self.buffer[self.pointer], self.buffer[self.pointer + 1:end]]
snippet = [strtrans(s) for s in snippet]
return ' ' * indent + head + ''.join(snippet) + tail + '\n' \
+ ' ' * (indent + len(head) + len(snippet[0])) + '^'
def __str__(self):
snippet = self.get_snippet()
where = " in \"%s\", line %d, column %d" \
% (self.name, self.line + 1, self.column + 1)
if snippet is not None:
where += ":\n" + snippet
if type(where) is str:
return where
else:
return where.encode('utf-8')
def echoerr(*args, **kwargs):
sys.stderr.write('\n')
sys.stderr.write(format_error(*args, **kwargs) + '\n')
def format_error(context=None, context_mark=None, problem=None, problem_mark=None, note=None):
lines = []
if context is not None:
lines.append(context)
if context_mark is not None \
and (problem is None or problem_mark is None
or context_mark.name != problem_mark.name
or context_mark.line != problem_mark.line
or context_mark.column != problem_mark.column):
lines.append(str(context_mark))
if problem is not None:
lines.append(problem)
if problem_mark is not None:
lines.append(str(problem_mark))
if note is not None:
lines.append(note)
return '\n'.join(lines)
class MarkedError(Exception):
def __init__(self, context=None, context_mark=None,
problem=None, problem_mark=None, note=None):
Exception.__init__(self, format_error(context, context_mark, problem,
problem_mark, note))

View file

@ -1,97 +0,0 @@
# Abstract classes.
class Event(object):
def __init__(self, start_mark=None, end_mark=None):
self.start_mark = start_mark
self.end_mark = end_mark
def __repr__(self):
attributes = [key for key in ['implicit', 'value']
if hasattr(self, key)]
arguments = ', '.join(['%s=%r' % (key, getattr(self, key))
for key in attributes])
return '%s(%s)' % (self.__class__.__name__, arguments)
class NodeEvent(Event):
def __init__(self, start_mark=None, end_mark=None):
self.start_mark = start_mark
self.end_mark = end_mark
class CollectionStartEvent(NodeEvent):
def __init__(self, implicit, start_mark=None, end_mark=None,
flow_style=None):
self.tag = None
self.implicit = implicit
self.start_mark = start_mark
self.end_mark = end_mark
self.flow_style = flow_style
class CollectionEndEvent(Event):
pass
# Implementations.
class StreamStartEvent(Event):
def __init__(self, start_mark=None, end_mark=None, encoding=None):
self.start_mark = start_mark
self.end_mark = end_mark
self.encoding = encoding
class StreamEndEvent(Event):
pass
class DocumentStartEvent(Event):
def __init__(self, start_mark=None, end_mark=None,
explicit=None, version=None, tags=None):
self.start_mark = start_mark
self.end_mark = end_mark
self.explicit = explicit
self.version = version
self.tags = tags
class DocumentEndEvent(Event):
def __init__(self, start_mark=None, end_mark=None,
explicit=None):
self.start_mark = start_mark
self.end_mark = end_mark
self.explicit = explicit
class AliasEvent(NodeEvent):
pass
class ScalarEvent(NodeEvent):
def __init__(self, implicit, value,
start_mark=None, end_mark=None, style=None):
self.tag = None
self.implicit = implicit
self.value = value
self.start_mark = start_mark
self.end_mark = end_mark
self.style = style
class SequenceStartEvent(CollectionStartEvent):
pass
class SequenceEndEvent(CollectionEndEvent):
pass
class MappingStartEvent(CollectionStartEvent):
pass
class MappingEndEvent(CollectionEndEvent):
pass

View file

@ -1,24 +0,0 @@
__all__ = ['Loader']
from .reader import Reader
from .scanner import Scanner
from .parser import Parser
from .composer import Composer
from .constructor import Constructor
from .resolver import Resolver
from .error import echoerr
class Loader(Reader, Scanner, Parser, Composer, Constructor, Resolver):
def __init__(self, stream):
Reader.__init__(self, stream)
Scanner.__init__(self)
Parser.__init__(self)
Composer.__init__(self)
Constructor.__init__(self)
Resolver.__init__(self)
self.haserrors = False
def echoerr(self, *args, **kwargs):
echoerr(*args, **kwargs)
self.haserrors = True

View file

@ -1,83 +0,0 @@
__all__ = ['gen_marked_value', 'MarkedValue']
try:
from __builtin__ import unicode
except ImportError:
unicode = str
def gen_new(cls):
def __new__(arg_cls, value, mark):
r = super(arg_cls, arg_cls).__new__(arg_cls, value)
r.mark = mark
r.value = value
return r
return __new__
class MarkedUnicode(unicode):
__new__ = gen_new(unicode)
def _proc_partition(self, part_result):
pointdiff = 1
r = []
for s in part_result:
mark = self.mark.copy()
# XXX Does not work properly with escaped strings, but this requires
# saving much more information in mark.
mark.column += pointdiff
mark.pointer += pointdiff
r.append(MarkedUnicode(s, mark))
pointdiff += len(s)
return tuple(r)
def rpartition(self, sep):
return self._proc_partition(super(MarkedUnicode, self).rpartition(sep))
def partition(self, sep):
return self._proc_partition(super(MarkedUnicode, self).partition(sep))
class MarkedInt(int):
__new__ = gen_new(int)
class MarkedFloat(float):
__new__ = gen_new(float)
class MarkedValue:
def __init__(self, value, mark):
self.mark = mark
self.value = value
specialclasses = {
unicode: MarkedUnicode,
int: MarkedInt,
float: MarkedFloat,
}
classcache = {}
def gen_marked_value(value, mark, use_special_classes=True):
if use_special_classes and value.__class__ in specialclasses:
Marked = specialclasses[value.__class__]
elif value.__class__ in classcache:
Marked = classcache[value.__class__]
else:
class Marked(MarkedValue):
for func in value.__class__.__dict__:
if func not in set(('__init__', '__new__', '__getattribute__')):
if func in set(('__eq__',)):
# HACK to make marked dictionaries always work
exec (('def {0}(self, *args):\n'
' return self.value.{0}(*[arg.value if isinstance(arg, MarkedValue) else arg for arg in args])').format(func))
else:
exec (('def {0}(self, *args, **kwargs):\n'
' return self.value.{0}(*args, **kwargs)\n').format(func))
classcache[value.__class__] = Marked
return Marked(value, mark)

View file

@ -1,53 +0,0 @@
class Node(object):
def __init__(self, tag, value, start_mark, end_mark):
self.tag = tag
self.value = value
self.start_mark = start_mark
self.end_mark = end_mark
def __repr__(self):
value = self.value
#if isinstance(value, list):
# if len(value) == 0:
# value = '<empty>'
# elif len(value) == 1:
# value = '<1 item>'
# else:
# value = '<%d items>' % len(value)
#else:
# if len(value) > 75:
# value = repr(value[:70]+u' ... ')
# else:
# value = repr(value)
value = repr(value)
return '%s(tag=%r, value=%s)' % (self.__class__.__name__, self.tag, value)
class ScalarNode(Node):
id = 'scalar'
def __init__(self, tag, value,
start_mark=None, end_mark=None, style=None):
self.tag = tag
self.value = value
self.start_mark = start_mark
self.end_mark = end_mark
self.style = style
class CollectionNode(Node):
def __init__(self, tag, value,
start_mark=None, end_mark=None, flow_style=None):
self.tag = tag
self.value = value
self.start_mark = start_mark
self.end_mark = end_mark
self.flow_style = flow_style
class SequenceNode(CollectionNode):
id = 'sequence'
class MappingNode(CollectionNode):
id = 'mapping'

View file

@ -1,240 +0,0 @@
__all__ = ['Parser', 'ParserError']
from .error import MarkedError
from .tokens import * # NOQA
from .events import * # NOQA
class ParserError(MarkedError):
pass
class Parser:
def __init__(self):
self.current_event = None
self.yaml_version = None
self.states = []
self.marks = []
self.state = self.parse_stream_start
def dispose(self):
# Reset the state attributes (to clear self-references)
self.states = []
self.state = None
def check_event(self, *choices):
# Check the type of the next event.
if self.current_event is None:
if self.state:
self.current_event = self.state()
if self.current_event is not None:
if not choices:
return True
for choice in choices:
if isinstance(self.current_event, choice):
return True
return False
def peek_event(self):
# Get the next event.
if self.current_event is None:
if self.state:
self.current_event = self.state()
return self.current_event
def get_event(self):
# Get the next event and proceed further.
if self.current_event is None:
if self.state:
self.current_event = self.state()
value = self.current_event
self.current_event = None
return value
# stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
# implicit_document ::= block_node DOCUMENT-END*
# explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
def parse_stream_start(self):
# Parse the stream start.
token = self.get_token()
event = StreamStartEvent(token.start_mark, token.end_mark,
encoding=token.encoding)
# Prepare the next state.
self.state = self.parse_implicit_document_start
return event
def parse_implicit_document_start(self):
# Parse an implicit document.
if not self.check_token(StreamEndToken):
token = self.peek_token()
start_mark = end_mark = token.start_mark
event = DocumentStartEvent(start_mark, end_mark, explicit=False)
# Prepare the next state.
self.states.append(self.parse_document_end)
self.state = self.parse_node
return event
else:
return self.parse_document_start()
def parse_document_start(self):
# Parse an explicit document.
if not self.check_token(StreamEndToken):
token = self.peek_token()
self.echoerr(None, None,
"expected '<stream end>', but found %r" % token.id,
token.start_mark)
return StreamEndEvent(token.start_mark, token.end_mark)
else:
# Parse the end of the stream.
token = self.get_token()
event = StreamEndEvent(token.start_mark, token.end_mark)
assert not self.states
assert not self.marks
self.state = None
return event
def parse_document_end(self):
# Parse the document end.
token = self.peek_token()
start_mark = end_mark = token.start_mark
explicit = False
event = DocumentEndEvent(start_mark, end_mark, explicit=explicit)
# Prepare the next state.
self.state = self.parse_document_start
return event
def parse_document_content(self):
return self.parse_node()
def parse_node(self, indentless_sequence=False):
start_mark = end_mark = None
if start_mark is None:
start_mark = end_mark = self.peek_token().start_mark
event = None
implicit = True
if self.check_token(ScalarToken):
token = self.get_token()
end_mark = token.end_mark
if token.plain:
implicit = (True, False)
else:
implicit = (False, True)
event = ScalarEvent(implicit, token.value,
start_mark, end_mark, style=token.style)
self.state = self.states.pop()
elif self.check_token(FlowSequenceStartToken):
end_mark = self.peek_token().end_mark
event = SequenceStartEvent(implicit,
start_mark, end_mark, flow_style=True)
self.state = self.parse_flow_sequence_first_entry
elif self.check_token(FlowMappingStartToken):
end_mark = self.peek_token().end_mark
event = MappingStartEvent(implicit,
start_mark, end_mark, flow_style=True)
self.state = self.parse_flow_mapping_first_key
else:
token = self.peek_token()
raise ParserError("while parsing a flow node", start_mark,
"expected the node content, but found %r" % token.id,
token.start_mark)
return event
def parse_flow_sequence_first_entry(self):
token = self.get_token()
self.marks.append(token.start_mark)
return self.parse_flow_sequence_entry(first=True)
def parse_flow_sequence_entry(self, first=False):
if not self.check_token(FlowSequenceEndToken):
if not first:
if self.check_token(FlowEntryToken):
self.get_token()
if self.check_token(FlowSequenceEndToken):
token = self.peek_token()
self.echoerr("While parsing a flow sequence", self.marks[-1],
"expected sequence value, but got %r" % token.id, token.start_mark)
else:
token = self.peek_token()
raise ParserError("while parsing a flow sequence", self.marks[-1],
"expected ',' or ']', but got %r" % token.id, token.start_mark)
if not self.check_token(FlowSequenceEndToken):
self.states.append(self.parse_flow_sequence_entry)
return self.parse_node()
token = self.get_token()
event = SequenceEndEvent(token.start_mark, token.end_mark)
self.state = self.states.pop()
self.marks.pop()
return event
def parse_flow_sequence_entry_mapping_end(self):
self.state = self.parse_flow_sequence_entry
token = self.peek_token()
return MappingEndEvent(token.start_mark, token.start_mark)
def parse_flow_mapping_first_key(self):
token = self.get_token()
self.marks.append(token.start_mark)
return self.parse_flow_mapping_key(first=True)
def parse_flow_mapping_key(self, first=False):
if not self.check_token(FlowMappingEndToken):
if not first:
if self.check_token(FlowEntryToken):
self.get_token()
if self.check_token(FlowMappingEndToken):
token = self.peek_token()
self.echoerr("While parsing a flow mapping", self.marks[-1],
"expected mapping key, but got %r" % token.id, token.start_mark)
else:
token = self.peek_token()
raise ParserError("while parsing a flow mapping", self.marks[-1],
"expected ',' or '}', but got %r" % token.id, token.start_mark)
if self.check_token(KeyToken):
token = self.get_token()
if not self.check_token(ValueToken,
FlowEntryToken, FlowMappingEndToken):
self.states.append(self.parse_flow_mapping_value)
return self.parse_node()
else:
token = self.peek_token()
raise ParserError("while parsing a flow mapping", self.marks[-1],
"expected value, but got %r" % token.id, token.start_mark)
elif not self.check_token(FlowMappingEndToken):
token = self.peek_token()
expect_key = self.check_token(ValueToken, FlowEntryToken)
if not expect_key:
self.get_token()
expect_key = self.check_token(ValueToken)
if expect_key:
raise ParserError("while parsing a flow mapping", self.marks[-1],
"expected string key, but got %r" % token.id, token.start_mark)
else:
token = self.peek_token()
raise ParserError("while parsing a flow mapping", self.marks[-1],
"expected ':', but got %r" % token.id, token.start_mark)
token = self.get_token()
event = MappingEndEvent(token.start_mark, token.end_mark)
self.state = self.states.pop()
self.marks.pop()
return event
def parse_flow_mapping_value(self):
if self.check_token(ValueToken):
token = self.get_token()
if not self.check_token(FlowEntryToken, FlowMappingEndToken):
self.states.append(self.parse_flow_mapping_key)
return self.parse_node()
token = self.peek_token()
raise ParserError("while parsing a flow mapping", self.marks[-1],
"expected mapping value, but got %r" % token.id, token.start_mark)

View file

@ -1,135 +0,0 @@
# This module contains abstractions for the input stream. You don't have to
# looks further, there are no pretty code.
__all__ = ['Reader', 'ReaderError']
from .error import MarkedError, Mark, NON_PRINTABLE
import codecs
try:
from __builtin__ import unicode
except ImportError:
unicode = str # NOQA
class ReaderError(MarkedError):
pass
class Reader(object):
# Reader:
# - determines the data encoding and converts it to a unicode string,
# - checks if characters are in allowed range,
# - adds '\0' to the end.
# Reader accepts
# - a file-like object with its `read` method returning `str`,
# Yeah, it's ugly and slow.
def __init__(self, stream):
self.name = None
self.stream = None
self.stream_pointer = 0
self.eof = True
self.buffer = ''
self.pointer = 0
self.full_buffer = unicode('')
self.full_pointer = 0
self.raw_buffer = None
self.raw_decode = codecs.utf_8_decode
self.encoding = 'utf-8'
self.index = 0
self.line = 0
self.column = 0
self.stream = stream
self.name = getattr(stream, 'name', "<file>")
self.eof = False
self.raw_buffer = None
while not self.eof and (self.raw_buffer is None or len(self.raw_buffer) < 2):
self.update_raw()
self.update(1)
def peek(self, index=0):
try:
return self.buffer[self.pointer + index]
except IndexError:
self.update(index + 1)
return self.buffer[self.pointer + index]
def prefix(self, length=1):
if self.pointer + length >= len(self.buffer):
self.update(length)
return self.buffer[self.pointer:self.pointer + length]
def update_pointer(self, length):
while length:
ch = self.buffer[self.pointer]
self.pointer += 1
self.full_pointer += 1
self.index += 1
if ch == '\n':
self.line += 1
self.column = 0
else:
self.column += 1
length -= 1
def forward(self, length=1):
if self.pointer + length + 1 >= len(self.buffer):
self.update(length + 1)
self.update_pointer(length)
def get_mark(self):
return Mark(self.name, self.line, self.column, self.full_buffer, self.full_pointer)
def check_printable(self, data):
match = NON_PRINTABLE.search(data)
if match:
self.update_pointer(match.start())
raise ReaderError('while reading from stream', None,
'found special characters which are not allowed',
Mark(self.name, self.line, self.column, self.full_buffer, self.full_pointer))
def update(self, length):
if self.raw_buffer is None:
return
self.buffer = self.buffer[self.pointer:]
self.pointer = 0
while len(self.buffer) < length:
if not self.eof:
self.update_raw()
try:
data, converted = self.raw_decode(self.raw_buffer,
'strict', self.eof)
except UnicodeDecodeError as exc:
character = self.raw_buffer[exc.start]
position = self.stream_pointer - len(self.raw_buffer) + exc.start
data, converted = self.raw_decode(self.raw_buffer[:exc.start], 'strict', self.eof)
self.buffer += data
self.full_buffer += data + '<' + str(ord(character)) + '>'
self.raw_buffer = self.raw_buffer[converted:]
self.update_pointer(exc.start - 1)
raise ReaderError('while reading from stream', None,
'found character #x%04x that cannot be decoded by UTF-8 codec' % ord(character),
Mark(self.name, self.line, self.column, self.full_buffer, position))
self.buffer += data
self.full_buffer += data
self.raw_buffer = self.raw_buffer[converted:]
self.check_printable(data)
if self.eof:
self.buffer += '\0'
self.raw_buffer = None
break
def update_raw(self, size=4096):
data = self.stream.read(size)
if self.raw_buffer is None:
self.raw_buffer = data
else:
self.raw_buffer += data
self.stream_pointer += len(data)
if not data:
self.eof = True

Some files were not shown because too many files have changed in this diff Show more