2013-09-05 4 views
0

У меня есть определенный пользователь исключение в моем приложении Django:Джанго: определяемый пользователь исключения не поймало

class TemplateMatchError(Exception): 
    ... 

У меня есть сегмент кода, который перехватывает это исключение в регулярном try ... except:

try: 
    if template.match(text): 
    return attrs 
except TemplateMatchError as e: 
    continue 

Я заметил, что в процессе производства, когда DEBUG=True, эта ошибка не поймана, и если она поднята, в моем браузере отображается желтая страница трассировки стека Django. Когда DEBUG=False, исключение поймано.

Я был удивлен этим поведением, так как это означает, что настройка отладки изменяет поведение обычного питона try...except. Это правильная интерпретация, и если да, то почему Django работает таким образом?

UPDATE: Согласно комментариям я отправляю реально отслеживающий ниже (имена отличаются от примера игрушечной выше):

Environment: 


Request Method: POST 
Request URL: http://mysite.com/api/call/6/ 

Django Version: 1.4.2 
Python Version: 2.7.3 
Installed Applications: 
('longerusername', 
'django.contrib.auth', 
'django.contrib.contenttypes', 
'django.contrib.sessions', 
'django.contrib.messages', 
'django.contrib.sites', 
'django.contrib.admin', 
'south', 
'django_extensions', 
'django.contrib.staticfiles', 
'crispy_forms', 
'api', 
'rest_framework') 
Installed Middleware: 
('django.middleware.common.CommonMiddleware', 
'django.contrib.sessions.middleware.SessionMiddleware', 
'django.middleware.csrf.CsrfViewMiddleware', 
'django.contrib.auth.middleware.AuthenticationMiddleware', 
'django.contrib.messages.middleware.MessageMiddleware') 


Traceback: 
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py" in get_response 
    111.       response = callback(request, *callback_args, **callback_kwargs) 
File "/usr/local/lib/python2.7/dist-packages/rest_framework/compat.py" in view 
    121.     return self.dispatch(request, *args, **kwargs) 
File "/usr/local/lib/python2.7/dist-packages/django/views/decorators/csrf.py" in wrapped_view 
    77.   return view_func(*args, **kwargs) 
File "/usr/local/lib/python2.7/dist-packages/rest_framework/views.py" in dispatch 
    327.    response = self.handle_exception(exc) 
File "/usr/local/lib/python2.7/dist-packages/rest_framework/views.py" in dispatch 
    324.    response = handler(request, *args, **kwargs) 
File "/usr/local/lib/python2.7/dist-packages/rest_framework/generics.py" in put 
    469.   return self.update(request, *args, **kwargs) 
File "/usr/local/lib/python2.7/dist-packages/rest_framework/mixins.py" in update 
    129.   if serializer.is_valid(): 
File "/usr/local/lib/python2.7/dist-packages/rest_framework/serializers.py" in is_valid 
    479.   return not self.errors 
File "/usr/local/lib/python2.7/dist-packages/rest_framework/serializers.py" in errors 
    471.     ret = self.from_native(data, files) 
File "/usr/local/lib/python2.7/dist-packages/rest_framework/serializers.py" in from_native 
    867.   instance = super(ModelSerializer, self).from_native(data, files) 
File "/usr/local/lib/python2.7/dist-packages/rest_framework/serializers.py" in from_native 
    319.     attrs = self.perform_validation(attrs) 
File "/usr/local/lib/python2.7/dist-packages/rest_framework/serializers.py" in perform_validation 
    260.      attrs = validate_method(attrs, source) 
File "/home/uname/api/serializers.py" in validate_text 
    68.     if template.match(text): 
File "/home/uname/api/models.py" in match 
    135.    raise TemplateMatchError() 

Exception Type: TemplateMatchError at /api/call/6/ 
Exception Value: Not a match 

Вот мой models.py:

import re 
from datetime import datetime 
from django.db import models 
from django.contrib.auth.models import User as AuthUser 
from otalo.ao.models import User 
from otalo.surveys.models import Survey 

class XCall(models.Model): 
    created_on = models.DateTimeField(auto_now_add=True) 
    send_on = models.DateTimeField(default=datetime.now) 
    auth_user = models.ForeignKey(AuthUser, related_name='calls') 
    recipient = models.ForeignKey(User) 
    text = models.CharField(max_length=4096) 
    backup_calls = models.IntegerField(blank=True, null=True) 

    ''' 
    ' Associate with the survey, since 
    ' all the calls can be traced through it. 
    ' This billing/auditing purposes. 
    ' 
    ' This can be lazily created at the time of 
    ' scheduling the call, so make it nullable 
    ' 
    ''' 
    survey = models.ForeignKey(Survey, null=True, blank=True) 


    def __unicode__(self): 
     return unicode(self.auth_user) + '-' + unicode(self.recipient) 

class TemplateMatchError(Exception): 
    STD_MESSAGE = 'Not a match' 
    def __init__(self, msg=None): 
     if msg is not None: 
      self.msg = TemplateMatchError.STD_MESSAGE + ': ' + msg 
     else: 
      self.msg = TemplateMatchError.STD_MESSAGE 
    def __str__(self): 
     return self.msg 

class XTemplate(models.Model): 

    VARTYPE_NUM = '_N_' 
    VARTYPE_WORD = '_W_' 
    VARTYPE_DATETIME = '_DT_' 
    VARTYPE_DATE = '_D_' 
    VARTYPE_TIME = '_T_' 

    # add grouping for regexes for easy extraction 
    VARTYPE_REGEXS = { VARTYPE_NUM: r'(\d+(?:\.\d{1,2})?)', # supports decimals up to two precision points. Could be more but then 
                  # the prompting would start to sound weird 
         VARTYPE_WORD: r'(\w+)', 
         # Match dates and times as words 
         # so that your match function can 
         # try to convert to datetime for more 
         # detailed error messages 
         VARTYPE_DATETIME: r'(\w+)', 
         VARTYPE_DATE: r'(\w+)', 
         VARTYPE_TIME: r'(\w+)', 
         } 

    DATE_FORMATS = { 
         VARTYPE_DATETIME: '%d-%m-%y %H:%M', 
         VARTYPE_DATE: '%d-%m-%y', 
         VARTYPE_TIME: '%H:%M' 
        } 

    created_on = models.DateTimeField(auto_now_add=True) 
    auth_user = models.ForeignKey(AuthUser, related_name='templates') 
    ''' 
    ' Encodes the wildcards and their type. 
    ' e.g. Your account number _N_ is of type _W_ expiring at time _D_ 
    ''' 
    text = models.CharField(max_length=4096) 

    ''' 
    ' For common prompts like numbers and dates and times 
    ''' 
    language = models.CharField(max_length=24) 

    STATUS_PENDING = 0 
    STATUS_ACTIVE = 1 
    STATUS_INACTIVE = 2 

    STATUSES = (
    (STATUS_PENDING, 'Pending'), 
    (STATUS_ACTIVE, 'Active'), 
    (STATUS_INACTIVE, 'Inactive'), 
    ) 
    status = models.IntegerField(choices=STATUSES) 

    ''' 
    ' Compare the inupt text to this template's text; 
    ' return the match object if it matches, else throw an error 
    ''' 
    def match(self, input): 
     pattern = self.text 

     # first convert the template pattern into a regular expression 
     vars = [var.group() for var in re.finditer('_[A-Z]_', pattern)] 
     re_pattern = pattern 
     for vartype, regex in XTemplate.VARTYPE_REGEXS.iteritems(): 
      re_pattern = re_pattern.replace(vartype, regex) 

     # now try an initial match of the structure of the input 
     match = re.match(re_pattern, input) 

     if match: 
      # make sure words are in the wordlist 
      # numbers are valid numbers 
      # and dates are in the proper format 
      vocab = [word.text for word in self.vocabulary.all()] 
      vals = match.groups() 
      for i in range(len(vars)): 
       if i > len(vals): 
        raise TemplateMatchError('Missing a variable in input') 
       var = vars[i] 
       val = vals[i] 
       if var == XTemplate.VARTYPE_NUM: 
        try: 
         float(val) 
        except ValueError as e: 
         raise TemplateMatchError('Invalid number') 
       elif var == XTemplate.VARTYPE_WORD: 
        if val not in vocab: 
         raise TemplateMatchError('Word not in vocabulary') 
       elif var == XTemplate.VARTYPE_DATETIME or var == XTemplate.VARTYPE_DATE or var == XTemplate.VARTYPE_TIME: 
        format = XTemplate.DATE_FORMATS[var] 
        try: 
         date = datetime.strptime(val, format) 
        except ValueError as e: 
         raise TemplateMatchError('Invalid date, time, or datetime format - ' + val) 
      return match 
     else: 
      raise TemplateMatchError() 

    def __unicode__(self): 
     return self.text + '-' + unicode(self.auth_user) 

class XWord(models.Model): 
    text = models.CharField(max_length=128) 
    template = models.ForeignKey(XTemplate, related_name='vocabulary') 

    def __unicode__(self): 
     return self.text 

сериализатору класс вопрос:

class CallSerializer(serializers.HyperlinkedModelSerializer): 
    url = serializers.HyperlinkedIdentityField(
     view_name='call-detail', 
    ) 
    recipient = PhoneNumberField(read_only=False) 
    status = SurveySerializer(source='survey', read_only=True) 

    def validate_text(self, attrs, source): 
     text = attrs['text'] 
     auth = self.context['request'].user 
     templates = auth.templates.all() 
     for template in templates: 
      try: 
       if template.match(text): 
        return attrs 
      except TemplateMatchError as e: 
       continue 

     raise serializers.ValidationError("Call text does not match a registered template") 

    class Meta: 
     model = XCall 
     fields = ('url', 'id', 'text', 'recipient', 'send_on', 'backup_calls', 'status') 
     lookup_field= 'pk' 
+4

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

+0

Ответ НЕТ. Исключения не выполняются таким образом. Однако изменение значения может повлиять на результат кода, например, переменные и управление потоком. – stormlifter

+0

@ThomasOrozco traceback добавлен к вопросу. Благодаря! – Neil

ответ

1

Проблема заключалась в том, что другой класс исключений был взят models.py, хотя имя было таким же.

В моих настройках.py не указан полный путь к приложению, в котором находится указанная model.py. После указания полного пути были сопоставлены классы исключений и исключение. Спасибо всем, кто дал большие советы.

+0

Вы нашли, как это соотносится с «DEBUG = True»? – hynekcer

+0

Нет, я этого не делал. Это все еще загадка, и поэтому ни один из этих ответов, включая мои, не является полным – Neil

0

Это поможет узнать больше о вашем коде вокруг исключения. Из того, что вы показали, что есть несколько вещей, чтобы посмотреть на:

  1. Я предполагаю, что TemplateMatchError является то, что вы первоначально назвали MyError
  2. Ваш код кажется не знаете, как template.match возвращает отрицательный результат. В serializers.py, похоже, ожидает nil/false возвращаемое значение, но сама функция вызывает исключение, а не возвращает что-то ложное.
  3. Сегмент кода, как вы показали, имеет плохой отступ, что может привести к сбою в ошибке.

Как вы уже показали, что это:

try: 
    template.match(text) 
    # Do other stuff, presumably including this: 
    try: 
     somethingElse() 
    except TemplateMatchError as e: 
     #this won't catch exceptions from template.match(text) 
     continue 

Как я думаю, что вы имеете в виду это:

try: 
    template.match(text) 
except TemplateMatchError as e: 
    # This will be caught 
    continue 

Надежда, что помогает.

+0

Я поставил точный код в вопросе выше. Это не ошибка отступа, обратите внимание, что все работает так, как ожидалось, когда Debug = False в производстве. Когда Debug = True, проблема возникает. Я знаю, что я не должен устанавливать его в True при производстве, но я пытаюсь понять, почему это вызывает такое поведение. – Neil

+0

Можете ли вы показать немного больше информации о 'serializers.py' и'? '. – Hbcdev

+0

Добавлено выше @Hbcdev – Neil

0

Вы уверены, что это тот же класс «TemplateMatchError», импортированный из того же модуля, который вы поднимаете, и пытаетесь поймать.

Если это два класса с тем же именем, но импортированные из другого модуля, python не будет их отличать от одного и того же Исключения, а затем никогда не будет вводить ваш блок catch.

+0

Да, я проверял, что они такие же. Опять же, я предполагаю, что это было бы проблемой, было ли у DEBUG установлено значение True или False – Neil

0

Измените код таким образом, чтобы проверить допущения в очень близкой точке.

import api 
    assert TemplateMatchError == api.models.TemplateMatchError 
    try: 
     if template.match(text): 
      return attrs 
    except TemplateMatchError as e: 
     continue 
    except Exception as e: 
     assert isinstance(e, TemplateMatchError) 
     import pdb; pdb.set_trace() 
     pass # if both asserts vere OK, but the exception is uncaught (not 
     #  probable) you are here and see the the line debugger started 
     raise # continue by caugting in external frames 

Начало TestServer по лучшим способом для отладки
python manage.py runserver --nothreading --noreload
Когда вы видите отладчика подсказку (Pdb), поместить эти команды для того, чтобы повторить его шаг за шагом:

l(ist) Enter 
j(ump) <line number of the line 'try:'> Enter 
b /home/uname/api/models.py:135 Enter # breakpoint at that raise command 
c(ontinue) Enter 
s(tep) Enter # press Enter five times to see steps, how the lines 
       # "except ... continue" are missed 
c(ontinue) # to reraise and see an error page in the browser 

Однако я подумайте, что одно из утверждений потерпит неудачу, если DEBUG = True, и вы будете знать больше, без отладчика.

+0

Спасибо, это дало мне подсказку, в которой я нуждался. Я отлаживался, чтобы обнаружить, что исключение Exception не было полным путем для моего приложения Django. Я изменил параметры settings.py, чтобы ссылаться на приложение по полному имени, которое исправило проблему. – Neil

Смежные вопросы