diff --git a/.drone.yml b/.drone.yml index 97b24fe..37d0fdf 100644 --- a/.drone.yml +++ b/.drone.yml @@ -8,8 +8,16 @@ platform: arch: amd64 steps: -- name: test - commands: - - dnf install -y python3 python3-pip - - pip3 install -U Django - - python3 manage.py test + - name: install deps + commands: + - dnf install -y python3 python3-pip + - pip3 install -U Django coverage flake8 pylint django-coverage-plugin pylint-django + - name: run unittests + commands: + - coverage run --source='.' manage.py test --noinput --parallel + - name: run flake8 + commands: + - flake8 + - name: run pylint + commands: + - pylint --rcfile=.pylintrc -- **/*.py diff --git a/.gitignore b/.gitignore index 894a44c..75b1991 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,6 @@ venv.bak/ # mypy .mypy_cache/ + + +.DS_Store diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000..8f79755 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,14 @@ +[MASTER] +load-plugins=pylint_django + +[FORMAT] +max-line-length=120 + +[MESSAGES CONTROL] +disable=missing-docstring,unnecessary-pass + +[DESIGN] +max-parents=13 + +[TYPECHECK] +generated-members=REQUEST,acl_users,aq_parent,"[a-zA-Z]+_set{1,2}",save,delete diff --git a/im/settings.py b/im/settings.py index 3969795..90623df 100644 --- a/im/settings.py +++ b/im/settings.py @@ -64,6 +64,7 @@ TEMPLATES = [ 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], + 'debug': DEBUG, }, }, ] @@ -100,6 +101,10 @@ AUTH_PASSWORD_VALIDATORS = [ }, ] +# enabling this may speed up testing +# PASSWORD_HASHERS = [ +# 'django.contrib.auth.hashers.MD5PasswordHasher', +# ] # Internationalization # https://docs.djangoproject.com/en/2.1/topics/i18n/ diff --git a/inventory/admin.py b/inventory/admin.py index b0d62c7..f154200 100644 --- a/inventory/admin.py +++ b/inventory/admin.py @@ -9,7 +9,6 @@ class PantryItemInLine(admin.TabularInline): extra = 1 - class LocationInLine(admin.TabularInline): model = Location extra = 1 @@ -17,11 +16,15 @@ class LocationInLine(admin.TabularInline): def upper_case_name(obj): return obj.name.upper() + + upper_case_name.short_description = 'Name' def capitalize_name(obj): return obj.name.capitalize() + + upper_case_name.short_description = 'Name' @@ -65,7 +68,7 @@ class PantryItemAdmin(admin.ModelAdmin): inlines = [PantryItemInLine] # TODO: make category a model - #autocomplete_fields = ['category',] + # autocomplete_fields = ['category',] fields = ( 'name', 'category', @@ -93,6 +96,7 @@ class ShoppingListItemAdmin(PantryItemAdmin): 'info', ) + admin.site.register(PantryItem, PantryItemAdmin) admin.site.register(ShoppingListItem, ShoppingListItemAdmin) admin.site.register(PantryItemLine, PantryItemLineAdmin) diff --git a/inventory/models.py b/inventory/models.py index 88ab969..4276539 100644 --- a/inventory/models.py +++ b/inventory/models.py @@ -57,7 +57,7 @@ class PantryItem(models.Model): # if expiry duration is set the expiration date for a pantryitemline will be set to now + duration on save # represents days expiry_duration = models.IntegerField(null=True, blank=True) - name = models.CharField(max_length=200) + name = models.CharField(max_length=200) unit = models.ForeignKey(Unit, on_delete=models.PROTECT, null=True) info = models.CharField(max_length=200, null=True, blank=True) # location is saved on a per item base, not itemline @@ -78,7 +78,7 @@ class PantryItemLine(models.Model): pantry_item = models.ForeignKey(PantryItem, on_delete=models.PROTECT) quantity = models.IntegerField(default=1) expiry_date = models.DateField(null=True, blank=True) - size = models.IntegerField(default=1) #, decimal_places=3, max_digits=32) + size = models.IntegerField(default=1) info = models.CharField(max_length=200, null=True, blank=True) def unit(self): @@ -88,5 +88,5 @@ class PantryItemLine(models.Model): return reverse('pantryitemlinedetail', kwargs={'pk': self.pk}) def __str__(self): - return ' '.join([str(x) for x in [self.pantry_item.name, self.quantity, 'X', self.size, self.pantry_item.unit]]) - + return ' '.join([str(x) for x in [self.pantry_item.name, self.quantity, 'X', + self.size, self.pantry_item.unit]]) diff --git a/inventory/tests.py b/inventory/tests.py index 7ce503c..205ae08 100644 --- a/inventory/tests.py +++ b/inventory/tests.py @@ -1,3 +1,25 @@ from django.test import TestCase +from django.test import Client -# Create your tests here. +from inventory.models import PantryItem, Category + + +class PantryItemTestCase(TestCase): + """ simple test case for a model""" + def setUp(self): + cat = Category.objects.create(name="UNCATEGORIZED") + PantryItem.objects.create(name="testitem", category=cat) + + def test_pantryitem_looksok(self): + """Pantryitems to string is ok""" + testitem = PantryItem.objects.get(name="testitem") + self.assertEqual(str(testitem), 'testitem') + + +class InterFaceTestCase(TestCase): + """Simple test case for the web interface""" + + def test_consume_view_exists(self): + client = Client() + response = client.get('/consume/') + self.assertTrue(b"TODO" not in response.content) diff --git a/inventory/views.py b/inventory/views.py index 5b54e9f..a3791f0 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -1,7 +1,5 @@ -from django.shortcuts import render, get_object_or_404 -from django.http import HttpResponse +from django.shortcuts import render from django.views import generic -from django.views.generic.edit import CreateView, DeleteView, UpdateView from django.db.models import F, Sum, Q @@ -26,9 +24,10 @@ class Shoppinglist(generic.ListView): """ Return pantryitems for which we have None itemlines or Itemlines whith a total quantitly less than required """ - return PantryItem.objects.annotate(total_quantity=Sum(F('pantryitemline__quantity') * - F('pantryitemline__size'))).filter(Q(min_quantity__gt=F('total_quantity')) | Q(pantryitemline=None, - min_quantity__gt=0)) + return PantryItem.objects.annotate( + total_quantity=Sum(F('pantryitemline__quantity') * + F('pantryitemline__size')) + ).filter(Q(min_quantity__gt=F('total_quantity')) | Q(pantryitemline=None, min_quantity__gt=0)) class Expirations(generic.ListView): diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..fa11995 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,9 @@ +[flake8] +max-line-length = 120 +exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules,venv + +[coverage:run] +include = '.' +omit = *migrations*, *tests* +plugins = + django_coverage_plugin