First commit
This commit is contained in:
284
.vim/plugin/pydiction.py
Normal file
284
.vim/plugin/pydiction.py
Normal file
@@ -0,0 +1,284 @@
|
||||
#!/usr/bin/env python
|
||||
# Last modified: July 23rd, 2009
|
||||
"""
|
||||
|
||||
pydiction.py 1.2 by Ryan Kulla (rkulla AT gmail DOT com).
|
||||
|
||||
Description: Creates a Vim dictionary of Python module attributes for Vim's
|
||||
completion feature. The created dictionary file is used by
|
||||
the Vim ftplugin "python_pydiction.vim".
|
||||
|
||||
Usage: pydiction.py <module> ... [-v]
|
||||
Example: The following will append all the "time" and "math" modules'
|
||||
attributes to a file, in the current directory, called "pydiction"
|
||||
with and without the "time." and "math." prefix:
|
||||
$ python pydiction.py time math
|
||||
To print the output just to stdout, instead of appending to the file,
|
||||
supply the -v option:
|
||||
$ python pydiction.py -v time math
|
||||
|
||||
License: BSD.
|
||||
"""
|
||||
|
||||
|
||||
__author__ = "Ryan Kulla (rkulla AT gmail DOT com)"
|
||||
__version__ = "1.2"
|
||||
__copyright__ = "Copyright (c) 2003-2009 Ryan Kulla"
|
||||
|
||||
|
||||
import os
|
||||
import sys
|
||||
import types
|
||||
import shutil
|
||||
|
||||
|
||||
# Path/filename of the vim dictionary file to write to:
|
||||
PYDICTION_DICT = r'complete-dict'
|
||||
# Path/filename of the vim dictionary backup file:
|
||||
PYDICTION_DICT_BACKUP = r'complete-dict.last'
|
||||
|
||||
# Sentintal to test if we should only output to stdout:
|
||||
STDOUT_ONLY = False
|
||||
|
||||
|
||||
def get_submodules(module_name, submodules):
|
||||
"""Build a list of all the submodules of modules."""
|
||||
|
||||
# Try to import a given module, so we can dir() it:
|
||||
try:
|
||||
imported_module = my_import(module_name)
|
||||
except ImportError, err:
|
||||
return submodules
|
||||
|
||||
mod_attrs = dir(imported_module)
|
||||
|
||||
for mod_attr in mod_attrs:
|
||||
if type(getattr(imported_module, mod_attr)) is types.ModuleType:
|
||||
submodules.append(module_name + '.' + mod_attr)
|
||||
|
||||
return submodules
|
||||
|
||||
|
||||
def write_dictionary(module_name):
|
||||
"""Write to module attributes to the vim dictionary file."""
|
||||
prefix_on = '%s.%s'
|
||||
prefix_on_callable = '%s.%s('
|
||||
prefix_off = '%s'
|
||||
prefix_off_callable = '%s('
|
||||
|
||||
try:
|
||||
imported_module = my_import(module_name)
|
||||
except ImportError, err:
|
||||
return
|
||||
|
||||
mod_attrs = dir(imported_module)
|
||||
|
||||
# Generate fully-qualified module names:
|
||||
write_to.write('\n--- import %s ---\n' % module_name)
|
||||
for mod_attr in mod_attrs:
|
||||
if callable(getattr(imported_module, mod_attr)):
|
||||
# If an attribute is callable, show an opening parentheses:
|
||||
format = prefix_on_callable
|
||||
else:
|
||||
format = prefix_on
|
||||
write_to.write(format % (module_name, mod_attr) + '\n')
|
||||
|
||||
# Generate submodule names by themselves, for when someone does
|
||||
# "from foo import bar" and wants to complete bar.baz.
|
||||
# This works the same no matter how many .'s are in the module.
|
||||
if module_name.count('.'):
|
||||
# Get the "from" part of the module. E.g., 'xml.parsers'
|
||||
# if the module name was 'xml.parsers.expat':
|
||||
first_part = module_name[:module_name.rfind('.')]
|
||||
# Get the "import" part of the module. E.g., 'expat'
|
||||
# if the module name was 'xml.parsers.expat'
|
||||
second_part = module_name[module_name.rfind('.') + 1:]
|
||||
write_to.write('\n--- from %s import %s ---\n' %
|
||||
(first_part, second_part))
|
||||
for mod_attr in mod_attrs:
|
||||
if callable(getattr(imported_module, mod_attr)):
|
||||
format = prefix_on_callable
|
||||
else:
|
||||
format = prefix_on
|
||||
write_to.write(format % (second_part, mod_attr) + '\n')
|
||||
|
||||
# Generate non-fully-qualified module names:
|
||||
write_to.write('\n--- from %s import * ---\n' % module_name)
|
||||
for mod_attr in mod_attrs:
|
||||
if callable(getattr(imported_module, mod_attr)):
|
||||
format = prefix_off_callable
|
||||
else:
|
||||
format = prefix_off
|
||||
write_to.write(format % mod_attr + '\n')
|
||||
|
||||
|
||||
def my_import(name):
|
||||
"""Make __import__ import "package.module" formatted names."""
|
||||
mod = __import__(name)
|
||||
components = name.split('.')
|
||||
for comp in components[1:]:
|
||||
mod = getattr(mod, comp)
|
||||
return mod
|
||||
|
||||
|
||||
def remove_duplicates(seq, keep=()):
|
||||
"""
|
||||
|
||||
Remove duplicates from a sequence while perserving order.
|
||||
|
||||
The optional tuple argument "keep" can be given to specificy
|
||||
each string you don't want to be removed as a duplicate.
|
||||
"""
|
||||
seq2 = []
|
||||
seen = set();
|
||||
for i in seq:
|
||||
if i in (keep):
|
||||
seq2.append(i)
|
||||
continue
|
||||
elif i not in seen:
|
||||
seq2.append(i)
|
||||
seen.add(i)
|
||||
return seq2
|
||||
|
||||
|
||||
def get_yesno(msg="[Y/n]?"):
|
||||
"""
|
||||
|
||||
Returns True if user inputs 'n', 'Y', "yes", "Yes"...
|
||||
Returns False if user inputs 'n', 'N', "no", "No"...
|
||||
If they enter an invalid option it tells them so and asks again.
|
||||
Hitting Enter is equivalent to answering Yes.
|
||||
Takes an optional message to display, defaults to "[Y/n]?".
|
||||
|
||||
"""
|
||||
while True:
|
||||
answer = raw_input(msg)
|
||||
if answer == '':
|
||||
return True
|
||||
elif len(answer):
|
||||
answer = answer.lower()[0]
|
||||
if answer == 'y':
|
||||
return True
|
||||
break
|
||||
elif answer == 'n':
|
||||
return False
|
||||
break
|
||||
else:
|
||||
print "Invalid option. Please try again."
|
||||
continue
|
||||
|
||||
|
||||
def main(write_to):
|
||||
"""Generate a dictionary for Vim of python module attributes."""
|
||||
submodules = []
|
||||
|
||||
for module_name in sys.argv[1:]:
|
||||
try:
|
||||
imported_module = my_import(module_name)
|
||||
except ImportError, err:
|
||||
print "Couldn't import: %s. %s" % (module_name, err)
|
||||
sys.argv.remove(module_name)
|
||||
|
||||
cli_modules = sys.argv[1:]
|
||||
|
||||
# Step through each command line argument:
|
||||
for module_name in cli_modules:
|
||||
print "Trying module: %s" % module_name
|
||||
submodules = get_submodules(module_name, submodules)
|
||||
|
||||
# Step through the current module's submodules:
|
||||
for submodule_name in submodules:
|
||||
submodules = get_submodules(submodule_name, submodules)
|
||||
|
||||
# Add the top-level modules to the list too:
|
||||
for module_name in cli_modules:
|
||||
submodules.append(module_name)
|
||||
|
||||
submodules.sort()
|
||||
|
||||
# Step through all of the modules and submodules to create the dict file:
|
||||
for submodule_name in submodules:
|
||||
write_dictionary(submodule_name)
|
||||
|
||||
if STDOUT_ONLY:
|
||||
return
|
||||
|
||||
# Close and Reopen the file for reading and remove all duplicate lines:
|
||||
write_to.close()
|
||||
print "Removing duplicates..."
|
||||
f = open(PYDICTION_DICT, 'r')
|
||||
file_lines = f.readlines()
|
||||
file_lines = remove_duplicates(file_lines, ('\n'))
|
||||
f.close()
|
||||
|
||||
# Delete the original file:
|
||||
os.unlink(PYDICTION_DICT)
|
||||
|
||||
# Recreate the file, this time it won't have any duplicates lines:
|
||||
f = open(PYDICTION_DICT, 'w')
|
||||
for attr in file_lines:
|
||||
f.write(attr)
|
||||
f.close()
|
||||
print "Done."
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
"""Process the command line."""
|
||||
|
||||
if sys.version_info[0:2] < (2, 3):
|
||||
sys.exit("You need a Python 2.x version of at least Python 2.3")
|
||||
|
||||
if len(sys.argv) <= 1:
|
||||
sys.exit("%s requires at least one argument. None given." %
|
||||
sys.argv[0])
|
||||
|
||||
if '-v' in sys.argv:
|
||||
write_to = sys.stdout
|
||||
sys.argv.remove('-v')
|
||||
STDOUT_ONLY = True
|
||||
elif os.path.exists(PYDICTION_DICT):
|
||||
# See if any of the given modules have already been pydiction'd:
|
||||
f = open(PYDICTION_DICT, 'r')
|
||||
file_lines = f.readlines()
|
||||
for module_name in sys.argv[1:]:
|
||||
for line in file_lines:
|
||||
if line.find('--- import %s ' % module_name) != -1:
|
||||
print '"%s" already exists in %s. Skipping...' % \
|
||||
(module_name, PYDICTION_DICT)
|
||||
sys.argv.remove(module_name)
|
||||
break
|
||||
f.close()
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
# Check if there's still enough command-line arguments:
|
||||
sys.exit("Nothing new to do. Aborting.")
|
||||
|
||||
if os.path.exists(PYDICTION_DICT_BACKUP):
|
||||
answer = get_yesno('Overwrite existing backup "%s" [Y/n]? ' % \
|
||||
PYDICTION_DICT_BACKUP)
|
||||
if (answer):
|
||||
print "Backing up old dictionary to: %s" % \
|
||||
PYDICTION_DICT_BACKUP
|
||||
try:
|
||||
shutil.copyfile(PYDICTION_DICT, PYDICTION_DICT_BACKUP)
|
||||
except IOError, err:
|
||||
print "Couldn't back up %s. %s" % (PYDICTION_DICT, err)
|
||||
else:
|
||||
print "Skipping backup..."
|
||||
|
||||
print 'Appending to: "%s"' % PYDICTION_DICT
|
||||
else:
|
||||
print "Backing up current %s to %s" % \
|
||||
(PYDICTION_DICT, PYDICTION_DICT_BACKUP)
|
||||
try:
|
||||
shutil.copyfile(PYDICTION_DICT, PYDICTION_DICT_BACKUP)
|
||||
except IOError, err:
|
||||
print "Couldn't back up %s. %s" % (PYDICTION_DICT, err)
|
||||
else:
|
||||
print 'Creating file: "%s"' % PYDICTION_DICT
|
||||
|
||||
|
||||
if not STDOUT_ONLY:
|
||||
write_to = open(PYDICTION_DICT, 'a')
|
||||
|
||||
main(write_to)
|
||||
Reference in New Issue
Block a user