2013-06-13 15 views
8

Aktualizacja: więcej informacji na temat debugowania na dole tego wpisu, co ujawnia coś bardzo nieprzyjemnego w stanie Pythona.Zaimportowane moduły stają się Brak podczas działania funkcji

Mam moduł, który importuje, między innymi, obiekt użytkownika django.

Import działa poprawnie, a kod ładuje się. Jednak, gdy wywołujesz funkcję w tym module, który używa obiektu User, oznacza to, że użytkownik jest typu NoneType.

Istnieje również szereg innych importów i niektóre zmienne globalne na poziomie modułu, które są również Brak do czasu wywołania tej funkcji.

To jest tylko problem w naszych środowiskach pomostowych (Ubuntu 12.04). Działa dobrze lokalnie, co prawdopodobnie najbardziej przypomina inscenizację z dodatkowymi pakietami Pythona do pracy dev. Również dobrze w produkcji.

Czy ktoś kiedyś się z tym zetknął i ma jakieś pomysły, co może spowodować?

Oto kod:

import urllib 
import time 
import urlparse 

# Django imports 
from django.db.models.signals import post_delete 
from django.db import models 
from django.contrib.auth.models import User 

from backends.cache.dualcache import cache 

# Piston imports 
from managers import TokenManager, ConsumerManager 
from signals import consumer_post_delete 

KEY_SIZE = 18 
SECRET_SIZE = 32 
VERIFIER_SIZE = 10 

CONSUMER_STATES = (
    ('pending', 'Pending'), 
    ('accepted', 'Accepted'), 
    ('canceled', 'Canceled'), 
    ('rejected', 'Rejected') 
) 


def generate_random(length=SECRET_SIZE): 
    return User.objects.make_random_password(length=length) 


class Consumer(models.Model): 
    name = models.CharField(max_length=255) 
    description = models.TextField() 

    key = models.CharField(max_length=KEY_SIZE) 
    secret = models.CharField(max_length=SECRET_SIZE) 

    status = models.CharField(max_length=16, choices=CONSUMER_STATES, default='pending') 

    objects = ConsumerManager() 

    def __unicode__(self): 
     return u"Consumer %s with key %s" % (self.name, self.key) 

    def generate_random_codes(self): 
     key = User.objects.make_random_password(length=KEY_SIZE) 
     secret = generate_random(SECRET_SIZE) 

     while Consumer.objects.filter(key__exact=key, secret__exact=secret).count(): 
      secret = generate_random(SECRET_SIZE) 

     self.key = key 
     self.secret = secret 
     self.save() 

a tu prace wokół, co oznacza po prostu importować co znowu trzeba wewnątrz funkcji:

import urllib 
import time 
import urlparse 

# Django imports 
from django.db.models.signals import post_delete 
from django.db import models 
from django.contrib.auth.models import User 

from backends.cache.dualcache import cache 

# Piston imports 
from managers import TokenManager, ConsumerManager 
from signals import consumer_post_delete 

KEY_SIZE = 18 
SECRET_SIZE = 32 
VERIFIER_SIZE = 10 

CONSUMER_STATES = (
    ('pending', 'Pending'), 
    ('accepted', 'Accepted'), 
    ('canceled', 'Canceled'), 
    ('rejected', 'Rejected') 
) 


def generate_random(length=SECRET_SIZE): 
    return User.objects.make_random_password(length=length) 


class Consumer(models.Model): 
    name = models.CharField(max_length=255) 
    description = models.TextField() 

    key = models.CharField(max_length=KEY_SIZE) 
    secret = models.CharField(max_length=SECRET_SIZE) 

    status = models.CharField(max_length=16, choices=CONSUMER_STATES, default='pending') 

    objects = ConsumerManager() 

    def __unicode__(self): 
     return u"Consumer %s with key %s" % (self.name, self.key) 

    def generate_random_codes(self): 
     from piston.models import KEY_SIZE, SECRET_SIZE, Consumer 
     from django.contrib.auth.models import User 
     from piston.models import generate_random 

     key = User.objects.make_random_password(length=KEY_SIZE) 
     secret = generate_random(SECRET_SIZE) 

     while Consumer.objects.filter(key__exact=key, secret__exact=secret).count(): 
      secret = generate_random(SECRET_SIZE) 

     self.key = key 
     self.secret = secret 
     self.save() 

Oto ślad stosu. Błąd jest spowodowany przez linię:

key = User.objects.make_random_password(length=KEY_SIZE) 

w funkcji generate_random_codes.

Traceback: 
File "/sites/tellybug/shared/webserver/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response 
    111.       response = callback(request, *callback_args, **callback_kwargs) 
File "/sites/tellybug/shared/webserver/local/lib/python2.7/site-packages/django/contrib/admin/options.py" in wrapper 
    366.     return self.admin_site.admin_view(view)(*args, **kwargs) 
File "/sites/tellybug/shared/webserver/local/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapped_view 
    91.      response = view_func(request, *args, **kwargs) 
File "/sites/tellybug/shared/webserver/local/lib/python2.7/site-packages/django/views/decorators/cache.py" in _wrapped_view_func 
    89.   response = view_func(request, *args, **kwargs) 
File "/sites/tellybug/shared/webserver/local/lib/python2.7/site-packages/django/contrib/admin/sites.py" in inner 
    196.    return view(request, *args, **kwargs) 
File "/sites/tellybug/shared/webserver/local/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapper 
    25.    return bound_func(*args, **kwargs) 
File "/sites/tellybug/shared/webserver/local/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapped_view 
    91.      response = view_func(request, *args, **kwargs) 
File "/sites/tellybug/shared/webserver/local/lib/python2.7/site-packages/django/utils/decorators.py" in bound_func 
    21.     return func(self, *args2, **kwargs2) 
File "/sites/tellybug/shared/webserver/local/lib/python2.7/site-packages/django/db/transaction.py" in inner 
    224.     return func(*args, **kwargs) 
File "/sites/tellybug/shared/webserver/local/lib/python2.7/site-packages/django/contrib/admin/options.py" in add_view 
    970.    form = ModelForm(initial=initial) 
File "/sites/tellybug/shared/webserver/local/lib/python2.7/site-packages/django/forms/models.py" in __init__ 
    234.    self.instance = opts.model() 
File "/sites/tellybug/shared/webserver/local/lib/python2.7/site-packages/django/db/models/base.py" in __init__ 
    349.     val = field.get_default() 
File "/sites/tellybug/shared/webserver/local/lib/python2.7/site-packages/django/db/models/fields/related.py" in get_default 
    983.   field_default = super(ForeignKey, self).get_default() 
File "/sites/tellybug/shared/webserver/local/lib/python2.7/site-packages/django/db/models/fields/__init__.py" in get_default 
    379.     return self.default() 
File "/sites/tellybug/releases/b92109dd526607b2af92ad6b7f494f3f06e31bb2/webserver/tellybug/tbapp/models/tellybugapp.py" in generate_new_consumer 
    11.  consumer.generate_random_codes() 
File "/sites/tellybug/releases/b92109dd526607b2af92ad6b7f494f3f06e31bb2/webserver/tellybug/piston/models.py" in generate_random_codes 
    57. key = User.objects.make_random_password(length=KEY_SIZE) 

Exception Type: AttributeError at /admin/tbapp/tellybugapp/add/ 
Exception Value: 'NoneType' object has no attribute 'objects' 

Aktualizacja: To nie jest coś po prostu usunięcie obiektu User - coś jest burzenie cały kontekst w funkcji.

def generate_random_codes(self): 
    """ 
    Used to generate random key/secret pairings. Use this after you've 
    added the other data in place of save(). 

    c = Consumer() 
    c.name = "My consumer" 
    c.description = "An app that makes ponies from the API." 
    c.user = some_user_object 
    c.generate_random_codes() 
    """ 
    import sys 
    print "Globals", globals() 
    print "Name ", __name__ 
    print "Package ", __package__ 
    print "Sys modules", sys.modules['piston.models'].__dict__ 
    key = User.objects.make_random_password(length=KEY_SIZE) 

Z tych stwierdzeń drukowania, wyjście jest:

Globals {'ColumnFamilyMap': None, 'datetime': None, 'KEY_SIZE': None, 'TokenManager': None, 'ConsistencyLevel': None, 'Nonce': None, 'uuid': None, 'cache': None, 'urllib': None, '__package__': None, 'models': None, 'User': None, .... } 
Name None 
Package None 
Sys modules {'ColumnFamilyMap': <class 'pycassa.columnfamilymap.ColumnFamilyMap'>, 'datetime': <type 'datetime.datetime'>, 'KEY_SIZE': 18, 'NonceType': <class 'piston.models.NonceType'>, 'OAuthToken': <class 'piston.models.OAuthToken'>, 'TokenManager': <class 'piston.managers.TokenManager'>, 'ConsistencyLevel': <class 'pycassa.cassandra.ttypes.ConsistencyLevel'>, 'Nonce': <class 'piston.models.Nonce'>, 'uuid': <module 'uuid' from '/usr/lib/python2.7/uuid.pyc'>, ...} 

Należy zauważyć, że zarówno __package__ i __name__ są niezdefiniowane, co uważałem, że było dość dużo niemożliwe, i że podczas gdy wersja z sys.modules moduł ma poprawną wartość __dict__, wartość zwracana z globals() jest nonsensem.

+1

Pokaż nam kod, który zgłasza wyjątek, oraz pełne informacje zwrotne. –

+0

Czy na pewno błąd pochodzi z modelu, a nie z innego miejsca? Proszę również wskazać drogę powrotną. –

+0

Dzięki, dodano ślad stosu i linię, która rzuca błąd. –

Odpowiedz

7

Zdarza się to w przypadku funkcji importowanego modułu, która wciąż jest wykonywana po tym, jak moduł jest zbierany śmieci.

Ponieważ Twój kod nie wystarcza do odtworzenia problemu, oto uproszczony przykład pokazujący zachowanie. Utwórz plik zawierający następujące elementy i zaimportuj go z wiersza poleceń Python lub innego pliku. To nie działa, jeśli po prostu uruchomisz go na najwyższym poziomie.

import sys 
import threading 

x = "foo" 

def run(): 
    while True: 
     print "%s %s\n" % (sys, x) 

threading.Thread(target = run).start() 
sys.stdin.readline() 

Running go:

$ python 
>>> import evil_threading 
<module 'sys' (built-in)> foo 

<module 'sys' (built-in)> foo 
... press Ctrl-C 
None None 

None None 
... press Ctrl-\ to kill the Python interpreter 

Podczas zamykania Pythona moduły są ustawione na None. This is an obscure Python behaviour that was removed in 3.4. W tym przykładzie zakończenie głównego wątku powoduje zamknięcie, ale drugi wątek nadal działa, więc widzi moduły jako None.

Istnieje prostszy przykład: from here, który robi to samo, usuwając odniesienie do modułu bezpośrednio z sys.modules.

import sys 
print sys 
del sys.modules['__main__'] 
print sys 
Powiązane problemy