2013-06-13 13 views
8

Aggiornamento: alcune ulteriori informazioni di debug in fondo a questo post, che rivelano qualcosa di molto vago nello stato python.I moduli importati diventano Nessuno quando si esegue una funzione

Ho un modulo che importa, tra le altre cose, l'oggetto utente django.

L'importazione funziona correttamente e il codice viene caricato. Tuttavia, quando si chiama una funzione in quel modulo che utilizza l'oggetto Utente, si sbaglia dicendo che l'utente è un NoneType.

Ci sono anche un certo numero di altre importazioni e alcune variabili globali a livello di modulo che sono anche None quando viene chiamata la funzione.

Stranamente, questo è solo un problema nei nostri ambienti di staging (Ubuntu 12.04). Funziona bene localmente, che probabilmente assomiglia di più alla messa in scena con pacchetti Python aggiuntivi per il lavoro di sviluppo. Va bene anche in produzione.

Qualcuno l'ha mai visto prima e ha qualche idea su cosa potrebbe causarlo?

Ecco il codice:

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() 

ed ecco il lavoro intorno, che in pratica significa importare ciò che è necessario ancora una volta all'interno della funzione:

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() 

Ecco la traccia dello stack. L'errore è causato dalla riga:

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

nella funzione 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' 

Aggiornamento: Non è qualcosa che solo l'eliminazione dell'oggetto d'uso - qualcosa sta distruggendo l'intero contesto in funzione.

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) 

Con queste dichiarazioni di stampa, l'output è:

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'>, ...} 

notare che sia __package__ e __name__ sono indefinita, che ho pensato che era praticamente impossibile, e che mentre la versione del sys.modules modulo ha un valore corretto __dict__, il valore restituito da globals() non ha senso.

+1

Si prega di mostrare il codice che genera l'eccezione, oltre al traceback completo. –

+0

Sei sicuro che l'errore proviene dal modello e non da dove? Si prega di mostrare anche il traceback. –

+0

Grazie, aggiunta traccia di stack e linea che sta generando l'errore. –

risposta

7

Questo succede a una funzione in un modulo importato che è ancora in esecuzione dopo che quel modulo è stato eliminato.

Poiché il codice non è sufficiente per riprodurre il problema, ecco un esempio semplificato che mostra il comportamento. Creare un file contenente quanto segue e importarlo dalla riga di comando di Python o da un altro file. Non funziona se lo esegui semplicemente al livello superiore .

import sys 
import threading 

x = "foo" 

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

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

Eseguirlo:

$ 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 

Durante l'arresto Python, moduli sono impostati None. This is an obscure Python behaviour that was removed in 3.4. In questo esempio, la chiusura del thread principale provoca l'arresto, ma l'altro thread è ancora in esecuzione, quindi vede i moduli come None.

C'è un esempio più semplice from here che fa la stessa cosa eliminando il riferimento del modulo direttamente da sys.modules.

import sys 
print sys 
del sys.modules['__main__'] 
print sys 
Problemi correlati