bad-checker 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,55 @@
1
+ Metadata-Version: 2.4
2
+ Name: bad-checker
3
+ Version: 0.1.0
4
+ Summary: A typo-tolerant blocklist checker.
5
+ Author-email: coder5330 <hello@jldev.com>
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Operating System :: OS Independent
9
+ Requires-Python: >=3.7
10
+ Description-Content-Type: text/markdown
11
+
12
+ # bad-checker
13
+
14
+ A fuzzy, keyboard-typo- and leetspeak-aware content blocklist for Python.
15
+
16
+ Install name: `bad-checker` &nbsp;|&nbsp; Import name: `bad`
17
+
18
+ ## Usage
19
+
20
+ ```python
21
+ import bad
22
+
23
+ if "something bad" in bad:
24
+ print("Caught it!")
25
+ ```
26
+
27
+ Matching combines:
28
+ - direct substring lookups against a blocklist
29
+ - leetspeak normalization (`v1agra` -> `viagra`, `fr33` -> `free`)
30
+ - a keyboard-proximity-aware Damerau-Levenshtein distance, so typos on
31
+ physically nearby keys (and adjacent-letter transpositions) are caught
32
+ cheaply while unrelated words are not
33
+
34
+ Add your own keywords at runtime:
35
+
36
+ ```python
37
+ bad.add_keywords("mycompanyscam", "internaltermtoflag")
38
+ ```
39
+
40
+ ## Install
41
+
42
+ ```bash
43
+ pip install bad-checker
44
+ ```
45
+
46
+ ## Build from source
47
+
48
+ ```bash
49
+ pip install --upgrade build
50
+ python -m build
51
+ ```
52
+
53
+ ## License
54
+
55
+ MIT
@@ -0,0 +1,44 @@
1
+ # bad-checker
2
+
3
+ A fuzzy, keyboard-typo- and leetspeak-aware content blocklist for Python.
4
+
5
+ Install name: `bad-checker` &nbsp;|&nbsp; Import name: `bad`
6
+
7
+ ## Usage
8
+
9
+ ```python
10
+ import bad
11
+
12
+ if "something bad" in bad:
13
+ print("Caught it!")
14
+ ```
15
+
16
+ Matching combines:
17
+ - direct substring lookups against a blocklist
18
+ - leetspeak normalization (`v1agra` -> `viagra`, `fr33` -> `free`)
19
+ - a keyboard-proximity-aware Damerau-Levenshtein distance, so typos on
20
+ physically nearby keys (and adjacent-letter transpositions) are caught
21
+ cheaply while unrelated words are not
22
+
23
+ Add your own keywords at runtime:
24
+
25
+ ```python
26
+ bad.add_keywords("mycompanyscam", "internaltermtoflag")
27
+ ```
28
+
29
+ ## Install
30
+
31
+ ```bash
32
+ pip install bad-checker
33
+ ```
34
+
35
+ ## Build from source
36
+
37
+ ```bash
38
+ pip install --upgrade build
39
+ python -m build
40
+ ```
41
+
42
+ ## License
43
+
44
+ MIT
@@ -0,0 +1,16 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "bad-checker"
7
+ version = "0.1.0"
8
+ authors = [{ name="coder5330", email="hello@jldev.com" }]
9
+ description = "A typo-tolerant blocklist checker."
10
+ readme = "README.md"
11
+ requires-python = ">=3.7"
12
+ classifiers = [
13
+ "Programming Language :: Python :: 3",
14
+ "License :: OSI Approved :: MIT License",
15
+ "Operating System :: OS Independent",
16
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,102 @@
1
+ import sys as _sys
2
+ import types as _types
3
+
4
+ __all__ = []
5
+
6
+ _ROWS = [
7
+ "`1234567890-=",
8
+ "qwertyuiop[]\\",
9
+ "asdfghjkl;'",
10
+ "zxcvbnm,./",
11
+ ]
12
+ _ROW_OFFSETS = [0.0, 0.5, 0.75, 1.25]
13
+
14
+ _KEY_COORDS = {}
15
+ for _row, _text in enumerate(_ROWS):
16
+ for _col, _char in enumerate(_text):
17
+ _KEY_COORDS[_char] = (_col + _ROW_OFFSETS[_row], float(_row))
18
+
19
+ _LEET_TABLE = str.maketrans({
20
+ "0": "o", "1": "i", "3": "e", "4": "a", "5": "s",
21
+ "7": "t", "@": "a", "$": "s", "!": "i", "+": "t",
22
+ })
23
+
24
+ _DEFAULT_BLOCKLIST = [
25
+ "microsoft", "blocksi"
26
+ ]
27
+
28
+
29
+ class _BadModule(_types.ModuleType):
30
+ @staticmethod
31
+ def _key_distance(c1, c2):
32
+ c1, c2 = c1.lower(), c2.lower()
33
+ if c1 == c2:
34
+ return 0.0
35
+ p1, p2 = _KEY_COORDS.get(c1), _KEY_COORDS.get(c2)
36
+ if p1 is None or p2 is None:
37
+ return 3.0
38
+ return ((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2) ** 0.5
39
+
40
+ @classmethod
41
+ def _sub_cost(cls, c1, c2):
42
+ if c1.lower() == c2.lower():
43
+ return 0.0
44
+ dist = cls._key_distance(c1, c2)
45
+ return min(1.0, 0.3 + 0.2 * dist)
46
+
47
+ @classmethod
48
+ def _fuzzy_distance(cls, w1, w2):
49
+ m, n = len(w1), len(w2)
50
+ dp = [[0.0] * (n + 1) for _ in range(m + 1)]
51
+ for i in range(m + 1):
52
+ dp[i][0] = float(i)
53
+ for j in range(n + 1):
54
+ dp[0][j] = float(j)
55
+
56
+ for i in range(1, m + 1):
57
+ for j in range(1, n + 1):
58
+ cost = cls._sub_cost(w1[i - 1], w2[j - 1])
59
+ dp[i][j] = min(
60
+ dp[i - 1][j] + 1.0,
61
+ dp[i][j - 1] + 1.0,
62
+ dp[i - 1][j - 1] + cost,
63
+ )
64
+ if (i > 1 and j > 1
65
+ and w1[i - 1] == w2[j - 2]
66
+ and w1[i - 2] == w2[j - 1]):
67
+ dp[i][j] = min(dp[i][j], dp[i - 2][j - 2] + 0.6)
68
+ return dp[m][n]
69
+
70
+ @staticmethod
71
+ def _deleet(text):
72
+ return text.translate(_LEET_TABLE)
73
+
74
+ def __contains__(self, text):
75
+ if not isinstance(text, str):
76
+ return False
77
+
78
+ normalized = text.lower()
79
+ deleeted = self._deleet(normalized)
80
+ words = deleeted.split()
81
+
82
+ for keyword in self.banned_keywords:
83
+ keyword = keyword.lower()
84
+
85
+ if keyword in normalized or keyword in deleeted:
86
+ return True
87
+
88
+ if " " in keyword:
89
+ continue
90
+
91
+ for word in words:
92
+ if abs(len(word) - len(keyword)) <= 2:
93
+ if self._fuzzy_distance(word, keyword) <= 1.0:
94
+ return True
95
+ return False
96
+
97
+ def add_keywords(self, *keywords):
98
+ self.banned_keywords.extend(k.lower() for k in keywords)
99
+
100
+ _mod = _sys.modules[__name__]
101
+ _mod.__class__ = _BadModule
102
+ _mod.banned_keywords = list(_DEFAULT_BLOCKLIST)
@@ -0,0 +1,55 @@
1
+ Metadata-Version: 2.4
2
+ Name: bad-checker
3
+ Version: 0.1.0
4
+ Summary: A typo-tolerant blocklist checker.
5
+ Author-email: coder5330 <hello@jldev.com>
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Operating System :: OS Independent
9
+ Requires-Python: >=3.7
10
+ Description-Content-Type: text/markdown
11
+
12
+ # bad-checker
13
+
14
+ A fuzzy, keyboard-typo- and leetspeak-aware content blocklist for Python.
15
+
16
+ Install name: `bad-checker` &nbsp;|&nbsp; Import name: `bad`
17
+
18
+ ## Usage
19
+
20
+ ```python
21
+ import bad
22
+
23
+ if "something bad" in bad:
24
+ print("Caught it!")
25
+ ```
26
+
27
+ Matching combines:
28
+ - direct substring lookups against a blocklist
29
+ - leetspeak normalization (`v1agra` -> `viagra`, `fr33` -> `free`)
30
+ - a keyboard-proximity-aware Damerau-Levenshtein distance, so typos on
31
+ physically nearby keys (and adjacent-letter transpositions) are caught
32
+ cheaply while unrelated words are not
33
+
34
+ Add your own keywords at runtime:
35
+
36
+ ```python
37
+ bad.add_keywords("mycompanyscam", "internaltermtoflag")
38
+ ```
39
+
40
+ ## Install
41
+
42
+ ```bash
43
+ pip install bad-checker
44
+ ```
45
+
46
+ ## Build from source
47
+
48
+ ```bash
49
+ pip install --upgrade build
50
+ python -m build
51
+ ```
52
+
53
+ ## License
54
+
55
+ MIT
@@ -0,0 +1,7 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/bad/__init__.py
4
+ src/bad_checker.egg-info/PKG-INFO
5
+ src/bad_checker.egg-info/SOURCES.txt
6
+ src/bad_checker.egg-info/dependency_links.txt
7
+ src/bad_checker.egg-info/top_level.txt