Getting "file object does not exist" error in python django - python

I have a few objects where I have no file attached.
I have this code:
if os.path.isfile(object.pdf_file.url):
object.url = object.pdf_file.url
else:
object.url = ""
But I am getting this error:
The 'pdf_file' attribute has no file associated with it.

if os.path.isfile(object.pdf_file.url):
This will throw the error because you need the file to get the url. I do not think that will work even if the file exists since isfile() needs a path, not the url which is relative to your webserver/django-settings for media url not where it is located on your server.
Try:
if object.pdf_file:
object.url = object.pdf_file.url
else:
object.url = ""
This will work since the FileField will return None if it is null.

Related

How to get the calling code for a filter in jinja

tl;dr: is it possible to find out where in a jinja template calls a jinja filter from within the filter?
Background
So I have a filter that I'm using in a jinja template called get_image_path(), essentially it takes in a file path and/or url and puts it into the proper format for the app.
I am trying to format traceback outputs so that I can get some idea where they are coming from if someone has an error. Basically when someone passes something that isn't a usable path I want to be able to throw an error and provide a message with the line in the template that called the filter so people know which variable to look for.
So is it possible for me to get the line in the template that called the filter, or do I have to do manual traceback formatting?
Current code for get_image_path()
def get_image_path(path:str) -> str:
# I omitted the docstring
try:
if path.startswith("http"):
return path
elif path.startswith("images"):
return f"{path}"
else:
return f"images/{path}"
except AttributeError as e:
traceback.print_tb(e.__traceback__, limit=7)
ValueError(f"ValueError: Could not get image path: {path}")
My solution
For me the issue is caused by an AttributeError:
def get_image_path(path:str) -> str:
try:
if path.startswith("http"):
return path
elif path.startswith("images"):
return f"{path}"
else:
return f"images/{path}"
except AttributeError:
for frameInfo in stack(): # Get the frame for the error raised
if frameInfo.frame.f_globals.get("__jinja_template__") is not None: # Find the jinja template namespace if it exists
template = frameInfo.frame.f_globals.get("__jinja_template__")
break
if not path: # If the image path is False (usually because a required image wasn't provided)
raise ValueError(f"\n\nNo path provided for required image in {template.filename} #line {template.get_corresponding_lineno(currentframe().f_back.f_lineno)}")
else: # If it's just an invalid image path
raise ValueError(f"\n\nCould not get image path: {path}\n Error occured on \n{template.filename} #line {template.get_corresponding_lineno(currentframe().f_back.f_lineno)}")
When the filter fails because a boolean is passed instead of an image path this message is now provided:
ValueError:
No path provided for required image in
c:\users\kieran\appdata\local\programs\python\python39\lib\site-packages\ezcv\themes\ethereal\index.jinja
#line 45
Background & How it works
So when in the except statement these lines:
for frameInfo in stack(): # Get the frame for the error raised
if frameInfo.frame.f_globals.get("__jinja_template__") is not None: # Find the jinja template namespace if it exists
template = frameInfo.frame.f_globals.get("__jinja_template__")
break
are using the inspect module to check if a value in the global namespace called __jinja_template__ is found. If this value is found it means the error was raised in a template and from that we can get the Jinja Template Object. This object contains the info about the line number and filename I want so it gets assigned to the template variable.
From there template.filename will give you the source file path, and template.get_corresponding_lineno(currentframe().f_back.f_lineno) (documentation here) will give you the line number, and the rest of the code is just formatting the ValueError to pass the information I want back to the user.
Thanks to #β.εηοιτ.βε for the suggestion of looking at their answer to How to get current line of source file when processing a macro? to figure all this out

How to check if Python request exists or not in FLASK

I need to check if python flask app that gets a POST json request.
But before returning anything, I need to check if that json exists or not.
Below is my code.
#app.route("/predict", methods=["POST", "GET"])
def get_predicted_values():
response_ = {}
predicted_values_list = []
request_data = request.get_json()
path = request_data["fpath"]
if path:
print("Found")
else:
print("Not Found")
But this way it gives an error (when I intentionally not passing any json object, because I need to check my if condition works above)
error is:
path = request_data["fpath"]
KeyError: 'fpath'
I want to tackle this error (if that json block is absent, don't throw an error, just do anything else (i.e prints Not Found instead of the above error)), I even used a try - except and still the error is the same.
Can someone please help?
Try is_json
if not request.is_json:
https://flask.palletsprojects.com/en/1.1.x/api/#flask.Request.is_json

Python error: Nonetype object not subscriptable, when loading JSON into variables

I have a program where I am reading in a JSON file, and executing some SQL based on parameters specified in the file. The
load_json_file()
method loads the json file to a Python object first (not seen here but works correctly)
The issue is with the piece of the code here:
class TestAutomation:
def __init__(self):
self.load_json_file()
# connect to Teradata and load session to be used for execution
def connection(self):
con = self.load_json_file()
cfg_dsn = con['config']['dsn']
cfg_usr = con['config']['username']
cfg_pwd = con['config']['password']
udaExec = teradata.UdaExec(appName="DataAnalysis", version="1.0", logConsole=False)
session = udaExec.connect(method="odbc", dsn=cfg_dsn, username=cfg_usr, password=cfg_pwd)
return session
the init_ method first loads the JSON file, and then I store that in 'con'. I am getting an error though that reads:
cfg_dsn = con['config']['dsn']
E TypeError: 'NoneType' object is not subscriptable
The JSON file looks like this:
{
"config":{
"src":"C:/Dev\\path",
"dsn":"XYZ",
"sheet_name":"test",
"out_file_prefix":"C:/Dev\\test\\OutputFile_",
"password":"pw123",
"username":"user123",
"start_table":"11",
"end_table":"26",
"skip_table":"1,13,17",
"spot_check_table":"77"
}
}
the load_json_file() is defined like this:
def load_json_file(self):
if os.path.isfile(os.path.dirname(os.path.realpath(sys.argv[0])) + '\dwconfig.json'):
with open('dwconfig.json') as json_data_file:
cfg_data = json.load(json_data_file)
return cfg_data
Any ideas why I am seeing the error?
problem is that you're checking if the configuration file exists, then read it.
If it doesn't, your function returns None. This is wrong in many ways because os.path.realpath(sys.argv[0]) can return an incorrect value, for instance if the command is run with just the base name, found through the system path ($0 returns the full path in bash but not in python or C).
That's not how you get the directory of the current command.
(plus afterwards you're going to do with open('dwconfig.json') as json_data_file: which is now the name of the file, without the full path, wrong again)
I would skip this test, but compute the config file path properly. And if it doesn't exist, let the program crash instead of returning None that will crash later.
def load_json_file(self):
with open(os.path.join(os.path.dirname(__file__),'dwconfig.json')) as json_data_file:
cfg_data = json.load(json_data_file)
return cfg_data
So... cfg_dsn = con['config']['dsn']
something in there is set to None
you could be safe and write it like
(con or {}).get('config',{}).get('dsn')
or make your data correct.

Upload file to CKAN with ckanapi (Python)

import ckanapi
try:
ckan = ckanapi.RemoteCKAN(serverurl,
apikey='myapikeyhere',
user_agent='useragenthere')
res = ckan.action.resource_create(
package_id='2ad3c9de-502c-403a-8b03-bfc619697ff2',
#url='url',
#revision_id='revid',
description='my first upload with CKANAPI',
upload=open('./upload.csv')
)
except Exception as e:
raise Exception(str(e.error_dict))
It fails with:
Field errors: {u'url': [u'Missing value'], u'__type': u'Validation Error'}
They made url a required attribute in this discussion on GitHub:
https://github.com/ckan/ckan/pull/1641
So what is the expected value of the url attribute?
If it's expecting the url to the local file, it's not hosted.
And I cannot supply the url of the file on CKAN, because the resourceid was not created, yet.
PS: When passing an arbitrary value for the url attribute, the upload succeeds.
It makes no sense to require the url attribute. Can anybody explain?
That's, in my opinion, a bug in CKAN. I've created a issue to track it at https://github.com/ckan/ckan/issues/2769. I've also wrote a pull request on ckanapi to abstract this bug at https://github.com/ckan/ckanapi/pull/74.
As a workaround in the mean time, you can set the url to an empty string.

lxml + loads of files = random SerialisationError: IO_WRITE

I'm using lxml and python 3 to parse many files and merge files that belong together.
The files are actually stored in pairs of two (that are also merged first) inside zip files but i don't think that matters here.
We're talking about 100k files that are about 900MB in zipped form.
My problems is that my script works fine but at somepoint (for multiple runs it's not always the same point so it shouldn't be a problem with a certain file) i get this error:
File "C:\Users\xxx\workspace\xxx\src\zip2xml.py", line 110, in
_writetonorm
normroot.getroottree().write(norm_file_path) File "lxml.etree.pyx", line 1866, in lxml.etree._ElementTree.write
(src/lxml\lxml.etree.c:46006) File "serializer.pxi", line 481, in
lxml.etree._tofilelike (src/lxml\lxml.etree.c:93719) File
"serializer.pxi", line 187, in lxml.etree._raiseSerialisationError
(src/lxml\lxml.etree.c:90965) lxml.etree.SerialisationError: IO_WRITE
I have no idea what causes this error.
The entire code is a little cumbersome so i hope the relevant areas suffice:
def _writetonorm(self, outputpath):
'''Writes the current XML to a file.
It'll update the file if it already exists and create the file otherwise'''
#Find Name
name = None
try:
name = self._xml.xpath("xxx")[0].text.rstrip().lstrip()
except Exception as e:
try:
name = self._xml.xpath("xxx")[0].text.rstrip().lstrip()
except Exception as e:
name = "damn it!"
if name != None:
#clean name a bit
name = name[:35]
table = str.maketrans(' /#*"$!&<>-:.,;()','_________________')
name = name.translate(table)
name = name.lstrip("_-").rstrip("_-")
#generate filename
norm_file_name = name + ".xml"
norm_file_path = os.path.join(outputpath, norm_file_name)
#Check if we have that completefile already. If we do, update it.
if os.path.isfile(norm_file_path):
norm_file = etree.parse(norm_file_path, self._parser)
try:
normroot = norm_file.getroot()
except:
print(norm_file_path + "is broken !!!!")
time.sleep(10)
else:
normroot = etree.Element("norm")
jurblock = etree.Element("jurblock")
self._add_jurblok_attributes(jurblock)
jurblock.insert(0, self._xml)
normroot.insert(0, jurblock)
try:
normroot.getroottree().write(norm_file_path) #here the Exception occurs
except Exception as e:
print(norm_file_path)
raise e
I know that my exception handling isn't great but this is just a proof of work for now.
Can anyone tell me why the error happens ?
Looking at the file that causes the error it's not wellformed but I suspect that is because the error happened and it was fine before the latest iteration.
It seems to have been a mistake to use maped network drives for this. No such Exception when letting it work with the files locally.
Learned something :)

Categories

Resources