Рефакторинг входящего poplib с использованием windows python 2.3

1

Привет, ребята, не могли бы вы помочь мне реорганизовать это так, чтобы это было разумно pythonic.

import sys
import poplib
import string
import StringIO, rfc822
import datetime
import logging

def _dump_pop_emails(self):
    self.logger.info("open pop account %s with username: %s" % (self.account[0], self.account[1]))
    self.popinstance = poplib.POP3(self.account[0])
    self.logger.info(self.popinstance.getwelcome()) 
    self.popinstance.user(self.account[1])
    self.popinstance.pass_(self.account[2])
    try:
        (numMsgs, totalSize) = self.popinstance.stat()
        for thisNum in range(1, numMsgs+1):
            (server_msg, body, octets) = self.popinstance.retr(thisNum)
            text = string.join(body, '\n')
            mesg = StringIO.StringIO(text)                               
            msg = rfc822.Message(mesg)
            name, email = msg.getaddr("From")
            emailpath = str(self._emailpath + self._inboxfolder + "\\" + email + "_" + msg.getheader("Subject") + ".eml")
            emailpath = self._replace_whitespace(emailpath)
            file = open(emailpath,"wb")
            file.write(text)
            file.close()
            self.popinstance.dele(thisNum)
    finally:
        self.logger.info(self.popinstance.quit())

def _replace_whitespace(self,name):
    name = str(name)
    return name.replace(" ", "_")   

Также в методе _replace_whitespace я хотел бы иметь какую-то процедуру очистки, которая вынимает все незаконные символы, которые могут вызвать обработку.

В основном я хочу написать электронное письмо в папку входящих сообщений стандартным образом.

Я делаю что-то не так здесь?

Теги:
email
refactoring
poplib

3 ответа

1
Лучший ответ

Это не рефакторинг (он не нуждается в рефакторинге, насколько я вижу), но некоторые предложения:

Вы должны использовать почтовый пакет, а не rfc822. Замените rfc822.Message на email.Message и используйте email.Utils.parseaddr(msg [ "From" ]), чтобы получить имя и адрес электронной почты, и msg [ "Subject" ], чтобы получить тему.

Используйте os.path.join для создания пути. Это:

emailpath = str(self._emailpath + self._inboxfolder + "\\" + email + "_" + msg.getheader("Subject") + ".eml")

становится:

emailpath = os.path.join(self._emailpath + self._inboxfolder, email + "_" + msg.getheader("Subject") + ".eml")

(Если папка self._inbox начинается с косой черты или self._emailpath заканчивается на одну, вы также можете заменить первую + запятой).

На самом деле ничего не повредит, но вы, вероятно, не должны использовать "файл" в качестве имени переменной, поскольку он затеняет встроенный тип (такие шашки, как pylint или pychecker, предупреждают вас об этом).

Если вы не используете self.popinstance вне этой функции (кажется маловероятным, учитывая, что вы подключаетесь и выходите из функции), тогда нет смысла делать его атрибутом self. Просто используйте "popinstance" самостоятельно.

Используйте xrange вместо диапазона.

Вместо того, чтобы просто импортировать StringIO, сделайте следующее:

try:
    import cStringIO as StringIO
except ImportError:
    import StringIO

Если это почтовый ящик POP, к которому можно получить доступ более чем одним клиентом за раз, вам может потребоваться включить try/except вокруг вызова RETR, чтобы продолжить, если вы не можете получить одно сообщение.

Как сказал Джон, используйте "\n".join, а не string.join, используйте try/finally, чтобы закрыть файл, только если он открыт, и передайте параметры ведения журнала отдельно.

Одна проблема рефакторинга, о которой я мог подумать, заключается в том, что вам действительно не нужно разбирать все сообщение, поскольку вы просто сбрасываете копию необработанных байтов, и все, что вам нужно, это заголовки From и Subject. Вместо этого вы можете использовать popinstance.top(0), чтобы получить заголовки, создать сообщение (пустое тело) и использовать это для заголовков. Затем выполните полный RETR, чтобы получить байты. Это было бы полезно, если бы ваши сообщения были большими (и поэтому их синтаксический анализ занимал много времени). Я бы определенно измерил, прежде чем я сделал эту оптимизацию.

Для вашей функции для дезинфекции имен это зависит от того, насколько хорошо вы хотите, чтобы имена были, и насколько вы уверены, что адрес электронной почты и тема делают уникальное имя файла (кажется довольно маловероятным). Вы можете сделать что-то вроде:

emailpath = "".join([c for c in emailpath if c in (string.letters + string.digits + "_ ")])

И вы получите только буквенно-цифровые символы и подчеркивание и пробел, которые выглядят как читаемый набор. Учитывая, что ваша файловая система (с Windows), вероятно, нечувствительна к регистру, вы также можете ввести нижний регистр (добавить .lower() в конец). Вы можете использовать emailpath.translate, если хотите что-то более сложное.

  • 0
    Спасибо, я реализовал большинство ваших предложений, но: электронная почта. Сообщение продолжает убивать меня. Я не могу понять это правильно, не могли бы вы привести пример с моим кодом? спасибо
3

Я не вижу ничего существенного в этом коде - это неправильное поведение, или вы просто ищете общие правила стиля?

Несколько примечаний:

  • Вместо logger.info ("foo %s %s" % (bar, baz)) используйте "foo %s %s", bar, baz. Это позволяет избежать накладных расходов на форматирование строк, если сообщение не будет напечатано.
  • Поместите a try...finally вокруг открытия emailpath.
  • Используйте '\n'.join (body) вместо string.join (body, '\n').
  • Вместо msg.getaddr("From") просто msg.From.
  • 0
    На самом деле я обнаружил, что From и name имеют некоторые недопустимые символы, такие как «:» и «/» и «\», что заставляет python пытаться записать поток в папку, а не в файл. поэтому я создал немного более чистый метод для удаления этих персонажей. Теперь все работает хорошо! спасибо за советы! сделаю их
0

В дополнение к моему комментарию по поводу ответа Джона

Я выяснил, в чем проблема: в поле имени и в поле Subject были обнаружены недопустимые символы, из-за которых python получал икоты, поскольку он пытался написать электронное письмо как каталог, увидев ":" и "/".

Пункт № 4 Джон не работает! поэтому я оставил его по-прежнему. Правильно ли также пункт № 1, правильно ли я сделал ваше предложение?

def _dump_pop_emails(self):
    self.logger.info("open pop account %s with username: %s", self.account[0], self.account[1])
    self.popinstance = poplib.POP3(self.account[0])
    self.logger.info(self.popinstance.getwelcome()) 
    self.popinstance.user(self.account[1])
    self.popinstance.pass_(self.account[2])
    try:
        (numMsgs, totalSize) = self.popinstance.stat()
        for thisNum in range(1, numMsgs+1):
            (server_msg, body, octets) = self.popinstance.retr(thisNum)
            text = '\n'.join(body)
            mesg = StringIO.StringIO(text)                               
            msg = rfc822.Message(mesg)
            name, email = msg.getaddr("From")
            emailpath = str(self._emailpath + self._inboxfolder + "\\" + self._sanitize_string(email + " " + msg.getheader("Subject") + ".eml"))
            emailpath = self._replace_whitespace(emailpath)
            print emailpath
            file = open(emailpath,"wb")
            file.write(text)
            file.close()
            self.popinstance.dele(thisNum)
    finally:
        self.logger.info(self.popinstance.quit())

def _replace_whitespace(self,name):
    name = str(name)
    return name.replace(" ", "_")   

def _sanitize_string(self,name):
    illegal_chars = ":", "/", "\\"
    name = str(name)
    for item in illegal_chars:
        name = name.replace(item, "_")
    return name

Ещё вопросы

Сообщество Overcoder
Наверх
Меню