Quelle est la mauvaise erreur de nombre magique?

320

Quel est le "Bad magic number" ImportError en python, et comment puis-je le corriger?

La seule chose que je peux trouver en ligne suggère que cela est dû à la compilation d'un fichier .py -> .pyc, puis à essayer de l'utiliser avec la mauvaise version de python. Dans mon cas, cependant, le fichier semble importer correctement certaines fois mais pas d'autres, et je ne sais pas pourquoi.

Les informations que python fournit dans le traçage ne sont pas particulièrement utiles (c'est pourquoi je demandais ici ...), mais ici, c'est au cas où cela aiderait:

Traceback (most recent call last):
  File "run.py", line 7, in <module>
    from Normalization import Normalizer
Noé
la source
Pourriez-vous fournir le code dans lequel le problème se produit?
Evan Fosmark
Et quelle version de python utilisez-vous?
paxdiablo
Et la normalisation est-elle l'un de vos fichiers ou un tiers?
paxdiablo
3
Hrm, d'accord, je pense que j'ai dû importer un ancien fichier .pyc qui a été laissé il y a longtemps lorsque j'ai déplacé le fichier .py, et donc j'ai pu importer la nouvelle version mais pas l'ancienne.
Noah
1
J'ai supprimé l'ancien fichier .pyc, donc je ne l'ai pas à portée de main, mais mon problème était avec les chemins d'importation - je pense que python aurait utilisé le fichier .py pour recréer le fichier .pyc si je ne l'avais pas déplacé (est-ce vrai?)
Noah

Réponses:

401

Le nombre magique provient de systèmes de type UNIX où les premiers octets d'un fichier contenaient un marqueur indiquant le type de fichier.

Python place un marqueur similaire dans ses pycfichiers lorsqu'il les crée.

L'interpréteur python s'assure ensuite que ce nombre est correct lors du chargement.

Tout ce qui endommage ce nombre magique causera votre problème. Cela inclut la modification du pycfichier ou la tentative d'exécution d'un à pycpartir d'une version différente de python (généralement plus tard) que votre interprète.

Si ce sont vos pyc fichiers, supprimez-les et laissez l'interprète recompiler les pyfichiers. Sur les systèmes de type UNIX, cela pourrait être quelque chose d'aussi simple que:

rm *.pyc

ou:

find . -name '*.pyc' -delete

S'ils ne vous appartiennent pas, vous devrez soit récupérer les pyfichiers à recompiler, soit utiliser un interpréteur capable d'exécuter les pycfichiers avec cette valeur magique particulière.

Une chose qui pourrait être à l'origine de la nature intermittente. Ce pycqui cause le problème ne peut être importé que sous certaines conditions. Il est très peu probable qu'il soit importé parfois. Vous devez vérifier la trace réelle de la pile complète lorsque l'importation échoue?

En passant, le premier mot de tous mes 2.5.1(r251:54863) pycfichiers est 62131, 2.6.1(r261:67517)est 62161. La liste de tous les nombres magiques se trouve dans Python/import.c, reproduite ici pour être complète (à jour au moment où la réponse a été publiée, elle peut avoir changé depuis):

1.5:   20121
1.5.1: 20121
1.5.2: 20121
1.6:   50428
2.0:   50823
2.0.1: 50823
2.1:   60202
2.1.1: 60202
2.1.2: 60202
2.2:   60717
2.3a0: 62011
2.3a0: 62021
2.3a0: 62011
2.4a0: 62041
2.4a3: 62051
2.4b1: 62061
2.5a0: 62071
2.5a0: 62081
2.5a0: 62091
2.5a0: 62092
2.5b3: 62101
2.5b3: 62111
2.5c1: 62121
2.5c2: 62131
2.6a0: 62151
2.6a1: 62161
2.7a0: 62171
paxdiablo
la source
2
Merci - cela ne m'a pas aidé directement à comprendre mon problème, mais c'est quand même bien de connaître la réponse!
Noah
Comment puis-je vérifier quel fichier pyc provoque le problème, j'ai supprimé tous les fichiers pyc mais j'obtiens toujours cette erreur.
sunprophit
Peut-être avez-vous besoin de 'rm __pycache __ / * pyc' maintenant, car les fichiers pyc sont maintenant dans ce dossier.
Arpad Horvath
1
Merci! Cela m'arrivait avec: ERREUR: tornado.general: Impossible de charger la traduction pour 'es': [Errno 0] Mauvais numéro magique: '/app/locale/es/LC_MESSAGES/django.mo'. En fait, c'est que le * .mo n'a pas été compilé correctement.
ericson.cepeda
60

La suppression de tous les fichiers .pyc corrigera l'erreur "Bad Magic Number".

find . -name "*.pyc" -delete
Akarca
la source
8
Il est probablement préférable de l'utiliser find . -name "*.pyc" -delete, car vous aurez des problèmes avec les espaces (et peut-être avec une ligne de commande trop longue) si vous développez tous les noms de fichiers à transmettre rm.
Andrew Aylett
25
L'OMI est un script assez dangereux. Et si un paquet était livré avec uniquement des fichiers .pyc afin de le garder fermé? Oups, vous venez de supprimer l'application.
Dan Mantyla
3
Il est probablement préférable d'exécuter d'abord find . -name "*.pyc" -print, puis de supprimer manuellement les fichiers problématiques et / ou d'exécuter la commande ci-dessus, après avoir vérifié que vous ne faites rien de regrettable.
michael
9
@DanMantyla Les packages de sources fermées méritent de toute façon d'être supprimés.
chat
25

Le chargement d'un *.pycfichier généré python3 avec python2 provoque également cette erreur.

jtm
la source
3
Cela pourrait être un commentaire, pas une réponse.
Kroltan
2
@Kroltan pourtant c'est une sacrément bonne réponse, meilleure que celle acceptée. Concis et précis.
Antony Hatchkins
@AntonyHatchkins Au moins à mon avis, cela pourrait être un commentaire sur l'une des réponses suggérant la suppression de .pyc. Même si c'est une cause possible , il n'y a pas de solution différente , donc c'est redondant. N'hésitez pas à être en désaccord, juste mon avis.
Kroltan
@Kroltan La partie «comment réparer» est assez évidente ici. La cause, c'est ce qui est vraiment intéressant - du moins pour moi -. J'ai fait beaucoup de manipulations avec différentes versions de Python 2.x et je n'ai jamais rencontré d'incompatibilité entre les versions .pyc. Et cette solution dit qu'il s'agit d'un problème python3 vs python2 - informations manquantes dans la réponse acceptée. De plus, j'aime les réponses courtes (si possible) :)
Antony Hatchkins
@AntonyHatchkins, cette solution peut bien dire que c'est un py2 / 3 problème , mais c'est seulement une possibilité et, d'ailleurs, on a suggéré dans la réponse acceptée (paragraphe 4) depuis sa toute première version :-)
paxdiablo
6

Prenez le fichier pyc sur une machine Windows. Utilisez n'importe quel éditeur Hex pour ouvrir ce fichier pyc. J'ai utilisé le freeware 'HexEdit'. Lisez maintenant la valeur hexadécimale des deux premiers octets. Dans mon cas, c'était 03 f3.

Ouvrez calc et convertissez son mode d'affichage en programmeur (scientifique dans XP) pour voir la conversion hexadécimale et décimale. Sélectionnez "Hex" dans le bouton Radio. Entrez d'abord les valeurs en tant que deuxième octet, puis le premier octet, c'est-à-dire f303 Cliquez maintenant sur le bouton radio "Dec" (décimal). La valeur affichée est celle qui correspond au nombre magique aka version de python.

Donc, compte tenu du tableau fourni dans la réponse précédente

  • 1.5 => 20121 => 4E99 pour que les fichiers aient le premier octet 99 et le second 4e
  • 1.6 => 50428 => C4FC pour que les fichiers aient le premier octet comme fc et le second comme c4
Sanjay Chopra
la source
2

L'erreur "Bad magic number" se produit également si vous avez nommé manuellement votre fichier avec une extension .pyc

Deke
la source
1

J'ai eu un cas étrange d'erreur Bad Magic Number en utilisant une très ancienne implémentation (1.5.2). J'ai généré un fichier .pyo et cela a déclenché l'erreur. Bizarrement, le problème a été résolu en changeant le nom du module. Le nom incriminé était sms.py. Si j'ai généré un sms.pyo à partir de ce module, une erreur Bad Magic Number a été le résultat. Lorsque j'ai changé le nom en smst.py, l'erreur a disparu. J'ai vérifié d'avant en arrière pour voir si sms.py interférait en quelque sorte avec tout autre module du même nom mais je n'ai trouvé aucune collision de noms. Même si la source de ce problème est restée un mystère pour moi, je recommande d'essayer un changement de nom de module.

Gábor Paller
la source
1

Cela peut également être dû à un __init__.pyfichier manquant dans le répertoire. Supposons que si vous créez un nouveau répertoire dans django pour séparer les tests unitaires en plusieurs fichiers et les placez dans un répertoire, vous devez également créer le __init__.pyfichier à côté de tous les autres fichiers dans le nouveau répertoire de test créé. sinon cela peut donner une erreur comme Traceback (most recent call last): File "C:\Users\USERNAME\AppData\Local\Programs\Python\Python35\Lib\unittest\loader.py",line 153, in loadTestsFromName module = __import__(module_name) ImportError: bad magic number in 'APPNAME.tests': b'\x03\xf3\r\n'

Shahraiz Ali
la source
0

C'est beaucoup plus efficace que ci-dessus.

find {directory-of-.pyc-files} -name "*.pyc" -print0 | xargs -0 rm -rf

{directory-of-.pyc-files}est le répertoire qui contient les fichiers python compilés.

ozgurv
la source
1
C'est au cas où vous avez les fichiers py sous la main, sinon vous devrez rétrograder l'installation de python.
Leon Fedotov
1
Ceci n'est toujours pas sûr pour certains cas marginaux. Aussi pourquoi faisons-nous une suppression récursive lorsque nous parlons de fichiers?
Jerome Baum
1
Pourquoi utilisez-vous deux processus? Même si find n'a pas été supprimé, vous pouvez toujours exécuterfind /dir -name "*.pyc" -exec rm '{}' ';'
mikemaccana
1
La commande 'find' ne fonctionnera pas en toute sécurité pour les noms de fichiers avec des espaces si l'opérateur final par défaut -print est utilisé directement par xargs rm. Python n'importe pas de fichiers nommés non identifiants comme celui-ci, mais les scripts peuvent toujours provoquer une rupture et ils ne seront pas supprimés. En règle générale, il est toujours plus sûr d'utiliser un extra -print0 (zéro à la fin) sur la commande find (comme dernier paramètre avant le symbole de tuyau '|'), puis l'option -0 sur xargs (c'est un trait d'union + zéro) pour comprendre le - sortie print0 avant la commande rm, lors de la recherche de tuyaux dans xargs.
Breezer
0

Dans mon cas, ce n'était pas de .pycvieux .mofichiers de traduction binaires après avoir renommé mon propre module, donc à l'intérieur de ce dossier de module, j'ai dû exécuter

find . -name \*.po -execdir sh -c 'msgfmt "$0" -o `basename $0 .po`.mo' '{}' \;

(veuillez faire une sauvegarde et essayer de réparer les .pycfichiers en premier)

d9k
la source
0

Cela peut également se produire si vous avez le mauvais fichier python27.dll (dans le cas de Windows), pour résoudre ce problème, il suffit de réinstaller (ou d'extraire) python avec la version dll correspondante exacte. J'ai eu une expérience similaire.

Ibrahim.H
la source
0

Je viens de faire face au même problème avec Fedora26 où de nombreux outils tels que dnf ont été cassés en raison d'un mauvais nombre magique pour six. Pour une raison inconnue, j'ai un fichier /usr/bin/six.pyc, avec le numéro magique inattendu. La suppression de ce fichier résout le problème

zedge
la source
0

Dans mon cas, j'ai git cloneune bibliothèque qui avait un interprète de

#!/usr/bin/env python

Alors que pythonconduisait à Python2.7même si mon code principal était en cours d' exécution avec python3.6 ... il encore créé un *.pycfichier pour la 2.7version ...

Je peux dire que cette erreur est probablement le résultat d'un mélange entre les versions 2.7 et 3+, c'est pourquoi le nettoyage (de toute façon vous pouvez penser à ce que vous utilisez) - vous aidera ici ...

  • n'oubliez pas d'ajuster le code Python2x -> python 3 ...
Ricky Levi
la source
-1

Ne les supprimez pas !!! Jusqu'à ce que..........

Trouvez une version sur votre dossier git, svn ou copy qui fonctionne.

Supprimez-les, puis récupérez tous les fichiers .pyc.

C'est du travail pour moi.

lauralacarra
la source
eyyy pourquoi ai-je -1? ça marche vraiment pour moi et j'étais dans une très mauvaise situation ¬¬
lauralacarra
2
revenir à la version précédente n'est pas une solution globale
ZiTAL
4
Pourquoi voudriez-vous jamais valider vos *.pycfichiers?
Manos Kounelakis
C'est l'erreur habituelle. Lorsque vous ne configurez pas correctement le fichier git ignore. Je donne donc la solution et ensuite vous devez commander votre git.
lauralacarra
-1

Vous devrez exécuter cette commande dans chaque chemin que vous avez dans votre environnement.

>>> import sys
>>> sys.path
['', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/usr/local/lib/python3.6/dist-packages', '/source_code/src/python', '/usr/lib/python3/dist-packages']

Ensuite, exécutez la commande dans chaque répertoire ici

find /usr/lib/python3.6/ -name "*.pyc" -delete
find /usr/local/lib/python3.6/dist-packages -name "*.pyc" -delete
# etc...
Ahmed
la source