home · contact · privacy
Use different exceptions throwing different HTTP codes for different cases.
authorChristian Heller <c.heller@plomlompom.de>
Wed, 27 Mar 2024 00:34:22 +0000 (01:34 +0100)
committerChristian Heller <c.heller@plomlompom.de>
Wed, 27 Mar 2024 00:34:22 +0000 (01:34 +0100)
plomtask/days.py
plomtask/db.py
plomtask/exceptions.py [new file with mode: 0644]
plomtask/http.py
plomtask/misc.py [deleted file]
plomtask/processes.py
run.py
tests/days.py
tests/processes.py

index 3b81a7f3bf526fd7bc56849558fbfaa451cdbe88..afdea33760b41df3149c857b306c6e2b447b7df8 100644 (file)
@@ -2,7 +2,7 @@
 from __future__ import annotations
 from datetime import datetime, timedelta
 from sqlite3 import Row
-from plomtask.misc import HandledException
+from plomtask.exceptions import BadFormatException, NotFoundException
 from plomtask.db import DatabaseConnection
 
 DATE_FORMAT = '%Y-%m-%d'
@@ -16,7 +16,7 @@ def valid_date(date_str: str) -> str:
         dt = datetime.strptime(date_str, DATE_FORMAT)
     except (ValueError, TypeError) as e:
         msg = f'Given date of wrong format: {date_str}'
-        raise HandledException(msg) from e
+        raise BadFormatException(msg) from e
     return dt.strftime(DATE_FORMAT)
 
 
@@ -76,7 +76,7 @@ class Day:
         for row in db_conn.exec('SELECT * FROM days WHERE date = ?', (date,)):
             return cls.from_table_row(row)
         if not create:
-            raise HandledException(f'Day not found for date: {date}')
+            raise NotFoundException(f'Day not found for date: {date}')
         return cls(date)
 
     @property
index e0a5d4f5df5426512c8a7552ca889c598dcaabfe..929a733cc381a6d6d7a2e24feda04a5a014081a7 100644 (file)
@@ -3,7 +3,7 @@ from os.path import isfile
 from difflib import Differ
 from sqlite3 import connect as sql_connect, Cursor
 from typing import Any
-from plomtask.misc import HandledException
+from plomtask.exceptions import HandledException
 
 PATH_DB_SCHEMA = 'scripts/init.sql'
 
diff --git a/plomtask/exceptions.py b/plomtask/exceptions.py
new file mode 100644 (file)
index 0000000..379ae9f
--- /dev/null
@@ -0,0 +1,19 @@
+"""
+Whatever fits nowhere else, and/or is too small/trivial
+to merit its own module at this point.
+"""
+
+
+class HandledException(Exception):
+    """To identify Exceptions based on expected (if faulty) user behavior."""
+    http_code = 400
+
+
+class BadFormatException(HandledException):
+    """To identify Exceptions on malformed inputs."""
+    http_code = 401
+
+
+class NotFoundException(HandledException):
+    """To identify Exceptions on unsuccessful queries."""
+    http_code = 404
index ddea087cb38fae73c713da589ef901925141cc5e..af1a60cd148ec86a83bf27bad8759a7e1cf74e6f 100644 (file)
@@ -6,7 +6,7 @@ from urllib.parse import urlparse, parse_qs
 from os.path import split as path_split
 from jinja2 import Environment as JinjaEnv, FileSystemLoader as JinjaFSLoader
 from plomtask.days import Day, todays_date
-from plomtask.misc import HandledException
+from plomtask.exceptions import HandledException, BadFormatException
 from plomtask.db import DatabaseConnection, DatabaseFile
 from plomtask.processes import Process
 
@@ -43,7 +43,7 @@ class TaskHandler(BaseHTTPRequestHandler):
                 try:
                     id__ = int(id_) if id_ else None
                 except ValueError as e:
-                    raise HandledException(f'Bad ?id= value: {id_}') from e
+                    raise BadFormatException(f'Bad ?id= value: {id_}') from e
                 html = self.do_GET_process(conn, id__)
             elif 'processes' == site:
                 html = self.do_GET_processes(conn)
@@ -53,7 +53,7 @@ class TaskHandler(BaseHTTPRequestHandler):
             conn.close()
             self._send_html(html)
         except HandledException as error:
-            self._send_msg(error)
+            self._send_msg(error, code=error.http_code)
 
     def do_GET_calendar(self, conn: DatabaseConnection,
                         start: str, end: str) -> str:
@@ -92,13 +92,13 @@ class TaskHandler(BaseHTTPRequestHandler):
                 try:
                     id__ = int(id_) if id_ else None
                 except ValueError as e:
-                    raise HandledException(f'Bad ?id= value: {id_}') from e
+                    raise BadFormatException(f'Bad ?id= value: {id_}') from e
                 self.do_POST_process(conn, id__, postvars)
             conn.commit()
             conn.close()
             self._redirect('/')
         except HandledException as error:
-            self._send_msg(error)
+            self._send_msg(error, code=error.http_code)
 
     def do_POST_day(self, conn: DatabaseConnection,
                     date: str, postvars: dict[str, list[str]]) -> None:
@@ -117,7 +117,7 @@ class TaskHandler(BaseHTTPRequestHandler):
         try:
             process.effort.set(float(effort))
         except ValueError as e:
-            raise HandledException(f'Bad effort value: {effort}') from e
+            raise BadFormatException(f'Bad effort value: {effort}') from e
         process.save(conn)
 
     def _init_handling(self) -> \
diff --git a/plomtask/misc.py b/plomtask/misc.py
deleted file mode 100644 (file)
index 1b780e2..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-"""
-Whatever fits nowhere else, and/or is too small/trivial
-to merit its own module at this point.
-"""
-
-
-class HandledException(Exception):
-    """To identify Exceptions based on expected (if faulty) user behavior."""
index 4867227e5f4e492ebeeac33c484039f36afca4fd..8b5ff4221ea292b1c8bcffb787671b44129f0a66 100644 (file)
@@ -3,7 +3,7 @@ from __future__ import annotations
 from sqlite3 import Row
 from datetime import datetime
 from plomtask.db import DatabaseConnection
-from plomtask.misc import HandledException
+from plomtask.exceptions import NotFoundException
 
 
 class Process:
@@ -46,7 +46,7 @@ class Process:
             break
         if not process:
             if not create:
-                raise HandledException(f'Process not found of id: {id_}')
+                raise NotFoundException(f'Process not found of id: {id_}')
             process = Process(id_)
         if process:
             for row in db_conn.exec('SELECT * FROM process_titles '
diff --git a/run.py b/run.py
index 31d11cee0534b5ae68c3bf84692f61b87b9e7481..e1bbe5dafa4a43664f3b6839fe2659dc80ff0f8b 100755 (executable)
--- a/run.py
+++ b/run.py
@@ -2,7 +2,7 @@
 """Call this to start the application."""
 from sys import exit as sys_exit
 from os import environ
-from plomtask.misc import HandledException
+from plomtask.exceptions import HandledException
 from plomtask.http import TaskHandler, TaskServer
 from plomtask.db import DatabaseFile
 
index f3ed08228aafa3550ed49caa1bf022f144285e6e..61a27edbb0d266b892182c241d769ae36a5846b4 100644 (file)
@@ -3,7 +3,7 @@ from unittest import TestCase
 from datetime import datetime
 from tests.utils import TestCaseWithDB, TestCaseWithServer
 from plomtask.days import Day, todays_date
-from plomtask.misc import HandledException
+from plomtask.exceptions import BadFormatException, NotFoundException
 
 
 class TestsSansDB(TestCase):
@@ -11,11 +11,11 @@ class TestsSansDB(TestCase):
 
     def test_Day_dates(self) -> None:
         """Test Day's date format."""
-        with self.assertRaises(HandledException):
+        with self.assertRaises(BadFormatException):
             Day('foo')
-        with self.assertRaises(HandledException):
+        with self.assertRaises(BadFormatException):
             Day('2024-02-30')
-        with self.assertRaises(HandledException):
+        with self.assertRaises(BadFormatException):
             Day('2024-02-01 23:00:00')
         self.assertEqual(datetime(2024, 1, 1), Day('2024-01-01').datetime)
 
@@ -37,12 +37,12 @@ class TestsWithDB(TestCaseWithDB):
 
     def test_Day_by_date(self) -> None:
         """Test Day.by_date()."""
-        with self.assertRaises(HandledException):
+        with self.assertRaises(NotFoundException):
             Day.by_date(self.db_conn, '2024-01-01')
         Day('2024-01-01').save(self.db_conn)
         self.assertEqual(Day('2024-01-01'),
                          Day.by_date(self.db_conn, '2024-01-01'))
-        with self.assertRaises(HandledException):
+        with self.assertRaises(NotFoundException):
             Day.by_date(self.db_conn, '2024-01-02')
         self.assertEqual(Day('2024-01-02'),
                          Day.by_date(self.db_conn, '2024-01-02', create=True))
@@ -97,7 +97,7 @@ class TestsWithServer(TestCaseWithServer):
         self.conn.request('GET', '/day?date=3000-01-01')
         self.assertEqual(self.conn.getresponse().status, 200)
         self.conn.request('GET', '/day?date=FOO')
-        self.assertEqual(self.conn.getresponse().status, 400)
+        self.assertEqual(self.conn.getresponse().status, 401)
         self.conn.request('GET', '/calendar')
         self.assertEqual(self.conn.getresponse().status, 200)
         self.conn.request('GET', '/calendar?start=&end=')
@@ -107,4 +107,4 @@ class TestsWithServer(TestCaseWithServer):
         self.conn.request('GET', '/calendar?start=2024-01-01&end=2025-01-01')
         self.assertEqual(self.conn.getresponse().status, 200)
         self.conn.request('GET', '/calendar?start=foo')
-        self.assertEqual(self.conn.getresponse().status, 400)
+        self.assertEqual(self.conn.getresponse().status, 401)
index 17af14edfe5a6c5c773084ffe1c3a9df7f32b52e..399eb9dfc354e73db88858a16dc10178f2825297 100644 (file)
@@ -3,7 +3,7 @@ from unittest import TestCase
 from urllib.parse import urlencode
 from tests.utils import TestCaseWithDB, TestCaseWithServer
 from plomtask.processes import Process
-from plomtask.misc import HandledException
+from plomtask.exceptions import NotFoundException
 
 
 class TestsSansDB(TestCase):
@@ -42,11 +42,11 @@ class TestsWithDB(TestCaseWithDB):
 
     def test_Process_by_id(self) -> None:
         """Test Process.by_id()."""
-        with self.assertRaises(HandledException):
+        with self.assertRaises(NotFoundException):
             Process.by_id(self.db_conn, None, create=False)
-        with self.assertRaises(HandledException):
+        with self.assertRaises(NotFoundException):
             Process.by_id(self.db_conn, 0, create=False)
-        with self.assertRaises(HandledException):
+        with self.assertRaises(NotFoundException):
             Process.by_id(self.db_conn, 1, create=False)
         self.assertNotEqual(Process(1).id_,
                             Process.by_id(self.db_conn, None, create=True).id_)
@@ -81,11 +81,11 @@ class TestsWithServer(TestCaseWithServer):
                               body=encoded_form_data, headers=headers)
             self.assertEqual(self.conn.getresponse().status, expect)
         form_data = {'title': 'foo', 'description': 'foo', 'effort': 1.0}
-        post_data_to_expect(form_data, '/process?id=FOO', 400)
+        post_data_to_expect(form_data, '/process?id=FOO', 401)
         form_data['effort'] = 'foo'
-        post_data_to_expect(form_data, '/process?id=', 400)
+        post_data_to_expect(form_data, '/process?id=', 401)
         form_data['effort'] = None
-        post_data_to_expect(form_data, '/process?id=', 400)
+        post_data_to_expect(form_data, '/process?id=', 401)
         form_data = {'title': None, 'description': 1, 'effort': 1.0}
         post_data_to_expect(form_data, '/process?id=', 302)
         retrieved = Process.by_id(self.db_conn, 1)
@@ -102,6 +102,6 @@ class TestsWithServer(TestCaseWithServer):
         self.conn.request('GET', '/process?id=0')
         self.assertEqual(self.conn.getresponse().status, 200)
         self.conn.request('GET', '/process?id=FOO')
-        self.assertEqual(self.conn.getresponse().status, 400)
+        self.assertEqual(self.conn.getresponse().status, 401)
         self.conn.request('GET', '/processes')
         self.assertEqual(self.conn.getresponse().status, 200)