Сценарий Python останавливается на разных строках и не выдает никаких исключений - PullRequest
0 голосов
/ 07 февраля 2019

У меня есть скрипт Python, который выполняет большую работу по анализу файла Word .docx (и он работал на всех предыдущих файлах).Внезапно он перестает работать на полпути без каких-либо исключений.Весь код обернут внутри предложения try-исключением, в основном так:

try:
    report.read_and_postprocess() #: My parsing process (with ALOT of code inside)
    print("Finished...")
except NoObjectForElementError as error:
    print("Known error")
    raise error
except:
    print("Other error")
    raise
finally:
    print("Write this!")

Чтобы найти ошибку, я попытался использовать операторы print(), чтобы изолировать, где код останавливается.Тем не менее, когда я подхожу близко, точка остановки перемещается в другое место.

Это заставляет меня думать, что есть утечка памяти или, возможно, какое-то другое ограничение в моей среде Python, которое включается - ноЯ не очень квалифицирован в отладке этого.Я посмотрел на использование памяти и процессора моего скрипта.В конце сценария он занимает всего около 87 МБ памяти, в результате чего общая память компьютера перемещается только с 67% до 68%.(Я смотрю только на диспетчер задач Windows 10 для этого, поэтому я не могу гарантировать, что память на мгновение не скачет до остановки скрипта)

Я перезапускал скрипт сотни раз и никогда не получалсообщение об ошибке, кроме двух раз с этой ошибкой:

Python Fatal Error: GC Object already Tracked

Понятия не имею, как продолжить отладку, есть у кого-нибудь какие-нибудь советы?Скорее всего, это вызвано памятью, или как я могу узнать?Есть ли какие-то другие ограничения Python, которые могут вызвать это?(Я читал, например, о 20-предельном числе вложенных циклов for - но это не должно быть для меня)

Обновление: Останавливается во время строки report.read_and_postprocess().

Информация об окружении: Windows 10, Anaconda 3, Python 3.7.Скрипт запускается в приглашении anaconda с активированной средой.

Обновление: Я нашел этот совет: https://stackoverflow.com/a/3443779/6700475 Может показаться, что мой код тратит много времени на оценкурегулярные выражения.В основном, такие линии были обычными при наблюдении за трассировкой:

sre_compile.py(596):     return isinstance(obj, (str, bytes))
sre_compile.py(763):         pattern = p
sre_compile.py(764):         p = sre_parse.parse(p, flags)
 --- modulename: sre_parse, funcname: parse
sre_parse.py(922):     source = Tokenizer(str)
 --- modulename: sre_parse, funcname: __init__
sre_parse.py(225):         self.istext = isinstance(string, str)
sre_parse.py(226):         self.string = string
sre_parse.py(227):         if not self.istext:
sre_parse.py(229):         self.decoded_string = string
sre_parse.py(230):         self.index = 0
sre_parse.py(231):         self.next = None
sre_parse.py(232):         self.__next()
 --- modulename: sre_parse, funcname: __next
sre_parse.py(234):         index = self.index
sre_parse.py(235):         try:
sre_parse.py(236):             char = self.decoded_string[index]
sre_parse.py(240):         if char == "\\":
sre_parse.py(247):         self.index = index + 1
sre_parse.py(248):         self.next = char
sre_parse.py(924):     if pattern is None:
sre_parse.py(925):         pattern = Pattern()
 --- modulename: sre_parse, funcname: __init__
sre_parse.py(77):         self.flags = 0
sre_parse.py(78):         self.groupdict = {}

Я запустил трассировку и (по крайней мере, на этот раз) она остановилась во время повторного матча, в частности, на третьей итерацииloop:

def is_numeric(text):
    """ Return whether a trimmed string is numeric 

    Numeric formats:
        1
        1.2 (US style)
        1,2 (EU style)
        1,200,340 (US style)
        1 200 340 (other style)
        1.200.340 (eu style?)
        1,200,340.67
        1 200 340,67
        1 200 340.67
        1.200.340,67
        -23
        -23.98
        -2 454 981.21
        + 24
        - 24
        + 24.9183
        12321
        543525,-
        123123,
        12389.
        12 489.
        12 432,
    """
    if len(text) == 0:
        return False

    #: Try float
    try:
        float(text)
    except ValueError:
        pass
    except:
        raise
    else:
        return True

    #: look for all characters that should not be in a number
    if not re.match(r"^[-+0-9., ]*$", text):
        return False

    #: Verify numeric format
    #:  1.200.200,78
    #:  1,200,200.78
    #:  1 200 200,78
    #:  1 200 200.78
    #:  1200200,78
    #:  1200200.78
    #:  - 1200200.78
    #:  + 1.200.200,78
    #:  1200200,-
    #:  -1 200 200,-
    #:  etc.
    variants = ((r",", r"\."),
                (r"\.", r","),
                (r" ", r","),
                (r" ", r"\."))
    for (tho, dec) in variants:
        dec_exp_opt = r"(%s[0-9]*)" % dec
        if dec == ",":
            dec_exp_opt = r"((%s)|(,-))" % dec_exp_opt
        threesep = r"[1-9][0-9]{0,2}(%s[0-9]{3})*(%s)?" % (tho, dec_exp_opt)
        nullsep = r"(([0-9]*(%s[0-9]+)?)|([0-9]+(%s)?))" % (dec, dec_exp_opt)
        expr = r"^([-+][ \t]*)?((%s)|(%s))$" % (threesep, nullsep)

        test = re.match(expr, text) #: IT HAS STOPPED HERE IN ITERATION 3!!
        if test:
            return True

    return False

Может быть (или не может) быть случайным, что выражение, которое он пытается решить в это время: ^([-+][ \t]*)?(([1-9][0-9]{0,2}( [0-9]{3})*((((,[0-9]*))|(,-)))?)|((([0-9]*(,[0-9]+)?)|([0-9]+((((,[0-9]*))|(,-)))?))))$ для значения 2017-05-29 (которое предпочтительно должно возвращать false).

Имеет ли смысл, что (плохие?) Регулярные выражения могут привести к тому, что скрипт просто остановится, не вызывая исключение?Есть ли в модуле re некоторое кэширование, которое может вызвать это?

Ответы [ 2 ]

0 голосов
/ 25 февраля 2019

Проблема была решена в конце концов.Я закончил отладку программы с помощью подсказки: Как я могу узнать, где висит мой скрипт на python?

python -m trace --trace YOURSCRIPT.py

Использование модуля трассировки позволило мне определить, где скрипт перестал работать,В моем случае я запустил цикл, где каждая итерация выполняла несколько проверок регулярных выражений.Скрипт глючил во время этих проверок, но каждый раз в разные моменты.Я не совсем уверен, но Катастрофическое возвращение назад было вероятной причиной, как предполагалось в ответе Михая Андрея.Я уверен, что я провел очень неэффективные проверки регулярных выражений.Я переписал всю часть регулярного выражения моего сценария, и теперь он работает нормально.

Итак, в заключение, ответ на мой вопрос:

  1. Отладка сценария с помощью trace модуль, чтобы узнать, где он останавливается.Это привело меня к (2)
  2. Обязательно избегайте Катастрофического обратного отслеживания (и возможных утечек памяти в регулярных выражениях [?])

ЕслиУ кого-либо есть более подробные объяснения, почему Python вызывает ошибки без сообщения об ошибке, или можете подтвердить, что утечки памяти в регулярных выражениях могут вызвать это, пожалуйста, добавьте в мой ответ!

0 голосов
/ 07 февраля 2019

Вы можете запустить его с помощью отладчика и приостановить выполнение при зависании.Смотрите трассировку стека.Такие инструменты, как strace на Linux, также могут помочь.Вероятно, ваш процесс заблокирован на каком-то io или застрял на каком-то тупике.

Удобный отладчик в pycharm.Экспортируйте ваш ipynb в обычный файл python.

РЕДАКТИРОВАТЬ новую информацию из вопроса

Не создавайте такого огромного, непредсказуемого регулярного выражения.Просто проверьте все шаблоны в цикле.

Возможно, вы создали регулярное выражение, склонное к катастрофическому возврату

На первый взгляд, я не выгляжу так, но это необходимовторой взгляд

p = r"^([-+][ \t]*)?(([1-9][0-9]{0,2}( [0-9]{3})*((((,[0-9]*))|(,-)))?)|((([0-9]*(,[0-9]+)?)|([0-9]+((((,[0-9]*))|(,-)))?))))$"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...