def _get_module_commands(module):
# type: (ast.Module) -> typing.Generator[_EntryPoint, None, None]
"""Yield all Command objects represented by the python module.
Module commands consist of a docopt-style module docstring and a callable
Command class.
Args:
module: An ast.Module object used to retrieve docopt-style commands.
Yields:
Command objects that represent entry points to append to setup.py.
"""
cls = next((n for n in module.body
if isinstance(n, ast.ClassDef) and n.name == 'Command'), None)
if not cls:
return
methods = (n.name for n in cls.body if isinstance(n, ast.FunctionDef))
if '__call__' not in methods:
return
docstring = ast.get_docstring(module)
for commands, _ in usage.parse_commands(docstring):
yield _EntryPoint(commands[0], next(iter(commands[1:]), None), None)
python类get_docstring()的实例源码
def _get_class_commands(module):
# type: (ast.Module) -> typing.Generator[_EntryPoint, None, None]
"""Yield all Command objects represented by python classes in the module.
Class commands are detected by inspecting all callable classes in the
module for docopt-style docstrings.
Args:
module: An ast.Module object used to retrieve docopt-style commands.
Yields:
Command objects that represent entry points to append to setup.py.
"""
nodes = (n for n in module.body if isinstance(n, ast.ClassDef))
for cls in nodes:
methods = (n.name for n in cls.body if isinstance(n, ast.FunctionDef))
if '__call__' in methods:
docstring = ast.get_docstring(cls)
for commands, _ in usage.parse_commands(docstring):
yield _EntryPoint(commands[0], next(iter(commands[1:]), None),
cls.name)
def _get_function_commands(module):
# type: (ast.Module) -> typing.Generator[_EntryPoint, None, None]
"""Yield all Command objects represented by python functions in the module.
Function commands consist of all top-level functions that contain
docopt-style docstrings.
Args:
module: An ast.Module object used to retrieve docopt-style commands.
Yields:
Command objects that represent entry points to append to setup.py.
"""
nodes = (n for n in module.body if isinstance(n, ast.FunctionDef))
for func in nodes:
docstring = ast.get_docstring(func)
for commands, _ in usage.parse_commands(docstring):
yield _EntryPoint(commands[0], next(iter(commands[1:]), None),
func.name)
def get_function_markdown(node):
"""Parse a function node."""
output = ""
output += "#### " + node.name + "("
if len(node.args.args) > 0:
output += ", ".join(
str(x.arg) for x in node.args.args)
output += ')'
output += '\n'
output += '\n'
doc_string = ast.get_docstring(node)
if doc_string:
output += "> " + doc_string + ""
else:
output += "> No docstring found."
output += '\n'
output += '\n'
return output
def visit_Module(self, node):
obj = {
'type': 'module',
'docstring': self.get_docstring(node),
'classes': [],
'functions': [],
'variables': [],
'imports': [],
}
for node in imap(self.visit, node.body):
if node['type'] == 'function':
obj['functions'].append(node)
elif node['type'] == 'class':
obj['classes'].append(node)
elif node['type'] == 'assign':
obj['variables'].append(node)
elif node['type'] in ('import', 'import_from'):
obj['imports'].append(node)
elif node['type'] in ('expr', ):
continue
return obj
def visit_ClassDef(self, node):
obj = {
'type': 'class',
'name': node.name,
'docstring': self.get_docstring(node),
'bases': list(ifilter(lambda k: k.get('name') != 'object', [
{'name': i.id} if isinstance(i, ast.Name) else self.visit(i) for i in node.bases
])),
'attributes': [],
'functions': [],
}
for node in imap(self.visit, node.body):
if node['type'] == 'function':
obj['functions'].append(node)
elif node['type'] == 'assign':
obj['attributes'].append(node)
return obj
def module_from_ast(self, module_name, filename, t):
code = self.compiler.code_for_module(module_name, filename, t)
module = types.ModuleType(module_name, ast.get_docstring(t))
self.interpreter.run(code, module.__dict__, None)
return module
def module_from_ast(module_name, filename, t):
code = compiler.code_for_module(module_name, filename, t)
module = types.ModuleType(module_name, ast.get_docstring(t))
byterun.interpreter.run(code, module.__dict__, None)
return module
def compile_function(self, t):
self.load_const(ast.get_docstring(t))
for arg in t.args.args:
self.varnames[arg.arg]
if t.args.vararg: self.varnames[t.args.vararg.arg]
if t.args.kwarg: self.varnames[t.args.kwarg.arg]
assembly = self(t.body) + self.load_const(None) + op.RETURN_VALUE
return self.make_code(assembly, t.name,
len(t.args.args), t.args.vararg, t.args.kwarg)
def compile_class(self, t):
docstring = ast.get_docstring(t)
assembly = ( self.load('__name__') + self.store('__module__')
+ self.load_const(t.name) + self.store('__qualname__')
+ (no_op if docstring is None else
self.load_const(docstring) + self.store('__doc__'))
+ self(t.body)
+ self.load_const(None) + op.RETURN_VALUE)
return self.make_code(assembly, t.name, 0, False, False)
def module_from_ast(module_name, filename, t):
code = code_for_module(module_name, filename, t)
module = types.ModuleType(module_name, ast.get_docstring(t))
exec(code, module.__dict__)
return module
def compile_function(self, t):
self.load_const(ast.get_docstring(t))
for arg in t.args.args:
self.varnames[arg.arg]
assembly = self(t.body) + self.load_const(None) + op.RETURN_VALUE
return self.make_code(assembly, t.name, len(t.args.args))
def compile_class(self, t):
docstring = ast.get_docstring(t)
assembly = ( self.load('__name__') + self.store('__module__')
+ self.load_const(t.name) + self.store('__qualname__')
+ (no_op if docstring is None else
self.load_const(docstring) + self.store('__doc__'))
+ self(t.body) + self.load_const(None) + op.RETURN_VALUE)
return self.make_code(assembly, t.name, 0)
def module_from_ast(module_name, filename, t):
code = code_for_module(module_name, filename, t)
module = types.ModuleType(module_name, ast.get_docstring(t))
exec(code, module.__dict__)
return module
def module_from_ast(module_name, filename, t):
code = code_for_module(module_name, filename, t)
module = types.ModuleType(module_name, ast.get_docstring(t))
exec(code, module.__dict__)
return module
def module_from_ast(module_name, filename, t):
code = code_for_module(module_name, filename, t)
module = types.ModuleType(module_name, ast.get_docstring(t))
exec(code, module.__dict__)
return module
def compile_class(self, t):
docstring = ast.get_docstring(t)
assembly = ( self.load('__name__') + self.store('__module__')
+ self.load_const(t.name) + self.store('__qualname__')
+ (no_op if docstring is None else
self.load_const(docstring) + self.store('__doc__'))
+ self(t.body) + self.load_const(None) + op.RETURN_VALUE)
return self.make_code(assembly, t.name, 0)
def module_from_ast(module_name, filename, t):
code = code_for_module(module_name, filename, t)
module = types.ModuleType(module_name, ast.get_docstring(t))
exec(code, module.__dict__)
return module
def compile_function(self, t):
self.load_const(ast.get_docstring(t))
for arg in t.args.args:
self.varnames[arg.arg]
assembly = self(t.body) + self.load_const(None) + op.RETURN_VALUE
return self.make_code(assembly, t.name, len(t.args.args))
def compile_class(self, t):
docstring = ast.get_docstring(t)
assembly = ( self.load('__name__') + self.store('__module__')
+ self.load_const(t.name) + self.store('__qualname__')
+ (no_op if docstring is None else
self.load_const(docstring) + self.store('__doc__'))
+ self(t.body) + self.load_const(None) + op.RETURN_VALUE)
return self.make_code(assembly, t.name, 0)
def module_from_ast(module_name, filename, t):
code = code_for_module(module_name, filename, t)
module = types.ModuleType(module_name, ast.get_docstring(t))
exec(code, module.__dict__)
return module
def visit_FunctionDef(self, node, is_async=False):
docstring = f"\"{get_docstring(node, True)}\""
body = node.body
if docstring:
body = body[1:] # Don't mention it
summary = ""\
+ f"{interpret_async(is_async)} function called \"{node.name}\""\
+ f", taking {self.visit(node.args)}"\
+ (f", and returning a value of {self.visit(node.returns)}" if node.returns else "")\
+ (f", with the docstring of {docstring}" if docstring else "")\
+ f", with a body of {self.visit(body)}"
return summary
def find_info(*path_parts):
finder = MetaDataFinder()
node = ast.parse(read(*path_parts).encode('utf-8'))
finder.visit(node)
info = finder.data
info['docstring'] = ast.get_docstring(node)
return info
def class_check(node, kw=False):
'''
Class specific check
Action - check private method, move to utils
check docstring
scan for class - recursive class check
scan for function - function check
'''
status = True
for child in ast.iter_child_nodes(node):
if isinstance(child, ast.FunctionDef):
if kw and child.name.startswith("_") and child.name != "__init__":
print node.name, child.name, "should move to utils"
status = False
tmp_status = func_check(child, kw)
status &= tmp_status
elif isinstance(child, ast.ClassDef):
tmp_status = class_check(child, kw)
status &= tmp_status
if ast.get_docstring(node) is None:
# check for docstring
print node.name, "doesn't contain any docstring"
status = False
return status
def visit_FunctionDef(self, node):
name = node.name
args = self.visit(node.args)
body = [self.visit(x) for x in node.body]
docstring = ast.get_docstring(node)
if docstring:
body = body[1:]
if hasattr(node, "returns"):
returns = self.visit(node.returns)
else:
returns = None
# TODO: decorator_list
return cpp.FunctionDef(name=name, args=args, body=body, docstring=docstring, returns=returns)
def visit_ClassDef(self, node):
name = node.name
bases = [self.visit(x) for x in node.bases]
if six.PY3:
keywords = [self.visit(x) for x in node.keywords]
body = [self.visit(x) for x in node.body]
docstring = ast.get_docstring(node)
if docstring:
body = body[1:]
# TODO: decorator_list
if six.PY3:
return cpp.ClassDef(name=name, bases=bases, keywords=keywords, body=body, docstring=docstring)
else:
return cpp.ClassDef(name=name, bases=bases, body=body, docstring=docstring)
def coerce_file(fn):
"""Coerce content of given file to something useful for setup(), turn :
.py into mock object with description and version fields,
.md into rst text. Remove images with "nopypi" alt text along the way.
:url: https://github.com/Kraymer/setupgoon
"""
import ast
import os
import re
import subprocess # noqa
text = open(os.path.join(os.path.dirname(__file__), fn)).read()
if fn.endswith('.py'): # extract version, docstring etc out of python file
mock = type('mock', (object,), {})()
for attr in ('version', 'author', 'author_email', 'license'):
regex = r'^__%s__\s*=\s*[\'"]([^\'"]*)[\'"]$' % attr
m = re.search(regex, text, re.MULTILINE)
setattr(mock, attr, m.group(1) if m else None)
mock.docstring = ast.get_docstring(ast.parse(text))
return mock
if fn.endswith('md') and 'upload' in sys.argv: # convert md to rest on pypi package upload
text = '\n'.join([l for l in text.split('\n') if '![nopypi' not in l])
p = subprocess.Popen(['pandoc', '-t', 'rst'], stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
text, stderr = p.communicate(text)
return text
def test_get_docstring(self):
node = ast.parse('def foo():\n """line one\n line two"""')
self.assertEqual(ast.get_docstring(node.body[0]),
'line one\nline two')
def _add_crc(self, node, kind, name):
self.current_crc = CRC(name, kind)
docstring = ast.get_docstring(node) or ""
for line in docstring.split('\n'):
self.get_collaborator(line)
self.get_responsibility(line)
self._crcs.append(self.current_crc)
def get_class_markdown(node):
"""Parse a class node."""
output = ""
if node.name.lower().strip() != "meta":
output += '--------------------'
output += '\n'
output += "## " + node.name
output += '\n'
doc_string = ast.get_docstring(node)
if doc_string:
output += "" + doc_string + ""
output += '\n'
output += '\n'
return output