How to display text on the web page using python and HTML - python

I have very simple web page example read from html file using python. the html called led.html as in bellow:
<html>
<body>
<br>
<p>
<p>
<img src="images/on.png">
</body>
</html>
and the python code is:
import cherrypy
import os.path
import struct
class Server(object):
led_switch=1
def index(self, switch=''):
html = open('led.html','r').read()
if switch:
self.led_switch = int(switch)
print "Hellow world"
return html
index.exposed = True
conf = {
'global' : {
'server.socket_host': '0.0.0.0', #0.0.0.0 or specific IP
'server.socket_port': 8080 #server port
},
'/images': { #images served as static files
'tools.staticdir.on': True,
'tools.staticdir.dir': os.path.abspath('images')
},
'/favicon.ico': { #favorite icon
'tools.staticfile.on': True,
'tools.staticfile.filename': os.path.abspath("images/bulb.ico")
}
}
cherrypy.quickstart(Server(), config=conf)
The web page contain only one button called "on", when I click it I can see the text "Hello World " display on the terminal.
My question is how to make this text display on the web page over the "on" button after click on that button?
Thanks in advance.

You're going to want to use some kind of templating system. I use Jinja2 it's great!
Instead of...
html = open('led.html','r').read()
you would use...
import cherrypy
import os.path
import struct
from jinja2 import Template
class Server(object):
led_switch=1
def index(self, switch=''):
myText = ''
if switch:
self.led_switch = int(switch)
myText = "Please Wait"
html = Template("""
<html>
<body onload='setTimeout(function(){document.getElementById("UserMessage").innerHTML = "Ok! it's done"}, 5000)'>
<br>
<p id="UserMessage">{{ htmlText }}<p>
<img src="images/on.png">
</body>
</html>
""")
return html.render(htmlText=myText)
index.exposed = True
conf = {
'global' : {
'server.socket_host': '0.0.0.0', #0.0.0.0 or specific IP
'server.socket_port': 8080 #server port
},
'/images': { #images served as static files
'tools.staticdir.on': True,
'tools.staticdir.dir': os.path.abspath('images')
},
'/favicon.ico': { #favorite icon
'tools.staticfile.on': True,
'tools.staticfile.filename': os.path.abspath("images/bulb.ico")
}
}
cherrypy.quickstart(Server(), config=conf)
Hope this helps!
Andrew

If you do not want to use Jinja (to avoid extra dependencies) you could still use string formatting:
class Server(object):
led_switch=1
def index(self, switch=''):
myText = ''
if switch:
self.led_switch = int(switch)
myText = "Hellow world"
html = """
<html>
<body>
<br>
<p>{htmlText}
<p>
<img src="images/on.png">
</body>
</html>
"""
return html.format(htmlText=myText)

Related

Add a custom javascript to the FastAPI Swagger UI docs webpage in Python

I want to load my custom javascript file or code to the FastAPI Swagger UI webpage, to add some dynamic interaction when I create a FastAPI object.
For example, in Swagger UI on docs webpage I would like to
<script src="custom_script.js"></script>
or
<script> alert('worked!') </script>
I tried:
api = FastAPI(docs_url=None)
api.mount("/static", StaticFiles(directory="static"), name="static")
#api.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
return get_swagger_ui_html(
openapi_url=api.openapi_url,
title=api.title + " - Swagger UI",
oauth2_redirect_url=api.swagger_ui_oauth2_redirect_url,
swagger_js_url="/static/sample.js",
swagger_css_url="/static/sample.css",
)
but it is not working. Is there a way just to insert my custom javascript code on docs webpage of FastAPI Swagger UI with Python ?
Finally I made it working. This is what I did:
from fastapi.openapi.docs import (
get_redoc_html,
get_swagger_ui_html,
get_swagger_ui_oauth2_redirect_html,
)
from fastapi.staticfiles import StaticFiles
api = FastAPI(docs_url=None)
path_to_static = os.path.join(os.path.dirname(__file__), 'static')
logger.info(f"path_to_static: {path_to_static}")
api.mount("/static", StaticFiles(directory=path_to_static), name="static")
#api.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
return get_swagger_ui_html(
openapi_url=api.openapi_url,
title="My API",
oauth2_redirect_url=api.swagger_ui_oauth2_redirect_url,
swagger_js_url="/static/custom_script.js",
# swagger_css_url="/static/swagger-ui.css",
# swagger_favicon_url="/static/favicon-32x32.png",
)
Important notes:
Make sure the static path is correct and all your files are in the static folder, by default the static folder should be in the same folder with the script that created the FastAPI object.
For example:
-parent_folder
Build_FastAPI.py
-static_folder
custom_script.js
custom_css.css
Find the swagger-ui-bundle.js on internet and copy-paste all its content to custom_script.js, then add your custom javascript code at the beginning or at the end of custom_script.js.
For example:
setTimeout(function(){alert('My custom script is working!')}, 5000);
...
.....
/*! For license information please see swagger-ui-bundle.js.LICENSE.txt */
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.SwaggerUIBundle=t():e.SwaggerUIBundle=t()}
...
.....
Save and refresh your browser, you are all way up!
IF SOMEBODY KNOWS A BETTER ANSWER YOUR ARE WELCOME, THE BEST ONE WILL BE ACCEPTED!
If you take a look at the get_swagger_ui_html function that is imported from fastapi.openapi.docs, you will see that the HTML for the docs page is constructed manually via string interpolation/concatenation. It would be trivial to modify this function to include an additional script element, as shown below:
# custom_swagger.py
import json
from typing import Any, Dict, Optional
from fastapi.encoders import jsonable_encoder
from fastapi.openapi.docs import swagger_ui_default_parameters
from starlette.responses import HTMLResponse
def get_swagger_ui_html(
*,
openapi_url: str,
title: str,
swagger_js_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist#4/swagger-ui-bundle.js",
swagger_css_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist#4/swagger-ui.css",
swagger_favicon_url: str = "https://fastapi.tiangolo.com/img/favicon.png",
oauth2_redirect_url: Optional[str] = None,
init_oauth: Optional[Dict[str, Any]] = None,
swagger_ui_parameters: Optional[Dict[str, Any]] = None,
custom_js_url: Optional[str] = None,
) -> HTMLResponse:
current_swagger_ui_parameters = swagger_ui_default_parameters.copy()
if swagger_ui_parameters:
current_swagger_ui_parameters.update(swagger_ui_parameters)
html = f"""
<!DOCTYPE html>
<html>
<head>
<link type="text/css" rel="stylesheet" href="{swagger_css_url}">
<link rel="shortcut icon" href="{swagger_favicon_url}">
<title>{title}</title>
</head>
<body>
<div id="swagger-ui">
</div>
"""
if custom_js_url:
html += f"""
<script src="{custom_js_url}"></script>
"""
html += f"""
<script src="{swagger_js_url}"></script>
<!-- `SwaggerUIBundle` is now available on the page -->
<script>
const ui = SwaggerUIBundle({{
url: '{openapi_url}',
"""
for key, value in current_swagger_ui_parameters.items():
html += f"{json.dumps(key)}: {json.dumps(jsonable_encoder(value))},\n"
if oauth2_redirect_url:
html += f"oauth2RedirectUrl: window.location.origin + '{oauth2_redirect_url}',"
html += """
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIBundle.SwaggerUIStandalonePreset
],
})"""
if init_oauth:
html += f"""
ui.initOAuth({json.dumps(jsonable_encoder(init_oauth))})
"""
html += """
</script>
</body>
</html>
"""
return HTMLResponse(html)
A new, optional parameter named custom_js_url is added:
custom_js_url: Optional[str] = None,
If a value is provided for this parameter, a script element is inserted into the DOM directly before the script element for swagger_js_url (this is an arbitrary choice, you can change the location of the custom script element based on your needs).
if custom_js_url:
html += f"""
<script src="{custom_js_url}"></script>
"""
If no value is provided, the HTML produced is the same as the original function.
Remember to update your import statements for get_swagger_ui_html and update your function for the /docs endpoint as shown below:
from fastapi.openapi.docs import (
get_redoc_html,
get_swagger_ui_oauth2_redirect_html,
)
from fastapi.staticfiles import StaticFiles
from custom_swagger import get_swagger_ui_html
api = FastAPI(docs_url=None)
path_to_static = os.path.join(os.path.dirname(__file__), 'static')
logger.info(f"path_to_static: {path_to_static}")
api.mount("/static", StaticFiles(directory=path_to_static), name="static")
#api.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
return get_swagger_ui_html(
openapi_url=api.openapi_url,
title="My API",
oauth2_redirect_url=api.swagger_ui_oauth2_redirect_url,
swagger_js_url="/static/swagger-ui-bundle.js",
swagger_css_url="/static/swagger-ui.css",
# swagger_favicon_url="/static/favicon-32x32.png",
custom_js_url="/static/custom_script.js",
)
This is still a pretty hacky solution, but I think it is much cleaner and more maintainable than putting a bunch of custom javascript inside the swagger-ui-bundle.js file.

Python webapp to set all query vars to a js object

I am building a simple web app with Python and web.py. My current challenge is to take all query vars (web.input()) and set a JavaScript object in the HTML template. However, I don't know how to ensure this gets rendered OK instead of a long string with encoding.
Thanks a million!
I have the following code in app.py, template HTML and content HTML:
app.py:
import web
urls = (
'/hello', 'hello',
'/bye/', 'bye'
)
app = web.application(urls, globals(), autoreload=True)
#test = "testwaarde"
test = web.input()
render = web.template.render('templates/', base='layout')
class hello:
def GET(self):
return render.index("Templates demo",test, "Hello", "A long time ago...")
class bye:
def GET(self):
return render.hell_form("Templates demo",test, "Bye", "14", "8", "25", "42", "19")
if __name__ == "__main__":
app.run()
Template:
$def with (page)
<html>
<head>
<title>$page.title</title>
<!-- Digital Data Layer -->
<script>
var test = "{{$page.path}}"
var digitalData = {
'page':{
'path': '$page.path'
}
};
</script>
</head>
<body>
<p>You are visiting page <b>$page.name</b>.</p>
$:page
</body>
</html>
index HTML:
$def with (title, **path,name, content)
$var title:$title
$var name:$name
$var path:$path
<p>$content</p>
You're close:
Move your call to test = web.input() to within your GET() methods, not at the top of the file. That's just a bug. (I know that's just your sample code, but it doesn't work.)
Within index.html, use
$var path = path
The using var path: $path sets the template variable to a string representation of path. You want to set it to the dict. That's one difference between the colon and the equal sign. Second, because it's '=', the right hand side is interpreted as python, so no leading '$'.
Within your template layout.html, change your javascript to something similar to:
var test = "$:page.path";
var digitalData = {
'page': {
'path': $:page.path
}
};
You'll want to escape the data using $: rather than $. That's why you're seeing the encoded values. Also, you don't want to surround the final $:page.path with quotes to set page.path to an object, rather than just a string.

Simple AJAX example with Python not working

I am trying to implement a simple AJAX example, based on the demo shown on this page:
http://www.degraeve.com/reference/simple-ajax-example.php
I have copied the HTML portion and named it ajax_demo.html. For example:
<html>
<head>
<title>Simple Ajax Example</title>
<script language="Javascript">
function xmlhttpPost(strURL) {
var xmlHttpReq = false;
var self = this;
// Mozilla/Safari
if (window.XMLHttpRequest) {
self.xmlHttpReq = new XMLHttpRequest();
}
// IE
else if (window.ActiveXObject) {
self.xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
}
self.xmlHttpReq.open('POST', strURL, true);
self.xmlHttpReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
self.xmlHttpReq.onreadystatechange = function() {
if (self.xmlHttpReq.readyState == 4) {
updatepage(self.xmlHttpReq.responseText);
}
}
self.xmlHttpReq.send(getquerystring());
}
function getquerystring() {
var form = document.forms['f1'];
var word = form.word.value;
qstr = 'w=' + escape(word); // NOTE: no '?' before querystring
return qstr;
}
function updatepage(str){
document.getElementById("result").innerHTML = str;
}
</script>
</head>
<body>
<form name="f1">
<p>word: <input name="word" type="text">
<input value="Go" type="button" onclick='JavaScript:xmlhttpPost("/cgi-bin/simple-ajax-example.py")'></p>
<div id="result"></div>
</form>
</body>
</html>
Not shown above is the full real path to my simple-ajax-example.py here:
<input value="Go" type="button" onclick='JavaScript:xmlhttpPost("/cgi-bin/simple-ajax-example.py")'>
Both files are on my apache server. For example:
http://myserver.com/ajax_demo.html
http://myserver.com/cgi-bin/simple-ajax-example.py
My Python script does work when called directly and looks like this:
import cgi
form = cgi.FieldStorage()
secret_word = form.getvalue('word')
print "Content-type: text/html"
print ""
print "<p>The secret word is", secret_word, "<p>"
Problem is, this simply doesn't work. In the ajax_demo.html text box, when I enter text and click Go, nothing seems to happen.
What am I missing?
You probably need open a server to serve ../cgi-bin/ directory :)
try this commend,
python -m simpleHTTPServer 8100
-----EDIT-----
secret_word = form.getvalue('word')
qstr = 'word=' + escape(word)
Your querystring key is misspelled.

Upload a file to a cherrypy server using ajax

I am trying to upload a file to a cherrypy server, but without changing the displayed page.
A simple alert will be enough for my needs to tell the user that the upload is done.
I am trying this with a simple file input type and a button:
<div>
<label>Upload Sound:</label>
<input id="pathSound" style="width: 80%" type="file" accept=".mp3"/><br>
<button id="uploadSound">Upload</button>
</div>
and a script for the button click:
$("#uploadSound").click(function(e) {
if (document.getElementById("pathSound").value=='') {
alert("No file selected!");
e.preventDefault();
return;
}
var cardID = $('#tagID').html();
var file = document.getElementById("pathSound").files[0];
alert( "Tag: " + cardID + " File: " + file);
$.post("/uploadSound", {"cardID": cardID, "myFile": file})
.done(function(res) {
alert("File Saved!");
});
});
on the server side i have this function so far, but it is never called:
import os, os.path
import cherrypy
from cherrypy.process import plugins
class MagicBoxInterface(object):
#cherrypy.expose
def index(self):
return file('index.html')
#cherrypy.expose
def uploadSound(self, cardID='', myFile=None):
print 'uploadSound : ', cardID
print 'uploadSound : ', myFile
return ''
if __name__ == '__main__':
conf = {
'/': {
'tools.sessions.on': True,
'tools.staticdir.root': os.path.abspath(os.getcwd())
},
'/static': {
'tools.staticdir.on': True,
'tools.staticdir.dir': './public'
}
}
interface = MagicBoxInterface()
cherrypy.quickstart(interface, '/', conf)
All the examples i find use normal post and show a result page after the upload, but this is not what i want to do! The displayed page must not change.
On a side note, i don't need to consider large files, because it will only handle files below 1-2 MB.
I have found some examples using frames, but i am not that familiar with html/javascript to fully understand how i can apply those to my needs.
And help on a simple solution is greatly appreciated.
Ok do this...
$("#uploadSound").click(function(e) {
if (document.getElementById("pathSound").value=='') {
alert("No file selected!");
e.preventDefault();
return;
}
var cardID = $('#tagID').html();
var file = document.getElementById("pathSound").files[0];
alert( "Tag: " + cardID + " File: " + file);
$.post("/MagicBoxInterface/uploadSound", {"cardID": cardID, "myFile": file})
.done(function(res) {
alert("File Saved!");
});
});
You just need to include the class in your post request path.
hope this helps!

ASP.NET equivalent to Python's os.system([string])

I have an app made in Python, which accesses a Linux server's command prompt with os.system([string])
Now I'd like to transfer this away from Python, into some language like ASP.NET or something.
Is there a way to access the server's command prompt and run commands with ASP.NET or any technology found in Visual Studio?
This needs to run in a web app, where a user will click a button, and then a server-side command will run, so it's important that the technology suggested is compatible with all that.
Well it isn't ASP.net specific but in c#:
using System.Diagnostics;
Process.Start([string]);
Or With more access to the specific parts of running a program (like arguments, and output streams)
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c dir *.cs";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
here is how you could combine this with an ASPx Page:
First Process.aspx:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Process.aspx.cs" Inherits="com.gnld.web.promote.Process" %>
<!DOCTYPE html>
<html>
<head>
<title>Test Process</title>
<style>
textarea { width: 100%; height: 600px }
</style>
</head>
<body>
<form id="form1" runat="server">
<asp:Button ID="RunCommand" runat="server" Text="Run Dir" onclick="RunCommand_Click" />
<h1>Output</h1>
<asp:TextBox ID="CommandOutput" runat="server" ReadOnly="true" TextMode="MultiLine" />
</form>
</body>
</html>
Then the code behind:
using System;
namespace com.gnld.web.promote
{
public partial class Process : System.Web.UI.Page
{
protected void RunCommand_Click(object sender, EventArgs e)
{
using (var cmd = new System.Diagnostics.Process()
{
StartInfo = new System.Diagnostics.ProcessStartInfo()
{
FileName = "cmd.exe",
Arguments = "/c dir *.*",
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true
}
})
{
cmd.Start();
CommandOutput.Text = cmd.StandardOutput.ReadToEnd();
};
}
}
}

Categories