Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More missing methods, improved documentation strings #7

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
154 changes: 131 additions & 23 deletions fakegir.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,38 @@
FAKEGIR_PATH = os.path.join(os.path.expanduser('~'), '.cache/fakegir')
XMLNS = "http://www.gtk.org/introspection/core/1.0"

GIR_TO_NATIVE_TYPEMAP = {'gboolean': 'bool',
'gint': 'int',
'guint': 'int',
'gint64': 'int',
'guint64': 'int',
'none': 'None',
'gchar': 'str',
'guchar': 'str',
'gchar*': 'str',
'guchar*': 'str',
'glong': 'long',
'gulong': 'long',
'glong64': 'long',
'gulong64': 'long',
'gfloat': 'float',
'gdouble': 'float',
'string': 'str',
'utf8': 'unicode',
'GString': 'str'}


def get_native_type(typename):
if typename[:len("const ")] == "const ":
typename = typename.replace("const ", "")

if (typename in GIR_TO_NATIVE_TYPEMAP):
return GIR_TO_NATIVE_TYPEMAP[typename]
else:
return typename

return ""


def get_docstring(callable_tag):
"""Return docstring text for a callable"""
Expand All @@ -17,6 +49,7 @@ def get_docstring(callable_tag):
return element.text.replace("\\x", 'x').encode('utf-8') + b"\n"
return ''


def get_parameter_type(element):
"""Returns the type of a parameter"""
parm_type = ""
Expand All @@ -29,6 +62,18 @@ def get_parameter_type(element):
return parm_type


def get_parameter_doc(element):
"""Returns the doc of a parameter"""
parm_doc = ""
for elem_property in element:
tag = etree.QName(elem_property)
if tag.localname == "doc":
parm_doc = element.text.replace("\\x", 'x').encode('utf-8').replace("\n", " ").strip()
break

return parm_doc


def get_parameters(element):
"""Return the parameters of a callable"""
params = []
Expand All @@ -44,43 +89,78 @@ def get_parameters(element):
param_name = param.attrib['name']

parm_type = get_parameter_type(param)
parm_doc = get_docstring(param).replace("\n", " ").strip()

if keyword.iskeyword(param_name):
param_name = "_" + param_name

if not param_name in params:
params.append( (param_name, parm_type) )
params.append((param_name, parm_doc, parm_type))
except KeyError:
pass
return params


def get_returntype(element):
"""Return the return-type of a callable"""
for elem_property in element:
tag = etree.QName(elem_property)
if tag.localname == 'return-value':
return_doc = get_docstring(elem_property).replace("\n", " ").strip()
for subelem in elem_property:
try:
subtag = etree.QName(subelem)
if subtag.localname == "type":
return (return_doc, subelem.attrib['name'])

except KeyError:
pass
return ("", "none")

def insert_function(name, args, depth, docstring=''):

def insert_function(name, args, returntype, depth, docstring='', annotation=''):
"""Returns a function as a string"""
if keyword.iskeyword(name):
name = "_" + name
arglist = ", ".join([arg[0] for arg in args])

epydoc_str = "\n".join(
["@param %s: %s" % (pname, ptype) if pname != "self" else ""
for (pname, ptype) in args])
epydoc_doc_strs = ["@param %s: %s" % (pname, pdoc)
if (len(pdoc) > 0 and pname != "self") else ""
for (pname, pdoc, ptype) in args]

epydoc_type_strs = ["@type %s: %s" % (pname, get_native_type(ptype))
if (len(ptype) > 0 and pname != "self") else ""
for (pname, pdoc, ptype) in args]

return_docstrs = []
if (returntype[1] == 'none'):
return_docstrs = ["@rtype: None"]
else:
return_docstrs = ["@returns: %s" % returntype[0],
"@rtype: %s" % get_native_type(returntype[1])]

def do_indent(lines):
return [' '*(depth+1) + l for l in lines]

from itertools import chain
full_docstr = "\n".join(
[' '*(depth+1) + l
for l in (docstring +
"\n" +
epydoc_str +
"\n").split("\n")])
return "%sdef %s(%s):\n%s\"\"\"\n%s\"\"\"\n" % (' ' * depth,
name,
arglist,
' ' * (depth + 1),
full_docstr)
do_indent(chain(docstring.split("\n"),
filter(lambda s: len(s) > 0, epydoc_doc_strs),
filter(lambda s: len(s) > 0, epydoc_type_strs),
return_docstrs,
[""],
)))

return "%s\n%sdef %s(%s):\n%s\"\"\"\n%s\"\"\"\n" % (' '*depth + annotation if len(annotation) > 0 else "",
' ' * depth,
name,
arglist,
' ' * (depth + 1),
full_docstr)


def insert_enum(element):
"""Returns an enum (class with attributes only) as text"""
"""returns an enum (class with attributes only) as text"""
enum_name = element.attrib['name']
docstring = get_docstring(element)
enum_content = "class %s:\n \"\"\"%s\"\"\"\n" % (enum_name, docstring)
Expand All @@ -96,21 +176,47 @@ def insert_enum(element):


def extract_methods(class_tag):
"""Return methods from a class element"""
"""return methods from a class element"""
methods_content = ''
for element in class_tag:
tag = etree.QName(element)
if (tag.localname == 'method') or (tag.localname == 'virtual-method'):
method_name = element.attrib['name']
docstring = get_docstring(element)
params = get_parameters(element)
returntype = get_returntype(element)

methods_content += insert_function(method_name, params, returntype,
1, docstring)

return methods_content


def extract_constructors(class_tag):
"""return the constructor methods for this class"""
class_name = class_tag.attrib["name"]
methods_content = ''
for element in class_tag:
tag = etree.QName(element)
if tag.localname == 'method':
if (tag.localname == 'constructor'):
method_name = element.attrib['name']
docstring = get_docstring(element)
params = get_parameters(element)
methods_content += insert_function(method_name, params, 1,
docstring)
returntype = ("Newly created " + class_name, class_name)

if method_name == "new":
params_init = list(params)
params_init.insert(0, ("self", "", ""))
methods_content += insert_function("__init__", params_init,
returntype, 1, docstring)

methods_content += insert_function(method_name, params,
returntype, 1, docstring, annotation="@staticmethod")
return methods_content


def build_classes(classes):
"""Order classes with correct dependency order also return external
"""order classes with correct dependency order also return external
imports"""
classes_text = ""
imports = set()
Expand Down Expand Up @@ -141,7 +247,7 @@ def build_classes(classes):


def extract_namespace(namespace):
"""Extract all information from a gir namespace"""
"""extract all information from a gir namespace"""
namespace_content = ""
classes = []
for element in namespace:
Expand All @@ -159,6 +265,7 @@ def extract_namespace(namespace):
parents.append(implement.attrib['name'])
class_content = ("\nclass %s(%s):\n \"\"\"%s\"\"\"\n"
% (class_name, ", ".join(parents), docstring))
class_content += extract_constructors(element)
class_content += extract_methods(element)
classes.append((class_name, parents, class_content))
if (tag_name == 'enumeration') or (tag_name == "bitfield"):
Expand All @@ -167,7 +274,8 @@ def extract_namespace(namespace):
function_name = element.attrib['name']
docstring = get_docstring(element)
params = get_parameters(element)
namespace_content += insert_function(function_name, params, 0,
returntype = get_returntype(element)
namespace_content += insert_function(function_name, params, returntype, 0,
docstring)
if tag_name == 'constant':
constant_name = element.attrib['name']
Expand Down
28 changes: 28 additions & 0 deletions force_cache.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/bin/bash

JEDI_PATH=$HOME/.vim/bundle/YouCompleteMe/third_party/jedi

#python fakegir.py
rm -rf $HOME/.cache/jedi

pkgs=""
echo '#/bin/env python' >/tmp/fakeprg.py
for f in ~/.cache/fakegir/gi/repository/*.py; do
pkgname=`basename $f|cut -d . -f 1`
pkgs="$pkgs $pkgname"
echo "from gi.repository import $pkgname" >> /tmp/fakeprg.py
done


for pkgname in $pkgs; do
echo Forcing cache for $pkgname
cp /tmp/fakeprg.py /tmp/${pkgname}-fakeprg.py
compl="w = ${pkgname}."
echo "$compl" >> /tmp/${pkgname}-fakeprg.py
fakeprg_lines=`wc -l /tmp/${pkgname}-fakeprg.py| cut -d ' ' -f 1`
compl_col=${#compl}

export PYTHONPATH=$HOME/.cache/fakegir
pushd $JEDI_PATH
$JEDI_PATH/sith.py -f run completions /tmp/${pkgname}-fakeprg.py $fakeprg_lines $compl_col
done