Display html pages containing css, jpg using Bottle - python

I have around 100 journal articles. Each journal article is represented as an HTML page. A journal's HTML page, its css file and the figures that are part of the journal are located within its folder. In other words, each html file refers to it's own css file and corresponding image files. And I have created the following folder structure ( | represents a folder, -- represents a file):
-- app.py
|views
-- Disp_Res.tpl
-- UI.tpl
|static
|articles
|PMC45677
--PMC45677.html
--jats-preview.css
--fig1_45677.jpg
--fig2_45677.jpg
|PMC23456
--PMC23456.html
--jats-preview.css
--fig1_23456.jpg
--fig2_23456.jpg
I have the following code within my app.py
#app.get('/articles/<pmc:re:PMC[0-9]*>')
def html_article(pmc):
global pmcno
pmcno = pmc;
pmc_article = pmcno + ".html"; print pmc_article
rootdir = os.path.join('static/articles', pmcno) #'static/articles/{pmcno}'
print "html_article", rootdir # This statement displays the right dir
return static_file(pmc_article, root=rootdir)
#app.get('/<filename:re:.*\.css>')
def stylesheets(filename):
rootdir = os.path.join('static/articles', pmcno)
print "stylesheets", rootdir # This statement does NOT display
return static_file(filename, root=rootdir)
#app.get('/<filename:re:.*\.(jpg|png|gif|ico)>')
def images(filename):
rootdir = os.path.join('static/articles', pmcno)
print "images", rootdir # This statement does NOT display
return static_file(filename, root=rootdir)
And needless to say this doesn't work. When I run app.py, it just gives me the error:
"Sorry, the requested URL 'http://localhost:8080/articles/PMC45677' caused an error:
File does not exist."
Any idea what I am doing wrong? Or do you have a better idea of achieving what I am aiming at? Please do let me know. Any help will be highly appreciated!
Thanks in advance.

Maybe because Bottle doesn't know what /articles/ is ?
Try to add this in top of your code :
#app.route('/articles/<filepath:path>')
def file_stac(filepath):
return static_file(filepath,root="./articles")

Related

Is it always correct to use URLs like "./about.html" or "../about.htm" instead of Absolute URLS like /about?

I'm a computer science student. Recently we were tasked to develop a static HTTP server from scratch without using any HTTP modules, solely depending on socket programming. So this means that I had to write all the logic for HTTP message parsing, extracting headers, parsing URLs, etc.
However, I'm stuck with some confusion. As I'm somewhat experienced in web development before, I'm used to using URLs in places like anchor tags like this "/about", and "/articles/article-1".However, I've seen people sometimes people to relative paths according to their folder structure like this. "./about.html", "../contact.html".This always seemed to be a bad idea to me. However, I realized that even though in my code I'm not supporting these kinds of URLs explicitly, it seems to work anyhow.
Following is the python code I'm using to get the path from the HTTP message and then get the corresponding path in the file system.
def get_http_url(self, raw_request_headers: list[str]):
"""
Method to get HTTP url by parsing request headers
"""
if len(raw_request_headers) > 0:
method_and_path_header = raw_request_headers[0]
method_and_path_header_segments = method_and_path_header.split(" ")
if len(method_and_path_header_segments) >= 2:
"""
example: GET / HTTP/1.1 => ['GET', '/', 'HTTP/1.1] => '/'
"""
url = method_and_path_header_segments[1]
return url
return False
def get_resource_path_for_url(self, path: str | Literal[False]):
"""
Method to get the resource path based on url
"""
if not path:
return False
else:
if path.endswith('/'):
# Removing trailing '/' to make it easy to parse the url
path = path[0:-1]
# Split to see if the url also includes the file extension
parts = path.split('.')
if path == '':
# if the requested path is "/"
path_to_resource = os.path.join(
os.getcwd(), "htdocs", "index.html")
else:
# Assumes the user entered a valid url with resources file extension as well, ex: http://localhost:2728/pages/about.html
if len(parts) > 1:
path_to_resource = os.path.join(
os.getcwd(), "htdocs", path[1:]) # Get the abslute path with the existing file extension
else:
# Assumes user requested a url without an extension and as such is hoping for a html response
path_to_resource = os.path.join(
os.getcwd(), "htdocs", f"{path[1:]}.html") # Get the absolute path to the corresponding html file
return path_to_resource
So in my code, I'm not explicitly adding any logic to handle that kind of relative path. But somehow, when I use things like ../about.html in my test HTML files, it somehow works?
Is this the expected behavior? As of now (I would like to know where this behavior is implemented), I'm on Windows if that matters. And if this is expected, can I depend on this behavior and conclude that it's safe to refer to HTML files and other assets with relative paths like this on my web server?
Thanks in advance for any help, and I apologize if my question is not clear or well-formed.

Can't show html using Flask

So I have been trying to get used to Flash in python but I've come across a problem. I want that when http://localhost:5000/ is inserted in the browser a html page is displayed. I've tried multiple ways to do this like using the render_template() but that returns me a jinja2.exceptions.TemplateNotFound: index.html. I've also tried a simple return redirect() but that throws something saying the adress was not recognized or understood. When I tried using the url_for() it threw 404 - not found. I really have no idea how to fix this.
# htppserver.py
import flask
import threading
app = Flask(__name__, template_folder="Dashboard/website")
#app.route("/site", methods=["GET"])
#app.route("/", methods=["GET"])
def get_site():
return render_template("index.html")
x = threading.Thread(target=app.run)
x.start()
Currently my dir system looks something like this
main_folder # This is the working directory accordingly to os.getcwd()
├──cogs
│ └──httpserver.py # Source code is here
└──Dashboard
└website
├──...
├──index.html # This is the file I want to show
└──...
Thanks
put your html files in a folder called "templates" in the same directory as the python file that serves

"non-zero exit status 1" due to pdf file not found when using pypdftk to fill pdf forms in Django project in virtual env on dev server in Windows

The following python code successfully fills out a pdf form:
import pypdftk
data_dict = {key:value pairs}
PDF_PATH = 'form.pdf' #form to be filled out in same folder as the file executing this code
out_file = 'out_file.pdf' #completed pdf file
generated_pdf = pypdftk.fill_form(
pdf_path = PDF_PATH,
datas = data_dict,
out_file = out_file,
)
However, the same code used in my django project results in the following error message:
Error: Unable to find file.
Error: Failed to open PDF file:
form.pdf
Errors encountered. No output created.
Done. Input errors, so no output created.
... REMAINDER OF TRACEBACK EXCLUDED FOR BREVITY IF YOU WANT TO SEE IT I'LL POST...
raise subprocess.CalledProcessError(retcode, cmd, output=output) output=output) df fill_form C:\Users\Home\AppData\Local\Temp\tmpbqq__7c4 output out_file.pdf flatten
subprocess.CalledProcessError: Command 'pdftk l_a_r.pdf fill_form C:\Users\Home\AppData\Local\Temp\tmpbqq_0 87495_7c4 output out_file.pdf flatten'
returned non-zero exit status 1.
pypdftk is installed in the virtual environment the project is running in.
The pdftk server is added as a windows path variable.
In the above example, and every other time this has happened the temp file referenced at the end of the error message contains all of the expected data in XML.
I've tried the following combinations of code to try to make this work:
Running the exact above code within a view function, with the pdf form to be filled in the same folder as the views.py file:
import pypdftk
def filler_view(request):
form = MyForm()
if request.method =='POST':
#code to successfully populate dictionary data_dict with form data
PDF_PATH = 'form.pdf' #form to be filled out in same folder as the file executing this code
out_file = 'out_file.pdf #completed pdf file
generated_pdf = pypdftk.fill_form(
pdf_path = PDF_PATH,
datas = data_dict,
out_file = out_file,
)
return render(request, 'success.html')
Storing the code and file in a folder and importing to call the relevant function within the view:
-appFolder
-pfd_filler_folder
-form.pdf
-form_filler.py
-views.py
views.py
from appFolder.pdf_filler_folder import form_filler as f
def filler_view(request):
form = MyForm()
if request.method =='POST':
#code to successfully populate dictionary data_dict with form data
f.fill_form(data_dict, 'output.pdf')
form_filler.py:
import pypdftk
def fill_form(data_dict, out_file):
PDF_PATH = 'form.pdf'
generated_pdf = pypdftk.fill_form(
pdf_path = PDF_PATH,
datas = data_dict,
out_file = out_file,
)
Running both of the above with the full path from c:\... of the form.pdf file.
I've also verified that I can successfully fill a form with the executing .py file and the form.pdf file in same folder on two storage drives and from within the django project itself, when not being executed by the django project. pdftk finds the forms.py with no problems at all in this circumstance.
I believe that the file not found error message is key, as it seems to refer to the pdf form I'm trying to fill out. I've spent from 1500 till 1800 researching this, and I haven't managed to get it to work, although I am lead to believe that my error message indicates a missing parameter in the cl execution command. I'm not sure what this would be, as all parameters seem present and correct.
Interestingly enough, a friend of mine is experiencing the same error message just in windows. I'm aware that pdftk can sometimes be touchy in windows, and I think there's probably a nuance I'm missing here.
The outcome I'd like is to fill out a pdf form from within my django project, with data obtained from a form through a post request.
I'd welcome either someone enlightening me as to why pdftk is struggling to either see or use the form file whilst being used from within my django project and pointing me in the right direction
I'm aware that there are alternatives to using pdftk, but pdftk is the simplest, and honestly pypdftk is the only library I've found to reliably work with python to fill out pdf forms so far in Windows. I don't want to go down the route of generating my own replica form and populating it with data, but I'm aware that that is also an option.
Question answered just now on Reddit:
When in Django, it is either wsgi.py or manage.py which is ultimately responsible for what goes on. On that basis, placing the form.pdf file in the same folder as wsgy.py solved the problem and the code now runs as intended, with an unbound form POSTing data back to a view, and a pdf form being filled out and a duplicate saved with said data. Hope that helps anyone else who comes up against this!

My Python file connected through the right path with my sqlite database but couldn't identify a table in that database

I want to connect my SQLite database/ or I think I'm connecting my "data.sqlite" (the blue highligted one in the picture below) with my views.py in the core folder (picture below) with:
rPath='../../Upchanges/data.sqlite'
conn = _sqlite3.connect(rPath, check_same_thread=False)
c = conn.cursor()
Path of the database I want to connect with:
Upchanges_desperate/Upchanges/data.sqlite
Path of the Python file I want to connect with the database:
Upchanges_desperate/Upchanges/core/views.py
Picture of my file orientation:
So this is my problem:
I later use these codes below in my python file:
from Upchanges.models import BlogPost( I set the __tablename__ to 'blog_post' in another python file)
#core.route('/', methods=['GET', 'POST'])
def index():
search = Blogsearch_form(request.form)
if request.method == 'POST':
c.execute("SELECT * FROM blog_post WHERE problem_name LIKE(?)", ('%' + str(search) + '%',))
results = c.fetchall()
print(results)
return render_template('blog_search_result.html', results=results)
page = request.args.get('page',1,type=int)
many_posts = BlogPost.query.order_by(BlogPost.date.desc()).paginate(page=page, per_page=10)
return render_template('index.html', many_posts=many_posts, form=search)
When I input something and click enter in the Blogsearch_form, my website shows this error: "sqlite3.OperationalError: no such table: blog_post". I also tried replacing blog_post with BlogPost but it shows the same error: "sqlite3.OperationalError: no such table: BlogPost"
I promise you I have a blog_post table in my data.sqlite database. I use it also in some codes below and my website query the data and work just fine (show everything later on in the HTML file):
page = request.args.get('page',1,type=int)
many_posts = BlogPost.query.order_by(BlogPost.date.desc()).paginate(page=page, per_page=10)
return render_template('index.html', many_posts=many_posts, form=search)
Addtionally, for more clarity, these codes below (which is in the init.py of my app.py file) are those that create my data.sqlite database:
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir,
'../Upchanges/data.sqlite')
So, I really think that something is wrong with the path in the _sqlite3.connect command. I would greatly appreciate if you could help me fix the problem above.
(Please use the picture when you think about the path as it is easier to imagine)
Thank you!!
P.s/ I tried this from my previous question: https://stackoverflow.com/a/61849867/13097721 but I still couldn't fix this problem.
In fact you do not necessarily know from which directory the application has been started from.
You could test this with
import os
print("My current working directory is", os.getcwd())
However if your database is located relative to a python file, then it is better to determine the path relative to the python file's directory than trying to determine it relative to the current working directory.
You can do this for example with with
import os
MYDIR = os.path.dirname(__file__)
SQLPATH = os.path.join(MYDIR, "..", "..", "data.sqlite")
I also suggest to add following line in your existing code or in your modified code.
It will show you exactly where you point to
print("THE REAL SQLPATH is", os.path.realpath(SQLPATH))
Comment after your feedback:
I Will add more prints (and remove one "..") but you will see what you need to do with two more prints.
import os
print("MY FILE = ", os.path.realpath(__file__))
MYDIR = os.path.dirname(__file__)
print("MYDIR = ", os.path.realpath(MYDIR))
SQLPATH = os.path.join(MYDIR, "..", "data.sqlite")
print("This gives me SQLPATH = ", os.path.realpath(SQLPATH))
Comment after next Feedback
So it seems how, that the database file is now properly located.
I suggest to inspect your database.
from a shell window type:
sqlite3 /Users/kienletrung/Desktop/Upchanges_desperate/Upchanges/data.sqlite
type then commands like
.tables to list all tables .schema <tablename> to look at a tables format. or select * from tablename; to look at all rows of a table.
alternatively just type:
echo .dump | sqlite3 /Users/kienletrung/Desktop/Upchanges_desperate/Upchanges/data.sqlite > fulldump.txt
to create a full ascii dump of your database.
If you don't have the sqlite command line client installed then just install it. It should simplify debugging.
You can of course use any other tool to inspect your data base in look at what tables / structures your python code expects and what the database really contains.

Error 404 on flask

When I run the server.py which is hosted on 127.0.0.1:5000 it generates the list of articles
#app.route("/")
def articles():
"""Show a list of article titles"""
return render_template('articles.html', my_list= Alist)
The code above generates the list of articles and is running properly when I run 127.0.0.1:5000, the list is displayed.
#app.route("/article/<topic>/<filename>")
def article(topic,filename):
"""
Show an article with relative path filename. Assumes the BBC structure of
topic/filename.txt so our URLs follow that.
"""
for art in articles_table:
if art[0]== "%s/%s" %(topic, filename):
title_str = art[1]
text_list = art[2].split('\n')
text_list = [t.lower() for t in text_list if len(t) >= 1]
rec = recommended(art[0], articles_table, 5)
break
return render_template('article.html', title=title_str, text=text_list,
fiveA= rec)
However, whenever I click on any of the articles it redirects to http://127.0.0.1:5000/article/data/bbc/business/003.txt
and generates error 404 but the file is present at a particular path in the local directory
I believe the error is in the 2nd code snippet.
I'm a beginner to flask so I'm really confused as to what to do. Any help will be appreciated
If I understand correctly you are trying to catch the topic and the filename in the route. The problem is the URL you're trying to access doesn't match the route you have defined.
You have 2 options:
Change the link so the URL is http://127.0.0.1:5000/article/business/003.txt. By doing this you'll be able to keep the same route you currently have #app.route("/article/<topic>/<filename>"). Here topicwill have the value of "business" and filename will have the value of "003.txt".
Or you can leave the link so the URL stays the same (http://127.0.0.1:5000/article/data/bbc/business/003.txt) and you can change your route to look like this: #app.route("/article/data/bbc/<topic>/<filename>"). Again topic will have the value of "business" and filename will have the value of "003.txt".
You can find more information about routes here

Categories