Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a base class for scorers #34

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ __pycache__
.vscode
py_readability_metrics.egg-info
dist
build
build
*.rsp
18 changes: 9 additions & 9 deletions readability/readability.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,41 +15,41 @@ def __init__(self, text, min_words=100):

def ari(self):
"""Calculate Automated Readability Index (ARI)."""
return ARI(self._statistics, self._min_words).score()
return ARI(self._statistics, self._min_words).results()

def coleman_liau(self):
"""Calculate Coleman Liau Index."""
return ColemanLiau(self._statistics, self._min_words).score()
return ColemanLiau(self._statistics, self._min_words).results()

def dale_chall(self):
"""Calculate Dale Chall."""
return DaleChall(self._statistics, self._min_words).score()
return DaleChall(self._statistics, self._min_words).results()

def flesch(self):
"""Calculate Flesch Reading Ease score."""
return Flesch(self._statistics, self._min_words).score()
return Flesch(self._statistics, self._min_words).results()

def flesch_kincaid(self):
"""Calculate Flesch-Kincaid Grade Level."""
return FleschKincaid(self._statistics, self._min_words).score()
return FleschKincaid(self._statistics, self._min_words).results()

def gunning_fog(self):
"""Calculate Gunning Fog score."""
return GunningFog(self._statistics, self._min_words).score()
return GunningFog(self._statistics, self._min_words).results()

def linsear_write(self):
"""Calculate Linsear Write."""
return LinsearWrite(self._statistics, self._min_words).score()
return LinsearWrite(self._statistics, self._min_words).results()

def smog(self,all_sentences=False, ignore_length=False):
"""SMOG Index.
`all_sentences` indicates whether SMOG should use a sample of 30 sentences, as described in the original paper, or if it should use all sentences in the text"""
return Smog(self._statistics, self._analyzer.sentences,
all_sentences=all_sentences, ignore_length=ignore_length).score()
all_sentences=all_sentences).results()

def spache(self):
"""Spache Index."""
return Spache(self._statistics, self._min_words).score()
return Spache(self._statistics, self._min_words).results()

def statistics(self):
return {
Expand Down
36 changes: 9 additions & 27 deletions readability/scorers/ari.py
Original file line number Diff line number Diff line change
@@ -1,39 +1,21 @@
import math
from readability.exceptions import ReadabilityException
from readability.scorers.base_scorer import ReadabilityScorer


class Result:
def __init__(self, score, grade_levels, ages):
self.score = score
self.grade_levels = grade_levels
self.ages = ages

def __str__(self):
return "score: {}, grade_levels: {}, ages: {}". \
format(self.score, self.grade_levels, self.ages)


class ARI:
class ARI(ReadabilityScorer):
def __init__(self, stats, min_words=100):
self._stats = stats
if stats.num_words < min_words:
raise ReadabilityException('{} words required.'.format(min_words))

def score(self):
score = self._score()
return Result(
score=score,
grade_levels=self._grade_levels(score),
ages=self._ages(score))
super().__init__(stats, min_words)
self.scorer_name = "ARI"

def _score(self):
def _raw_score(self):
s = self._stats
letters_per_word = s.num_letters / s.num_words
words_per_sent = s.num_words / s.num_sentences
return 4.71 * letters_per_word + 0.5 * words_per_sent - 21.43

def _grade_levels(self, score):
score = math.ceil(score)
def _grade_level(self):
score = math.ceil(self._score)
if score <= 1:
return ['K']
elif score <= 2:
Expand Down Expand Up @@ -63,8 +45,8 @@ def _grade_levels(self, score):
else:
return ['college_graduate']

def _ages(self, score):
score = math.ceil(score)
def _age(self):
score = math.ceil(self._score)
if score <= 1:
return [5, 6]
elif score <= 2:
Expand Down
78 changes: 78 additions & 0 deletions readability/scorers/base_scorer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
from readability.exceptions import ReadabilityException
from readability.text import AnalyzerStatistics


class Result:
def __init__(self, scorer_name, score, grade_level, age, scale_value, cloze_score, description):
self.name = scorer_name

self.score = score
self.grade_level = grade_level
self.age = age
self.scale_value = scale_value
self.cloze_score = cloze_score
self.description = description

def __str__(self):
if self.name is not None:
result = "{}: ".format(self.name)
else:
result = ""

if self.score is not None:
if isinstance(self.score, float):
result += "score = {:.2f}, ".format(self.score)
else:
result += "score = {}, ".format(self.score)

if self.grade_level is not None:
result += "grade_level = {}, ".format(self.grade_level)
if self.age is not None:
result += "age = {}, ".format(self.age)
if self.scale_value is not None:
result += "scale_value = {:.2f}, ".format(self.scale_value)
if self.cloze_score is not None:
result += "cloze_score = {:.2f}, ".format(self.cloze_score)
if self.description is not None:
result += "{}, ".format(self.description)

return result[:-2]


class ReadabilityScorer:
def __init__(self, stats: AnalyzerStatistics, min_words=100):
if stats.num_words < min_words:
raise ReadabilityException('{} words required.'.format(min_words))

self._stats = stats
self.scorer_name = None

def results(self):
self._score = self._raw_score()
return Result(
scorer_name=self.scorer_name,
score=self._score,
grade_level=self._grade_level(),
age=self._age(),
scale_value=self._scale_value(),
cloze_score=self._cloze_score(),
description=self._description(),
)

def _raw_score(self):
return None

def _grade_level(self):
return None

def _age(self):
return None

def _scale_value(self):
return None

def _cloze_score(self):
return None

def _description(self):
return None
30 changes: 7 additions & 23 deletions readability/scorers/coleman_liau.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,20 @@
from readability.exceptions import ReadabilityException
from readability.scorers.base_scorer import ReadabilityScorer


class Result:
def __init__(self, score, grade_level):
self.score = score
self.grade_level = grade_level

def __str__(self):
return "score: {}, grade_level: '{}'". \
format(self.score, self.grade_level)


class ColemanLiau:
class ColemanLiau(ReadabilityScorer):
def __init__(self, stats, min_words=100):
self._stats = stats
if stats.num_words < min_words:
raise ReadabilityException('{} words required.'.format(min_words))

def score(self):
score = self._score()
return Result(
score=score,
grade_level=self._grade_level(score)
)
super().__init__(stats, min_words)
self.scorer_name = 'Coleman-Liau'

def _score(self):
def _raw_score(self):
s = self._stats
scalar = s.num_words / 100
letters_per_100_words = s.num_letters / scalar
sentences_per_100_words = s.num_sentences / scalar
return 0.0588 * letters_per_100_words - \
0.296 * sentences_per_100_words - 15.8

def _grade_level(self, score):
return str(round(score))
def _grade_level(self):
return str(round(self._score))
30 changes: 7 additions & 23 deletions readability/scorers/dale_chall.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,12 @@
from readability.exceptions import ReadabilityException
from readability.scorers.base_scorer import ReadabilityScorer


class Result:
def __init__(self, score, grade_levels):
self.score = score
self.grade_levels = grade_levels

def __str__(self):
return "score: {}, grade_levels: {}". \
format(self.score, self.grade_levels)


class DaleChall:
class DaleChall(ReadabilityScorer):
def __init__(self, stats, min_words=100):
self._stats = stats
if stats.num_words < min_words:
raise ReadabilityException('{} words required.'.format(min_words))

def score(self):
score = self._score()
return Result(
score=score,
grade_levels=self._grade_levels(score))
super().__init__(stats, min_words)
self.scorer_name = "Dale-Chall"

def _score(self):
def _raw_score(self):
stats = self._stats
words_per_sent = stats.num_words / stats.num_sentences
percent_difficult_words = \
Expand All @@ -34,7 +17,8 @@ def _score(self):
else raw_score
return adjusted_score

def _grade_levels(self, score):
def _grade_level(self):
score = self._score
if score <= 4.9:
return ['1', '2', '3', '4']
elif score >= 5 and score < 6:
Expand Down
35 changes: 9 additions & 26 deletions readability/scorers/flesch.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,19 @@
from readability.exceptions import ReadabilityException
from readability.scorers.base_scorer import ReadabilityScorer


class Result:
def __init__(self, score, grade_levels, ease):
self.score = score
self.ease = ease
self.grade_levels = grade_levels

def __str__(self):
return "score: {}, ease: '{}', grade_levels: {}". \
format(self.score, self.ease, self.grade_levels)


class Flesch:
class Flesch(ReadabilityScorer):
def __init__(self, stats, min_words=100):
self._stats = stats
if stats.num_words < min_words:
raise ReadabilityException('{} words required.'.format(min_words))

def score(self):
score = self._score()
return Result(
score=score,
ease=self._ease(score),
grade_levels=self._grade_levels(score))
super().__init__(stats, min_words)
self.scorer_name = "Flesch"

def _score(self):
def _raw_score(self):
stats = self._stats
words_per_sent = stats.num_words / stats.num_sentences
syllables_per_word = stats.num_syllables / stats.num_words
return 206.835 - (1.015 * words_per_sent) - (84.6 * syllables_per_word)

def _ease(self, score):
def _description(self):
score = self._score
if score >= 90 and score <= 100:
return 'very_easy'
elif score >= 80 and score < 90:
Expand All @@ -47,7 +29,8 @@ def _ease(self, score):
else:
return 'very_confusing'

def _grade_levels(self, score):
def _grade_level(self):
score = self._score
if score >= 90 and score <= 100:
return ['5']
elif score >= 80 and score < 90:
Expand Down
32 changes: 7 additions & 25 deletions readability/scorers/flesch_kincaid.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,15 @@
from readability.exceptions import ReadabilityException
from readability.scorers.base_scorer import ReadabilityScorer


class Result:
def __init__(self, score, grade_level):
self.score = score
self.grade_level = grade_level

def __str__(self):
return "score: {}, grade_level: '{}'". \
format(self.score, self.grade_level)


class FleschKincaid:
class FleschKincaid(ReadabilityScorer):
def __init__(self, stats, min_words=100):
self._stats = stats
if stats.num_words < min_words:
raise ReadabilityException('{} words required.'.format(min_words))

def score(self):
score = self._score()
return Result(
score=score,
grade_level=self._grade_level(score)
)
super().__init__(stats, min_words)
self.scorer_name = "Flesh-Kincaid"

def _score(self):
def _raw_score(self):
stats = self._stats
return (0.38 * stats.avg_words_per_sentence +
11.8 * stats.avg_syllables_per_word) - 15.59

def _grade_level(self, score):
return str(round(score))
def _grade_level(self):
return str(round(self._score))
Loading