Python HTTP Server to activate Code - python

I am trying to setup a python script that I can have running all the time and then use a HTTP command to activate an action in the script. So that when I type a command like this into a web browser:
http://localhost:port/open
The script executes a piece of code.
The idea is that I will run this script on a computer on my network and activate the code remotely from elsewhere on the network.
I know this is possible with other programming languages as I've seen it before, but I can't find any documentation on how to do it in python.
Is there an easy way to do this in Python or do I need to look into other languages?

First, you need to select a web framework. I will recommand using Flask, since it is lightweight and really easy to start using it fast.
We begin by initializing your app and setting a route. your_open_func() (in the code below) which is decorated with the #app.route("/open") decorator will be triggered and run when you will send a request to that preticular url (for example http://127.0.0.1:5000/open)
As Flask's website says: flask is fun. The very first example (with minor modifications) from there suits your needs:
from flask import Flask
app = Flask(__name__)
#app.route("/open")
def your_open_func():
# Do your stuff right here.
return 'ok' # Remember to return or a ValueError will be raised.
In order to run your app app.run() is usually enough, but in your case you want other computers on your network to be able to access the app, so you should call the run() method like so: app.run(host="0.0.0.0").
By passing that parameter you are making the server publicly available.

Related

Is it possible run a fastapi in command line?

We can run any script in python doing:
python main.py
Is it possible do the same if the script was a FastApi application?
Something like:
python main.py GET /login.html
To call a GET method that returns a login.html page.
If not, how I could start a FastApi application without using Uvicorn or another webserver?
I would like can run the script only when necessary.
Thanks
FastApi is designed to allow you to BUILD APIs which can be queried using a HTTP client, not directly query those APIs yourself; however, technically I believe you could.
When you start the script you could start the FastApi app in a another process running in the background, then send a request to it.
import subprocess
import threading
import requests
url = "localhost/some_path"
# launch sub process in background task while redirecting all output to /dev/null
thread = threading.Thread(target=lambda: subprocess.check_output(["uvcorn", "main:app"]))
thread.start()
response = requests.get(url)
# do something with the response...
thread.join()
Obviously this snippet has MUCH room for improvement, for example the thread will never actually end unless something bad happens, this is just a minimal example.
This is method has the clear drawback of starting the API each time you want to run the command. A better approach would be to emulate applications such as Docker, in which you would start up a local server daemon which you would then ping using the command line app.
This would mean that you would have the API running for much longer in the background, but typically these APIs are fairly light and you shouldn't notice and hit to you computer's performance. This also provides the benefit of multiple users being able to run the command at the same time.
If you used the first previous method you may run into situations where user A send a GET request, starting up the server taking hold of the configured host port combo. When user B tries to run the same command just after, they will find themselves unable to start the server. and perform the request.
This will also allow you to eventually move the API to an external server with minimal effort down the line. All you would need to do is change the base url of the requests.
TLDR; Run the FastApi application as a daemon, and query the local server from the command line program instead.

Testing a Flask application with requests

Ever since I read
A untested application is broken
in the flask documentation about testing here
I have been working down my list of things to make for some of my applications.
I currently have a flask web app when I write a new route I just write a requests.get('https://api.github.com/user', auth=('user', 'pass')), post, put, etc to test the route.
Is this a decent alternative? Or should I try and do tests via what flask's documentation says, and if so why?
Fundamentally it's the same concept, you are running functionality tests as they do. However, you have a prerequisite, a live application running somewhere (if I got it right). They create a fake application (aka mock) so you can test it without being live, e.g. you want to run tests in a CI environment.
In my opinion it's a better alternative than a live system. Your current approach consumes more resources on your local machine, since you are required to run the whole system to test something (i.e. at least a DB and the application itself). In their approach they don't, the fake instance does not need to have real data, thus no connection to a DB or any other external dependency.
I suggest you to switch to their testing, in the end you will like it.

Django responding to different request from different browser with one python session

I'm actually a php(CodeIgniter) web developer though I love python I just installed Bitnami's Django Stack which has Apache, MySQL, PostgreSQL and Python 2.7.9 with Django installed. During installation itself it generated a simple Django project.
Though it looked familiar to me I started adding some lines of codes to it but when I save it and refresh the page or even restart the browser I found that python instance is still running the old script. The script updates only when I restart start the Apache Server(I believe that's where the Python instance got terminated).
So, to clarify this problem with Python I created a simple view and URLed it to r'^test/'
from django.http import HttpResponse
i = 0
def test_view(request):
global i
i += 1
return HttpResponse(str(i))
Then I found that even switching between different browser the i value keep on increasing i.e increasing value continues with the other browse.
So, can anyone tell me is this a default behavior of Django or is there something wrong with my Apache installation.
This is the default behavior, it may reset if you were running with gunicorn and killing workers after X requests or so, I don't remember. It's like this because the app continues to run after a request has been served.
Its been a while I've worked with PHP but I believe, a request comes in, php starts running a script which returns output and then that script terminates. Special global variables like $_SESSION aside, nothing can really cross requests.
Your Django app starts up and continues to run unless something tells it to reload (when running with ./manage.py runserver it will reload whenever it detects changes to the code, this is what you want during development).
If you are interested in per visitor data see session data. It would look something like:
request.session['i'] = request.session.get('i', 0) + 1
You can store data in there for the visitor and it will stick around until they lose their session.

How to communicate with a running python process from an Objective-C app?

I'm building an Objective-C mac app. I'd like that app to be able to start and continuously communicate with the same running python process.
For example, the basic flow might be:
App starts, I start a python process in the background
The app imports some libraries and initializes some variables in the python process
User does something, I run some python code on this python process using the initialized variables and use the result of the python expression in my mac app
What techniques can I use to accomplish this? Any guidance would be incredibly helpful.
A possible solution is to run a mock web service by your Python process. Define your own interfaces (most likely RESTful APIs) for your Objective-C app to access. Maybe it will be a little expensive in performance - it depends on the complexity of your actual task and the amount of data you want to transfer between the two processes.
For example, in Python process, run a standard HTTP service on 8080 port, listening all the time. Then the Obj-C app send a request to localhost, something like:
http://127.0.0.1:8080/my_service/start_task
http://127.0.0.1:8080/my_service/get_progress
http://127.0.0.1:8080/my_service/get_result
and Python handles that request, do something and return the result in HTTP response.
By the way, maybe you could consider calling Python methods directly by C interface in your Obj-C app rather than run Python scripts in a seperate process.
In my eyes the simplest way to establish communication between two applications is the client-server protocol XMLRPC. Both Cocoa and Python do support it.
The Python part is fairly simple:
import xmlrpc.client
rpcProxy = xmlrpc.client.ServerProxy(URL_OF_SERVER)
rpcProxy.doJobInMacApp(arg1, arg2)
As for the Objective-C-part, I don't know, but it seems to be possible: XML-RPC Server in Cocoa or Best way to use XML-RPC in Cocoa application?

Python: Best method to reload class in XMLRPC Server

I have a multit-threaded xmlrpc service running which stores a huge amount of data ~2G in memory. Currently, if I want to update a method the server exposes I have to restart the service. The problem here is that if I restart the service it needs to load all of the data it had in memory back into memory by using a database or using shelved data.
I am using methods like this:
xmlrpc_getUser(self, uid):
return self.users[uid]
What I was hoping I could do is just use these methods as a proxy to another module, so my methods would look more like this
xmlrpc_getUser(self, uid):
return self.proxy.getUser(uid)
This way I could update code on the development server then simply copy my update proxy module to the production server without the need for a restart.
I tried adding
import service_proxy
to the constructor of my xmlrpc service controller, but I think the module is cached and won't reload.
Is there a good way to do this? Thanks.
You could use the reload method. You would need to write some code to check the last modified time of the modules file.
If reload doesn't work, you could try twisted.python.rebuild; your application need not be written in Twisted to use this twisted.python utility.
I also recently saw this livecoding thing ("a code reloading library for Python"), but it talks about a custom module system and I don't know what's going on there.

Categories

Resources