I was working on an issue from a small script I have written. It's a hook between two application. The issue is one application have been updated and now it use yaml instead of json as config file.
import os
import yaml
import json
config = {
'version': "2.0.2",
'journals': {
"default": "/test/yaml/bhla"
},
'editor': os.getenv('VISUAL') or os.getenv('EDITOR') or "",
'encrypt': False,
'template': False,
'default_hour': 9,
'default_minute': 0,
'timeformat': "%Y-%m-%d %H:%M",
'tagsymbols': '@',
'highlight': True,
'linewrap': 79,
'indent_character': '|',
}
with open("jrnl.yaml", 'w') as f:
yaml.safe_dump(config, f, encoding='utf-8', allow_unicode=True, default_flow_style=False)
This will create a yaml file where you will have run the code.
I first wrote this simple patch to allow my hook to work with both (json and yaml).
JRNL_CONFIG_PATH = "jrnl.yaml"
with open(JRNL_CONFIG_PATH, "r") as f:
try:
JRNL_CONFIG = json.load(f)
except json.JSONDecodeError:
JRNL_CONFIG = yaml.load(f, Loader=yaml.FullLoader)
TAGS_SYMBOL = JRNL_CONFIG.get("tagsymbols", "@")
But as a big suprise, when error is catched, f
is closed because JRNL_CONFIG
will return None and produce this error:
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-141-bc1ef847563b> in <module>()
----> 1 JRNL_CONFIG.get("tagsymbols", "@")
AttributeError: 'NoneType' object has no attribute 'get'
.json
, .yaml
)try:
f = open(JRNL_CONFIG_PATH, "r")
JRNL_CONFIG = json.load(f)
except json.JSONDecodeError:
f = open(JRNL_CONFIG_PATH, "r")
JRNL_CONFIG = yaml.load(f, Loader=yaml.FullLoader)
finally:
f.close()
Question 1 : Why catching an exception close the open file, with and without context?
Have been awser by @jedwards
Question 2 : What is the best method to catch the json error and still be able to parse the file as yaml?
Have been awsered by @chepner
The issue isn't that the file is being closed (it's not), it's that the file pointer is no longer at the expected place (the beginning of the file) when you try to use your fallback:
with open("some.yaml") as f:
try:
print("before", f.tell())
data = json.load(f)
except json.JSONDecodeError:
print("after", f.tell())
print("is closed:", f.closed)
Here, the .tell()
method returns the location of the file pointer.
One solution would be to reset the file pointer inside the except block:
with open("some.yaml") as f:
try:
JRNL_CONFIG = json.load(f)
except json.JSONDecodeError:
f.seek(0)
JRNL_CONFIG = yaml.load(f, Loader=yaml.FullLoader)
What about:
with open(JRNL_CONFIG_PATH, "r") as f:
data = f.read()
try:
JRNL_CONFIG = json.loads(data)
except json.JSONDecodeError:
JRNL_CONFIG = yaml.load(data, Loader=yaml.FullLoader)
TAGS_SYMBOL = JRNL_CONFIG.get("tagsymbols", "@")
There's no need to try both json.load
and yaml.load
, because YAML is a superset of JSON and yaml.load
will parse anything json.load
can.
JRNL_CONFIG_PATH = "jrnl.json"
with open(JRNL_CONFIG_PATH, "r") as f:
JRNL_CONFIG = yaml.load(f, Loader=yaml.FullLoader)
TAGS_SYMBOL = JRNL_CONFIG.get("tagsymbols", "@")
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.