diff --git a/InvenTree/build/admin.py b/InvenTree/build/admin.py
index 640cf0778a..eec7376ede 100644
--- a/InvenTree/build/admin.py
+++ b/InvenTree/build/admin.py
@@ -1,3 +1,5 @@
+"""Admin functionality for the BuildOrder app"""
+
 from django.contrib import admin
 
 from import_export.admin import ImportExportModelAdmin
@@ -39,6 +41,7 @@ class BuildResource(ModelResource):
     notes = Field(attribute='notes')
 
     class Meta:
+        """Metaclass options"""
         models = Build
         skip_unchanged = True
         report_skipped = False
@@ -50,6 +53,7 @@ class BuildResource(ModelResource):
 
 
 class BuildAdmin(ImportExportModelAdmin):
+    """Class for managing the Build model via the admin interface"""
 
     exclude = [
         'reference_int',
@@ -81,6 +85,7 @@ class BuildAdmin(ImportExportModelAdmin):
 
 
 class BuildItemAdmin(admin.ModelAdmin):
+    """Class for managing the BuildItem model via the admin interface"""
 
     list_display = (
         'build',
diff --git a/InvenTree/build/api.py b/InvenTree/build/api.py
index 143e3643f9..a84473a139 100644
--- a/InvenTree/build/api.py
+++ b/InvenTree/build/api.py
@@ -27,7 +27,7 @@ class BuildFilter(rest_filters.FilterSet):
     active = rest_filters.BooleanFilter(label='Build is active', method='filter_active')
 
     def filter_active(self, queryset, name, value):
-
+        """Filter the queryset to either include or exclude orders which are active"""
         if str2bool(value):
             queryset = queryset.filter(status__in=BuildStatus.ACTIVE_CODES)
         else:
@@ -38,7 +38,7 @@ class BuildFilter(rest_filters.FilterSet):
     overdue = rest_filters.BooleanFilter(label='Build is overdue', method='filter_overdue')
 
     def filter_overdue(self, queryset, name, value):
-
+        """Filter the queryset to either include or exclude orders which are overdue"""
         if str2bool(value):
             queryset = queryset.filter(Build.OVERDUE_FILTER)
         else:
@@ -112,6 +112,7 @@ class BuildList(APIDownloadMixin, generics.ListCreateAPIView):
         return queryset
 
     def download_queryset(self, queryset, export_format):
+        """Download the queryset data as a file"""
         dataset = build.admin.BuildResource().export(queryset=queryset)
 
         filedata = dataset.export(export_format)
@@ -120,7 +121,7 @@ class BuildList(APIDownloadMixin, generics.ListCreateAPIView):
         return DownloadFile(filedata, filename)
 
     def filter_queryset(self, queryset):
-
+        """Custom query filtering for the BuildList endpoint"""
         queryset = super().filter_queryset(queryset)
 
         params = self.request.query_params
@@ -184,7 +185,7 @@ class BuildList(APIDownloadMixin, generics.ListCreateAPIView):
         return queryset
 
     def get_serializer(self, *args, **kwargs):
-
+        """Add extra context information to the endpoint serializer"""
         try:
             part_detail = str2bool(self.request.GET.get('part_detail', None))
         except AttributeError:
@@ -215,7 +216,7 @@ class BuildUnallocate(generics.CreateAPIView):
     serializer_class = build.serializers.BuildUnallocationSerializer
 
     def get_serializer_context(self):
-
+        """Add extra context information to the endpoint serializer"""
         ctx = super().get_serializer_context()
 
         try:
@@ -232,6 +233,7 @@ class BuildOrderContextMixin:
     """Mixin class which adds build order as serializer context variable."""
 
     def get_serializer_context(self):
+        """Add extra context information to the endpoint serializer"""
         ctx = super().get_serializer_context()
 
         ctx['request'] = self.request
@@ -265,6 +267,7 @@ class BuildOutputDelete(BuildOrderContextMixin, generics.CreateAPIView):
     """API endpoint for deleting multiple build outputs."""
 
     def get_serializer_context(self):
+        """Add extra context information to the endpoint serializer"""
         ctx = super().get_serializer_context()
 
         ctx['to_complete'] = False
@@ -338,7 +341,7 @@ class BuildItemList(generics.ListCreateAPIView):
     serializer_class = build.serializers.BuildItemSerializer
 
     def get_serializer(self, *args, **kwargs):
-
+        """Returns a BuildItemSerializer instance based on the request"""
         try:
             params = self.request.query_params
 
@@ -361,7 +364,7 @@ class BuildItemList(generics.ListCreateAPIView):
         return query
 
     def filter_queryset(self, queryset):
-
+        """Customm query filtering for the BuildItem list"""
         queryset = super().filter_queryset(queryset)
 
         params = self.request.query_params
diff --git a/InvenTree/build/apps.py b/InvenTree/build/apps.py
index 9025e77e0e..683e410b66 100644
--- a/InvenTree/build/apps.py
+++ b/InvenTree/build/apps.py
@@ -1,5 +1,8 @@
+"""Django app for the BuildOrder module"""
+
 from django.apps import AppConfig
 
 
 class BuildConfig(AppConfig):
+    """BuildOrder app config class"""
     name = 'build'
diff --git a/InvenTree/build/models.py b/InvenTree/build/models.py
index 76be632e10..cc81fd7f26 100644
--- a/InvenTree/build/models.py
+++ b/InvenTree/build/models.py
@@ -92,10 +92,11 @@ class Build(MPTTModel, ReferenceIndexingMixin):
 
     @staticmethod
     def get_api_url():
+        """Return the API URL associated with the BuildOrder model"""
         return reverse('api-build-list')
 
     def api_instance_filters(self):
-
+        """Returns custom API filters for the particular BuildOrder instance"""
         return {
             'parent': {
                 'exclude_tree': self.pk,
@@ -115,7 +116,7 @@ class Build(MPTTModel, ReferenceIndexingMixin):
         return defaults
 
     def save(self, *args, **kwargs):
-
+        """Custom save method for the BuildOrder model"""
         self.rebuild_reference_field()
 
         try:
@@ -126,6 +127,7 @@ class Build(MPTTModel, ReferenceIndexingMixin):
             })
 
     class Meta:
+        """Metaclass options for the BuildOrder model"""
         verbose_name = _("Build Order")
         verbose_name_plural = _("Build Orders")
 
@@ -170,12 +172,13 @@ class Build(MPTTModel, ReferenceIndexingMixin):
         return queryset
 
     def __str__(self):
-
+        """String representation of a BuildOrder"""
         prefix = getSetting("BUILDORDER_REFERENCE_PREFIX")
 
         return f"{prefix}{self.reference}"
 
     def get_absolute_url(self):
+        """Return the web URL associated with this BuildOrder"""
         return reverse('build-detail', kwargs={'pk': self.id})
 
     reference = models.CharField(
@@ -393,9 +396,11 @@ class Build(MPTTModel, ReferenceIndexingMixin):
 
     @property
     def output_count(self):
+        """Return the number of build outputs (StockItem) associated with this build order"""
         return self.build_outputs.count()
 
     def has_build_outputs(self):
+        """Returns True if this build has more than zero build outputs"""
         return self.output_count > 0
 
     def get_build_outputs(self, **kwargs):
@@ -436,7 +441,7 @@ class Build(MPTTModel, ReferenceIndexingMixin):
 
     @property
     def complete_count(self):
-
+        """Return the total quantity of completed outputs"""
         quantity = 0
 
         for output in self.complete_outputs:
@@ -1049,6 +1054,7 @@ class BuildOrderAttachment(InvenTreeAttachment):
     """Model for storing file attachments against a BuildOrder object."""
 
     def getSubdir(self):
+        """Return the media file subdirectory for storing BuildOrder attachments"""
         return os.path.join('bo_files', str(self.build.id))
 
     build = models.ForeignKey(Build, on_delete=models.CASCADE, related_name='attachments')
@@ -1069,20 +1075,17 @@ class BuildItem(models.Model):
 
     @staticmethod
     def get_api_url():
+        """Return the API URL used to access this model"""
         return reverse('api-build-item-list')
 
-    def get_absolute_url(self):
-        # TODO - Fix!
-        return '/build/item/{pk}/'.format(pk=self.id)
-        # return reverse('build-detail', kwargs={'pk': self.id})
-
     class Meta:
+        """Serializer metaclass"""
         unique_together = [
             ('build', 'stock_item', 'install_into'),
         ]
 
     def save(self, *args, **kwargs):
-
+        """Custom save method for the BuildItem model"""
         self.clean()
 
         super().save()
diff --git a/InvenTree/build/serializers.py b/InvenTree/build/serializers.py
index ea4321c04b..6659dd1e42 100644
--- a/InvenTree/build/serializers.py
+++ b/InvenTree/build/serializers.py
@@ -66,6 +66,7 @@ class BuildSerializer(ReferenceIndexingSerializerMixin, InvenTreeModelSerializer
         return queryset
 
     def __init__(self, *args, **kwargs):
+        """Determine if extra serializer fields are required"""
         part_detail = kwargs.pop('part_detail', True)
 
         super().__init__(*args, **kwargs)
@@ -74,6 +75,7 @@ class BuildSerializer(ReferenceIndexingSerializerMixin, InvenTreeModelSerializer
             self.fields.pop('part_detail')
 
     class Meta:
+        """Serializer metaclass"""
         model = Build
         fields = [
             'pk',
@@ -127,7 +129,7 @@ class BuildOutputSerializer(serializers.Serializer):
     )
 
     def validate_output(self, output):
-
+        """Perform validation for the output (StockItem) provided to the serializer"""
         build = self.context['build']
 
         # As this serializer can be used in multiple contexts, we need to work out why we are here
@@ -159,6 +161,7 @@ class BuildOutputSerializer(serializers.Serializer):
         return output
 
     class Meta:
+        """Serializer metaclass"""
         fields = [
             'output',
         ]
@@ -182,13 +185,15 @@ class BuildOutputCreateSerializer(serializers.Serializer):
     )
 
     def get_build(self):
+        """Return the Build instance associated with this serializer"""
         return self.context["build"]
 
     def get_part(self):
+        """Return the Part instance associated with the build"""
         return self.get_build().part
 
     def validate_quantity(self, quantity):
-
+        """Validate the provided quantity field"""
         if quantity <= 0:
             raise ValidationError(_("Quantity must be greater than zero"))
 
@@ -219,7 +224,7 @@ class BuildOutputCreateSerializer(serializers.Serializer):
     )
 
     def validate_serial_numbers(self, serial_numbers):
-
+        """Clean the provided serial number string"""
         serial_numbers = serial_numbers.strip()
 
         return serial_numbers
@@ -292,6 +297,7 @@ class BuildOutputDeleteSerializer(serializers.Serializer):
     """DRF serializer for deleting (cancelling) one or more build outputs."""
 
     class Meta:
+        """Serializer metaclass"""
         fields = [
             'outputs',
         ]
@@ -302,7 +308,7 @@ class BuildOutputDeleteSerializer(serializers.Serializer):
     )
 
     def validate(self, data):
-
+        """Perform data validation for this serializer"""
         data = super().validate(data)
 
         outputs = data.get('outputs', [])
@@ -329,6 +335,7 @@ class BuildOutputCompleteSerializer(serializers.Serializer):
     """DRF serializer for completing one or more build outputs."""
 
     class Meta:
+        """Serializer metaclass"""
         fields = [
             'outputs',
             'location',
@@ -370,7 +377,7 @@ class BuildOutputCompleteSerializer(serializers.Serializer):
     )
 
     def validate(self, data):
-
+        """Perform data validation for this serializer"""
         super().validate(data)
 
         outputs = data.get('outputs', [])
@@ -409,15 +416,17 @@ class BuildOutputCompleteSerializer(serializers.Serializer):
 
 
 class BuildCancelSerializer(serializers.Serializer):
+    """DRF serializer class for cancelling an active BuildOrder"""
 
     class Meta:
+        """Serializer metaclass"""
         fields = [
             'remove_allocated_stock',
             'remove_incomplete_outputs',
         ]
 
     def get_context_data(self):
-
+        """Retrieve extra context data from this serializer"""
         build = self.context['build']
 
         return {
@@ -441,7 +450,7 @@ class BuildCancelSerializer(serializers.Serializer):
     )
 
     def save(self):
-
+        """Cancel the specified build"""
         build = self.context['build']
         request = self.context['request']
 
@@ -465,7 +474,7 @@ class BuildCompleteSerializer(serializers.Serializer):
     )
 
     def validate_accept_unallocated(self, value):
-
+        """Check if the 'accept_unallocated' field is required"""
         build = self.context['build']
 
         if not build.are_untracked_parts_allocated() and not value:
@@ -481,7 +490,7 @@ class BuildCompleteSerializer(serializers.Serializer):
     )
 
     def validate_accept_incomplete(self, value):
-
+        """Check if the 'accept_incomplete' field is required"""
         build = self.context['build']
 
         if build.remaining > 0 and not value:
@@ -490,7 +499,7 @@ class BuildCompleteSerializer(serializers.Serializer):
         return value
 
     def validate(self, data):
-
+        """Perform validation of this serializer prior to saving"""
         build = self.context['build']
 
         if build.incomplete_count > 0:
@@ -502,7 +511,7 @@ class BuildCompleteSerializer(serializers.Serializer):
         return data
 
     def save(self):
-
+        """Complete the specified build output"""
         request = self.context['request']
         build = self.context['build']
 
@@ -537,8 +546,7 @@ class BuildUnallocationSerializer(serializers.Serializer):
     )
 
     def validate_output(self, stock_item):
-
-        # Stock item must point to the same build order!
+        """Validation for the output StockItem instance. Stock item must point to the same build order!"""
         build = self.context['build']
 
         if stock_item and stock_item.build != build:
@@ -573,7 +581,7 @@ class BuildAllocationItemSerializer(serializers.Serializer):
     )
 
     def validate_bom_item(self, bom_item):
-        """Check if the parts match!"""
+        """Check if the parts match"""
         build = self.context['build']
 
         # BomItem should point to the same 'part' as the parent build
@@ -596,7 +604,7 @@ class BuildAllocationItemSerializer(serializers.Serializer):
     )
 
     def validate_stock_item(self, stock_item):
-
+        """Perform validation of the stock_item field"""
         if not stock_item.in_stock:
             raise ValidationError(_("Item must be in stock"))
 
@@ -610,7 +618,7 @@ class BuildAllocationItemSerializer(serializers.Serializer):
     )
 
     def validate_quantity(self, quantity):
-
+        """Perform validation of the 'quantity' field"""
         if quantity <= 0:
             raise ValidationError(_("Quantity must be greater than zero"))
 
@@ -625,6 +633,7 @@ class BuildAllocationItemSerializer(serializers.Serializer):
     )
 
     class Meta:
+        """Serializer metaclass"""
         fields = [
             'bom_item',
             'stock_item',
@@ -633,7 +642,7 @@ class BuildAllocationItemSerializer(serializers.Serializer):
         ]
 
     def validate(self, data):
-
+        """Perfofrm data validation for this item"""
         super().validate(data)
 
         build = self.context['build']
@@ -684,6 +693,7 @@ class BuildAllocationSerializer(serializers.Serializer):
     items = BuildAllocationItemSerializer(many=True)
 
     class Meta:
+        """Serializer metaclass"""
         fields = [
             'items',
         ]
@@ -700,7 +710,7 @@ class BuildAllocationSerializer(serializers.Serializer):
         return data
 
     def save(self):
-
+        """Perform the allocation"""
         data = self.validated_data
 
         items = data.get('items', [])
@@ -732,6 +742,7 @@ class BuildAutoAllocationSerializer(serializers.Serializer):
     """DRF serializer for auto allocating stock items against a build order."""
 
     class Meta:
+        """Serializer metaclass"""
         fields = [
             'location',
             'exclude_location',
@@ -770,7 +781,7 @@ class BuildAutoAllocationSerializer(serializers.Serializer):
     )
 
     def save(self):
-
+        """Perform the auto-allocation step"""
         data = self.validated_data
 
         build = self.context['build']
@@ -799,7 +810,7 @@ class BuildItemSerializer(InvenTreeModelSerializer):
     quantity = InvenTreeDecimalField()
 
     def __init__(self, *args, **kwargs):
-
+        """Determine which extra details fields should be included"""
         build_detail = kwargs.pop('build_detail', False)
         part_detail = kwargs.pop('part_detail', False)
         location_detail = kwargs.pop('location_detail', False)
@@ -816,6 +827,7 @@ class BuildItemSerializer(InvenTreeModelSerializer):
             self.fields.pop('location_detail')
 
     class Meta:
+        """Serializer metaclass"""
         model = BuildItem
         fields = [
             'pk',
@@ -837,6 +849,7 @@ class BuildAttachmentSerializer(InvenTreeAttachmentSerializer):
     """Serializer for a BuildAttachment."""
 
     class Meta:
+        """Serializer metaclass"""
         model = BuildOrderAttachment
 
         fields = [
diff --git a/InvenTree/build/tasks.py b/InvenTree/build/tasks.py
index 8192e83a43..ef32fc73ee 100644
--- a/InvenTree/build/tasks.py
+++ b/InvenTree/build/tasks.py
@@ -1,3 +1,5 @@
+"""Background task definitions for the BuildOrder app"""
+
 from decimal import Decimal
 import logging
 
diff --git a/InvenTree/build/test_api.py b/InvenTree/build/test_api.py
index 95fbf9a17b..bd969bcea9 100644
--- a/InvenTree/build/test_api.py
+++ b/InvenTree/build/test_api.py
@@ -1,3 +1,5 @@
+"""Unit tests for the BuildOrder API"""
+
 from datetime import datetime, timedelta
 
 from django.urls import reverse
@@ -91,16 +93,12 @@ class BuildAPITest(InvenTreeAPITestCase):
         'build.add'
     ]
 
-    def setUp(self):
-
-        super().setUp()
-
 
 class BuildTest(BuildAPITest):
     """Unit testing for the build complete API endpoint."""
 
     def setUp(self):
-
+        """Basic setup for this test suite"""
         super().setUp()
 
         self.build = Build.objects.get(pk=1)
@@ -477,7 +475,7 @@ class BuildTest(BuildAPITest):
         self.assertIn('This build output has already been completed', str(response.data))
 
     def test_download_build_orders(self):
-
+        """Test that we can download a list of build orders via the API"""
         required_cols = [
             'reference',
             'status',
@@ -532,7 +530,7 @@ class BuildAllocationTest(BuildAPITest):
     """
 
     def setUp(self):
-
+        """Basic operation as part of test suite setup"""
         super().setUp()
 
         self.assignRole('build.add')
diff --git a/InvenTree/build/test_build.py b/InvenTree/build/test_build.py
index 298fbb583a..d3bf330246 100644
--- a/InvenTree/build/test_build.py
+++ b/InvenTree/build/test_build.py
@@ -1,3 +1,5 @@
+"""Unit tests for the BuildOrder app"""
+
 from ctypes import Union
 from django.test import TestCase
 
@@ -114,6 +116,7 @@ class BuildTestBase(TestCase):
 
 
 class BuildTest(BuildTestBase):
+    """Basic set of tests for the Build model"""
 
     def test_ref_int(self):
         """Test the "integer reference" field used for natural sorting."""
@@ -133,8 +136,7 @@ class BuildTest(BuildTestBase):
             self.assertEqual(build.reference_int, ii)
 
     def test_init(self):
-        # Perform some basic tests before we start the ball rolling
-
+        """Perform some basic tests before we start the ball rolling"""
         self.assertEqual(StockItem.objects.count(), 10)
 
         # Build is PENDING
@@ -158,8 +160,7 @@ class BuildTest(BuildTestBase):
         self.assertFalse(self.build.is_complete)
 
     def test_build_item_clean(self):
-        # Ensure that dodgy BuildItem objects cannot be created
-
+        """Ensure that dodgy BuildItem objects cannot be created"""
         stock = StockItem.objects.create(part=self.assembly, quantity=99)
 
         # Create a BuiltItem which points to an invalid StockItem
@@ -185,8 +186,7 @@ class BuildTest(BuildTestBase):
         b.save()
 
     def test_duplicate_bom_line(self):
-        # Try to add a duplicate BOM item - it should fail!
-
+        """Try to add a duplicate BOM item - it should fail!"""
         with self.assertRaises(IntegrityError):
             BomItem.objects.create(
                 part=self.assembly,
@@ -291,7 +291,7 @@ class BuildTest(BuildTestBase):
 
         self.assertEqual(BuildItem.objects.count(), 0)
         """
-        pass
+        ...
 
     def test_complete(self):
         """Test completion of a build output."""
@@ -370,7 +370,7 @@ class AutoAllocationTests(BuildTestBase):
     """Tests for auto allocating stock against a build order."""
 
     def setUp(self):
-
+        """Create some data as part of this test suite"""
         super().setUp()
 
         # Add a "substitute" part for bom_item_2
diff --git a/InvenTree/build/test_migrations.py b/InvenTree/build/test_migrations.py
index 831d1fda67..0a6ea3dd8b 100644
--- a/InvenTree/build/test_migrations.py
+++ b/InvenTree/build/test_migrations.py
@@ -38,7 +38,7 @@ class TestForwardMigrations(MigratorTestCase):
         )
 
     def test_items_exist(self):
-
+        """Test to ensure that the 'assembly' field is correctly configured"""
         Part = self.new_state.apps.get_model('part', 'part')
 
         self.assertEqual(Part.objects.count(), 1)
@@ -96,7 +96,7 @@ class TestReferenceMigration(MigratorTestCase):
                 print(build.reference)
 
     def test_build_reference(self):
-
+        """Test that the build reference is correctly assigned to the PK of the Build"""
         Build = self.new_state.apps.get_model('build', 'build')
 
         self.assertEqual(Build.objects.count(), 3)
diff --git a/InvenTree/build/tests.py b/InvenTree/build/tests.py
index 89534fae19..e09e59d958 100644
--- a/InvenTree/build/tests.py
+++ b/InvenTree/build/tests.py
@@ -1,3 +1,5 @@
+"""Basic unit tests for the BuildOrder app"""
+
 from django.urls import reverse
 
 from datetime import datetime, timedelta
@@ -11,6 +13,7 @@ from InvenTree.status_codes import BuildStatus
 
 
 class BuildTestSimple(InvenTreeTestCase):
+    """Basic set of tests for the BuildOrder model functionality"""
 
     fixtures = [
         'category',
@@ -26,7 +29,7 @@ class BuildTestSimple(InvenTreeTestCase):
     ]
 
     def test_build_objects(self):
-        # Ensure the Build objects were correctly created
+        """Ensure the Build objects were correctly created"""
         self.assertEqual(Build.objects.count(), 5)
         b = Build.objects.get(pk=2)
         self.assertEqual(b.batch, 'B2')
@@ -35,10 +38,12 @@ class BuildTestSimple(InvenTreeTestCase):
         self.assertEqual(str(b), 'BO0002')
 
     def test_url(self):
+        """Test URL lookup"""
         b1 = Build.objects.get(pk=1)
         self.assertEqual(b1.get_absolute_url(), '/build/1/')
 
     def test_is_complete(self):
+        """Test build completion status"""
         b1 = Build.objects.get(pk=1)
         b2 = Build.objects.get(pk=2)
 
@@ -63,6 +68,7 @@ class BuildTestSimple(InvenTreeTestCase):
         self.assertFalse(build.is_overdue)
 
     def test_is_active(self):
+        """Test active / inactive build status"""
         b1 = Build.objects.get(pk=1)
         b2 = Build.objects.get(pk=2)
 
@@ -70,8 +76,9 @@ class BuildTestSimple(InvenTreeTestCase):
         self.assertEqual(b2.is_active, False)
 
     def test_required_parts(self):
-        # TODO - Generate BOM for test part
-        pass
+        """Test set of required BOM items for the build"""
+        # TODO: Generate BOM for test part
+        ...
 
     def test_cancel_build(self):
         """Test build cancellation function."""
@@ -101,6 +108,7 @@ class TestBuildViews(InvenTreeTestCase):
     ]
 
     def setUp(self):
+        """Fixturing for this suite of unit tests"""
         super().setUp()
 
         # Create a build output for build # 1
diff --git a/InvenTree/build/views.py b/InvenTree/build/views.py
index 652943ee36..9d01ddc3d6 100644
--- a/InvenTree/build/views.py
+++ b/InvenTree/build/views.py
@@ -31,7 +31,7 @@ class BuildDetail(InvenTreeRoleMixin, InvenTreePluginViewMixin, DetailView):
     context_object_name = 'build'
 
     def get_context_data(self, **kwargs):
-
+        """Return extra context information for the BuildDetail view"""
         ctx = super().get_context_data(**kwargs)
 
         build = self.get_object()