Permalink
Browse files

refactor setup and configs, fixed pip install issue

  • Loading branch information...
1 parent 1ce8bb8 commit b7d5caf31932b1425123e25056f5c2905121ae46 @roycehaynes roycehaynes committed Nov 13, 2012
View
1 MANIFEST.in
@@ -0,0 +1 @@
+include VERSION
View
0 __init__.py
No changes.
View
168 email_reply_parser/__init__.py
@@ -0,0 +1,168 @@
+import re
+import email_reply_parser
+
+"""
+ email_reply_parser is a python library port of GitHub's Email Reply Parser.
+
+ For more information, visit https://github.com/zapier/email-reply-parser
+"""
+
+#: PEP 396
+__version__ = "0.1.8"
+version_info = (0, 1, 8)
+
+
+class EmailReplyParser():
+ """ Represents a email message that is parsed.
+ """
+
+ @classmethod
+ def read(cls, text):
+ """ Factory method that splits email into list of fragments
+
+ text - A string email body
+
+ Returns an EmailMessage instance
+ """
+ return EmailMessage(text).read()
+
+ @classmethod
+ def parse_reply(cls, text):
+ """ Provides the reply portion of email.
+
+ text - A string email body
+
+ Returns reply body message
+ """
+ return EmailReplyParser.read(text).reply
+
+
+class EmailMessage():
+ """ An email message represents a parsed email body.
+ """
+
+ SIG_REGEX = r'(--|__|-\w)|(^Sent from my (\w+\s*){1,3})'
+ QUOTE_HDR_REGEX = r'^:etorw.*nO'
+ MULTI_QUOTE_HDR_REGEX = r'(On\s.*?wrote:)'
+ QUOTED_REGEX = r'(>+)'
+
+ def __init__(self, text):
+ self.fragments = []
+ self.fragment = None
+ self.text = text.replace('\r\n', '\n')
+ self.found_visible = False
+
+ def read(self):
+ """ Creates new fragment for each line
+ and labels as a signature, quote, or hidden.
+
+ Returns EmailMessage instance
+ """
+
+ self.found_visible = False
+
+ is_multi_quote_header = re.search(self.MULTI_QUOTE_HDR_REGEX, self.text, re.MULTILINE | re.DOTALL)
+ if is_multi_quote_header:
+ self.text = re.sub(self.MULTI_QUOTE_HDR_REGEX, \
+ is_multi_quote_header.groups()[0].replace('\n', ''), \
+ self.text, \
+ flags=re.DOTALL)
+
+ self.lines = self.text.split('\n')
+ self.lines.reverse()
+
+ for line in self.lines:
+ self._scan_line(line)
+
+ self._finish_fragment()
+
+ self.fragments.reverse()
+
+ return self
+
+ @property
+ def reply(self):
+ """ Captures reply message within email
+ """
+ reply = []
+ for f in self.fragments:
+ if not (f.hidden or f.quoted):
+ reply.append(f.content)
+ return '\n'.join(reply)
+
+ def _scan_line(self, line):
+ """ Reviews each line in email message and determines fragment type
+
+ line - a row of text from an email message
+ """
+
+ line.strip('\n')
+
+ if re.match(self.SIG_REGEX, line):
+ line.lstrip()
+
+ is_quoted = re.match(self.QUOTED_REGEX, line) != None
+
+ if self.fragment and len(line.strip()) == 0:
+ if re.match(self.SIG_REGEX, self.fragment.lines[-1]):
+ self.fragment.signature = True
+ self._finish_fragment()
+
+ if self.fragment and ((self.fragment.quoted == is_quoted)
+ or (self.fragment.quoted and (self.quote_header(line) or len(line.strip()) == 0))):
+
+ self.fragment.lines.append(line)
+ else:
+ self._finish_fragment()
+ self.fragment = Fragment(is_quoted, line)
+
+ def quote_header(self, line):
+ """ Determines whether line is part of a quoted area
+
+ line - a row of the email message
+
+ Returns True or False
+ """
+ return re.match(self.QUOTE_HDR_REGEX, line[::-1]) != None
+
+ def _finish_fragment(self):
+ """ Creates fragment
+ """
+
+ if self.fragment:
+ self.fragment.finish()
+ if not self.found_visible:
+ if self.fragment.quoted \
+ or self.fragment.signature \
+ or (len(self.fragment.content.strip()) == 0):
+
+ self.fragment.hidden = True
+ else:
+ self.found_visible = True
+ self.fragments.append(self.fragment)
+ self.fragment = None
+
+
+class Fragment():
+ """ A Fragment is a part of
+ an Email Message, labeling each part.
+ """
+
+ def __init__(self, quoted, first_line):
+ self.signature = False
+ self.hidden = False
+ self.quoted = quoted
+ self.content = None
+ self.lines = [first_line]
+
+ def finish(self):
+ """ Creates block of content with lines
+ belonging to fragment.
+ """
+ self.lines.reverse()
+ self.content = '\n'.join(self.lines)
+ self.lines = None
+
+ @property
+ def content(self):
+ return self.content
View
161 email_reply_parser/email_reply_parser.py
@@ -1,161 +0,0 @@
-import re
-
-"""
- Email Reply Parser is a port of GitHub's Email Reply Parser for Python.
-"""
-
-
-class EmailReplyParser():
- """ Represents a email message that is parsed.
- """
-
- @staticmethod
- def read(text):
- """ Factory method that splits email into list of fragments
-
- text - A string email body
-
- Returns an EmailMessage instance
- """
- return EmailMessage(text).read()
-
- @staticmethod
- def parse_reply(text):
- """ Provides the reply portion of email.
-
- text - A string email body
-
- Returns reply body message
- """
- return EmailReplyParser.read(text).reply
-
-
-class EmailMessage():
- """ An email message represents a parsed email body.
- """
-
- SIG_REGEX = r'(--|__|-\w)|(^Sent from my (\w+\s*){1,3})'
- QUOTE_HDR_REGEX = r'^:etorw.*nO'
- MULTI_QUOTE_HDR_REGEX = r'(On\s.*?wrote:)'
- QUOTED_REGEX = r'(>+)'
-
- def __init__(self, text):
- self.fragments = []
- self.fragment = None
- self.text = text.replace('\r\n', '\n')
- self.found_visible = False
-
- def read(self):
- """ Creates new fragment for each line
- and labels as a signature, quote, or hidden.
-
- Returns EmailMessage instance
- """
-
- self.found_visible = False
-
- is_multi_quote_header = re.search(self.MULTI_QUOTE_HDR_REGEX, self.text, re.MULTILINE | re.DOTALL)
- if is_multi_quote_header:
- self.text = re.sub(self.MULTI_QUOTE_HDR_REGEX, \
- is_multi_quote_header.groups()[0].replace('\n', ''), \
- self.text, \
- flags=re.DOTALL)
-
- self.lines = self.text.split('\n')
- self.lines.reverse()
-
- for line in self.lines:
- self._scan_line(line)
-
- self._finish_fragment()
-
- self.fragments.reverse()
-
- return self
-
- @property
- def reply(self):
- """ Captures reply message within email
- """
- reply = []
- for f in self.fragments:
- if not (f.hidden or f.quoted):
- reply.append(f.content)
- return '\n'.join(reply)
-
- def _scan_line(self, line):
- """ Reviews each line in email message and determines fragment type
-
- line - a row of text from an email message
- """
-
- line.strip('\n')
-
- if re.match(self.SIG_REGEX, line):
- line.lstrip()
-
- is_quoted = re.match(self.QUOTED_REGEX, line) != None
-
- if self.fragment and len(line.strip()) == 0:
- if re.match(self.SIG_REGEX, self.fragment.lines[-1]):
- self.fragment.signature = True
- self._finish_fragment()
-
- if self.fragment and ((self.fragment.quoted == is_quoted)
- or (self.fragment.quoted and (self.quote_header(line) or len(line.strip()) == 0))):
-
- self.fragment.lines.append(line)
- else:
- self._finish_fragment()
- self.fragment = Fragment(is_quoted, line)
-
- def quote_header(self, line):
- """ Determines whether line is part of a quoted area
-
- line - a row of the email message
-
- Returns True or False
- """
- return re.match(self.QUOTE_HDR_REGEX, line[::-1]) != None
-
- def _finish_fragment(self):
- """ Creates fragment
- """
-
- if self.fragment:
- self.fragment.finish()
- if not self.found_visible:
- if self.fragment.quoted \
- or self.fragment.signature \
- or (len(self.fragment.content.strip()) == 0):
-
- self.fragment.hidden = True
- else:
- self.found_visible = True
- self.fragments.append(self.fragment)
- self.fragment = None
-
-
-class Fragment():
- """ A Fragment is a part of
- an Email Message, labeling each part.
- """
-
- def __init__(self, quoted, first_line):
- self.signature = False
- self.hidden = False
- self.quoted = quoted
- self.content = None
- self.lines = [first_line]
-
- def finish(self):
- """ Creates block of content with lines
- belonging to fragment.
- """
- self.lines.reverse()
- self.content = '\n'.join(self.lines)
- self.lines = None
-
- @property
- def content(self):
- return self.content
View
1 email_reply_parser/version.py
@@ -0,0 +1 @@
+VERSION = '0.1.8'
View
22 setup.py
@@ -1,21 +1,25 @@
# -*- coding: utf-8 -*-
-from setuptools import setup, find_packages
import os
+import sys
+try:
+ from setuptools import setup
+except ImportError:
+ from distutils.core import setup
-def read(fname):
- return open(os.path.join(os.path.dirname(__file__), fname)).read()
+sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'email_reply_parser'))
+import version
setup(
name='email_reply_parser',
- version='0.1.5',
- description='A email parser library, making it easy to extract a signature, reply, or quote block from a text-formatted email.',
- packages=find_packages('email_reply_parser', 'tests'),
- long_description=read('README.md'),
+ version=version.VERSION,
+ description='Email reply parser',
+ packages=['email_reply_parser'],
+ package_data={'email_reply_parser': ['../VERSION']},
author='Royce Haynes',
author_email='royce.haynes@gmail.com',
url='https://github.com/zapier/email-reply-parser',
- license=read('LICENSE'),
- test_suite='tests.test_email_reply_parser'
+ license='MIT',
+ test_suite='test'
)
View
0 tests/__init__.py → test/__init__.py
File renamed without changes.
View
0 tests/emails/correct_sig.txt → test/emails/correct_sig.txt
File renamed without changes.
View
0 tests/emails/email_1_1.txt → test/emails/email_1_1.txt
File renamed without changes.
View
0 tests/emails/email_1_2.txt → test/emails/email_1_2.txt
File renamed without changes.
View
0 tests/emails/email_1_3.txt → test/emails/email_1_3.txt
File renamed without changes.
View
0 tests/emails/email_1_4.txt → test/emails/email_1_4.txt
File renamed without changes.
View
0 tests/emails/email_1_5.txt → test/emails/email_1_5.txt
File renamed without changes.
View
0 tests/emails/email_1_6.txt → test/emails/email_1_6.txt
File renamed without changes.
View
0 tests/emails/email_1_7.txt → test/emails/email_1_7.txt
File renamed without changes.
View
0 tests/emails/email_2_1.txt → test/emails/email_2_1.txt
File renamed without changes.
View
0 tests/emails/email_BlackBerry.txt → test/emails/email_BlackBerry.txt
File renamed without changes.
View
0 tests/emails/email_bullets.txt → test/emails/email_bullets.txt
File renamed without changes.
View
0 tests/emails/email_iPhone.txt → test/emails/email_iPhone.txt
File renamed without changes.
View
0 ...multi_word_sent_from_my_mobile_device.txt → ...multi_word_sent_from_my_mobile_device.txt
File renamed without changes.
View
0 tests/emails/email_one_is_not_on.txt → test/emails/email_one_is_not_on.txt
File renamed without changes.
View
0 ...ails/email_sent_from_my_not_signature.txt → ...ails/email_sent_from_my_not_signature.txt
File renamed without changes.
View
13 tests/test_email_reply_parser.py → test/test_email_reply_parser.py
@@ -1,6 +1,9 @@
+import os
+import sys
import unittest
-import email_reply_parser
-from email_reply_parser.email_reply_parser import EmailReplyParser
+
+sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
+from email_reply_parser import EmailReplyParser
class EmailMessageTest(unittest.TestCase):
@@ -83,17 +86,17 @@ def test_reply_is_parsed(self):
self.assertTrue("You can list the keys for the bucket" in message.reply)
def test_sent_from_iphone(self):
- with open('tests/emails/email_iPhone.txt') as email:
+ with open('test/emails/email_iPhone.txt') as email:
self.assertTrue("Sent from my iPhone" not in EmailReplyParser.parse_reply(email.read()))
def test_email_one_is_not_on(self):
- with open('tests/emails/email_one_is_not_on.txt') as email:
+ with open('test/emails/email_one_is_not_on.txt') as email:
self.assertTrue("On Oct 1, 2012, at 11:55 PM, Dave Tapley wrote:" not in EmailReplyParser.parse_reply(email.read()))
def get_email(self, name):
""" Return EmailMessage instance
"""
- text = open('tests/emails/%s.txt' % name).read()
+ text = open('test/emails/%s.txt' % name).read()
return EmailReplyParser.read(text)
View
5 tests/context.py
@@ -1,5 +0,0 @@
-import os
-import sys
-sys.path.insert(0, os.path.abspath('..'))
-
-import email_reply_parser

0 comments on commit b7d5caf

Please sign in to comment.