From 5e6d49102d85d772bd02a7083f8da9ba7302e6a9 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 27 Apr 2019 21:21:58 +1000 Subject: [PATCH] Add docstring documentation to the main InvenTree app --- InvenTree/InvenTree/forms.py | 5 +++ InvenTree/InvenTree/helpers.py | 46 +++++++++++++++++++------ InvenTree/InvenTree/models.py | 54 ++++++++++++++---------------- InvenTree/InvenTree/serializers.py | 7 ++++ InvenTree/InvenTree/urls.py | 7 ++++ InvenTree/InvenTree/views.py | 51 +++++++++++++++++++++++----- docs/conf.py | 5 +++ 7 files changed, 128 insertions(+), 47 deletions(-) diff --git a/InvenTree/InvenTree/forms.py b/InvenTree/InvenTree/forms.py index 002a83e896..8d574f7a38 100644 --- a/InvenTree/InvenTree/forms.py +++ b/InvenTree/InvenTree/forms.py @@ -1,3 +1,7 @@ +""" +Helper forms which subclass Django forms to provide additional functionality +""" + # -*- coding: utf-8 -*- from __future__ import unicode_literals @@ -6,6 +10,7 @@ from crispy_forms.helper import FormHelper class HelperForm(forms.ModelForm): + """ Provides simple integration of crispy_forms extension. """ def __init__(self, *args, **kwargs): super(forms.ModelForm, self).__init__(*args, **kwargs) diff --git a/InvenTree/InvenTree/helpers.py b/InvenTree/InvenTree/helpers.py index a492ca353d..7b8f1b57c1 100644 --- a/InvenTree/InvenTree/helpers.py +++ b/InvenTree/InvenTree/helpers.py @@ -1,3 +1,7 @@ +""" +Provides helper functions used throughout the InvenTree project +""" + import io from wsgiref.util import FileWrapper @@ -5,7 +9,14 @@ from django.http import StreamingHttpResponse def str2bool(text, test=True): - """ Test if a string 'looks' like a boolean value + """ Test if a string 'looks' like a boolean value. + + Args: + text: Input text + test (default = True): Set which boolean value to look for + + Returns: + True if the text looks like the selected boolean value """ if test: return str(text).lower() in ['1', 'y', 'yes', 't', 'true', 'ok', ] @@ -13,21 +24,36 @@ def str2bool(text, test=True): return str(text).lower() in ['0', 'n', 'no', 'none', 'f', 'false', ] -def WrapWithQuotes(text): - # TODO - Make this better - if not text.startswith('"'): - text = '"' + text +def WrapWithQuotes(text, quote='"'): + """ Wrap the supplied text with quotes - if not text.endswith('"'): - text = text + '"' + Args: + text: Input text to wrap + quote: Quote character to use for wrapping (default = "") + + Returns: + Supplied text wrapped in quote char + """ + + if not text.startswith(quote): + text = quote + text + + if not text.endswith(quote): + text = text + quote return text def DownloadFile(data, filename, content_type='application/text'): - """ - Create a dynamic file for the user to download. - @param data is the raw file data + """ Create a dynamic file for the user to download. + + Args: + data: Raw file data (string or bytes) + filename: Filename for the file download + content_type: Content type for the download + + Return: + A StreamingHttpResponse object wrapping the supplied data """ filename = WrapWithQuotes(filename) diff --git a/InvenTree/InvenTree/models.py b/InvenTree/InvenTree/models.py index 2b49f7b908..0c1e1f10ee 100644 --- a/InvenTree/InvenTree/models.py +++ b/InvenTree/InvenTree/models.py @@ -1,3 +1,7 @@ +""" +Generic models which provide extra functionality over base Django model types. +""" + from __future__ import unicode_literals from django.db import models @@ -11,6 +15,7 @@ from django.dispatch import receiver class InvenTreeTree(models.Model): """ Provides an abstracted self-referencing tree model for data categories. + - Each Category has one parent Category, which can be blank (for a top-level Category). - Each Category can have zero-or-more child Categor(y/ies) """ @@ -69,10 +74,12 @@ class InvenTreeTree(models.Model): @property def has_children(self): + """ True if there are any children under this item """ return self.children.count() > 0 @property def children(self): + """ Return the children of this item """ contents = ContentType.objects.get_for_model(type(self)) childs = contents.get_all_objects_for_this_type(parent=self.id) @@ -100,11 +107,10 @@ class InvenTreeTree(models.Model): @property def parentpath(self): - """ Return the parent path of this category + """ Get the parent path of this category - Todo: - This function is recursive and expensive. - It should be reworked such that only a single db call is required + Returns: + List of category names from the top level to the parent of this category """ if self.parent: @@ -114,10 +120,21 @@ class InvenTreeTree(models.Model): @property def path(self): + """ Get the complete part of this category. + + e.g. ["Top", "Second", "Third", "This"] + + Returns: + List of category names from the top level to this category + """ return self.parentpath + [self] @property def pathstring(self): + """ Get a string representation for the path of this item. + + e.g. "Top/Second/Third/This" + """ return '/'.join([item.name for item in self.path]) def __setattr__(self, attrname, val): @@ -157,38 +174,19 @@ class InvenTreeTree(models.Model): super(InvenTreeTree, self).__setattr__(attrname, val) def __str__(self): - """ String representation of a category is the full path to that category - - Todo: - This is recursive - Make it not so. - """ + """ String representation of a category is the full path to that category """ return self.pathstring @receiver(pre_delete, sender=InvenTreeTree, dispatch_uid='tree_pre_delete_log') def before_delete_tree_item(sender, instance, using, **kwargs): + """ Receives pre_delete signal from InvenTreeTree object. + + Before an item is deleted, update each child object to point to the parent of the object being deleted. + """ # Update each tree item below this one for child in instance.children.all(): child.parent = instance.parent child.save() - - -def FilterChildren(queryset, parent): - """ Filter a queryset, limit to only objects that are a child of the given parent - Filter is passed in the URL string, e.g. '/?parent=123' - To accommodate for items without a parent, top-level items can be specified as: - none / false / null / top / 0 - """ - - if not parent: - return queryset - elif str2bool(parent, False): - return queryset.filter(parent=None) - else: - parent_id = int(parent) - if parent_id == 0: - return queryset.filter(parent=None) - else: - return queryset.filter(parent=parent_id) diff --git a/InvenTree/InvenTree/serializers.py b/InvenTree/InvenTree/serializers.py index 4ab1fd694d..77e38ade21 100644 --- a/InvenTree/InvenTree/serializers.py +++ b/InvenTree/InvenTree/serializers.py @@ -1,3 +1,8 @@ +""" +Serializers used in various InvenTree apps +""" + + # -*- coding: utf-8 -*- from __future__ import unicode_literals @@ -7,6 +12,7 @@ from django.contrib.auth.models import User class UserSerializer(serializers.ModelSerializer): + """ Serializer for User - provides all fields """ class Meta: model = User @@ -14,6 +20,7 @@ class UserSerializer(serializers.ModelSerializer): class UserSerializerBrief(serializers.ModelSerializer): + """ Serializer for User - provides limited information """ class Meta: model = User diff --git a/InvenTree/InvenTree/urls.py b/InvenTree/InvenTree/urls.py index c33689be61..ccc828de55 100644 --- a/InvenTree/InvenTree/urls.py +++ b/InvenTree/InvenTree/urls.py @@ -1,3 +1,10 @@ +""" +Top-level URL lookup for InvenTree application. + +Passes URL lookup downstream to each app as required. +""" + + from django.conf.urls import url, include from django.contrib import admin from django.contrib.auth import views as auth_views diff --git a/InvenTree/InvenTree/views.py b/InvenTree/InvenTree/views.py index c160398caf..fee5d2481f 100644 --- a/InvenTree/InvenTree/views.py +++ b/InvenTree/InvenTree/views.py @@ -1,3 +1,10 @@ +""" +Various Views which provide extra functionality over base Django Views. + +In particular these views provide base functionality for rendering Django forms +as JSON objects and passing them to modal forms (using jQuery / bootstrap). +""" + # -*- coding: utf-8 -*- from __future__ import unicode_literals @@ -12,6 +19,8 @@ from rest_framework import views class TreeSerializer(views.APIView): + """ JSON View for serializing a Tree object. + """ def itemToJson(self, item): @@ -52,20 +61,34 @@ class TreeSerializer(views.APIView): class AjaxMixin(object): + """ AjaxMixin provides basic functionality for rendering a Django form to JSON. + Handles jsonResponse rendering, and adds extra data for the modal forms to process + on the client side. + """ ajax_form_action = '' ajax_form_title = '' def get_data(self): + """ Get extra context data (default implementation is empty dict) + + Returns: + dict object (empty) + """ return {} - def getAjaxTemplate(self): - if hasattr(self, 'ajax_template_name'): - return self.ajax_template_name - else: - return self.template_name - def renderJsonResponse(self, request, form=None, data={}, context={}): + """ Render a JSON response based on specific class context. + + Args: + request: HTTP request object (e.g. GET / POST) + form: Django form object (may be None) + data: Extra JSON data to pass to client + context: Extra context data to pass to template rendering + + Returns: + JSON response object + """ if form: context['form'] = form @@ -73,7 +96,7 @@ class AjaxMixin(object): data['title'] = self.ajax_form_title data['html_form'] = render_to_string( - self.getAjaxTemplate(), + self.ajax_template_name, context, request=request ) @@ -88,7 +111,8 @@ class AjaxMixin(object): class AjaxView(AjaxMixin, View): - """ Bare-bones AjaxView """ + """ An 'AJAXified' View for displaying an object + """ # By default, point to the modal_form template # (this can be overridden by a child class) @@ -201,7 +225,7 @@ class AjaxDeleteView(AjaxMixin, DeleteView): data = {'id': self.get_object().id, 'delete': False, 'title': self.ajax_form_title, - 'html_data': render_to_string(self.getAjaxTemplate(), + 'html_data': render_to_string(self.ajax_template_name, self.get_context_data(), request=request) } @@ -229,15 +253,24 @@ class AjaxDeleteView(AjaxMixin, DeleteView): class IndexView(TemplateView): + """ View for InvenTree index page """ template_name = 'InvenTree/index.html' class SearchView(TemplateView): + """ View for InvenTree search page. + + Displays results of search query + """ template_name = 'InvenTree/search.html' def post(self, request, *args, **kwargs): + """ Handle POST request (which contains search query). + + Pass the search query to the page template + """ context = self.get_context_data() diff --git a/docs/conf.py b/docs/conf.py index 3b21b24458..295dee688f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -41,6 +41,8 @@ autoapi_dirs = [ autoapi_options = [ 'members', + 'private-members', + 'special-members', ] autoapi_type = 'python' @@ -51,6 +53,9 @@ autoapi_ignore = [ '**/manage.py', '**/apps.py', '**/admin.py', + '**/middleware.py', + '**/utils.py', + '**/wsgi.py', '**/templates/', ]