J'ai créé une classe nommée Options. Cela fonctionne bien mais pas avec Python 2. Et je veux que cela fonctionne à la fois Python 2 et 3. Le problème est identifié: FileNotFoundError n'existe pas) dans Python 2. Mais si j'utilise IOError cela ne fonctionne pas dans Python 3
Modifié dans la version 3.3: EnvironmentError, IOError, WindowsError, VMSError, socket.error, select.error et mmap.error ont été fusionnés dans OSError.
Que dois-je faire ??? (Veuillez ne pas discuter de mon choix de portabilité, j'ai des raisons.)
Voici le code:
#!/usr/bin/python
#-*-coding:utf-8*
#option_controller.py
#Walle Cyril
#25/01/2014
import json
import os
class Options():
"""Options is a class designed to read, add and change informations in a JSON file with a dictionnary in it.
The entire object works even if the file is missing since it re-creates it.
If present it must respect the JSON format: e.g. keys must be strings and so on.
If something corrupted the file, just destroy the file or call read_file method to remake it."""
def __init__(self,directory_name="Cache",file_name="options.json",imported_default_values=None):
#json file
self.option_file_path=os.path.join(directory_name,file_name)
self.directory_name=directory_name
self.file_name=file_name
#self.parameters_json_file={'sort_keys':True, 'indent':4, 'separators':(',',':')}
#the default data
if imported_default_values is None:
DEFAULT_INDENT = 2
self.default_values={\
"translate_html_level": 1,\
"indent_size":DEFAULT_INDENT,\
"document_title":"Titre"}
else:
self.default_values=imported_default_values
def read_file(self,read_this_key_only=False):
"""returns the value for the given key or a dictionary if the key is not given.
returns None if it s impossible"""
try:
text_in_file=open(self.option_file_path,'r').read()
except FileNotFoundError:#not 2.X compatible
text_in_file=""#if the file is not there we re-make one with default values
if text_in_file=="":#same if the file is empty
self.__insert_all_default_values()
text_in_file=open(self.option_file_path,'r').read()
try:
option_dict=json.loads(text_in_file)
except ValueError:
#if the json file is broken we re-make one with default values
self.__insert_all_default_values()
text_in_file=open(self.option_file_path,'r').read()
option_dict=json.loads(text_in_file)
if read_this_key_only:
if read_this_key_only in option_dict:
return option_dict[read_this_key_only]#
else:
#if the value is not there it should be written for the next time
if read_this_key_only in self.default_values:
self.add_option_to_file(read_this_key_only,self.default_values[read_this_key_only])
return self.default_values[read_this_key_only]
else:
#impossible because there is not default value so the value isn t meant to be here
return None
else:
return option_dict
def add_option_to_file(self,key,value):#or update
"""Adds or updates an option(key and value) to the json file if the option exists in the default_values of the object."""
option_dict=self.read_file()
if key in self.default_values:
option_dict[key]=value
open(self.option_file_path,'w').write(\
json.dumps(option_dict,sort_keys=True, indent=4, separators=(',',':')))
def __insert_all_default_values(self):
"""Recreate json file with default values.
called if the document is empty or non-existing or corrupted."""
try:
open(self.option_file_path,'w').write(\
json.dumps(self.default_values,sort_keys=True, indent=4, separators=(',',':')))
except FileNotFoundError:
os.mkdir(self.directory_name)#Create the directory
if os.path.isdir(self.directory_name):#succes
self.__insert_all_default_values()
else:
print("Impossible to write in %s and file %s not found" % (os.getcwd(),self.option_file_path))
#demo
if __== '__main__':
option_file_object=Options()
print(option_file_object.__doc__)
print(option_file_object.read_file())
option_file_object.add_option_to_file("","test")#this should have no effect
option_file_object.add_option_to_file("translate_html_level","0")#this should have an effect
print("value of translate_html_level:",option_file_object.read_file("translate_html_level"))
print(option_file_object.read_file())
Vous pouvez utiliser l'exception de classe de base EnvironmentError et utiliser l'attribut 'errno' pour déterminer quelle exception a été déclenchée:
from __future__ import print_function
import os
import errno
try:
open('no file of this name') # generate 'file not found error'
except EnvironmentError as e: # OSError or IOError...
print(os.strerror(e.errno))
Ou utilisez simplement IOError de la même manière:
try:
open('/Users/test/Documents/test') # will be a permission error
except IOError as e:
print(os.strerror(e.errno))
Cela fonctionne sur Python 2 ou Python 3.
Faites attention à ne pas comparer directement les valeurs numériques, car elles peuvent être différentes sur différentes plateformes. À la place, utilisez les constantes nommées dans bibliothèque standard de Python errno
module qui utilisera les valeurs correctes pour la plate-forme d'exécution.
Si FileNotFoundError
n'est pas là, définissez-le:
try:
FileNotFoundError
except NameError:
FileNotFoundError = IOError
Vous pouvez maintenant attraper FileNotFoundError
dans Python 2 car c'est vraiment IOError
.
Attention cependant, IOError
a d'autres significations. En particulier, tout message devrait probablement dire "le fichier n'a pas pu être lu" plutôt que "le fichier est introuvable".
La manière Python 2/3 compatible d'exclure un FileNotFoundError
est la suivante:
import errno
try:
with open('some_file_that_does_not_exist', 'r'):
pass
except EnvironmentError as e:
if e.errno != errno.ENOENT:
raise
Les autres réponses sont proches, mais ne relancez pas si le numéro d'erreur ne correspond pas.
L'utilisation de IOError
est très bien dans la plupart des cas, mais pour une raison quelconque os.listdir()
et ses amis lèvent OSError
à la place sur Python 2. Puisque IOError
hérite de OSError
, il est juste de toujours attraper OSError
et de vérifier le numéro d'erreur.
Edit: La phrase précédente n'est vraie que sur Python 3. Pour être compatible, attrapez plutôt EnvironmentError
et vérifiez le numéro d'erreur.
Pour ce que ça vaut, bien que le IOError
soit à peine mentionné dans document officiel de Python et n'apparaisse même pas dans sa hiérarchie d'exceptions officielle , il est toujours là, et c'est la classe parente de FileNotFoundError
dans Python 3. Voir python3 -c "print(isinstance(FileNotFoundError(), IOError))"
vous donnant un True
. Par conséquent, vous pouvez écrivez techniquement votre code de cette manière, ce qui fonctionne à la fois pour Python 2 et Python 3.
try:
content = open("somefile.txt").read()
except IOError: # Works in both Python 2 & 3
print("Oops, we can not read this file")
Il pourrait être "assez bon" dans de nombreux cas. Bien qu'en général, il n'est pas recommandé de s'appuyer sur un comportement non documenté. Donc, je ne suggère pas vraiment cette approche. J'utilise personnellement réponse de Kindall .