88from datetime import datetime , timedelta
99from decimal import Decimal
1010from pathlib import Path
11+ from urllib .parse import urlparse
1112from uuid import uuid4
1213
1314import dateutil
1415import hyperlink
1516import tagulous .admin
1617from auditlog .registry import auditlog
18+ from dateutil .parser import parse as datetutilsparse
1719from dateutil .relativedelta import relativedelta
1820from django import forms
1921from django .conf import settings
4143from polymorphic .models import PolymorphicModel
4244from tagulous .models import TagField
4345from tagulous .models .managers import FakeTagRelatedManager
46+ from titlecase import titlecase
4447
4548from dojo .validators import cvss3_validator , cvss4_validator
4649
@@ -670,7 +673,7 @@ class System_Settings(models.Model):
670673 "This is a performance enhancement to avoid fetching objects unnecessarily." ,
671674 ))
672675
673- from dojo .middleware import System_Settings_Manager
676+ from dojo .middleware import System_Settings_Manager # noqa: PLC0415 circular import
674677 objects = System_Settings_Manager ()
675678
676679 def clean (self ):
@@ -870,7 +873,6 @@ def __str__(self):
870873 return self .name
871874
872875 def get_absolute_url (self ):
873- from django .urls import reverse
874876 return reverse ("product_type" , args = [str (self .id )])
875877
876878 def get_breadcrumbs (self ):
@@ -1092,7 +1094,7 @@ def save(self, *args, **kwargs):
10921094 product .async_updating = True
10931095 super (Product , product ).save ()
10941096 # launch the async task to update all finding sla expiration dates
1095- from dojo .sla_config .helpers import update_sla_expiration_dates_sla_config_async
1097+ from dojo .sla_config .helpers import update_sla_expiration_dates_sla_config_async # noqa: I001, PLC0415 circular import
10961098 update_sla_expiration_dates_sla_config_async (self , products , tuple (severities ))
10971099
10981100 def clean (self ):
@@ -1254,11 +1256,10 @@ def save(self, *args, **kwargs):
12541256 sla_config .async_updating = True
12551257 super (SLA_Configuration , sla_config ).save ()
12561258 # launch the async task to update all finding sla expiration dates
1257- from dojo .sla_config .helpers import update_sla_expiration_dates_product_async
1259+ from dojo .sla_config .helpers import update_sla_expiration_dates_product_async # noqa: I001, PLC0415 circular import
12581260 update_sla_expiration_dates_product_async (self , sla_config )
12591261
12601262 def get_absolute_url (self ):
1261- from django .urls import reverse
12621263 return reverse ("view_product" , args = [str (self .id )])
12631264
12641265 @cached_property
@@ -1309,7 +1310,7 @@ def open_findings(self, start_date=None, end_date=None):
13091310 if start_date is None or end_date is None :
13101311 return {}
13111312
1312- from dojo .utils import get_system_setting
1313+ from dojo .utils import get_system_setting # noqa: PLC0415 circular import
13131314 findings = Finding .objects .filter (test__engagement__product = self ,
13141315 mitigated__isnull = True ,
13151316 false_p = False ,
@@ -1347,7 +1348,7 @@ def open_findings_list(self):
13471348
13481349 @property
13491350 def has_jira_configured (self ):
1350- import dojo .jira_link .helper as jira_helper
1351+ import dojo .jira_link .helper as jira_helper # noqa: PLC0415 circular import
13511352 return jira_helper .has_jira_configured (self )
13521353
13531354 def violates_sla (self ):
@@ -1578,7 +1579,6 @@ def __str__(self):
15781579 "%b %d, %Y" ))
15791580
15801581 def get_absolute_url (self ):
1581- from django .urls import reverse
15821582 return reverse ("view_engagement" , args = [str (self .id )])
15831583
15841584 def copy (self ):
@@ -1624,7 +1624,7 @@ def get_breadcrumbs(self):
16241624 # only used by bulk risk acceptance api
16251625 @property
16261626 def unaccepted_open_findings (self ):
1627- from dojo .utils import get_system_setting
1627+ from dojo .utils import get_system_setting # noqa: PLC0415 circular import
16281628
16291629 findings = Finding .objects .filter (risk_accepted = False , active = True , duplicate = False , test__engagement = self )
16301630 if get_system_setting ("enforce_verified_status" , True ) or get_system_setting ("enforce_verified_status_metrics" , True ):
@@ -1637,7 +1637,7 @@ def accept_risks(self, accepted_risks):
16371637
16381638 @property
16391639 def has_jira_issue (self ):
1640- import dojo .jira_link .helper as jira_helper
1640+ import dojo .jira_link .helper as jira_helper # noqa: PLC0415 circular import
16411641 return jira_helper .has_jira_issue (self )
16421642
16431643 @property
@@ -1646,8 +1646,8 @@ def is_ci_cd(self):
16461646
16471647 def delete (self , * args , ** kwargs ):
16481648 logger .debug ("%d engagement delete" , self .id )
1649- from dojo .finding import helper
1650- helper .prepare_duplicates_for_delete (engagement = self )
1649+ from dojo .finding import helper as finding_helper # noqa: PLC0415 circular import
1650+ finding_helper .prepare_duplicates_for_delete (engagement = self )
16511651 super ().delete (* args , ** kwargs )
16521652 with suppress (Engagement .DoesNotExist , Product .DoesNotExist ):
16531653 # Suppressing a potential issue created from async delete removing
@@ -1820,7 +1820,6 @@ def __str__(self):
18201820 return url
18211821
18221822 def get_absolute_url (self ):
1823- from django .urls import reverse
18241823 return reverse ("view_endpoint" , args = [str (self .id )])
18251824
18261825 def clean (self ):
@@ -2038,7 +2037,6 @@ def from_uri(uri):
20382037 try :
20392038 url = hyperlink .parse (url = uri )
20402039 except UnicodeDecodeError :
2041- from urllib .parse import urlparse
20422040 url = hyperlink .parse (url = "//" + urlparse (uri ).netloc )
20432041 except hyperlink .URLParseError as e :
20442042 msg = f"Invalid URL format: { e } "
@@ -2151,7 +2149,6 @@ def __str__(self):
21512149 return str (self .test_type )
21522150
21532151 def get_absolute_url (self ):
2154- from django .urls import reverse
21552152 return reverse ("view_test" , args = [str (self .id )])
21562153
21572154 def test_type_name (self ) -> str :
@@ -2191,7 +2188,7 @@ def copy(self, engagement=None):
21912188 # only used by bulk risk acceptance api
21922189 @property
21932190 def unaccepted_open_findings (self ):
2194- from dojo .utils import get_system_setting
2191+ from dojo .utils import get_system_setting # noqa: PLC0415 circular import
21952192 findings = Finding .objects .filter (risk_accepted = False , active = True , duplicate = False , test = self )
21962193 if get_system_setting ("enforce_verified_status" , True ) or get_system_setting ("enforce_verified_status_metrics" , True ):
21972194 findings = findings .filter (verified = True )
@@ -2740,16 +2737,15 @@ def __str__(self):
27402737 def save (self , dedupe_option = True , rules_option = True , product_grading_option = True , # noqa: FBT002
27412738 issue_updater_option = True , push_to_jira = False , user = None , * args , ** kwargs ): # noqa: FBT002 - this is bit hard to fix nice have this universally fixed
27422739 logger .debug ("Start saving finding of id " + str (self .id ) + " dedupe_option:" + str (dedupe_option ) + " (self.pk is %s)" , "None" if self .pk is None else "not None" )
2743- from dojo .finding import helper as finding_helper
2740+ from dojo .finding import helper as finding_helper # noqa: PLC0415 circular import
27442741
27452742 # if not isinstance(self.date, (datetime, date)):
27462743 # raise ValidationError(_("The 'date' field must be a valid date or datetime object."))
27472744
27482745 if not user :
2749- from dojo .utils import get_current_user
2746+ from dojo .utils import get_current_user # noqa: PLC0415 circular import
27502747 user = get_current_user ()
27512748 # Title Casing
2752- from titlecase import titlecase
27532749 self .title = titlecase (self .title [:511 ])
27542750 # Set the date of the finding if nothing is supplied
27552751 if self .date is None :
@@ -2788,7 +2784,7 @@ def save(self, dedupe_option=True, rules_option=True, product_grading_option=Tru
27882784
27892785 if self .pk is None :
27902786 # We enter here during the first call from serializers.py
2791- from dojo .utils import apply_cwe_to_template
2787+ from dojo .utils import apply_cwe_to_template # noqa: PLC0415 circular import
27922788 # No need to use the returned variable since `self` Is updated in memory
27932789 apply_cwe_to_template (self )
27942790 if (self .file_path is not None ) and (len (self .unsaved_endpoints ) == 0 ):
@@ -2826,7 +2822,6 @@ def save(self, dedupe_option=True, rules_option=True, product_grading_option=Tru
28262822 logger .debug ("no options selected that require finding post processing" )
28272823
28282824 def get_absolute_url (self ):
2829- from django .urls import reverse
28302825 return reverse ("view_finding" , args = [str (self .id )])
28312826
28322827 def copy (self , test = None ):
@@ -2863,8 +2858,8 @@ def copy(self, test=None):
28632858
28642859 def delete (self , * args , ** kwargs ):
28652860 logger .debug ("%d finding delete" , self .id )
2866- from dojo .finding import helper
2867- helper .finding_delete (self )
2861+ from dojo .finding import helper as finding_helper # noqa: PLC0415 circular import
2862+ finding_helper .finding_delete (self )
28682863 super ().delete (* args , ** kwargs )
28692864 with suppress (Finding .DoesNotExist , Test .DoesNotExist , Engagement .DoesNotExist , Product .DoesNotExist ):
28702865 # Suppressing a potential issue created from async delete removing
@@ -2874,7 +2869,7 @@ def delete(self, *args, **kwargs):
28742869 # only used by bulk risk acceptance api
28752870 @classmethod
28762871 def unaccepted_open_findings (cls ):
2877- from dojo .utils import get_system_setting
2872+ from dojo .utils import get_system_setting # noqa: PLC0415 circular import
28782873 results = cls .objects .filter (active = True , duplicate = False , risk_accepted = False )
28792874 if get_system_setting ("enforce_verified_status" , True ) or get_system_setting ("enforce_verified_status_metrics" , True ):
28802875 results = results .filter (verified = True )
@@ -3084,9 +3079,8 @@ def status(self):
30843079 return ", " .join ([str (s ) for s in status ])
30853080
30863081 def _age (self , start_date ):
3087- from dateutil .parser import parse
30883082 if start_date and isinstance (start_date , str ):
3089- start_date = parse (start_date ).date ()
3083+ start_date = datetutilsparse (start_date ).date ()
30903084
30913085 if isinstance (start_date , datetime ):
30923086 start_date = start_date .date ()
@@ -3183,7 +3177,7 @@ def github_conf_new(self):
31833177
31843178 @property
31853179 def has_jira_issue (self ):
3186- import dojo .jira_link .helper as jira_helper
3180+ import dojo .jira_link .helper as jira_helper # noqa: PLC0415 circular import
31873181 return jira_helper .has_jira_issue (self )
31883182
31893183 @cached_property
@@ -3196,12 +3190,12 @@ def has_jira_group_issue(self):
31963190 if not self .has_finding_group :
31973191 return False
31983192
3199- import dojo .jira_link .helper as jira_helper
3193+ import dojo .jira_link .helper as jira_helper # noqa: PLC0415 circular import
32003194 return jira_helper .has_jira_issue (self .finding_group )
32013195
32023196 @property
32033197 def has_jira_configured (self ):
3204- import dojo .jira_link .helper as jira_helper
3198+ import dojo .jira_link .helper as jira_helper # noqa: PLC0415 circular import
32053199 return jira_helper .has_jira_configured (self )
32063200
32073201 @cached_property
@@ -3281,7 +3275,7 @@ def latest_note(self):
32813275 return ""
32823276
32833277 def get_sast_source_file_path_with_link (self ):
3284- from dojo .utils import create_bleached_link
3278+ from dojo .utils import create_bleached_link # noqa: PLC0415 circular import
32853279 if self .sast_source_file_path is None :
32863280 return None
32873281 if self .test .engagement .source_code_management_uri is None :
@@ -3292,7 +3286,7 @@ def get_sast_source_file_path_with_link(self):
32923286 return create_bleached_link (link , self .sast_source_file_path )
32933287
32943288 def get_file_path_with_link (self ):
3295- from dojo .utils import create_bleached_link
3289+ from dojo .utils import create_bleached_link # noqa: PLC0415 circular import
32963290 if self .file_path is None :
32973291 return None
32983292 if self .test .engagement .source_code_management_uri is None :
@@ -3406,9 +3400,7 @@ def get_file_path_with_raw_link(self):
34063400 return link
34073401
34083402 def get_references_with_links (self ):
3409- import re
3410-
3411- from dojo .utils import create_bleached_link
3403+ from dojo .utils import create_bleached_link # noqa: PLC0415 circular import
34123404 if self .references is None :
34133405 return None
34143406 matches = re .findall (r"([\(|\[]?(https?):((//)|(\\\\))+([\w\d:#@%/;$~_?\+-=\\\.&](#!)?)*[\)|\]]?)" , self .references )
@@ -3452,7 +3444,7 @@ def violates_sla(self):
34523444 return (self .sla_expiration_date and self .sla_expiration_date < timezone .now ().date ())
34533445
34543446 def set_hash_code (self , dedupe_option ):
3455- from dojo .utils import get_custom_method
3447+ from dojo .utils import get_custom_method # noqa: PLC0415 circular import
34563448 if hash_method := get_custom_method ("FINDING_HASH_METHOD" ):
34573449 hash_method (self , dedupe_option )
34583450 # Finding.save is called once from serializers.py with dedupe_option=False because the finding is not ready yet, for example the endpoints are not built
@@ -3481,7 +3473,6 @@ def __str__(self):
34813473 return self .vulnerability_id
34823474
34833475 def get_absolute_url (self ):
3484- from django .urls import reverse
34853476 return reverse ("view_finding" , args = [str (self .finding .id )])
34863477
34873478
@@ -3524,7 +3515,7 @@ def __str__(self):
35243515
35253516 @property
35263517 def has_jira_issue (self ):
3527- import dojo .jira_link .helper as jira_helper
3518+ import dojo .jira_link .helper as jira_helper # noqa: PLC0415 circular import
35283519 return jira_helper .has_jira_issue (self )
35293520
35303521 @cached_property
@@ -3585,7 +3576,6 @@ def get_sla_start_date(self):
35853576 return min (find .get_sla_start_date () for find in self .findings .all ())
35863577
35873578 def get_absolute_url (self ):
3588- from django .urls import reverse
35893579 return reverse ("view_test" , args = [str (self .test .id )])
35903580
35913581 class Meta :
@@ -3624,7 +3614,6 @@ def __str__(self):
36243614 return self .title
36253615
36263616 def get_absolute_url (self ):
3627- from django .urls import reverse
36283617 return reverse ("edit_template" , args = [str (self .id )])
36293618
36303619 def get_breadcrumbs (self ):
@@ -4567,7 +4556,7 @@ class TextQuestion(Question):
45674556
45684557 def get_form (self ):
45694558 """Returns the form for this model"""
4570- from .forms import TextQuestionForm
4559+ from .forms import TextQuestionForm # noqa: PLC0415
45714560 return TextQuestionForm
45724561
45734562
@@ -4600,7 +4589,7 @@ class ChoiceQuestion(Question):
46004589
46014590 def get_form (self ):
46024591 """Returns the form for this model"""
4603- from .forms import ChoiceQuestionForm
4592+ from .forms import ChoiceQuestionForm # noqa: PLC0415
46044593 return ChoiceQuestionForm
46054594
46064595
0 commit comments