summaryrefslogtreecommitdiff
path: root/ishtar_common
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2023-04-11 12:27:23 +0200
committerÉtienne Loks <etienne.loks@iggdrasil.net>2023-04-17 15:47:16 +0200
commit367059ddef14a495e277f68ceaf3455c092f839d (patch)
treeae625ff0265fecd122946c71d3a2d6afefae4817 /ishtar_common
parentff5aee7158bd46e4ae22bc431adadd7060a6e277 (diff)
downloadIshtar-367059ddef14a495e277f68ceaf3455c092f839d.tar.bz2
Ishtar-367059ddef14a495e277f68ceaf3455c092f839d.zip
bandit checker: mark false security issues - fix security issues (low severity)
Diffstat (limited to 'ishtar_common')
-rw-r--r--ishtar_common/admin.py4
-rw-r--r--ishtar_common/data_importer.py25
-rw-r--r--ishtar_common/forms_common.py16
-rw-r--r--ishtar_common/ignf_utils.py3
-rw-r--r--ishtar_common/libreoffice.py2
-rw-r--r--ishtar_common/models.py24
-rw-r--r--ishtar_common/models_common.py14
-rw-r--r--ishtar_common/models_imports.py15
-rw-r--r--ishtar_common/models_rest.py14
-rw-r--r--ishtar_common/rest.py13
-rw-r--r--ishtar_common/tests.py6
-rw-r--r--ishtar_common/utils.py16
-rw-r--r--ishtar_common/utils_migrations.py4
-rw-r--r--ishtar_common/views.py19
-rw-r--r--ishtar_common/views_item.py16
-rw-r--r--ishtar_common/wizards.py25
16 files changed, 131 insertions, 85 deletions
diff --git a/ishtar_common/admin.py b/ishtar_common/admin.py
index ab24ff58b..c824b36f5 100644
--- a/ishtar_common/admin.py
+++ b/ishtar_common/admin.py
@@ -998,8 +998,8 @@ class ImportGEOJSONActionAdmin(object):
json_file = json_file_obj.read()
try:
dct = json.loads(json_file)
- assert "features" in dct
- assert dct["features"]
+ if "features" not in dct or not dct["features"]:
+ raise ValueError()
except (ValueError, AssertionError):
error = _("Bad geojson file")
return self.import_geojson_error(
diff --git a/ishtar_common/data_importer.py b/ishtar_common/data_importer.py
index ae3c8387a..796a75699 100644
--- a/ishtar_common/data_importer.py
+++ b/ishtar_common/data_importer.py
@@ -371,8 +371,9 @@ class YearFormater(Formater):
return
try:
value = int(value)
- assert value > 0 and value < (datetime.date.today().year + 30)
- except (ValueError, AssertionError):
+ if value <= 0 or value > (datetime.date.today().year + 30):
+ raise ValueError()
+ except ValueError:
raise ValueError(_('"%(value)s" is not a valid date') % {"value": value})
return value
@@ -384,8 +385,9 @@ class YearNoFuturFormater(Formater):
return
try:
value = int(value)
- assert value > 0 and value < datetime.date.today().year
- except (ValueError, AssertionError):
+ if value <= 0 or value > datetime.date.today().year:
+ raise ValueError()
+ except ValueError:
raise ValueError(_('"%(value)s" is not a valid date') % {"value": value})
return value
@@ -674,7 +676,7 @@ class DateFormater(Formater):
for date_format in self.date_formats:
try:
return datetime.datetime.strptime(value, date_format).date()
- except:
+ except ValueError:
continue
raise ValueError(_('"%(value)s" is not a valid date') % {"value": value})
@@ -1013,7 +1015,8 @@ class Importer(object):
self.current_csv_line = None
self.conservative_import = conservative_import
# for a conservative_import UNICITY_KEYS should be defined
- assert not self.conservative_import or bool(self.UNICITY_KEYS)
+ if self.conservative_import and not bool(self.UNICITY_KEYS):
+ raise ValueError("A conservative import should have unicity key defined")
self.DB_TARGETS = {}
self.match_table = {}
self.concats = set()
@@ -1097,7 +1100,8 @@ class Importer(object):
(further exploitation by web interface)
- user: associated user
"""
- assert output in ("silent", "cli", "db")
+ if output not in ("silent", "cli", "db"):
+ raise ValueError("initialize called with a bad output option")
vals = []
for idx_line, line in enumerate(table):
if self.skip_lines > idx_line:
@@ -1356,7 +1360,8 @@ class Importer(object):
for idx_col, val in enumerate(line):
try:
self._row_processing(c_row, idx_col, idx_line, val, data)
- except:
+ # nosec: no catch to force continue processing of lines
+ except: # nosec
pass
self.validity.append(c_row)
@@ -2288,8 +2293,8 @@ class Importer(object):
target_name = field.name
elif rel_model == obj.__class__:
item_name = field.name
- assert target_name is not None
- assert item_name is not None
+ if target_name is None or item_name is None:
+ raise IntegrityError(f"Configuration error for attribute {attr}.")
inter_model.objects.get_or_create(
**{item_name: obj, target_name: v}
)
diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py
index bcc5a28be..f031b280f 100644
--- a/ishtar_common/forms_common.py
+++ b/ishtar_common/forms_common.py
@@ -320,8 +320,9 @@ class NewImportForm(BaseImportForm):
value = self.cleaned_data.get("imported_images_link", None)
if value:
try:
- assert is_downloadable(value)
- except (AssertionError, requests.exceptions.RequestException):
+ if not is_downloadable(value):
+ raise forms.ValidationError("")
+ except (requests.exceptions.RequestException, forms.ValidationError):
raise forms.ValidationError(
_("Invalid link or no file is available for this link.")
)
@@ -378,18 +379,21 @@ class NewImportGISForm(BaseImportForm):
if value:
try:
ext = value.name.lower().split(".")[-1]
- assert ext in ("zip", "gpkg", "csv")
+ if ext not in ("zip", "gpkg", "csv"):
+ raise forms.ValidationError("")
if ext == "zip":
zip_file = zipfile.ZipFile(value)
- assert not zip_file.testzip()
+ if zip_file.testzip():
+ raise forms.ValidationError("")
has_correct_file = False
for name in zip_file.namelist():
in_ext = name.lower().split(".")[-1]
if in_ext in ("shp", "gpkg"):
has_correct_file = True
break
- assert has_correct_file
- except AssertionError:
+ if not has_correct_file:
+ raise forms.ValidationError("")
+ except forms.ValidationError:
raise forms.ValidationError(
_("GIS file must be a zip containing a ShapeFile or GeoPackage file.")
)
diff --git a/ishtar_common/ignf_utils.py b/ishtar_common/ignf_utils.py
index 94429d458..6be83407f 100644
--- a/ishtar_common/ignf_utils.py
+++ b/ishtar_common/ignf_utils.py
@@ -1,4 +1,5 @@
-import xml.etree.ElementTree as ET
+# nosec: parsing only used by programmer to generate previous dict from a trusted source
+import xml.etree.ElementTree as ET # nosec
# from the bellow script
diff --git a/ishtar_common/libreoffice.py b/ishtar_common/libreoffice.py
index 482364a73..7dbb36e30 100644
--- a/ishtar_common/libreoffice.py
+++ b/ishtar_common/libreoffice.py
@@ -202,7 +202,7 @@ class UnoCalc(UnoClient):
if k.startswith("get"):
try:
print(k, getattr(validation, k)())
- except:
+ except (AttributeError, TypeError):
pass
def test_image(self):
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index f7baebfe4..ba317998f 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -36,7 +36,9 @@ import string
import tempfile
import time
from io import BytesIO
-from subprocess import Popen, PIPE
+# nosec: only script inside the script directory can be executed
+# script directory is not web available
+from subprocess import Popen, PIPE # nosec
from PIL import Image
from markdown import markdown
from ooopy.OOoPy import OOoPy
@@ -45,7 +47,8 @@ import ooopy.Transforms as OOTransforms
import uuid
import zipfile
from urllib.parse import urlencode
-from xml.etree import ElementTree as ET
+# nosec: ElementTree used to create XML not for parsing
+from xml.etree import ElementTree as ET # nosec
from django.apps import apps
from django.conf import settings
@@ -408,9 +411,7 @@ def is_unique(cls, field):
# unique validator for models
def func(value):
query = {field: value}
- try:
- assert cls.objects.filter(**query).count() == 0
- except AssertionError:
+ if cls.objects.filter(**query).count() != 0:
raise ValidationError(_("This item already exists."))
return func
@@ -922,9 +923,8 @@ class RelationsViews(models.Model):
Check view or table properly created with settings on the profile
:return: True if table or view updated
"""
- assert cls.CREATE_SQL
- assert cls.DELETE_SQL
- assert cls.CREATE_TABLE_SQL
+ if not cls.CREATE_SQL or not cls.DELETE_SQL or not cls.CREATE_TABLE_SQL:
+ raise NotImplementedError("CREATE_SQL or DELETE_SQL or CREATE_TABLE_SQL is missing.")
profile = get_current_profile(force=True)
table_type = ""
with connection.cursor() as cursor:
@@ -2456,7 +2456,8 @@ def documentation_get_gender_values():
class BaseGenderedType(ValueGetter):
def get_values(self, prefix="", **kwargs):
dct = super(BaseGenderedType, self).get_values(prefix=prefix, **kwargs)
- assert hasattr(self, "grammatical_gender")
+ if not hasattr(self, "grammatical_gender"):
+ raise NotImplementedError("This model should have a grammatical_gender field")
dct[prefix + "grammatical_gender"] = self.grammatical_gender
return dct
@@ -5144,6 +5145,7 @@ class AdministrationTask(models.Model):
script_name = None
# only script inside the script directory can be executed
+ # script directory is not web available
for name in os.listdir(script_dir):
if name == self.script.path:
if os.path.isfile(os.path.join(script_dir, name)):
@@ -5165,7 +5167,9 @@ class AdministrationTask(models.Model):
self.finished_date = datetime.datetime.now()
try:
- session = Popen([script_name], stdout=PIPE, stderr=PIPE)
+ # nosec: only script inside the script directory can be executed
+ # this script directory is not web available
+ session = Popen([script_name], stdout=PIPE, stderr=PIPE) # nosec
stdout, stderr = session.communicate()
except OSError as e:
self.state = "FE"
diff --git a/ishtar_common/models_common.py b/ishtar_common/models_common.py
index fd12f19be..1e6da2b7d 100644
--- a/ishtar_common/models_common.py
+++ b/ishtar_common/models_common.py
@@ -1356,10 +1356,11 @@ class HistoricalRecords(BaseHistoricalRecords):
def create_historical_record(self, instance, history_type, using=None):
try:
history_modifier = getattr(instance, "history_modifier", None)
- assert history_modifier
- except (User.DoesNotExist, AssertionError):
+ except User.DoesNotExist:
# on batch removing of users, user could have disappeared
return
+ if not history_modifier:
+ return
history_date = getattr(instance, "_history_date", datetime.datetime.now())
history_change_reason = getattr(instance, "changeReason", None)
force = getattr(instance, "_force_history", False)
@@ -1550,7 +1551,8 @@ class BaseHistorizedItem(
"""
Get a "step" previous state of the item
"""
- assert step or date
+ if not step and not date:
+ raise AttributeError("Need to provide step or date")
historized = self.history.all()
item = None
if step:
@@ -1720,7 +1722,8 @@ class BaseHistorizedItem(
or not self.last_modified:
self.last_modified = datetime.datetime.now()
if not getattr(self, "skip_history_when_saving", False):
- assert hasattr(self, "history_modifier")
+ if not hasattr(self, "history_modifier"):
+ raise NotImplementedError("Should have a history_modifier field.")
if created:
self.history_creator = self.history_modifier
# external ID can have related item not available before save
@@ -3751,7 +3754,8 @@ class QuickAction:
self.target = target
self.module = module
self.is_popup = is_popup
- assert self.target in ("one", "many", None)
+ if self.target not in ("one", "many", None):
+ raise AttributeError("target must be one, many or None")
def is_available(self, user, session=None, obj=None):
if self.module and not getattr(get_current_profile(), self.module):
diff --git a/ishtar_common/models_imports.py b/ishtar_common/models_imports.py
index 76121d846..e91a94868 100644
--- a/ishtar_common/models_imports.py
+++ b/ishtar_common/models_imports.py
@@ -49,12 +49,15 @@ from django.template.defaultfilters import slugify
from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _, pgettext_lazy
-try:
- assert settings.USE_LIBREOFFICE
- from ishtar_common.libreoffice import UnoCalc
- from com.sun.star.awt.FontSlant import ITALIC
-except (AssertionError, ImportError):
- UnoCalc = None
+UnoCalc = None
+ITALIC = None
+if settings.USE_LIBREOFFICE:
+ try:
+ from ishtar_common.libreoffice import UnoCalc
+ from com.sun.star.awt.FontSlant import ITALIC
+ except ImportError:
+ pass
+
from ishtar_common.model_managers import SlugModelManager
from ishtar_common.utils import (
diff --git a/ishtar_common/models_rest.py b/ishtar_common/models_rest.py
index 411404325..05b1206d1 100644
--- a/ishtar_common/models_rest.py
+++ b/ishtar_common/models_rest.py
@@ -10,12 +10,14 @@ from django.contrib.postgres.fields import ArrayField
from django.core.files import File
from django.utils.text import slugify
-try:
- assert settings.USE_LIBREOFFICE
- from ishtar_common.libreoffice import UnoCalc
- from com.sun.star.awt.FontSlant import ITALIC
-except (AssertionError, ImportError):
- UnoCalc = None
+UnoCalc = None
+ITALIC = None
+if settings.USE_LIBREOFFICE:
+ try:
+ from ishtar_common.libreoffice import UnoCalc
+ from com.sun.star.awt.FontSlant import ITALIC
+ except ImportError:
+ pass
from django.apps import apps
from django.template import loader
diff --git a/ishtar_common/rest.py b/ishtar_common/rest.py
index e489e5f80..08fc2dc36 100644
--- a/ishtar_common/rest.py
+++ b/ishtar_common/rest.py
@@ -32,7 +32,8 @@ class SearchAPIView(APIView):
permission_classes = (permissions.IsAuthenticated, IpModelPermission)
def __init__(self, **kwargs):
- assert self.model is not None
+ if not self.model:
+ raise NotImplementedError("model attribute is not defined")
super(SearchAPIView, self).__init__(**kwargs)
def search_model_query(self, request):
@@ -99,9 +100,10 @@ class FacetAPIView(APIView):
select_forms = []
def __init__(self, **kwargs):
- assert self.models
- assert self.select_forms
- assert len(self.models) == len(self.select_forms)
+ if not self.models or not self.select_forms:
+ raise NotImplementedError("models or select_forms attribute is not defined")
+ if len(self.models) != len(self.select_forms):
+ raise NotImplementedError("len of models and select_forms must be equals")
super().__init__(**kwargs)
def get(self, request, format=None):
@@ -223,7 +225,8 @@ class GetAPIView(generics.RetrieveAPIView):
model = None
def __init__(self, **kwargs):
- assert self.model is not None
+ if self.model is None:
+ raise NotImplementedError("model attribute is not defined")
super().__init__(**kwargs)
def search_model_query(self, request):
diff --git a/ishtar_common/tests.py b/ishtar_common/tests.py
index 97002f13d..7328a5f95 100644
--- a/ishtar_common/tests.py
+++ b/ishtar_common/tests.py
@@ -171,7 +171,8 @@ def create_superuser():
return username, password, user
-def create_user(username="username678", password="dcbqj756aaa456!@%"):
+# nosec: hard coded password used for test
+def create_user(username="username678", password="dcbqj756aaa456!@%"): # nosec
q = User.objects.filter(username=username)
if q.count():
return username, password, q.all()[0]
@@ -245,7 +246,8 @@ class SearchText:
SEARCH_URL = ""
def _test_search(self, client, result, context=""):
- assert self.SEARCH_URL
+ if not self.SEARCH_URL:
+ raise NotImplementedError("No SEARCH_URL defined.")
for q, expected_result in result:
search = {"search_vector": q}
response = client.get(reverse(self.SEARCH_URL), search)
diff --git a/ishtar_common/utils.py b/ishtar_common/utils.py
index 91591e0b2..1757612ef 100644
--- a/ishtar_common/utils.py
+++ b/ishtar_common/utils.py
@@ -36,7 +36,8 @@ import requests
from secretary import Renderer as MainSecretaryRenderer, UndefinedSilently
import shutil
import string
-import subprocess
+# nosec: no user input
+import subprocess # nosec
import sys
import tempfile
import time
@@ -751,7 +752,8 @@ def get_random_item_image_link(request):
if not total:
return ""
- image_nb = random.randint(0, total - 1)
+ # nosec: not used for security/cryptographic purposes
+ image_nb = random.randint(0, total - 1) # nosec
return _get_image_link(q.all()[image_nb])
@@ -1413,7 +1415,8 @@ def generate_relation_graph(
svg_tmp_name = tempdir + os.path.sep + "relations.svg"
with open(svg_tmp_name, "w") as svg_file:
- popen = subprocess.Popen(args, stdout=svg_file)
+ # nosec: no user input
+ popen = subprocess.Popen(args, stdout=svg_file) # nosec
popen.wait()
# scale image if necessary
@@ -2132,7 +2135,8 @@ def generate_pdf_preview(item, save=True, tempdir=None, page_number=None):
item.associated_file.path, preview_tmp_name)
try:
- popen = subprocess.Popen(args)
+ # nosec: no user input
+ popen = subprocess.Popen(args) # nosec
popen.wait(timeout=5)
except subprocess.SubprocessError:
return
@@ -2183,7 +2187,7 @@ def create_osm_town(rel_id, name, numero_insee=None):
retry += 1
try:
geojson = response.json()
- except:
+ except requests.JSONDecodeError:
requests.get(OSM_REFRESH_URL.format(rel_id))
time.sleep(3)
if not geojson:
@@ -2194,7 +2198,7 @@ def create_osm_town(rel_id, name, numero_insee=None):
try:
geojson_simplify = response.json()
geojson = geojson_simplify
- except:
+ except requests.JSONDecodeError:
pass
default = {"name": name}
if not numero_insee:
diff --git a/ishtar_common/utils_migrations.py b/ishtar_common/utils_migrations.py
index ec0b46509..1aead83e8 100644
--- a/ishtar_common/utils_migrations.py
+++ b/ishtar_common/utils_migrations.py
@@ -96,7 +96,7 @@ def reinit_last_modified(apps, app_name, models):
model = apps.get_model(app_name, model_name)
try:
historical_model = apps.get_model(app_name, "Historical" + model_name)
- except:
+ except LookupError:
continue
for item in model.objects.all():
q = historical_model.objects.filter(id=item.pk).order_by("-history_date")
@@ -192,7 +192,7 @@ def migrate_created_field(apps, app_name, model_names):
model = apps.get_model(app_name, model_name)
try:
model_history = apps.get_model(app_name, "Historical" + model_name)
- except:
+ except LookupError:
continue
for item in model.objects.all():
q = model_history.objects.filter(id=item.pk).order_by("history_date")
diff --git a/ishtar_common/views.py b/ishtar_common/views.py
index ac4e995d1..ba9be495a 100644
--- a/ishtar_common/views.py
+++ b/ishtar_common/views.py
@@ -1256,8 +1256,9 @@ class QRCodeView(DynamicModelView, IshtarMixin, LoginRequiredMixin, View):
model = self.get_model(kwargs)
try:
item = model.objects.get(pk=kwargs.get("pk"))
- assert hasattr(item, "qrcode")
- except (model.DoesNotExist, AssertionError):
+ except model.DoesNotExist:
+ raise Http404()
+ if not hasattr(item, "qrcode"):
raise Http404()
if not item.qrcode or not item.qrcode.name:
@@ -2191,8 +2192,9 @@ class DocumentEditView(DocumentFormMixin, UpdateView):
kwargs = super(DocumentEditView, self).get_form_kwargs()
try:
document = models.Document.objects.get(pk=self.kwargs.get("pk"))
- assert check_permission(self.request, "document/edit", document.pk)
- except (AssertionError, models.Document.DoesNotExist):
+ except models.Document.DoesNotExist:
+ raise Http404()
+ if not check_permission(self.request, "document/edit", document.pk):
raise Http404()
initial = {}
for k in (
@@ -2475,7 +2477,8 @@ class QAItemForm(IshtarMixin, LoginRequiredMixin, FormView):
return self.model.get_quick_action_by_url(self.base_url)
def pre_dispatch(self, request, *args, **kwargs):
- assert self.model
+ if not self.model:
+ raise NotImplementedError("No attribute model defined.")
pks = [int(pk) for pk in kwargs.get("pks").split("-")]
self.items = list(self.model.objects.filter(pk__in=pks))
if not self.items:
@@ -2836,8 +2839,10 @@ class GeoEditView(GeoFormMixin, UpdateView):
kwargs = super(GeoEditView, self).get_form_kwargs()
try:
geo = models.GeoVectorData.objects.get(pk=self.kwargs.get("pk"))
- assert check_permission(self.request, "geo/edit", geo.pk)
- except (AssertionError, models.GeoVectorData.DoesNotExist):
+ except models.GeoVectorData.DoesNotExist:
+ raise Http404()
+
+ if not check_permission(self.request, "geo/edit", geo.pk):
raise Http404()
initial = {}
diff --git a/ishtar_common/views_item.py b/ishtar_common/views_item.py
index 5947a6798..b2b924992 100644
--- a/ishtar_common/views_item.py
+++ b/ishtar_common/views_item.py
@@ -9,7 +9,8 @@ import json
import logging
import re
import requests
-import subprocess
+# nosec: no user input used
+import subprocess # nosec
from tempfile import NamedTemporaryFile
import unidecode
@@ -405,12 +406,13 @@ def show_item(model, name, extra_dct=None, model_for_perms=None):
dct["IS_HISTORY"] = True
if item.get_last_history_date() != date:
item = item.get_previous(date=date)
- assert item is not None
+ if item is None:
+ raise ValueError("No previous history entry.")
dct["previous"] = item._previous
dct["next"] = item._next
else:
date = None
- except (ValueError, AssertionError):
+ except ValueError:
return HttpResponse("", content_type="text/plain")
if not date:
historized = item.history.all()
@@ -466,7 +468,8 @@ def show_item(model, name, extra_dct=None, model_for_perms=None):
html_source.name,
]
try:
- subprocess.check_call(
+ # nosec: no user input
+ subprocess.check_call( # nosec
pandoc_args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
)
except subprocess.CalledProcessError:
@@ -1011,7 +1014,7 @@ def _manage_facet_search(model, dct, and_reqs):
rel = getattr(model, base_k).field.related_model
if not hasattr(rel, "label") and hasattr(rel, "cached_label"):
lbl_name = "__cached_label__"
- except:
+ except AttributeError:
pass
suffix = (
"{}icontains".format(lbl_name)
@@ -2311,7 +2314,8 @@ def get_item(
try:
start = int(request_items.get("start"))
page_nb = start // row_nb + 1
- assert page_nb >= 1
+ if page_nb < 1:
+ raise ValueError("Page number is not relevant.")
except (TypeError, ValueError, AssertionError):
start = 0
page_nb = 1
diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py
index 030bb4af2..8dcb16b70 100644
--- a/ishtar_common/wizards.py
+++ b/ishtar_common/wizards.py
@@ -587,9 +587,10 @@ class Wizard(IshtarWizard):
fields.pop("DELETE")
multi = len(fields) > 1
if multi:
- assert hasattr(frm, "base_model") or hasattr(
- frm, "base_models"
- ), "Must define a base_model(s) for " + str(frm.__class__)
+ if not hasattr(frm, "base_model") and not hasattr(frm, "base_models"):
+ raise NotImplementedError(
+ f"Must define a base_model(s) for {frm.__class__}"
+ )
for frm in form.forms:
if not frm.is_valid():
continue
@@ -703,7 +704,8 @@ class Wizard(IshtarWizard):
continue
vals = k.split("__")
- assert len(vals) == 2, "Only one level of dependant item is managed"
+ if len(vals) != 2:
+ raise NotImplementedError("Only one level of dependant item is managed")
dependant_item, key = vals
if dependant_item not in other_objs:
other_objs[dependant_item] = {}
@@ -906,9 +908,10 @@ class Wizard(IshtarWizard):
model = related_model.through
# not m2m -> foreign key
if not hasattr(related_model, "clear"):
- assert hasattr(
- model, "MAIN_ATTR"
- ), "Must define a MAIN_ATTR for " + str(model.__class__)
+ if not hasattr(model, "MAIN_ATTR"):
+ raise NotImplementedError(
+ f"Must define a MAIN_ATTR for {model.__class__}."
+ )
value[getattr(model, "MAIN_ATTR")] = obj
# check old links
@@ -1112,7 +1115,7 @@ class Wizard(IshtarWizard):
idx = items[-2]
try:
int(idx)
- except:
+ except ValueError:
continue
if items[-1] == "DELETE":
to_delete.add(idx)
@@ -1710,7 +1713,8 @@ class DeletionWizard(Wizard):
hasattr(self, "model") and hasattr(self.model, "TABLE_COLS")
):
self.fields = self.model.TABLE_COLS
- assert self.model
+ if not self.model:
+ raise NotImplementedError("Missing model attribute")
super(DeletionWizard, self).__init__(*args, **kwargs)
def get_formated_datas(self, forms):
@@ -1785,7 +1789,8 @@ class MultipleDeletionWizard(MultipleItemWizard):
hasattr(self, "model") and hasattr(self.model, "TABLE_COLS")
):
self.fields = self.model.TABLE_COLS
- assert self.model
+ if not self.model:
+ raise NotImplementedError("Missing model attribute")
super(MultipleDeletionWizard, self).__init__(*args, **kwargs)
def get_template_names(self):