relative URL paths when serving static files with FastAPI/Starlette - static-files

I have a simple FastAPI application that serves a file test.html in app/main.py like so:
#app.get('/')
def index():
return FileResponse('static/test.html')
The directory structure is like so:
app/main.py
app/static/test.html
Can I change this do that it works with a modified directory structure where app/ and static/ are siblings?
I have tried return FileResponse('../static/test.html') but that has not worked so far; the resulting error is "RuntimeError: File at path ../static/test.html does not exist."

If your 'static' dir is in the same dir as your main.py
Try:
return FileResponse('./static/test.txt')
Looks like you were looking in the folder above.
you could could os.path to get the parent dir
import os
parent_dir_path = os.path.dirname(os.path.realpath(__file__))
#app.get('/')
def index():
return FileResponse(parent_dir_path + '/static/test.html')

My proposal: then you have static mounted.
import os
script_dir = os.path.dirname(__file__)
st_abs_file_path = os.path.join(script_dir, "static/")
app.mount("/static", StaticFiles(directory=st_abs_file_path), name="static")
or use without that:
return FileResponse(st_abs_file_path + 'test.html')
More explained here: https://stackoverflow.com/a/69401919/5824889

Related

Is there any way to download .tar files from web to local folder fast?

I am trying to download a batch of files from the following website to my local folder. But the download is very slow. Average size of each file is in the range of 30 - 60 MB. Is there a better way to improve this code so that I can download them fast?
import requests
from os import mkdir
from os.path import isdir
from bs4 import BeautifulSoup
from os import chdir, getcwd
url = "https://opendata.dwd.de/climate_environment/CDC/grids_germany/hourly/radolan/historical/asc/"
years = [str(year) for year in range(2005,2021)]
links = [url + i + "/" for i in years]
Creating an empty list to store list of list:
t_links = []
def get_tarlinks():
for i in links:
#create response object
r = requests.get(i)
#create beautiful object
soup = BeautifulSoup(r.content, 'html5lib')
#find all links on webpage
a_links = soup.find_all('a')
#filter the link sending with .tar
tar_links = [i + link['href'] for link in a_links if link['href'].endswith('.tar')]
t_links.append(tar_links)
return t_links
t_links = get_tarlinks()
src_path = "D:/Sandeep/Thesis/Data/"
Download files to local machine:
for i in t_links:
for j in i:
year,filename = j.split('/')[10:]
r = requests.get(j, allow_redirects=True)
if isdir(src_path+year) == False:
mkdir(src_path+year)
chdir(src_path+year)
open(filename, "wb").write(r.content)
else:
open(filename, "wb").write(r.content)
Note: Please check for the indentation when you copy this code to your IDE. Thanks!

How to convert yolo annotations to coco format. Json?

I want to convert my labels in yolo format to coco format
I have tried
https://github.com/Taeyoung96/Yolo-to-COCO-format-converter
And
Pylabel
They all have a bugs.
I want to train on detectron 2 but it fails to load the dataset because of the wrong json file.
Thanks everybody
Could you try with this tool (disclaimer: I'm the author)? It is not (yet) a Python package so you need to downloads the repo first. This should ressemble something like:
from ObjectDetectionEval import *
from pathlib import Path
def main() -> None:
path = Path("/path/to/annotations/") # Where the .txt files are
names_file = Path("/path/to/classes.names")
save_file = Path("coco.json")
annotations = AnnotationSet.from_yolo(gts_path).map_labels(names)
# If you need to change the labels
# names = Annotation.parse_names_file(names_file)
# annotations.map_labels(names)
annotations.save_coco(save_file)
if __name__ == "__main__":
main()
If you need more control (coordinate format, images location and extension, etc.) you should use the more generic AnnotationSet.from_txt(). If it does not suit your needs you can easily implement your own parser using AnnotationSet.from_folder().

Unable to create local directories error while running Ansible in AWS Lambda

I am running the following Python script which runs a playbook:
#!/usr/bin/python
from __future__ import print_function
import json
import os
import ansible.inventory
import ansible.playbook
import ansible.runner
import ansible.constants
from ansible import utils
from ansible import callbacks
print('Loading function')
def run_playbook(**kwargs):
stats = callbacks.AggregateStats()
playbook_cb = callbacks.PlaybookCallbacks(verbose=utils.VERBOSITY)
runner_cb = callbacks.PlaybookRunnerCallbacks(
stats, verbose=utils.VERBOSITY)
# use /tmp instead of $HOME
ansible.constants.DEFAULT_REMOTE_TMP = '/test'
out = ansible.playbook.PlayBook(
callbacks=playbook_cb,
runner_callbacks=runner_cb,
stats=stats,
**kwargs
).run()
return out
def lambda_handler(event, context):
return main()
def main():
out = run_playbook(
playbook='/test/little.yml',
)
return(out)
if __name__ == '__main__':
main()
And, this is my ansible.cfg file:
[ssh_connection]
ssh_args=-o ForwardAgent=yes
retries=2
sk_sudo_pass = yes
[defaults]
remote_user = root
host_key_checking = False
#remote_tmp = tmp
local_tmp = ~/tmp
I am getting the following error, when the lambda function is invoked:
START RequestId: ccfe076e-0016-11e7-befa-7ba330223a64 Version: $LATEST
module initialization error: Unable to create local directories(/home/sbx_user1080/tmp): [Errno 30] Read-only file system: '/home/sbx_user1080'
END RequestId: ccfe076e-0016-11e7-befa-7ba330223a64
which means that Ansible is not able to create the tmp file due to permissions problem in the container which Lambda is spinning up.
So, how do I work around it? Also, according to this discussion, Lambda supports writing files to the /tmp directory. So, how do I set the local_tmp to that directory?
You can only write to /tmp in an AWS Lambda environment. You can't create a ~/tmp directory in that environment. It looks like you need to change this:
local_tmp = ~/tmp
to this:
local_tmp = /tmp

How to read the latest image in a folder using python?

I have to read the latest image in a folder using python. How can I do this?
Another similar way, with some pragmatic (non-foolproof) image validation added:
import os
def get_latest_image(dirpath, valid_extensions=('jpg','jpeg','png')):
"""
Get the latest image file in the given directory
"""
# get filepaths of all files and dirs in the given dir
valid_files = [os.path.join(dirpath, filename) for filename in os.listdir(dirpath)]
# filter out directories, no-extension, and wrong extension files
valid_files = [f for f in valid_files if '.' in f and \
f.rsplit('.',1)[-1] in valid_extensions and os.path.isfile(f)]
if not valid_files:
raise ValueError("No valid images in %s" % dirpath)
return max(valid_files, key=os.path.getmtime)
Walk over the filenames, get their modification time and keep track of the latest modification time you found:
import os
import glob
ts = 0
found = None
for file_name in glob.glob('/path/to/your/interesting/directory/*'):
fts = os.path.getmtime(file_name)
if fts > ts:
ts = fts
found = file_name
print(found)

Is there an easy way of referring to the public directory in Sinatra?

Imagine this structure:
/project
/templates
view1.haml
view2.haml
misc_views/
view3.haml
view4.haml
even_deeper/
view5.haml
/public
script1.js
The depth of the templates can vary, and I would like to refer to the public directory if I want to include some files from it. Is there a helper or some other gimmick that takes me to the public directory? It seems bad to have something like ../../../public/script1.js , or ../../public/script1.js in my views. Surely there must be a better way.
You can use the settings.public configuration to refer to the public directory. For example:
get "/" do
js = File.join( settings.public, 'script1.js' )
File.exists?( js ) #=> true
end
As this is an absolute path, there is no need to make it relative to your view to get the file. You could reach out to this from your view, but I would personally set the path as an instance variable from the controller.
get "/" do
# If you really only need the directory
#public = settings.public
# If you actually need the path to a specific file
#main = File.join( settings.public, 'main.js' )
# If you actually need the contents of a file
#js = IO.read( File.join( settings.public, 'main.js' ) )
end
You must include the static resources by the root of the web address or a relative request path, as it will be the browser who requests it, not your server-side code. Unless I am mistaken in your case?
<script type="text/javascript" src="/script1.js"></script>

Resources