profy-filter 0.1.0a1__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,41 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ test:
9
+ runs-on: ubuntu-latest
10
+ strategy:
11
+ fail-fast: false
12
+ matrix:
13
+ python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: ${{ matrix.python-version }}
19
+ - run: python -m pip install --upgrade pytest
20
+ - run: python -m pytest
21
+
22
+ build:
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ - uses: actions/setup-python@v5
27
+ with:
28
+ python-version: "3.12"
29
+ - run: python -m pip install --upgrade build
30
+ - run: python -m build
31
+ - run: python -m venv /tmp/profy-venv
32
+ - run: /tmp/profy-venv/bin/python -m pip install dist/profy_filter-*.whl
33
+ - run: |
34
+ cd /tmp
35
+ /tmp/profy-venv/bin/python - <<'PY'
36
+ from profy import filter_text
37
+
38
+ result = filter_text("Das ist scheisse", languages="german")
39
+ assert result.clean == "Das ist ********"
40
+ assert filter_text("Scunthorpe").is_clean
41
+ PY
@@ -0,0 +1,38 @@
1
+ name: Release
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ push:
6
+ tags:
7
+ - "v*"
8
+
9
+ permissions:
10
+ contents: write
11
+ id-token: write
12
+
13
+ jobs:
14
+ release:
15
+ runs-on: ubuntu-latest
16
+ environment: pypi
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ - uses: actions/setup-python@v5
20
+ with:
21
+ python-version: "3.12"
22
+ - run: python -m pip install --upgrade build pytest
23
+ - run: python -m pytest
24
+ - run: python -m build
25
+ - uses: actions/upload-artifact@v4
26
+ with:
27
+ name: profy-dist
28
+ path: dist/*
29
+ - uses: softprops/action-gh-release@v2
30
+ if: github.ref_type == 'tag'
31
+ with:
32
+ prerelease: true
33
+ files: dist/*
34
+ generate_release_notes: true
35
+ - uses: pypa/gh-action-pypi-publish@release/v1
36
+ with:
37
+ packages-dir: dist/
38
+ skip-existing: true
@@ -0,0 +1,17 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ .pytest_cache/
5
+ .venv/
6
+ .wheel-venv/
7
+ dist/
8
+ build/
9
+ *.egg-info/
10
+
11
+ # Local/editor
12
+ .DS_Store
13
+ .idea/
14
+ .vscode/
15
+
16
+ # Upstream sync cache
17
+ .cache/
@@ -0,0 +1,9 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0a1
4
+
5
+ - Initial alpha release of Profy.
6
+ - Replaced the PHP/Laravel fork contents with a standalone Python package.
7
+ - Ported Blasp's core obfuscation-aware profanity matching, masking, severity scoring, allow/block lists, and result objects.
8
+ - Bundled English, Spanish, German, and French dictionaries exported from Blasp's PHP config.
9
+ - Added Python CI, release workflow, and upstream Blasp sync tooling.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Michael Deeming
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,142 @@
1
+ Metadata-Version: 2.4
2
+ Name: profy-filter
3
+ Version: 0.1.0a1
4
+ Summary: A Python profanity filter forked from Blaspsoft/blasp.
5
+ Project-URL: Homepage, https://github.com/mantleCurve/profy
6
+ Project-URL: Repository, https://github.com/mantleCurve/profy
7
+ Project-URL: Issues, https://github.com/mantleCurve/profy/issues
8
+ Project-URL: Changelog, https://github.com/mantleCurve/profy/blob/main/CHANGELOG.md
9
+ Project-URL: Upstream, https://github.com/Blaspsoft/blasp
10
+ Author: MantleCurve
11
+ License-Expression: MIT
12
+ License-File: LICENSE.md
13
+ Keywords: blasp,filter,moderation,profanity,text-cleaning
14
+ Classifier: Development Status :: 3 - Alpha
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Text Processing :: Filters
25
+ Requires-Python: >=3.9
26
+ Provides-Extra: dev
27
+ Requires-Dist: build>=1.0; extra == 'dev'
28
+ Requires-Dist: pytest>=8.0; extra == 'dev'
29
+ Description-Content-Type: text/markdown
30
+
31
+ # Profy
32
+
33
+ Profy is a Python fork of [Blaspsoft/blasp](https://github.com/Blaspsoft/blasp), focused on the core profanity filtering engine rather than Laravel integration. It ports Blasp's dictionary-driven, obfuscation-aware matching into a standalone Python package.
34
+
35
+ The repository lives at [mantleCurve/profy](https://github.com/mantleCurve/profy).
36
+
37
+ ## Install
38
+
39
+ ```bash
40
+ pip install profy-filter
41
+ ```
42
+
43
+ The import package is `profy`:
44
+
45
+ ```python
46
+ from profy import filter_text, clean_text, check_text
47
+
48
+ result = filter_text("This is f-uuck!ng noisy")
49
+
50
+ print(result.is_offensive) # True
51
+ print(result.clean) # This is ********* noisy
52
+ print(result.unique_words) # ['fucking']
53
+ print(result.score) # severity-weighted score from 0 to 100
54
+
55
+ assert check_text("f**k")
56
+ assert clean_text("shit") == "****"
57
+ ```
58
+
59
+ ## Development
60
+
61
+ ```bash
62
+ python -m pip install -e ".[dev]"
63
+ python -m pytest
64
+ ```
65
+
66
+ ## Reuse a Filter
67
+
68
+ Create a `ProfanityFilter` when you need to process many strings with the same options.
69
+
70
+ ```python
71
+ from profy import ProfanityFilter, Severity
72
+
73
+ shield = ProfanityFilter(
74
+ languages=["english", "spanish"],
75
+ mask="#",
76
+ minimum_severity=Severity.MODERATE,
77
+ allow=["heck"],
78
+ block=["internal-ban-word"],
79
+ )
80
+
81
+ result = shield.check("clean this text")
82
+ print(result.to_dict())
83
+ ```
84
+
85
+ ## Options
86
+
87
+ `filter_text()` and `ProfanityFilter()` accept:
88
+
89
+ - `languages`: a language name or iterable. Bundled data includes `english`, `spanish`, `german`, and `french`.
90
+ - `all_languages`: use every bundled language dictionary.
91
+ - `allow`: words that should never be flagged.
92
+ - `block`: extra words that should always be flagged.
93
+ - `mask`: a replacement character or callback `(word, length) -> str`.
94
+ - `minimum_severity`: `mild`, `moderate`, `high`, or `extreme`.
95
+
96
+ ## Result Shape
97
+
98
+ ```python
99
+ {
100
+ "original": "This is shit",
101
+ "clean": "This is ****",
102
+ "is_offensive": True,
103
+ "score": 40,
104
+ "count": 1,
105
+ "unique_words": ["shit"],
106
+ "severity": "high",
107
+ "words": [
108
+ {
109
+ "text": "shit",
110
+ "base": "shit",
111
+ "severity": "high",
112
+ "position": 8,
113
+ "length": 4,
114
+ "language": "english",
115
+ }
116
+ ],
117
+ }
118
+ ```
119
+
120
+ ## Scope
121
+
122
+ This fork intentionally ports the profanity filter itself, not Blasp's Laravel service provider, middleware, Eloquent helpers, events, facades, or cache layer.
123
+
124
+ ## Upstream Sync
125
+
126
+ Use `scripts/sync_from_blasp.py` to fetch the latest Blasp PHP repository, export updated dictionary/config data into Profy's Python package, and generate an implementation-change report for PHP files that need manual port review.
127
+
128
+ ```bash
129
+ python scripts/sync_from_blasp.py
130
+ ```
131
+
132
+ ## Release
133
+
134
+ Alpha releases use PEP 440 versions such as `0.1.0a1` and Git tags such as `v0.1.0a1`. The GitHub Actions release workflow runs tests, builds the source distribution and wheel, uploads them as artifacts, and attaches them to the GitHub Release.
135
+
136
+ ## Attribution
137
+
138
+ Profy is a Python fork of [Blaspsoft/blasp](https://github.com/Blaspsoft/blasp), originally authored by Michael Deeming and released under the MIT license.
139
+
140
+ ## License
141
+
142
+ MIT. See [LICENSE.md](LICENSE.md).
@@ -0,0 +1,112 @@
1
+ # Profy
2
+
3
+ Profy is a Python fork of [Blaspsoft/blasp](https://github.com/Blaspsoft/blasp), focused on the core profanity filtering engine rather than Laravel integration. It ports Blasp's dictionary-driven, obfuscation-aware matching into a standalone Python package.
4
+
5
+ The repository lives at [mantleCurve/profy](https://github.com/mantleCurve/profy).
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pip install profy-filter
11
+ ```
12
+
13
+ The import package is `profy`:
14
+
15
+ ```python
16
+ from profy import filter_text, clean_text, check_text
17
+
18
+ result = filter_text("This is f-uuck!ng noisy")
19
+
20
+ print(result.is_offensive) # True
21
+ print(result.clean) # This is ********* noisy
22
+ print(result.unique_words) # ['fucking']
23
+ print(result.score) # severity-weighted score from 0 to 100
24
+
25
+ assert check_text("f**k")
26
+ assert clean_text("shit") == "****"
27
+ ```
28
+
29
+ ## Development
30
+
31
+ ```bash
32
+ python -m pip install -e ".[dev]"
33
+ python -m pytest
34
+ ```
35
+
36
+ ## Reuse a Filter
37
+
38
+ Create a `ProfanityFilter` when you need to process many strings with the same options.
39
+
40
+ ```python
41
+ from profy import ProfanityFilter, Severity
42
+
43
+ shield = ProfanityFilter(
44
+ languages=["english", "spanish"],
45
+ mask="#",
46
+ minimum_severity=Severity.MODERATE,
47
+ allow=["heck"],
48
+ block=["internal-ban-word"],
49
+ )
50
+
51
+ result = shield.check("clean this text")
52
+ print(result.to_dict())
53
+ ```
54
+
55
+ ## Options
56
+
57
+ `filter_text()` and `ProfanityFilter()` accept:
58
+
59
+ - `languages`: a language name or iterable. Bundled data includes `english`, `spanish`, `german`, and `french`.
60
+ - `all_languages`: use every bundled language dictionary.
61
+ - `allow`: words that should never be flagged.
62
+ - `block`: extra words that should always be flagged.
63
+ - `mask`: a replacement character or callback `(word, length) -> str`.
64
+ - `minimum_severity`: `mild`, `moderate`, `high`, or `extreme`.
65
+
66
+ ## Result Shape
67
+
68
+ ```python
69
+ {
70
+ "original": "This is shit",
71
+ "clean": "This is ****",
72
+ "is_offensive": True,
73
+ "score": 40,
74
+ "count": 1,
75
+ "unique_words": ["shit"],
76
+ "severity": "high",
77
+ "words": [
78
+ {
79
+ "text": "shit",
80
+ "base": "shit",
81
+ "severity": "high",
82
+ "position": 8,
83
+ "length": 4,
84
+ "language": "english",
85
+ }
86
+ ],
87
+ }
88
+ ```
89
+
90
+ ## Scope
91
+
92
+ This fork intentionally ports the profanity filter itself, not Blasp's Laravel service provider, middleware, Eloquent helpers, events, facades, or cache layer.
93
+
94
+ ## Upstream Sync
95
+
96
+ Use `scripts/sync_from_blasp.py` to fetch the latest Blasp PHP repository, export updated dictionary/config data into Profy's Python package, and generate an implementation-change report for PHP files that need manual port review.
97
+
98
+ ```bash
99
+ python scripts/sync_from_blasp.py
100
+ ```
101
+
102
+ ## Release
103
+
104
+ Alpha releases use PEP 440 versions such as `0.1.0a1` and Git tags such as `v0.1.0a1`. The GitHub Actions release workflow runs tests, builds the source distribution and wheel, uploads them as artifacts, and attaches them to the GitHub Release.
105
+
106
+ ## Attribution
107
+
108
+ Profy is a Python fork of [Blaspsoft/blasp](https://github.com/Blaspsoft/blasp), originally authored by Michael Deeming and released under the MIT license.
109
+
110
+ ## License
111
+
112
+ MIT. See [LICENSE.md](LICENSE.md).
@@ -0,0 +1,36 @@
1
+ # Releases
2
+
3
+ Profy follows semantic versioning with PEP 440 pre-release suffixes for alpha builds, for example `0.1.0a1`.
4
+
5
+ ## Publishing
6
+
7
+ ```bash
8
+ python -m pip install --upgrade build twine
9
+ python -m build
10
+ python -m twine upload dist/*
11
+ ```
12
+
13
+ Create a matching Git tag:
14
+
15
+ ```bash
16
+ git tag v0.1.0a1
17
+ git push origin v0.1.0a1
18
+ ```
19
+
20
+ Pushing that tag runs the `Release` GitHub Actions workflow, which runs tests, builds the source distribution and wheel, uploads them as workflow artifacts, and attaches them to a GitHub Release.
21
+
22
+ The same workflow publishes to PyPI using Trusted Publishing. Configure PyPI with:
23
+
24
+ - Project name: `profy-filter`
25
+ - Owner: `mantleCurve`
26
+ - Repository: `profy`
27
+ - Workflow: `release.yml`
28
+ - Environment: `pypi`
29
+
30
+ GitHub Releases should include:
31
+
32
+ - version number
33
+ - installation command
34
+ - upstream Blasp commit, if synced
35
+ - highlights
36
+ - any compatibility or behavior notes
@@ -0,0 +1,51 @@
1
+ # Profy Documentation
2
+
3
+ Profy is a Python fork of [Blaspsoft/blasp](https://github.com/Blaspsoft/blasp). It keeps Blasp's core profanity filtering ideas and bundled language data while exposing a small Python API.
4
+
5
+ ## API
6
+
7
+ Use `filter_text()` when you want the full `ShieldResult`, `clean_text()` when you only need sanitized text, and `check_text()` when you only need a boolean.
8
+
9
+ ```python
10
+ from profy import filter_text
11
+
12
+ result = filter_text("f-u-c-k", mask="*")
13
+ assert result.clean == "*******"
14
+ ```
15
+
16
+ ## Matching Behavior
17
+
18
+ The detector is regex-based and uses Blasp-style generated expressions for each dictionary word. It supports:
19
+
20
+ - case-insensitive matching
21
+ - substitution characters such as `@`, `$`, `!`, `1`, `*`, and accented variants
22
+ - separators between letters
23
+ - repeated substitution characters
24
+ - invisible Unicode format character removal
25
+ - false-positive guards for known words, UUIDs, long hex tokens, and many embedded clean words
26
+
27
+ ## Languages
28
+
29
+ Bundled dictionaries: English, Spanish, German, and French.
30
+
31
+ ```python
32
+ from profy import filter_text
33
+
34
+ result = filter_text("maldición", languages="spanish")
35
+ ```
36
+
37
+ For multi-language checks:
38
+
39
+ ```python
40
+ result = filter_text("text", languages=["english", "spanish"])
41
+ result = filter_text("text", all_languages=True)
42
+ ```
43
+
44
+ ## Release Checklist
45
+
46
+ 1. Update `profy/__init__.py` and `pyproject.toml` with the new version.
47
+ 2. Update `CHANGELOG.md`.
48
+ 3. Install development dependencies with `python -m pip install -e ".[dev]"`.
49
+ 4. Run `python -m pytest`.
50
+ 5. Build with `python -m build`.
51
+ 6. Create and push a `v*` version tag.
@@ -0,0 +1,18 @@
1
+ # Upstream Blasp Sync Report
2
+
3
+ - Upstream: `https://github.com/Blaspsoft/blasp.git`
4
+ - Current commit: `cce2dd02e0cdad5c504d18d554322098d4ee2c28`
5
+ - Previous synced commit: `cce2dd02e0cdad5c504d18d554322098d4ee2c28`
6
+ - Synced at: `2026-05-07T05:59:47.679144+00:00`
7
+
8
+ ## Exported Data
9
+
10
+ - `profy/data/global.json`
11
+ - `profy/data/languages/english.json`
12
+ - `profy/data/languages/french.json`
13
+ - `profy/data/languages/german.json`
14
+ - `profy/data/languages/spanish.json`
15
+
16
+ ## PHP Implementation Changes
17
+
18
+ No tracked PHP implementation files changed since the previous sync.
@@ -0,0 +1,23 @@
1
+ """Profy: a Python profanity filter forked from Blaspsoft/blasp."""
2
+
3
+ from .core import (
4
+ Match,
5
+ ProfanityFilter,
6
+ Severity,
7
+ ShieldResult,
8
+ check_text,
9
+ clean_text,
10
+ filter_text,
11
+ )
12
+
13
+ __all__ = [
14
+ "Match",
15
+ "ProfanityFilter",
16
+ "Severity",
17
+ "ShieldResult",
18
+ "check_text",
19
+ "clean_text",
20
+ "filter_text",
21
+ ]
22
+
23
+ __version__ = "0.1.0a1"