Skip to content

Commit

Permalink
Get rid of subclass validation in base API
Browse files Browse the repository at this point in the history
  • Loading branch information
drdavella committed Sep 25, 2023
1 parent 3696e2e commit a72983a
Show file tree
Hide file tree
Showing 5 changed files with 20 additions and 69 deletions.
32 changes: 2 additions & 30 deletions src/codemodder/codemods/base_codemod.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from dataclasses import dataclass, asdict
from dataclasses import dataclass
from enum import Enum
import itertools
from typing import List, ClassVar
Expand Down Expand Up @@ -30,25 +30,6 @@ class BaseCodemod:
execution_context: CodemodExecutionContext
file_context: FileContext

def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)

if "codemodder.codemods.base_codemod.SemgrepCodemod" in str(cls):
# hack: SemgrepCodemod won't NotImplementedError but all other child
# classes will.
return

for attr in ["SUMMARY", "METADATA"]:
if getattr(cls, attr) is NotImplemented:
raise NotImplementedError(
f"You forgot to define {attr} for {cls.__name__}"
)
for k, v in asdict(cls.METADATA).items():
if v is NotImplemented:
raise NotImplementedError(f"You forgot to define METADATA.{k}")
if not v:
raise NotImplementedError(f"METADATA.{k} should not be None or empty")

def __init__(self, execution_context: CodemodExecutionContext, file_context):
self.execution_context = execution_context
self.file_context = file_context
Expand Down Expand Up @@ -88,18 +69,9 @@ class SemgrepCodemod(BaseCodemod):
YAML_FILES: ClassVar[List[str]] = NotImplemented
is_semgrep = True

def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)

if cls.YAML_FILES is NotImplemented:
raise NotImplementedError(
"You forgot to define class attribute: YAML_FILES"
)

cls.RULE_IDS = rule_ids_from_yaml_files(cls.YAML_FILES)

def __init__(self, *args):
super().__init__(*args)
self.RULE_IDS = rule_ids_from_yaml_files(self.YAML_FILES)
self._results = list(
itertools.chain.from_iterable(
map(lambda rId: self.file_context.results_by_id[rId], self.RULE_IDS)
Expand Down
33 changes: 0 additions & 33 deletions tests/codemods/test_base_codemod.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from typing import DefaultDict
import libcst as cst
from libcst.codemod import Codemod, CodemodContext
import pytest
import mock
from codemodder.codemods.base_codemod import (
SemgrepCodemod,
Expand Down Expand Up @@ -43,35 +42,3 @@ def run_and_assert(self, input_code, expexted_output):
def test_empty_results(self):
input_code = """print('Hello World')"""
self.run_and_assert(input_code, input_code)


class TestSemgrepCodemod:
# pylint: disable=unused-variable
def test_missing_class_attrs(self):
with pytest.raises(NotImplementedError):

class MissingInfoCodemod(SemgrepCodemod):
...

with pytest.raises(NotImplementedError):

class MissingNameCodemod(SemgrepCodemod):
METADATA = CodemodMetadata(
"Description", None, ReviewGuidance.MERGE_WITHOUT_REVIEW
)

with pytest.raises(NotImplementedError):

class MissingDescriptionCodemod(SemgrepCodemod):
METADATA = CodemodMetadata(
"", "Name", ReviewGuidance.MERGE_WITHOUT_REVIEW
)

with pytest.raises(NotImplementedError):

class MissingAuthorCodemod(SemgrepCodemod):
METADATA = CodemodMetadata(
NotImplemented,
"Name",
ReviewGuidance.MERGE_WITHOUT_REVIEW,
)
8 changes: 6 additions & 2 deletions tests/codemods/test_django_debug_flag_on.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
class TestDjangoDebugFlagOn(BaseDjangoCodemodTest):
codemod = DjangoDebugFlagOn

def test_rule_ids(self):
assert self.codemod.RULE_IDS == ["django-debug-flag-on"]
def test_rule_ids(self, mocker):
assert self.codemod(
mocker.MagicMock(),
mocker.MagicMock(),
mocker.MagicMock(),
).RULE_IDS == ["django-debug-flag-on"]

def test_settings_dot_py(self, tmpdir):
django_root, settings_folder = self.create_dir_structure(tmpdir)
Expand Down
8 changes: 6 additions & 2 deletions tests/codemods/test_django_session_cookie_secure_off.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@
class TestDjangoSessionSecureCookieOff(BaseDjangoCodemodTest):
codemod = DjangoSessionCookieSecureOff

def test_rule_ids(self):
assert self.codemod.RULE_IDS == ["found-settings-file"]
def test_rule_ids(self, mocker):
assert self.codemod(
mocker.MagicMock(),
mocker.MagicMock(),
mocker.MagicMock(),
).RULE_IDS == ["found-settings-file"]

def test_not_settings_dot_py(self, tmpdir):
django_root, settings_folder = self.create_dir_structure(tmpdir)
Expand Down
8 changes: 6 additions & 2 deletions tests/codemods/test_url_sandbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@
class TestUrlSandbox(BaseSemgrepCodemodTest):
codemod = UrlSandbox

def test_rule_ids(self):
assert self.codemod.RULE_IDS == ["sandbox-url-creation"]
def test_rule_ids(self, mocker):
assert self.codemod(
mocker.MagicMock(),
mocker.MagicMock(),
mocker.MagicMock(),
).RULE_IDS == ["sandbox-url-creation"]

def test_import_requests(self, tmpdir):
input_code = """import requests
Expand Down

0 comments on commit a72983a

Please sign in to comment.