Add missing args to docstrings

This commit is contained in:
Matthias 2022-05-28 20:27:20 +02:00
parent ff9873f92c
commit c24882bf66
No known key found for this signature in database
GPG Key ID: AB6D0E6C4CB65093
15 changed files with 165 additions and 106 deletions

View File

@ -162,7 +162,7 @@ def normalize(d):
def increment(n):
"""Attempt to increment an integer (or a string that looks like an integer!)
"""Attempt to increment an integer (or a string that looks like an integer).
e.g.
@ -332,7 +332,7 @@ def GetExportFormats():
]
def DownloadFile(data, filename, content_type='application/text', inline=False):
def DownloadFile(data, filename, content_type='application/text', inline=False) -> StreamingHttpResponse:
"""Create a dynamic file for the user to download.
Args:
@ -362,7 +362,7 @@ def DownloadFile(data, filename, content_type='application/text', inline=False):
def extract_serial_numbers(serials, expected_quantity, next_number: int):
"""Attempt to extract serial numbers from an input string:
"""Attempt to extract serial numbers from an input string.
Requirements:
- Serial numbers can be either strings, or integers

View File

@ -211,7 +211,7 @@ class AjaxMixin(InvenTreeRoleMixin):
ajax_form_title = ''
def get_form_title(self):
"""Default implementation - return the ajax_form_title variable"""
"""Default implementation - return the ajax_form_title variable."""
return self.ajax_form_title
def get_param(self, name, method='GET'):
@ -230,7 +230,7 @@ class AjaxMixin(InvenTreeRoleMixin):
return self.request.GET.get(name, None)
def get_data(self):
"""Get extra context data (default implementation is empty dict)
"""Get extra context data (default implementation is empty dict).
Returns:
dict object (empty)
@ -444,6 +444,9 @@ class AjaxUpdateView(AjaxMixin, UpdateView):
Args:
object - The current object, to be updated
form - The validated form
Returns:
object instance for supplied form
"""
self.object = form.save()

View File

@ -340,9 +340,12 @@ class Build(MPTTModel, ReferenceIndexingMixin):
@property
def is_overdue(self):
"""Returns true if this build is "overdue":
"""Returns true if this build is "overdue".
Makes use of the OVERDUE_FILTER to avoid code duplication
Returns:
bool: Is the build overdue
"""
query = Build.objects.filter(pk=self.pk)
query = query.filter(Build.OVERDUE_FILTER)
@ -574,9 +577,9 @@ class Build(MPTTModel, ReferenceIndexingMixin):
def unallocateStock(self, bom_item=None, output=None):
"""Unallocate stock from this Build.
Arguments:
- bom_item: Specify a particular BomItem to unallocate stock against
- output: Specify a particular StockItem (output) to unallocate stock against
Args:
bom_item: Specify a particular BomItem to unallocate stock against
output: Specify a particular StockItem (output) to unallocate stock against
"""
allocations = BuildItem.objects.filter(
build=self,
@ -693,8 +696,9 @@ class Build(MPTTModel, ReferenceIndexingMixin):
@transaction.atomic
def delete_output(self, output):
"""Remove a build output from the database:
"""Remove a build output from the database.
Executes:
- Unallocate any build items against the output
- Delete the output StockItem
"""
@ -882,8 +886,8 @@ class Build(MPTTModel, ReferenceIndexingMixin):
"""Get the quantity of a part required to complete the particular build output.
Args:
part: The Part object
output - The particular build output (StockItem)
bom_item: The Part object
output: The particular build output (StockItem)
"""
quantity = bom_item.quantity
@ -895,14 +899,14 @@ class Build(MPTTModel, ReferenceIndexingMixin):
return quantity
def allocated_bom_items(self, bom_item, output=None):
"""Return all BuildItem objects which allocate stock of <bom_item> to <output>
"""Return all BuildItem objects which allocate stock of <bom_item> to <output>.
Note that the bom_item may allow variants, or direct substitutes,
making things difficult.
Args:
bom_item - The BomItem object
output - Build output (StockItem).
bom_item: The BomItem object
output: Build output (StockItem).
"""
allocations = BuildItem.objects.filter(
build=self,
@ -991,7 +995,7 @@ class Build(MPTTModel, ReferenceIndexingMixin):
@property
def required_parts(self):
"""Returns a list of parts required to build this part (BOM)"""
"""Returns a list of parts required to build this part (BOM)."""
parts = []
for item in self.bom_items:

View File

@ -1,3 +1,4 @@
from ctypes import Union
from django.test import TestCase
from django.core.exceptions import ValidationError
@ -193,12 +194,12 @@ class BuildTest(BuildTestBase):
quantity=99
)
def allocate_stock(self, output, allocations):
def allocate_stock(self, output: Union[StockItem, None], allocations: dict[StockItem, int]) -> None:
"""Allocate stock to this build, against a particular output.
Args:
output - StockItem object (or None)
allocations - Map of {StockItem: quantity}
output (Union[StockItem, None]): StockItem object or None
allocations (dict[StockItem, int]): Map of `{StockItem: quantity}`
"""
for item, quantity in allocations.items():
BuildItem.objects.create(

View File

@ -94,8 +94,11 @@ class FileManager:
"""Try to match a header (from the file) to a list of known headers.
Args:
header - Header name to look for
threshold - Match threshold for fuzzy search
header (Any): Header name to look for
threshold (int, optional): Match threshold for fuzzy search. Defaults to 80.
Returns:
Any: Matched headers
"""
# Replace null values with empty string
if header is None:

View File

@ -477,7 +477,7 @@ class BaseInvenTreeSetting(models.Model):
pass
def choices(self):
"""Return the available choices for this setting (or None if no choices are defined)"""
"""Return the available choices for this setting (or None if no choices are defined)."""
return self.__class__.get_setting_choices(self.key, **self.get_kwargs())
def valid_options(self):
@ -1519,7 +1519,7 @@ class PriceBreak(models.Model):
"""Convert the unit-price at this price break to the specified currency code.
Args:
currency_code - The currency code to convert to (e.g "USD" or "AUD")
currency_code: The currency code to convert to (e.g "USD" or "AUD")
"""
try:
converted = convert_money(self.price, currency_code)

View File

@ -231,7 +231,7 @@ class Company(models.Model):
return self.purchase_orders.filter(status__in=PurchaseOrderStatus.OPEN)
def pending_purchase_orders(self):
"""Return purchase orders which are PENDING (not yet issued)"""
"""Return purchase orders which are PENDING (not yet issued)."""
return self.purchase_orders.filter(status=PurchaseOrderStatus.PENDING)
def closed_purchase_orders(self):
@ -598,12 +598,12 @@ class SupplierPart(models.Model):
def unit_pricing(self):
return self.get_price(1)
def add_price_break(self, quantity, price):
def add_price_break(self, quantity, price) -> None:
"""Create a new price break for this part.
Args:
quantity - Numerical quantity
price - Must be a Money object
quantity: Numerical quantity
price: Must be a Money object
"""
# Check if a price break at that quantity already exists...
if self.price_breaks.filter(quantity=quantity, part=self.pk).exists():

View File

@ -329,16 +329,24 @@ class PurchaseOrder(Order):
return reverse('po-detail', kwargs={'pk': self.id})
@transaction.atomic
def add_line_item(self, supplier_part, quantity, group=True, reference='', purchase_price=None):
"""Add a new line item to this purchase order. This function will check that:
def add_line_item(self, supplier_part, quantity, group: bool = True, reference: str = '', purchase_price=None):
"""Add a new line item to this purchase order.
This function will check that:
* The supplier part matches the supplier specified for this purchase order
* The quantity is greater than zero
Args:
supplier_part - The supplier_part to add
quantity - The number of items to add
group - If True, this new quantity will be added to an existing line item for the same supplier_part (if it exists)
supplier_part: The supplier_part to add
quantity : The number of items to add
group (bool, optional): If True, this new quantity will be added to an existing line item for the same supplier_part (if it exists). Defaults to True.
reference (str, optional): Reference to item. Defaults to ''.
purchase_price (optional): Price of item. Defaults to None.
Raises:
ValidationError: quantity is smaller than 0
ValidationError: quantity is not type int
ValidationError: supplier is not supplier of purchase order
"""
try:
quantity = int(quantity)
@ -416,7 +424,11 @@ class PurchaseOrder(Order):
return query.exists()
def can_cancel(self):
"""A PurchaseOrder can only be cancelled under the following circumstances:"""
"""A PurchaseOrder can only be cancelled under the following circumstances.
- Status is PLACED
- Status is PENDING
"""
return self.status in [
PurchaseOrderStatus.PLACED,
PurchaseOrderStatus.PENDING
@ -655,7 +667,7 @@ class SalesOrder(Order):
@property
def is_overdue(self):
"""Returns true if this SalesOrder is "overdue":
"""Returns true if this SalesOrder is "overdue".
Makes use of the OVERDUE_FILTER to avoid code duplication.
"""
@ -692,7 +704,7 @@ class SalesOrder(Order):
return False
def is_completed(self):
"""Check if this order is "shipped" (all line items delivered)"""
"""Check if this order is "shipped" (all line items delivered)."""
return self.lines.count() > 0 and all([line.is_completed() for line in self.lines.all()])
def can_complete(self, raise_error=False):
@ -749,8 +761,9 @@ class SalesOrder(Order):
@transaction.atomic
def cancel_order(self):
"""Cancel this order (only if it is "pending")
"""Cancel this order (only if it is "pending").
Executes:
- Mark the order as 'cancelled'
- Delete any StockItems which have been allocated
"""
@ -1110,7 +1123,7 @@ class SalesOrderLineItem(OrderLineItem):
return self.allocated_quantity() > self.quantity
def is_completed(self):
"""Return True if this line item is completed (has been fully shipped)"""
"""Return True if this line item is completed (has been fully shipped)."""
return self.shipped >= self.quantity
@ -1222,8 +1235,9 @@ class SalesOrderShipment(models.Model):
@transaction.atomic
def complete_shipment(self, user, **kwargs):
"""Complete this particular shipment:
"""Complete this particular shipment.
Executes:
1. Update any stock items associated with this shipment
2. Update the "shipped" quantity of all associated line items
3. Set the "shipment_date" to now
@ -1295,8 +1309,9 @@ class SalesOrderAllocation(models.Model):
return reverse('api-so-allocation-list')
def clean(self):
"""Validate the SalesOrderAllocation object:
"""Validate the SalesOrderAllocation object.
Executes:
- Cannot allocate stock to a line item without a part reference
- The referenced part must match the part associated with the line item
- Allocated quantity cannot exceed the quantity of the stock item
@ -1385,8 +1400,9 @@ class SalesOrderAllocation(models.Model):
return self.item.purchase_order
def complete_allocation(self, user):
"""Complete this allocation (called when the parent SalesOrder is marked as "shipped"):
"""Complete this allocation (called when the parent SalesOrder is marked as "shipped").
Executes:
- Determine if the referenced StockItem needs to be "split" (if allocated quantity != stock quantity)
- Mark the StockItem as belonging to the Customer (this will remove it from stock)
"""

View File

@ -11,7 +11,7 @@ from company.models import ManufacturerPart, SupplierPart
from InvenTree.helpers import DownloadFile, GetExportFormats, normalize
from .admin import BomItemResource
from .models import BomItem
from .models import BomItem, Part
def IsValidBOMFormat(fmt):
@ -20,7 +20,7 @@ def IsValidBOMFormat(fmt):
def MakeBomTemplate(fmt):
"""Generate a Bill of Materials upload template file (for user download)"""
"""Generate a Bill of Materials upload template file (for user download)."""
fmt = fmt.strip().lower()
if not IsValidBOMFormat(fmt):
@ -42,12 +42,21 @@ def MakeBomTemplate(fmt):
return DownloadFile(data, filename)
def ExportBom(part, fmt='csv', cascade=False, max_levels=None, parameter_data=False, stock_data=False, supplier_data=False, manufacturer_data=False):
def ExportBom(part: Part, fmt='csv', cascade: bool = False, max_levels: int = None, parameter_data=False, stock_data=False, supplier_data=False, manufacturer_data=False):
"""Export a BOM (Bill of Materials) for a given part.
Args:
fmt: File format (default = 'csv')
cascade: If True, multi-level BOM output is supported. Otherwise, a flat top-level-only BOM is exported.
part (Part): Part for which the BOM should be exported
fmt (str, optional): file format. Defaults to 'csv'.
cascade (bool, optional): If True, multi-level BOM output is supported. Otherwise, a flat top-level-only BOM is exported.. Defaults to False.
max_levels (int, optional): Levels of items that should be included. None for np sublevels. Defaults to None.
parameter_data (bool, optional): Additonal data that should be added. Defaults to False.
stock_data (bool, optional): Additonal data that should be added. Defaults to False.
supplier_data (bool, optional): Additonal data that should be added. Defaults to False.
manufacturer_data (bool, optional): Additonal data that should be added. Defaults to False.
Returns:
StreamingHttpResponse: Response that can be passed to the endpoint
"""
if not IsValidBOMFormat(fmt):
fmt = 'csv'

View File

@ -1,5 +1,7 @@
"""Part database model definitions."""
from __future__ import annotations
import decimal
import hashlib
import logging
@ -110,11 +112,14 @@ class PartCategory(MetadataMixin, InvenTreeTree):
verbose_name = _("Part Category")
verbose_name_plural = _("Part Categories")
def get_parts(self, cascade=True):
def get_parts(self, cascade=True) -> set[Part]:
"""Return a queryset for all parts under this category.
Args:
cascade - If True, also look under subcategories (default = True)
cascade (bool, optional): If True, also look under subcategories. Defaults to True.
Returns:
set[Part]: All matching parts
"""
if cascade:
"""Select any parts which exist in this category or any child categories."""
@ -129,7 +134,7 @@ class PartCategory(MetadataMixin, InvenTreeTree):
return self.partcount()
def partcount(self, cascade=True, active=False):
"""Return the total part count under this category (including children of child categories)"""
"""Return the total part count under this category (including children of child categories)."""
query = self.get_parts(cascade=cascade)
if active:
@ -1071,8 +1076,9 @@ class Part(MetadataMixin, MPTTModel):
@property
def net_stock(self):
"""Return the 'net' stock. It takes into account:
"""Return the 'net' stock.
It takes into account:
- Stock on hand (total_stock)
- Stock on order (on_order)
- Stock allocated (allocation_count)
@ -1370,12 +1376,12 @@ class Part(MetadataMixin, MPTTModel):
return queryset.prefetch_related('sub_part')
def get_installed_part_options(self, include_inherited=True, include_variants=True):
def get_installed_part_options(self, include_inherited: bool = True, include_variants: bool = True):
"""Return a set of all Parts which can be "installed" into this part, based on the BOM.
Arguments:
include_inherited - If set, include BomItem entries defined for parent parts
include_variants - If set, include variant parts for BomItems which allow variants
include_inherited (bool): If set, include BomItem entries defined for parent parts
include_variants (bool): If set, include variant parts for BomItems which allow variants
"""
parts = set()
@ -1480,7 +1486,7 @@ class Part(MetadataMixin, MPTTModel):
return str(result_hash.digest())
def is_bom_valid(self):
"""Check if the BOM is 'valid' - if the calculated checksum matches the stored value"""
"""Check if the BOM is 'valid' - if the calculated checksum matches the stored value."""
return self.get_bom_hash() == self.bom_checksum or not self.has_bom
@transaction.atomic
@ -1728,8 +1734,8 @@ class Part(MetadataMixin, MPTTModel):
"""Create a new price break for this part.
Args:
quantity - Numerical quantity
price - Must be a Money object
quantity: Numerical quantity
price: Must be a Money object
"""
# Check if a price break at that quantity already exists...
if self.price_breaks.filter(quantity=quantity, part=self.pk).exists():
@ -1774,8 +1780,8 @@ class Part(MetadataMixin, MPTTModel):
"""Copy the BOM from another part.
Args:
other - The part to copy the BOM from
clear - Remove existing BOM items first (default=True)
other: The part to copy the BOM from
clear (bool, optional): Remove existing BOM items first. Defaults to True.
"""
# Ignore if the other part is actually this part?
if other == self:
@ -2017,10 +2023,9 @@ class Part(MetadataMixin, MPTTModel):
@property
def can_convert(self):
"""Check if this Part can be "converted" to a different variant:
"""Check if this Part can be "converted" to a different variant.
It can be converted if:
a) It has non-virtual variant parts underneath it
b) It has non-virtual template parts above it
c) It has non-virtual sibling variants
@ -2064,8 +2069,9 @@ class Part(MetadataMixin, MPTTModel):
return filtered_parts
def get_related_parts(self):
"""Return list of tuples for all related parts:
"""Return list of tuples for all related parts.
Includes:
- first value is PartRelated object
- second value is matching Part object
"""
@ -2408,7 +2414,7 @@ class PartCategoryParameterTemplate(models.Model):
]
def __str__(self):
"""String representation of a PartCategoryParameterTemplate (admin interface)"""
"""String representation of a PartCategoryParameterTemplate (admin interface)."""
if self.default_value:
return f'{self.category.name} | {self.parameter_template.name} | {self.default_value}'
else:
@ -2489,11 +2495,12 @@ class BomItem(models.Model, DataImportMixin):
return reverse('api-bom-list')
def get_valid_parts_for_allocation(self, allow_variants=True, allow_substitutes=True):
"""Return a list of valid parts which can be allocated against this BomItem:
"""Return a list of valid parts which can be allocated against this BomItem.
- Include the referenced sub_part
- Include any directly specvified substitute parts
- If allow_variants is True, allow all variants of sub_part
Includes:
- The referenced sub_part
- Any directly specvified substitute parts
- If allow_variants is True, all variants of sub_part
"""
# Set of parts we will allow
parts = set()
@ -2591,10 +2598,9 @@ class BomItem(models.Model, DataImportMixin):
)
def get_item_hash(self):
"""Calculate the checksum hash of this BOM line item:
"""Calculate the checksum hash of this BOM line item.
The hash is calculated from the following fields:
- Part.full_name (if the part name changes, the BOM checksum is invalidated)
- Quantity
- Reference field
@ -2794,8 +2800,9 @@ class BomItemSubstitute(models.Model):
super().save(*args, **kwargs)
def validate_unique(self, exclude=None):
"""Ensure that this BomItemSubstitute is "unique":
"""Ensure that this BomItemSubstitute is "unique".
Ensure:
- It cannot point to the same "part" as the "sub_part" of the parent "bom_item"
"""
super().validate_unique(exclude=exclude)
@ -2830,7 +2837,7 @@ class BomItemSubstitute(models.Model):
class PartRelated(models.Model):
"""Store and handle related parts (eg. mating connector, crimps, etc.)"""
"""Store and handle related parts (eg. mating connector, crimps, etc.)."""
part_1 = models.ForeignKey(Part, related_name='related_parts_1',
verbose_name=_('Part 1'), on_delete=models.DO_NOTHING)

View File

@ -52,7 +52,7 @@ class BarcodeMixin:
"""Initialize the BarcodePlugin instance.
Args:
barcode_data - The raw barcode data
barcode_data: The raw barcode data
"""
self.data = barcode_data

View File

@ -10,16 +10,17 @@ from plugin.registry import registry
logger = logging.getLogger('inventree')
def print_label(plugin_slug, label_image, label_instance=None, user=None):
def print_label(plugin_slug: str, label_image, label_instance=None, user=None):
"""Print label with the provided plugin.
This task is nominally handled by the background worker.
If the printing fails (throws an exception) then the user is notified.
Arguments:
plugin_slug: The unique slug (key) of the plugin
label_image: A PIL.Image image object to be printed
Args:
plugin_slug (str): The unique slug (key) of the plugin
label_image (_type_): A PIL.Image image object to be printed
label_instance (Union[LabelTemplate, None], optional): The template instance that should be printed. Defaults to None.
user (Union[User, None], optional): User that should be informed of errors. Defaults to None.
"""
logger.info(f"Plugin '{plugin_slug}' is printing a label")

View File

@ -46,13 +46,13 @@ class MetadataMixin(models.Model):
return self.metadata.get(key, backup_value)
def set_metadata(self, key: str, data, commit=True):
def set_metadata(self, key: str, data, commit: bool = True):
"""Save the provided metadata under the provided key.
Args:
key: String key for saving metadata
data: Data object to save - must be able to be rendered as a JSON string
overwrite: If true, existing metadata with the provided key will be overwritten. If false, a merge will be attempted
key (str): Key for saving metadata
data (Any): Data object to save - must be able to be rendered as a JSON string
commit (bool, optional): If true, existing metadata with the provided key will be overwritten. If false, a merge will be attempted. Defaults to True.
"""
if self.metadata is None:
# Handle a null field value

View File

@ -1,5 +1,7 @@
"""Stock database model definitions."""
from __future__ import annotations
import os
from datetime import datetime, timedelta
from decimal import Decimal, InvalidOperation
@ -129,8 +131,12 @@ class StockLocation(MetadataMixin, InvenTreeTree):
)
@property
def barcode(self):
"""Brief payload data (e.g. for labels)"""
def barcode(self) -> str:
"""Get Brief payload data (e.g. for labels).
Returns:
str: Brief pyload data
"""
return self.format_barcode(brief=True)
def get_stock_items(self, cascade=True):
@ -335,8 +341,9 @@ class StockItem(MetadataMixin, MPTTModel):
return None
def save(self, *args, **kwargs):
"""Save this StockItem to the database. Performs a number of checks:
"""Save this StockItem to the database.
Performs a number of checks:
- Unique serial number requirement
- Adds a transaction note when the item is first created.
"""
@ -433,10 +440,9 @@ class StockItem(MetadataMixin, MPTTModel):
raise ValidationError({"serial": _("StockItem with this serial number already exists")})
def clean(self):
"""Validate the StockItem object (separate to field validation)
"""Validate the StockItem object (separate to field validation).
The following validation checks are performed:
- The 'part' and 'supplier_part.part' fields cannot point to the same Part object
- The 'part' does not belong to itself
- Quantity must be 1 if the StockItem has a serial number
@ -558,7 +564,11 @@ class StockItem(MetadataMixin, MPTTModel):
@property
def barcode(self):
"""Brief payload data (e.g. for labels)"""
"""Get Brief payload data (e.g. for labels).
Returns:
str: Brief pyload data
"""
return self.format_barcode(brief=True)
uid = models.CharField(blank=True, max_length=128, help_text=("Unique identifier field"))
@ -825,8 +835,9 @@ class StockItem(MetadataMixin, MPTTModel):
return self.expiry_date < today
def clearAllocations(self):
"""Clear all order allocations for this StockItem:
"""Clear all order allocations for this StockItem.
Clears:
- SalesOrder allocations
- Build allocations
"""
@ -966,8 +977,9 @@ class StockItem(MetadataMixin, MPTTModel):
return max(self.quantity - self.allocation_count(), 0)
def can_delete(self):
"""Can this stock item be deleted? It can NOT be deleted under the following circumstances:
"""Can this stock item be deleted?
It can NOT be deleted under the following circumstances:
- Has installed stock items
- Is installed inside another StockItem
- It has been assigned to a SalesOrder
@ -981,13 +993,16 @@ class StockItem(MetadataMixin, MPTTModel):
return True
def get_installed_items(self, cascade=False):
def get_installed_items(self, cascade: bool = False) -> set[StockItem]:
"""Return all stock items which are *installed* in this one!
Args:
cascade - Include items which are installed in items which are installed in items
Note: This function is recursive, and may result in a number of database hits!
Args:
cascade (bool, optional): Include items which are installed in items which are installed in items. Defaults to False.
Returns:
set[StockItem]: Sll stock items which are installed
"""
installed = set()
@ -1157,15 +1172,14 @@ class StockItem(MetadataMixin, MPTTModel):
def has_tracking_info(self):
return self.tracking_info_count > 0
def add_tracking_entry(self, entry_type, user, deltas=None, notes='', **kwargs):
def add_tracking_entry(self, entry_type: int, user: User, deltas: dict = None, notes: str = '', **kwargs):
"""Add a history tracking entry for this StockItem.
Args:
entry_type - Integer code describing the "type" of historical action (see StockHistoryCode)
user - The user performing this action
deltas - A map of the changes made to the model
notes - User notes associated with this tracking entry
url - Optional URL associated with this tracking entry
entry_type (int): Code describing the "type" of historical action (see StockHistoryCode)
user (User): The user performing this action
deltas (dict, optional): A map of the changes made to the model. Defaults to None.
notes (str, optional): URL associated with this tracking entry. Defaults to ''.
"""
if deltas is None:
deltas = {}
@ -1915,7 +1929,7 @@ class StockItemAttachment(InvenTreeAttachment):
class StockItemTracking(models.Model):
"""Stock tracking entry - used for tracking history of a particular StockItem
"""Stock tracking entry - used for tracking history of a particular StockItem.
Note: 2021-05-11
The legacy StockTrackingItem model contained very litle information about the "history" of the item.

View File

@ -348,12 +348,12 @@ def update_group_roles(group, debug=False):
permissions_to_delete = set()
def add_model(name, action, allowed):
"""Add a new model to the pile:
"""Add a new model to the pile.
Args:
name - The name of the model e.g. part_part
action - The permission action e.g. view
allowed - Whether or not the action is allowed
name: The name of the model e.g. part_part
action: The permission action e.g. view
allowed: Whether or not the action is allowed
"""
if action not in ['view', 'add', 'change', 'delete']: # pragma: no cover
raise ValueError("Action {a} is invalid".format(a=action))
@ -400,7 +400,7 @@ def update_group_roles(group, debug=False):
"""Find the permission object in the database, from the simplified permission string.
Args:
permission_string - a simplified permission_string e.g. 'part.view_partcategory'
permission_string: a simplified permission_string e.g. 'part.view_partcategory'
Returns the permission object in the database associated with the permission string
"""
@ -521,10 +521,11 @@ class Owner(models.Model):
@classmethod
def get_owners_matching_user(cls, user):
"""Return all "owner" objects matching the provided user:
"""Return all "owner" objects matching the provided user.
A) An exact match for the user
B) Any groups that the user is a part of
Includes:
- An exact match for the user
- Any groups that the user is a part of
"""
user_type = ContentType.objects.get(app_label='auth', model='user')
group_type = ContentType.objects.get(app_label='auth', model='group')