2012-06-05 6 views
13

Ricevo questo errore nell'applicazione Django, tuttavia, si verifica solo una volta al giorno o meno e risulta estremamente difficile eseguire il debug.Impossibile decapitare <tipo 'funzione'>: funzione di ricerca attributo __builtin __. Non riuscita

Environment: 

Request Method: POST 

Django Version: 1.3.1 
Python Version: 2.6.6 
Installed Applications: 
['django.contrib.contenttypes', 
'django.contrib.sessions', 
'django.contrib.sites', 
'fimedlabs', 
'data', 
'djcelery'] 
Installed Middleware: 
('django.middleware.common.CommonMiddleware', 
'django.contrib.sessions.middleware.SessionMiddleware', 
'fimedlabs.auth.userMiddleWare') 


Traceback: 
File "/usr/local/lib/python2.6/dist-packages/django/core/handlers/base.py" in get_response 
    178.     response = middleware_method(request, response) 
File "/usr/local/lib/python2.6/dist-packages/django/contrib/sessions/middleware.py" in process_response 
    36.     request.session.save() 
File "/usr/local/lib/python2.6/dist-packages/django/contrib/sessions/backends/db.py" in save 
    57.    session_data = self.encode(self._get_session(no_load=must_create)), 
File "/usr/local/lib/python2.6/dist-packages/django/contrib/sessions/backends/base.py" in encode 
    93.   pickled = pickle.dumps(session_dict, pickle.HIGHEST_PROTOCOL) 

Exception Type: PicklingError at/
Exception Value: Can't pickle <type 'function'>: attribute lookup __builtin__.function failed 

ho provato la risposta a questo:

How to tell for which object attribute pickle fails?

aggiungendo sé per l'errore effettivo per vedere se questo sarebbe stampare qualsiasi cosa nell'errore Django senza alcun risultato.

Dove posso stampare l'oggetto che genera problemi da questo errore in modo che venga visualizzato nella pagina di errore di Django?

Grazie! ~ Matt

EDIT: L'unico oggetto che sto memorizzazione nella cache, è un oggetto utente con il codice:

class user(object): 
username = str() 
userid = uuid.UUID(int=0) 

client = models.Client() 
clientid = uuid.UUID(int=0) 
clientname = '' 

data = models.User() 
accesslevel = models.AccessLevel() 

active = False 
client_active = False 
isFimed = False 
isFimedAdmin = False 
isClientAdmin = False 
isFimedManager = False 
mysettingsform = None 
viewingas = False 

menu = [] 

_exists = False 
_authenticated = False 

def __str__(self): 
    return str(self.__dict__.copy()) 

def __getstate__(self): 
    return self.__dict__.copy() 

def __setstate__(self, dict): 
    self.__dict__ = dict 

def __init__(self, username=None): 
    if username: 
     self.initialize(username) 

def initialize(self, username): 
    self.username = username 
    model = models.User.objects.filter(username=username).all() 
    if len(model) == 1: 
     model = model[0] 
     self.data = model 
     self._exists = True 
     self.userid = self.data.id 
     self.active = self.data.active 
     self.isFimed = self.data.isFimed() 
     self.isFimedAdmin = self.data.isFimedAdmin() 
     self.isClientAdmin = self.data.isClientAdmin() 
     self.isFimedManager = self.data.isFimedManager() 
     self.mysettingsform = UserFormSelf(initial={"id":model.id, "username":model.username, "name":model.name, "email":model.email, "phone":model.phone}) 

     self.accesslevel = models.AccessLevel.objects.filter(id=self.data.accesslevel_id)[:1][0].level 
     cli = self.data.client 
     self.client = cli 
     self.clientid = cli.id 
     self.clientname = cli.name 
     if cli.active: 
      self.client_active = True 

     model.lastlogin = datetime.datetime.now() 
     model.save() 

     self.menu = getMenu(self.data) 
    else: 
     self._exists = False 

def authenticate(self, password): 
    self._authenticated = False 
    if (self.active == False or self.client_active == False): 
     return False 
    if self._exists: 
     import hashlib 
     hash = hashlib.md5('%s%s' % (str(password), self.data.pwsalt)).hexdigest() 
     if hash == self.data.pwhash: 
      self._authenticated = True 
      return True 
    return False 

def updateUser(self): 
    self.initialize(models.User.objects.filter(id=self.userid).get().username) 

def mkContext(self): 
    c = Context() 
    c['menu'] = self.menu 
    c['user'] = self 
    c['language'] = language 
    c['colors'] = colors 
    c["isFimed"] = self.isFimed 
    c["isFimedAdmin"] = self.isFimedAdmin 
    c["isClientAdmin"] = self.isClientAdmin 
    c["isFimedManager"] = self.isFimedManager 
    c["mysettingsform"] = self.mysettingsform 
    return c 

EDIT: il file WSGI dopo Werkzeug:

import django.core.handlers.wsgi 
djangoapplication = django.core.handlers.wsgi.WSGIHandler() 
def application(environ, start_response): 
    if 'SCRIPT_NAME' in environ: 
     del environ['SCRIPT_NAME'] 
    return djangoapplication(environ, start_response) 
# The following lines enable the werkzeug debugger 
import django.views.debug 
def null_technical_500_response(request, exc_type, exc_value, tb): 
    raise exc_type, exc_value, tb 
django.views.debug.technical_500_response = null_technical_500_response 
from werkzeug.debug import DebuggedApplication 
application = DebuggedApplication(application, evalex=True) 

risposta

6

Dove posso stampare l'oggetto che genera problemi da questo errore in modo che venga visualizzato nella pagina di errore di Django?

La risposta breve - senza ricompilare cPickle, non è possibile.

più lunga risposta: Questo è il pezzo di codice che solleva l'eccezione:

root $ grep -Hra "attribute lookup" /usr/lib64/ 2>/dev/null | grep -a failed 
/usr/lib64/python2.7/lib-dynload/cPickle.so:H�H���P0H�5zM H�=1��M��H��H�ZM �����H�=�1�H���M��H��H��M �����H�4M H�5~H���H���������H�M H�5tH���H���������H��L H�5�H���qH�����d���H�M H�5NH���SH�����F���H�dM H�5bH���5H�����(���H�=X1��O��H�HC H�5I H�=U1�A��H��L �vH��H��I�������H���RK��H�=.H����J��H�5$H��H��H�D$�G��H�D$H��tH�H��H��H��gH�DL�ttH�qH�5nH�=kH��1��XK��H�5bH��H��I����F��H�5\L��H���F��H��tH�EH��H��H�E��M�������I�$H��H��I�$�t���I�DL���P0�d���f�H�EH��H��H�E�F���H�H���P0�7���@H�|$H��P0�����H�H���P0�����H�H���P0�k�����UH��SH�H�H: H���tH�;: H���H�H���u�H�[��H��M��H��attribute deletion is not supportedunsupported pickle protocol: %dargument must have 'read' and 'readline' attributespickle protocol %d asked for; the highest available protocol is %dargument must have 'write' attributeGlobal and instance pickles are not supported.Attempt to getvalue() a non-list-based picklerUnexpected data in internal listBINSTRING pickle has negative byte countno int where int expected in memoCan't pickle %s: import of module %s failedCan't pickle %s: attribute lookup %s.%s failedCan't pickle %s: it's not the same object as %s.%sCan't pickle %s: extension code %s isn't an integerCan't pickle %s: extension code %ld is out of rangecould not convert string to intLONG pickle has negative byte countcould not convert string to floatBINUNICODE pickle has negative byte countunregistered extension code %ld_inverted_registry[%ld] isn't a 2-tuple of stringsA load persistent id instruction was encountered, 

Se si guarda abbastanza vicino, c'è un pezzo che dice

Can't pickle %s: attribute lookup %s.%s failed 

Ora, se si scarica fonti Python , è possibile trovare facilmente il pezzo di codice responsabile dell'innalzamento dell'eccezione nella funzione static int save_global(Picklerobject *self, PyObject *args, PyObject *name) di ./Modules/cPickle.c:

klass = PyObject_GetAttrString(mod, name_str); 
if (klass == NULL) { 
    cPickle_ErrFormat(PicklingError, 
         "Can't pickle %s: attribute lookup %s.%s " 
         "failed", 
         "OSS", args, module, global_name); 
    goto finally; 
} 

Quindi, la cosa migliore che si può fare per eseguire il debug di questo errore è formattare la stringa in modo diverso (probabilmente fornendo PyString_AS_STRING((PyStringObject *)name), ricompilare e installare la versione modificata di Python.

Sì, lo so che è troppo male. Ho appena avuto lo stesso problema me stesso.

+0

Grazie! Se/quando tornerà, farò sicuramente un tentativo. Non è mai successo in 2-3 settimane. Accetterò questo però :) Come il debugger werkeug non ha finito per lavorare per me. – MatthewKremer

1

Usa qualcosa come django-extensions per installare il debugger werkzeug. Sarai in grado di interagire con ogni stackframe. A quel punto, puoi provare a decapare tutte le chiavi e i valori nella dicitura di sessione.

+0

Va bene, ho installato django-estensioni e werkzeug, poi avvolto il mio file WSGI (vedi 1 ° posto per quello che ho modificato a). Tuttavia, quando si verifica l'errore werkzeug, e scrivo qualcosa nella sua console, restituisce semplicemente la stessa pagina 500 tramite AJAX invece di fare qualcosa con il comando console. Qualche idea? – MatthewKremer

+0

Questo di solito significa che il materiale del debugger è già stato distrutto sul lato server. Puoi replicare l'errore usando il server di sviluppo django (invocando con 'runserver_plus')? Potrebbe funzionare un po 'meglio lì. – Marcin

+0

C'è un modo per farlo funzionare con runserver_plus all'avvio invece di runserver? È quasi impossibile da riprodurre, succede solo casualmente (sembra), quindi non posso eseguire quel comando, quindi provo a eseguirne il debug davvero. – MatthewKremer

1

Se si memorizza un oggetto utente, si può essere interessati da questo bug: https://code.djangoproject.com/ticket/16563

Detto questo, la cosa migliore sarà di modificare solo il codice sorgente di Django alla linea 93 di/usr/local/lib/python2.6/dist-packages/django/contrib/sessions/backends/base.py dove si verifica l'eccezione.

Basta registrare session_dict. Nella maggior parte dei casi sarà davvero ovvio cosa c'è che non va.(Infatti, se il tuo traceback mostra Local Vars, hai già questo)

9

Nel mio caso (non correlato a Django) questa eccezione è stata generata da multiprocessing.Pool.map quando una lambda è stata passata come funzione di destinazione. La creazione di una funzione con nome e il passaggio delle strutture di dati del contesto necessarie tramite il parametro initargs (anziché tramite la chiusura) hanno risolto il problema.

Per riassumere, il cattivo caso d'uso che ha attivato l'eccezione è:

import multiprocessing as mp 
context = some_object 
pool = mp.Pool() 
worker_func = lambda x: work(x, context) 
results = pool.map(worker_func, data_list) 
+0

'worker_func = lambda x: work (x, context)' non funziona in Python2.7, ma 'def worker_func (x): restituisce work (x, context)'. E dovrebbe mettere la funzione ** before ** 'pool = mp.Pool()' – WeizhongTu

Problemi correlati