Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ HateSonar allows you to detect hate speech and offensive language in text, witho
## Feature Support
* Hate speech and offensive language detection

HateSonar officially supports Python 2.7 & 3.4–3.6
HateSonar officially supports Python 3.9+

## Installation
To install HateSonar, simply use `pip`:
Expand Down
8 changes: 2 additions & 6 deletions hatesonar/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,13 @@
Model API.
"""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import os

import joblib
import numpy as np


class Sonar(object):
class Sonar:

def __init__(self):
BASE_DIR = os.path.join(os.path.dirname(__file__), './data')
Expand Down Expand Up @@ -49,7 +45,7 @@ def get_class_idx():
return i

class_idx = get_class_idx()
features = self.preprocessor.get_feature_names()
features = self.preprocessor.get_feature_names_out()
weights = self.estimator.coef_[class_idx]
word2weight = {f: w for f, w in zip(features, weights)}
tokenize = self.preprocessor.build_analyzer()
Expand Down
2 changes: 1 addition & 1 deletion hatesonar/crawler/blog.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import requests


class BlogCrawler(object):
class BlogCrawler:

def __init__(self):
pass
2 changes: 1 addition & 1 deletion hatesonar/crawler/twitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def load_keys():
return consumer_key, consumer_secret, access_token, access_token_secret


class TwitterAPI(object):
class TwitterAPI:

def __init__(self, consumer_key, consumer_secret, access_token, access_token_secret):
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
Expand Down
Binary file modified hatesonar/data/model.joblib
Binary file not shown.
Binary file modified hatesonar/data/preprocess.joblib
Binary file not shown.
12 changes: 4 additions & 8 deletions hatesonar/trainer/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,11 @@
Baseline model.
"""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse
import os

import joblib
import pandas as pd
from sklearn.externals import joblib
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report
Expand All @@ -28,7 +24,7 @@ def main(args):
x_train = vectorizer.fit_transform(x_train)

print('Fitting...')
clf = LogisticRegression(penalty='l1')
clf = LogisticRegression(penalty='l1', solver='saga', max_iter=1000)
clf.fit(x_train, y_train)

print('Saving...')
Expand All @@ -48,8 +44,8 @@ def main(args):
SAVE_DIR = os.path.join(os.path.dirname(__file__), '../data')
parser = argparse.ArgumentParser(description='Training a classifier')
parser.add_argument('--dataset', default=os.path.join(DATA_DIR, 'labeled_data.csv'), help='dataset')
parser.add_argument('--model_file', default=os.path.join(SAVE_DIR, 'model.pkl'), help='model file')
parser.add_argument('--preprocessor', default=os.path.join(SAVE_DIR, 'preprocess.pkl'), help='preprocessor')
parser.add_argument('--model_file', default=os.path.join(SAVE_DIR, 'model.joblib'), help='model file')
parser.add_argument('--preprocessor', default=os.path.join(SAVE_DIR, 'preprocess.joblib'), help='preprocessor')
parser.add_argument('--test_size', type=float, default=0.3, help='test data size')
args = parser.parse_args()
main(args)
32 changes: 16 additions & 16 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
click==7.1.2
Flask==1.1.2
gunicorn==20.1.0
itsdangerous==1.1.0
Jinja2==3.0.3
joblib==1.0.1
MarkupSafe==1.1.1
numpy==1.22.2
pandas==1.2.4
python-dateutil==2.8.1
pytz==2021.1
scikit-learn==0.24.2
scipy==1.8.0
six==1.16.0
threadpoolctl==2.1.0
Werkzeug==2.0.3
click>=8.0.0
Flask>=2.0.0
gunicorn>=20.1.0
itsdangerous>=2.0.0
Jinja2>=3.0.0
joblib>=1.0.0
MarkupSafe>=2.0.0
numpy>=1.19.0
pandas>=1.1.0
python-dateutil>=2.8.0
pytz>=2021.1
scikit-learn>=0.24.0
scipy>=1.5.0
six>=1.15.0
threadpoolctl>=2.1.0
Werkzeug>=2.0.0
16 changes: 9 additions & 7 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@
sys.exit()

required = [
'numpy>=1.14.0', 'pandas>=0.22.0', 'scikit-learn>=0.19.1', 'scipy>=1.0.0', 'joblib>=0.16.0'
'numpy>=1.19.0', 'pandas>=1.1.0', 'scikit-learn>=0.24.0', 'scipy>=1.5.0', 'joblib>=1.0.0'
]

setup(
name=NAME,
version='0.0.7',
version='0.0.8',
description=DESCRIPTION,
long_description=long_description,
long_description_content_type='text/markdown',
Expand All @@ -41,14 +41,16 @@
install_requires=required,
include_package_data=True,
license=LICENSE,
python_requires='>=3.9',
classifiers=[
'License :: OSI Approved :: MIT License',
'Programming Language :: Python',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Programming Language :: Python :: 3.13',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy'
],
)
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[tox]
envlist = py27,py36
envlist = py39,py310,py311,py312

[testenv]
deps=pytest
Expand Down
117 changes: 117 additions & 0 deletions verify_migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#!/usr/bin/env python
"""
Verification script for Python 3.9+ migration.
Run this after installing dependencies to verify the migration was successful.
"""

import sys

def check_python_version():
"""Check if Python version is 3.9 or higher."""
print(f"Python version: {sys.version}")
if sys.version_info < (3, 9):
print("❌ ERROR: Python 3.9+ is required!")
return False
print("✅ Python version OK")
return True

def check_imports():
"""Check if all required imports work."""
try:
import joblib
print(f"✅ joblib {joblib.__version__}")
except ImportError as e:
print(f"❌ Failed to import joblib: {e}")
return False

try:
import numpy
print(f"✅ numpy {numpy.__version__}")
except ImportError as e:
print(f"❌ Failed to import numpy: {e}")
return False

try:
import pandas
print(f"✅ pandas {pandas.__version__}")
except ImportError as e:
print(f"❌ Failed to import pandas: {e}")
return False

try:
import sklearn
print(f"✅ scikit-learn {sklearn.__version__}")
except ImportError as e:
print(f"❌ Failed to import sklearn: {e}")
return False

try:
import scipy
print(f"✅ scipy {scipy.__version__}")
except ImportError as e:
print(f"❌ Failed to import scipy: {e}")
return False

return True

def check_hatesonar():
"""Check if hatesonar can be imported and works."""
try:
from hatesonar import Sonar
print("✅ HateSonar imported successfully")

# Try to create an instance
sonar = Sonar()
print("✅ Sonar instance created successfully")

# Try a simple prediction
result = sonar.ping(text="This is a test")
print("✅ Sonar.ping() works correctly")
print(f" Result keys: {result.keys()}")

return True
except Exception as e:
print(f"❌ Failed to test HateSonar: {e}")
import traceback
traceback.print_exc()
return False

def main():
"""Run all verification checks."""
print("=" * 60)
print("HateSonar Python 3.9+ Migration Verification")
print("=" * 60)
print()

print("Step 1: Checking Python version...")
version_ok = check_python_version()
print()

if not version_ok:
print("Please install Python 3.9 or higher and try again.")
sys.exit(1)

print("Step 2: Checking dependencies...")
imports_ok = check_imports()
print()

if not imports_ok:
print("Please install dependencies: pip install -e .")
sys.exit(1)

print("Step 3: Testing HateSonar...")
hatesonar_ok = check_hatesonar()
print()

if hatesonar_ok:
print("=" * 60)
print("✅ All checks passed! Migration successful!")
print("=" * 60)
else:
print("=" * 60)
print("❌ Some checks failed. Please review the errors above.")
print("=" * 60)
sys.exit(1)

if __name__ == "__main__":
main()
Loading