Repository: opsdroid/opsdroid

Issue:
Add Google Style Docstrings
We should implement Google Style Docstrings to every function, method, class in opsdroid. This style will support existing documentation and will help in the future by generating documentation automatically.

This consists in a bit of effort so this issue can be worked by more than one contributor, just make sure that everyone knows what you are working on in order to avoid other contributors spending time on something that you are working on.

If you are unfamiliar with the Google Style Docstrings I'd recommend that you check these resources:

 - [Sphix 1.8.0+ - Google Style Docstrings](https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html)



Docstrings that need to be updated:

- main.py
  - [x] configure_lang
  - [ ] configure_log
  - [ ] get_logging_level
  - [ ] check_dependencies
  - [ ] print_version
  - [ ] print_example_config
  - [ ] edit_files
  - [x] welcome_message
- ~~helper.py~~
  - [x] get_opsdroid
  - [x] del_rw
  - [x] move_config_to_appdir
- memory.py
  - [x] Memory
  - [x] get
  - [x] put
  - [x] _get_from_database
  - [x] _put_to_database
- message.py
  - [x] Message
  - [x]  __init__
  - [x]  _thinking_delay
  - [x]  _typing delay
  - [x]  respond
  - [x]  react
- web.py
  - [ ] Web
  - [x] get_port
  - [x] get_host
  - [x]  get_ssl_context
  - [ ]  start
  - [ ]  build_response
  - [ ]  web_index_handler
  - [ ]  web_stats_handler
- matchers.py
  - [ ] match_regex
  - [ ] match_apiai_action
  - [ ] match_apiai_intent
  - [ ]  match_dialogflow_action
  - [ ]  match_dialogflow_intent
  - [ ] match_luisai_intent
  - [ ] match_rasanlu
  - [ ] match_recastai
  - [ ] match_witai
  - [ ] match_crontab
  - [ ] match_webhook
  - [ ] match_always
- core.py
  - [ ] OpsDroid
  - [ ] default_connector
  - [ ] exit
  - [ ] critical
  - [ ]  call_stop
  - [ ] disconnect
  - [ ] stop
  - [ ] load
  - [ ] start_loop
  - [x] setup_skills
  - [ ] train_parsers
  - [ ] start_connector_tasks
  - [ ] start_database
  - [ ] run_skill
  - [ ] get_ranked_skills
  - [ ] parse
- loader.py
  - [ ] Loader
  - [x] import_module_from_spec
  - [x] import_module
  - [x] check_cache
  - [x] build_module_import_path
  - [x] build_module_install_path
  - [x] git_clone
  - [x] git_pull
  - [x] pip_install_deps
  - [x] create_default_config
  - [x] load_config_file
  - [ ] envvar_constructor
  - [ ] include_constructor
  - [x] setup_modules_directory
  - [x] load_modules_from_config
  - [x] _load_modules
  - [x] _install_module
  - [x] _update_module
  - [ ] _install_git_module
  - [x] _install_local_module









---- ORIGINAL POST ---- 
I've been wondering about this for a while now and I would like to know if we should replace/update all the docstrings in opsdroid with the Google Style doc strings. 

I think this could help new and old contributors to contribute and commit to opsdroid since the Google Style docstrings give more information about every method/function and specifies clearly what sort of input the function/method expects, what will it return and what will be raised (if applicable).

The downsize of this style is that the length of every .py file will increase due to the doc strings, but since most IDE's allow you to hide those fields it shouldn't be too bad.

Here is a good example of Google Style Doc strings:  [Sphix 1.8.0+ - Google Style Docstrings](http://www.sphinx-doc.org/en/master/ext/example_google.html)

I would like to know what you all think about this idea and if its worth spending time on it.


Discussion:
Yes we should definitely do this!

It can also be really useful for automatically generating reference documentation. 
Awesome I'll wait a few days to see if anyone is opposed to this idea or if they would like to give some advice/comment on the issue. 

If in a few days no one says anything I'll edit this issue just to explain more in depth what we expect of the comments and how to do it - I'd recommend dividing opsdroid per each .py file so different people can contribute to the issue 😄 
I like the idea. Is it possible to add a test that inspects the doc strings,  and fails if they don't match the format? If so, would Jacob be happy with test coverage "reducing" in the short term as this test was added,  but before all the doc strings complied?



On 29 April 2018 2:42:05 am AEST, "Fábio Rosado" <notifications@github.com> wrote:
>Awesome I'll wait a few days to see if anyone is opposed to this idea
>or if they would like to give some advice/comment on the issue. 
>
>If in a few days no one says anything I'll edit this issue just to
>explain more in depth what we expect of the comments and how to do it -
>I'd recommend dividing opsdroid per each .py file so different people
>can contribute to the issue 😄 
>
>-- 
>You are receiving this because you are subscribed to this thread.
>Reply to this email directly or view it on GitHub:
>https://github.com/opsdroid/opsdroid/issues/532#issuecomment-385189370

-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.
Yes I'm happy with that approach. 

I've been thinking about it and I think there are two reasons why anyone would want to do this. The first is for autogenerating documentation, the second is making it easier for people to contribute. 

As you said you are intending this to help people contribute, and I definitely agree. I just want to be clear on why we are doing this beyond it just being a thing that some projects do. 

We currently run `pydocstyle` as part of the lint suite. I wonder if there is a way of telling it to enforce this docstring style?
I'm not sure if it's possible to enforce google doc style in the lint, but I know that you can run tests on the docstrings like @go8ose  suggested, Sphinx has a command for this (it uses the doctest module), but this tests might provide some issues and headaches.

The doctests will use the string representation present in the docstring to run the tests, if the result is not consistent like... a function that deals with dates for example and uses date.now() this test will always fail.
Another example would be running doctests with dictionaries, these tests will mostly fail due to the unsorted nature of dicts, the only way to make them pass would be to sort the dict all the time.  

One way to work around it would be to just test some docstrings and not others. In Sphinx you can just add the command: 

```
..doctest::
  >>> foo()
  bar
```

Finally, I believe that all the tests that we have at the moment do a very good job at testing every single piece of code in opsdroid so perhaps adding the doctests would be extra effort for no real gain - these will test what it's being tested already.

--EDIT--

I've updated my first post with all the functions,classes and methods that need to be updated, let me know if you need some added in or removed 👍 
Hi Fabio,

I'm not suggesting we add more tests in the form of doctests. That would indeed be a waste of effort. I'm suggesting we check conformance with the google style doc strings.

Jacob suggested seeing if this can be checked in the linting run. That is a good idea,  linting is what I should have suggested initially.

Cheers, 
Geoff

On 30 April 2018 5:51:38 pm AEST, "Fábio Rosado" <notifications@github.com> wrote:
>I'm not sure if it's possible to enforce google doc style in the lint,
>but I know that you can run tests on the docstrings like @go8ose 
>suggested, Sphinx has a command for this (it uses the doctest module),
>but this tests might provide some issues and headaches.
>
>The doctests will use the string representation present in the
>docstring to run the tests, if the result is not consistent like... a
>function that deals with dates for example and uses date.now() this
>test will always fail.
>Another example would be running doctests with dictionaries, these
>tests will mostly fail due to the unsorted nature of dicts, the only
>way to make them pass would be to sort the dict all the time.  
>
>One way to work around it would be to just test some docstrings and not
>others. In Sphinx you can just add the command: 
>
>``` ..doctest::
>>>> foo()
>bar
>```
>
>Finally, I believe that all the tests that we have at the moment do a
>very good job at testing every single piece of code in opsdroid so
>perhaps adding the doctests would be extra effort for no real gain -
>these will test what it's being tested already.
>
>-- 
>You are receiving this because you were mentioned.
>Reply to this email directly or view it on GitHub:
>https://github.com/opsdroid/opsdroid/issues/532#issuecomment-385332374

-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.
This tool looks like it tests the docstrings against the google convention. We should explore it more.

https://github.com/terrencepreilly/darglint
Hi Fabio,
I like your idea, i new here on this project i can try to do something and make a pull request.
For my part i'm going to begin with **helper.py** it's Thk ok for you ?
Thk best regards
Heya @sims34 yeah that would be much appreciated, let me know in gitter if you need any help with this 👍 
Hi Fabio, 
I am new here on this project. I was hoping I could help out with main.py
Regards
Hey @purvaudai, please go ahead!
Hello @purvaudai did you manage to work on `main.py`? If you are stuck with something let us know, we would be happy to help you getting started 👍 
Hi Guys is anyone working on this issue
@mraza007 not currently. Please go ahead.
Sure I will start working on this issue. Is there a way that you can assign this issue to me and on what files do I have to add google style doc string functions

Sorry for the lack of replies from my side. I tried solving this issue but
got confused, so I decided to look through the docs again, and I got
carried away learning. I am sorry for the lack of professionalism from my
side.

On Mon, 25 Jun 2018 at 19:33, Muhammad <notifications@github.com> wrote:

> Sure I will start working on this issue. Is there a way that you can
> assign this issue to me and on what files do I have to add google style doc
> string functions
>
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub
> <https://github.com/opsdroid/opsdroid/issues/532#issuecomment-399963131>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AeXNt1F1hUU9JhsW2bl75KQG7SRQEceRks5uAO2_gaJpZM4TqkMs>
> .
>


-- 
Purva Udai Singh

@purvaudai Hey are working on this issue do you want to continue
Hi guys I'd love to contribute too.  
@mraza007 @purvaudai  I know you guys are working on this, but if you need my help with any of the file, I'll be more than happy to contribute.
@mraza007 @purvaudai @NikhilRaverkar Thanks for all wanting to contribute! There is a lot to be done on this issue so I strongly recommend picking a file and starting work on it. 

Don't worry too much about duplicates, it's unlikely to happen given the number of methods that need updating. I would also be happy for you to submit lots of small PRs. Just pick a few methods, update the docstrings and raise a PR.
Yup I think that would be a great idea
@purvaudai  Don't worry my friend sometimes these things happen, if you want to contribute to opsdroid in the future we will be glad to help you 👍 

@mraza007  @NikhilRaverkar  If you guys need any help, let us know. You can work on different files if you want and if something is not clear feel free to hit us up either in here or our [gitter channel](https://gitter.im/opsdroid/developers)
Sure I just joined the channel I will start working on this over the weekend
I’ll start working on this over the weekend.

Thanks a lot,
Nikhil 

> On Jun 28, 2018, at 10:44 AM, Muhammad <notifications@github.com> wrote:
> 
> Sure I just joined the channel I will start working on this over the week
> 
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub, or mute the thread.

I would like to contribute to this. For starters I was thinking about taking the web.py file. :smile:
Hello, please go ahead and let us know if you need any help 
@FabioRosado Can I grab message.py? This would be my first issue!
@archime please go ahead! Let me know if you need any help with this issue. Also, welcome to the project 👍
Hey, I'd like to add couple of docstrings, however I've got a question first.
The Google style guide in the description seems to be deprecated.
Should I reference this one https://github.com/google/styleguide/blob/gh-pages/pyguide.md instead?
Hello @kritokrator Thanks for showing interest in this matter. 
The sphinx documentation has an up to date style. We are not using typehints in our codebase yet so we will be specifying the type as:


```
Args:
   arg1 (String): This arg does things
   arg2 (Boolean, optional): This arg can be true, its optional
```

This is a very brief explanation but should get you started, I also recommend you check the [Facebook Connector](https://github.com/opsdroid/opsdroid/blob/master/opsdroid/connector/facebook/__init__.py) as an example of how we would like the doc strings 👍 

Resolving patch:
diff --git a/opsdroid/memory.py b/opsdroid/memory.py
--- a/opsdroid/memory.py
+++ b/opsdroid/memory.py
@@ -7,15 +7,33 @@
 
 
 class Memory:
-    """An object to store and persist data outside of opsdroid."""
+    """A Memory object.
+
+    An object to obtain, store and persist data outside of opsdroid.
+
+    Attributes:
+        databases (:obj:`list` of :obj:`Database`): List of database objects.
+        memory (:obj:`dict`): In-memory dictionary to store data.
+
+    """
 
     def __init__(self):
-        """Create memory dictionary."""
+        """Create object with minimum properties."""
         self.memory = {}
         self.databases = []
 
     async def get(self, key):
-        """Get data object for a given key."""
+        """Get data object for a given key.
+
+        Gets the key value found in-memory or from the database(s).
+
+        Args:
+            key (str): Key to retrieve data.
+
+        Returns:
+            A data object for the given key, otherwise `None`.
+
+        """
         _LOGGER.debug(_("Getting %s from memory."), key)
         database_result = await self._get_from_database(key)
         if database_result is not None:
@@ -26,24 +44,53 @@ async def get(self, key):
         return None
 
     async def put(self, key, data):
-        """Put a data object to a given key."""
+        """Put a data object to a given key.
+
+        Stores the key and value in memory and the database(s).
+
+        Args:
+            key (str): Key for the data to store.
+            data (obj): Data object to store.
+
+        """
         _LOGGER.debug(_("Putting %s to memory"), key)
         self.memory[key] = data
         await self._put_to_database(key, self.memory[key])
 
     async def _get_from_database(self, key):
-        """Get updates from databases for a given key."""
+        """Get updates from databases for a given key.
+
+        Gets the first key value found from the database(s).
+
+        Args:
+            key (str): Key to retrieve data from a database.
+
+        Returns:
+            The first key value (data object) found from the database(s).
+            Or `None` when no database is defined or no value is found.
+
+        Todo:
+            * Handle multiple databases
+
+        """
         if not self.databases:
             return None
 
         results = []
         for database in self.databases:
             results.append(await database.get(key))
-        # TODO: Handle multiple databases
         return results[0]
 
     async def _put_to_database(self, key, data):
-        """Put updates into databases for a given key."""
+        """Put updates into databases for a given key.
+
+        Stores the key and value on each database defined.
+
+        Args:
+            key (str): Key for the data to store.
+            data (obj): Data object to store.
+
+        """
         if self.databases:
             for database in self.databases:
                 await database.put(key, data)


Test patch: