diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5e510a7..f4a9d88 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,7 +13,7 @@ If you are contributing new code, then reports via `pylint my_feature.py --reports=n` and then enable again once all issues have been corrected. Make sure that you test all parts of your code using a coverage tool such as `py-cov`. -3. Update [ACKNOWLEDGMENTS](ACKNOWLEDGMENTS.md) to make sure you get credit for +3. Update [CONTRIBUTORS](CONTRIBUTORS.md) to make sure you get credit for your contribution. 4. Update [README](README.md) to explain how to use your feature. 5. Make all your commits to your feature branch and check that all tests pass. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..98dcf08 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,2 @@ +include mydocstring/*.py +include mydocstring/tests/*.py diff --git a/README.md b/README.md index 0561ed5..d38bbcd 100644 --- a/README.md +++ b/README.md @@ -1,216 +1,81 @@ -# Docstring -[Docstring](README.md) is a small Python package that allows you to extract docstrings from -source code and display them as plain-text, markdown, or JSON data. It is meant -to serve as a basic building-block for building customized documentation -systems. Simply put, [Docstring](README.md) extracts and parses docstrings and -gives you access to their data so you can decide what you want to do with it. - -* Support for `Python` code (support `C` is planned). +# MyDocstring +[MyDocstring](README.md) is a small Python package that allows you to extract docstrings display them as either plain-text, [markdown](http://commonmark.org/), or [JSON](https://www.json.org/) data. + +* Support for Python-code (support for C-code is planned). * Support for [Google-style docstrings](http://google.github.io/styleguide/pyguide.html) * Produces [JSON](https://www.json.org/), plain-text, and [markdown](http://commonmark.org/) output for modules, classes, functions, and methods. -## Contents - * [Getting Started](#getting-started) - * [Usage](#usage) - * [Python Examples](#python-examples) - * [Installing](#installing) - * [Dependencies](#dependencies) - * [Troubleshooting](#troubleshooting) - * [Contributing](#contributing) - * [Showcase](#showcase) - * [Pull requests](#pull-requests) - * [Running tests](#running-tests) - * [License](#license) - ## Getting Started -Once [installed](#installing), you can begin extracting and converting docstrings using the -command-line interface application `docstring`. - -### Usage - -``` -$ docstring --help -docstring - -Usage: - docstring [-tmj] [-T=] - docstring -h | --help - docstring --version - -Options: - -h --help Show help (this screen). - --version Show version. - -m --markdown Output extracted docstring as Markdown. - -t --text Output extracted docstring as plain-text. - -j --json Output extracted docstring as JSON. - -T= --template= Set template for Markdown output. - -Examples: - Extract the module docstring - docstring module.py . --markdown - Extract a module function docstring - docstring module.py function --markdown - Extract a class docstring - docstring module.py Class --markdown - Extract a method docstring - docstring module.py Class.method --markdown - -Help: - Please see the issue tracker for the Github repository: - https://github.com/ooreilly/docstring -``` +You can begin extracting and converting docstrings using the command line tool +`mydocstring` that comes with package. Simply type `mydocstring --help` to see how to use it. +Let's extract the docstring from the following example code and convert it to +markdown: ```python def example_function(arg1, arg2=1): """ - This is an example of a docstring that conforms to the Google style guide. - The indentation uses four spaces (no tabs). Note that each section starts - with a header such as `Arguments` or `Returns` and its contents is indented. + This is an example of a Google-style docstring. Arguments: arg1 (`int`): This description for this argument fits on one line. arg2 (`int`, optional): This description is too long to fit on a single line. Note that it is continued by being indented. - - Returns: - - `bool` : Stating the return type here is optional. - - We can continue putting explanations in this section as long as the text - is indented. - - This text is no longer indented and therefore not part of the `Returns` - section. - - Raises: - - ValueError: This is exception is raised when arg1 and arg2 are equal. - """ - if arg1 == arg2: - raise ValueError("`arg1` and `arg2` cannot be equal.") - if arg1 > arg2: - return True - else: - return False -``` - -#### Plain-text - -Next, we extract the docstring for the function above and output it as -plain-text by calling -``` -$ docstring examples/example.py example_function --text > examples/example_py.txt - + pass ``` -Go to [examples/example.txt](examples/example_py.txt) to view the output. - -#### Markdown -To output markdown, we simply call +A more detailed example code is found in [examples/example.py](examples/example.py). ``` -$ docstring examples/example.py --markdown > examples/example_py.md - +$ docstring examples/example.py example_function --markdown > examples/example_py.md ``` Go to [examples/example_py.md](examples/example_py.md) to -view the output. - -#### Customization - -If you are not satisfied with the resulting markdown, you can provide your own +view the output. If you are not satisfied with the resulting markdown, you can provide your own [mako](http://makotemplates.org) template + ``` $ docstring examples/example.py example_function --markdown --template customization.md - ``` -Go to [docstring/templates/](docstring/templates/) to see how to make your own +Go to [mydocstring/templates/](mydocstring/templates/) to see how to make your own template. -#### JSON - -Another possibility is to output JSON data (then its up to you how you to -format the data) - -``` -$ docstring examples/example.py --json > examples/example_py.md - -``` -Go to [examples/example_py.json](examples/example_py.json) to -view the output for this example. +It is also possible to output plain-text, or JSON-data using the flags args +`--text` and `--json`. Example output can be found [here](examples/). -### Installing -Use setup tools or pip to install this package. +## Installation +The package is available on the Python packaging index [PyPi](https://pypi.python.org/pypi) and can be installed via pip as follows. ```bash -$ pip install docstring -``` -*or* -```bash -$ sudo python setup.py install +$ pip install mydocstring ``` -### Dependencies +## Dependencies This project uses: * [docopt](http://docopt.org/) for the command-line interface application. * [mako](http://www.makotemplates.org/) for producing markdown templates. * [pytest](https://docs.pytest.org/en/latest/) for testing. -### Troubleshooting +## Issues If you are having problems extracting your docstrings, or parts of their content -end up missing. Please make sure that your are only using spaces (no tabs). -Four spaces should be used for each level of indentation as stated in PEP . +end up missing, then please make sure that your are only using spaces (no tabs). +Four spaces should be used for each level of indentation. Also, make sure that you conform to the [Google style guide](http://google.github.io/styleguide/pyguide.html) when writing your -docstrings. It's easy to forget indentation or mess something else up! - -That said, this tool likely breaks for some edge-cases and it is completely -possible that you have discovered a bug. Please see the issue tracker to see if -this problem is known. If not, please submit a new issue with a minimum example -that introduces the problem and also what the excepted output is supposed to be. +docstrings. +Otherwise, please submit a new issue using the [issue tracker](https://github.com/ooreilly/mydocstring/issues) and explain the problem. ## Contributing -### Showcase +Contributions are more than welcome. Please reach out via the issue tracker to +discuss and also see [here](contributing.md) for +some guidelines. + +## Showcase If you end up using this tool in your project in one way or another. I would love to hear about it and showcase it here. Please go ahead and make a pull request. -## Pull requests -You are more than welcome to contribute to this project. In fact, getting some help -developing and maintaining this package would be fantastic! Please use the issue -tracker to look for any issues you think you can resolve, or feel free to post a -new issue if you want to suggest a new feature. Ideally, post a feature -request to discuss it before you implement it and make a pull request. - -If you are contributing new code, then -1. First, fork the repository and create your own branch. Commit your changes to - this branch. -2. In your commit, please include a test case that demonstrates that your - contribution works as expected using `pytest`. - Having a test case will make it easier to review your code and therefore lead - to your pull request being approved faster. Please also use `pylint` to check - for issues. During development it is usually simplest to disable - reports via `pylint my_feature.py --reports=n` and then enable again once all - issues have been corrected. Make sure that you test all parts of your code - using a coverage tool such as `py-cov`. -3. Update [ACKNOWLEDGMENTS](ACKNOWLEDGMENTS.md) to make sure you get credit for - your contribution. -4. Update [README](README.md) to explain how to use your feature. -5. Make all your commits to your feature branch and check that all tests pass. - Then go ahead and submit a pull request! - -## Running tests -[Pytest](https://docs.pytest.org/en/latest/) is used for testing. Currently, the -tests are quite limited in scope. More tests should definitely be developed to identify -edge cases and facilitate future code refactoring. - -To run the tests, go to the `docstring` directory and type - -```bash -$ pytest -``` ## Acknowledgments These are some projects that inspired me to develop this tool. * [pdoc](https://github.com/BurntSushi/pdoc/) A tool for auto-generating API diff --git a/gdocstr/templates/class.md b/gdocstr/templates/class.md deleted file mode 100644 index 2022c8b..0000000 --- a/gdocstr/templates/class.md +++ /dev/null @@ -1,7 +0,0 @@ -# % ${class['name']} -${class['description']} - -%if docstr['has_methods'] -## Methods - -%endif diff --git a/gdocstr/__init__.py b/mydocstring/__init__.py similarity index 100% rename from gdocstr/__init__.py rename to mydocstring/__init__.py diff --git a/gdocstr/command.py b/mydocstring/command.py similarity index 100% rename from gdocstr/command.py rename to mydocstring/command.py diff --git a/gdocstr/docstring.py b/mydocstring/docstring.py similarity index 62% rename from gdocstr/docstring.py rename to mydocstring/docstring.py index 2f756db..b8d53fa 100644 --- a/gdocstr/docstring.py +++ b/mydocstring/docstring.py @@ -1,17 +1,18 @@ """ -docstring +docstringout Usage: - docstring [-tmj] - docstring -h | --help - docstring --version + docstringout [-tmj] [-T=] + docstringout -h | --help + docstringout --version Options: -h --help Show help (this screen). --version Show version. - -m --markdown Render docstring as Markdown. - -t --text Render docstring as text. - -j --json Render docstring as JSON. + -m --markdown Output extracted docstring as Markdown. + -t --text Output extracted docstring as plain-text. + -j --json Output extracted docstring as JSON. + -T= --template= Set template for Markdown output. Examples: Extract the module docstring @@ -25,7 +26,7 @@ Help: Please see the issue tracker for the Github repository: - https://github.com/ooreilly/docstring + https://github.com/ooreilly/docstringout """ from docopt import docopt from . import command diff --git a/gdocstr/extract.py b/mydocstring/extract.py similarity index 94% rename from gdocstr/extract.py rename to mydocstring/extract.py index 579ec88..520e7e2 100644 --- a/gdocstr/extract.py +++ b/mydocstring/extract.py @@ -135,7 +135,11 @@ def find(self, pattern): signature = matches[0][2] indent = len(matches[0][3]) docstring = remove_indent(matches[0][4], indent) - source = textwrap.dedent('def ' + function + signature + ':\n' + matches[0][5]) + if self.dtype == 'function' or self.dtype == 'method': + source = textwrap.dedent('def ' + function + signature + ':\n' + + matches[0][5]) + else: + source = '' out = {} out['class'] = cls @@ -155,7 +159,7 @@ class PyExtract(Extract): """ def extract_function(self): - pattern = (r'^\s*()def\s(%s)(\((?!self)[:=,\s\w]*\)):' % self.funcname + pattern = (r'^\s*()def\s(%s)(\((?!self).*\)):.*' % self.funcname + r'\n*(\s+)"""([\w\W]*?)"""\n((\4.*\n+)+)?') return self.find(pattern) @@ -166,7 +170,7 @@ def extract_class(self): def extract_method(self): pattern = (r'class\s+(%s)\(?\w*\)?:[\n\s]+[\w\W]*?' % self.classname + - r'[\n\s]+def\s+(%s)(\(self[:=\w,\s]*\)):\n' % self.funcname + + r'[\n\s]+def\s+(%s)(\(self.*\)):.*\n' % self.funcname + r'(\s+)"""([\w\W]*?)"""\n((?:\4.*\n+)+)?') return self.find(pattern) diff --git a/mydocstring/fixtures/example.py b/mydocstring/fixtures/example.py new file mode 100644 index 0000000..926db35 --- /dev/null +++ b/mydocstring/fixtures/example.py @@ -0,0 +1,60 @@ +""" +Module docstring +""" + +def function_with_docstring(arg1, arg2=True): + """Short description. + Example of a function with a doc string. + + Args: + arg1(type): description for arg1. + arg2 : description for arg2 + that spans multiple lines. + + Returns: + bool: `True` or `False`. Defaults to `True`. + + The return section can also have a detailed description that spans + multiple lines. It is important that this description is indented. + + """ + pass + +class ExampleOldClass: + """ + An example of a docstring for an old-style class. + """ + + def __init__(self): + """ + Description of the __init__ function. + + """ + pass + + def class_function_with_docstring(self, arg1, arg2): + """ + Description of a class function. + + Args: + arg1(type) : description for arg1. + arg2 : description for arg1. + + """ + pass + +class ExampleNewClass(object): + """ + An example of a docstring for a new-style class. + """ + def __init__(self): + """ + Example of a docstring for the init function. + """ + pass + +def __init__(arg1): + """ + Example of docstring for a function with the same name as a method. + """ + pass diff --git a/gdocstr/parse.py b/mydocstring/parse.py similarity index 90% rename from gdocstr/parse.py rename to mydocstring/parse.py index c942a56..9054cc7 100644 --- a/gdocstr/parse.py +++ b/mydocstring/parse.py @@ -22,10 +22,6 @@ class DocString(object): def __init__(self, docstring, config=None): self.header = {} - # Copy header data from docstring - #for doc in docstring: - # if doc != 'docstring': - # self.header[doc] = docstring[doc] self.docstring = docstring self.data = [] self._config = config @@ -80,37 +76,19 @@ def __str__(self): """ This method should be overloaded to specify how to output to plain-text. """ - #TODO: move function signature - #txt = '' - #if self.header['class']: - # txt += self.header['class'] - # if self.header['function']: - # txt += '.' - #for prop in ['function', 'signature']: - # if prop in self.header: - # txt += self.header[prop] - #txt += self.docstring return self.docstring - def __markdown__(self, filename=None): + def markdown(self): """ - Output docstring as markdown using a template. + Output data relevant data needed for markdown rendering. Args: filename (str, optional) : select template to use for markdown rendering. """ - from mako.template import Template - if not filename: - filename = self._config['template'] - template = Template(filename=filename) data = self.data headers = self._config['headers'].split('|') - hd1 = '#' - hd2 = '##' - hd3 = '###' - return template.render(header=self.header, sections=data, - headers=headers, h1=hd1, h2=hd2, h3=hd3) + return headers, data class GoogleDocString(DocString): @@ -129,8 +107,6 @@ def __init__(self, docstring, config=None): config['indent'] = 4 config['delimiter'] = ':' config['arg_delimiter'] = ': ' - config['template'] = os.path.join(os.path.dirname(__file__), - 'templates/google_docstring.md') super(GoogleDocString, self).__init__(docstring, config) diff --git a/gdocstr/templates/google_docstring.md b/mydocstring/templates/google_docstring.md similarity index 88% rename from gdocstr/templates/google_docstring.md rename to mydocstring/templates/google_docstring.md index 5ac62be..e51e181 100644 --- a/gdocstr/templates/google_docstring.md +++ b/mydocstring/templates/google_docstring.md @@ -1,6 +1,5 @@ ## -*- coding: utf-8 -*- - %if header['function']: %if header['class']: ${h1} ${header['class']}.${header['function']} @@ -20,10 +19,16 @@ class ${header['class']}${header['signature']}: %for section in sections: %if section['header']: ${h2} ${section['header']} + %else: +--- %endif %if section['args']: %for arg in section['args']: + %if arg['field']: * **${arg['field']}** ${arg['signature']} : ${arg['description']} + %else: +* ${arg['description']} + %endif %endfor %endif ${section['text']} @@ -35,4 +40,3 @@ ${h2} Source ${header['source']} ``` %endif - diff --git a/gdocstr/tests/__init__.py b/mydocstring/tests/__init__.py similarity index 100% rename from gdocstr/tests/__init__.py rename to mydocstring/tests/__init__.py diff --git a/gdocstr/tests/test_extract.py b/mydocstring/tests/test_extract.py similarity index 100% rename from gdocstr/tests/test_extract.py rename to mydocstring/tests/test_extract.py diff --git a/gdocstr/tests/test_parse.py b/mydocstring/tests/test_parse.py similarity index 100% rename from gdocstr/tests/test_parse.py rename to mydocstring/tests/test_parse.py diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..cab44fe --- /dev/null +++ b/setup.py @@ -0,0 +1,17 @@ +from setuptools import setup + +setup(name='mydocstring', + version='0.1.0', + description="""A tool for extracting and converting Google-style docstrings to + plain-text, markdown, and JSON.""", + url='http://github.com/ooreilly/mydocstring', + author="Ossian O'Reilly", + license='MIT', + packages=['mydocstring'], + install_requires=['mako', 'docopt'], + entry_points = { + 'console_scripts': [ + 'mydocstring=mydocstring.docstring:main', + ], + }, + zip_safe=False)