<NME> sentiments.py
<BEF> # -*- coding: utf-8 -*-
"""Sentiment analysis implementations.

.. versionadded:: 0.5.0
"""
from __future__ import absolute_import
from textblob.packages import nltk
from textblob.en import sentiment as pattern_sentiment
from textblob.tokenizers import WordTokenizer
from textblob.tokenizers import word_tokenize
from textblob.decorators import requires_nltk_corpus
from textblob.base import BaseSentimentAnalyzer, DISCRETE, CONTINUOUS


class PatternAnalyzer(BaseSentimentAnalyzer):
    '''Sentiment analyzer that uses the same implementation as the
    pattern library. Returns results as a tuple of the form:

    ``(polarity, subjectivity)``
    '''

    kind = CONTINUOUS

    def analyze(self, text):
        """Return the sentiment as a tuple of the form:
        ``(polarity, subjectivity)``
        """
        return pattern_sentiment(text)


class NaiveBayesAnalyzer(BaseSentimentAnalyzer):

    '''Naive Bayes analyzer that is trained on a dataset of movie reviews.
    Returns results as a tuple of the form:

    ``(classification, pos_probability, neg_probability)``
    '''

    kind = DISCRETE

    def __init__(self):
        super(NaiveBayesAnalyzer, self).__init__()
def _default_feature_extractor(words):
    """Default feature extractor for the NaiveBayesAnalyzer."""
    return dict(((word, True) for word in words))


class NaiveBayesAnalyzer(BaseSentimentAnalyzer):
    """Naive Bayes analyzer that is trained on a dataset of movie reviews.
    Returns results as a named tuple of the form:
    ``Sentiment(classification, p_pos, p_neg)``

    :param callable feature_extractor: Function that returns a dictionary of
        features, given a list of words.
    """

    kind = DISCRETE
    #: Return type declaration
    RETURN_TYPE = namedtuple('Sentiment', ['classification', 'p_pos', 'p_neg'])

    def __init__(self, feature_extractor=_default_feature_extractor):
        super(NaiveBayesAnalyzer, self).__init__()
        self._classifier = None
        self.feature_extractor = feature_extractor

    @requires_nltk_corpus
    def train(self):
        """Train the Naive Bayes classifier on the movie review corpus."""
        super(NaiveBayesAnalyzer, self).train()
        feats = self._extract_feats(filtered)
        prob_dist = self._classifier.prob_classify(feats)
        # classification, p_pos, p_neg
        return prob_dist.max(), prob_dist.prob('pos'), prob_dist.prob("neg")

    def analyze(self, text):
        """Return the sentiment as a named tuple of the form:
        ``Sentiment(classification, p_pos, p_neg)``
        """
        # Lazily train the classifier
        super(NaiveBayesAnalyzer, self).analyze(text)
        tokens = word_tokenize(text, include_punc=False)
        filtered = (t.lower() for t in tokens if len(t) >= 3)
        feats = self.feature_extractor(filtered)
        prob_dist = self._classifier.prob_classify(feats)
        return self.RETURN_TYPE(
            classification=prob_dist.max(),
            p_pos=prob_dist.prob('pos'),
            p_neg=prob_dist.prob("neg")
        )

<MSG> Sentiment analyzer returns namedtuples

Fixes all failing doctests

<DFF> @@ -4,6 +4,8 @@
 .. versionadded:: 0.5.0
 """
 from __future__ import absolute_import
+from collections import namedtuple
+
 from textblob.packages import nltk
 from textblob.en import sentiment as pattern_sentiment
 from textblob.tokenizers import WordTokenizer
@@ -16,27 +18,29 @@ class PatternAnalyzer(BaseSentimentAnalyzer):
     '''Sentiment analyzer that uses the same implementation as the
     pattern library. Returns results as a tuple of the form:
 
-    ``(polarity, subjectivity)``
+    ``Sentiment(polarity, subjectivity)``
     '''
 
     kind = CONTINUOUS
+    RETURN_TYPE = namedtuple('Sentiment', ['polarity', 'subjectivity'])
 
     def analyze(self, text):
         """Return the sentiment as a tuple of the form:
         ``(polarity, subjectivity)``
         """
-        return pattern_sentiment(text)
+        return self.RETURN_TYPE(*pattern_sentiment(text))
 
 
 class NaiveBayesAnalyzer(BaseSentimentAnalyzer):
 
     '''Naive Bayes analyzer that is trained on a dataset of movie reviews.
-    Returns results as a tuple of the form:
+    Returns results as a named tuple of the form:
 
-    ``(classification, pos_probability, neg_probability)``
+    ``Sentiment(classification, p_pos, p_neg)``
     '''
 
     kind = DISCRETE
+    RETURN_TYPE = namedtuple('Sentiment', ['classification', 'p_pos', 'p_neg'])
 
     def __init__(self):
         super(NaiveBayesAnalyzer, self).__init__()
@@ -70,4 +74,8 @@ class NaiveBayesAnalyzer(BaseSentimentAnalyzer):
         feats = self._extract_feats(filtered)
         prob_dist = self._classifier.prob_classify(feats)
         # classification, p_pos, p_neg
-        return prob_dist.max(), prob_dist.prob('pos'), prob_dist.prob("neg")
+        return self.RETURN_TYPE(
+            classification=prob_dist.max(),
+            p_pos=prob_dist.prob('pos'),
+            p_neg=prob_dist.prob("neg")
+        )

{'addition_count': 13, 'commit_subject': 'Sentiment analyzer returns namedtuples', 'deletion_count': 5, 'file_extension': '.py', 'lang': 'py', 'license': 'mit', 'repo_name': 'sloria/TextBlob'}