Bottle cannot find route when separating "app" init, routes and main function into different files - bottle

routes.py:
from server import app
#app.route("/index")
def index():
return "Hello World"
server.py:
from bottle import Bottle, run
app = Bottle()
#app.route("/index",method=["POST"])
run.py:
from server import app
from bottle import Bottle, run
if __name__ == "__main__":
run(app, host='localhost', port=8080, debug=True)
After I split them into different files, I get the 404 error. I didn't find much information about this on google.

You're not importing routes anywhere, so routes.py is never executed.
If I were you, I would merge routes.py and server.py. But if you insist on separating them, then something like this might work:
run.py:
from bottle import Bottle, run
from server import app
import routes
...

Related

Python Bokeh FileInput Widget for DLIS file

I am trying a web app in bokeh where i import a dlis file through the widget fileinput.
I am using the following libraries
from dlisio import dlis
from pybase64 import b64decode
import io
def upload_file_dlis(attr, old, new):
print('upload_file_dlis')
decoded = b64decode(new)
f = io.BytesIO(decoded)
file_input_dlis.on_change('value', upload_file_dlis)
I have the following issue:
OSError: '<_io.BytesIO object at 0x000001CE6507CF40>' is not an existing regular file
I guess it is because dlis files are not handled by Io library.
What is the best way to work on this?
Do you have any suggestions?

How can I use FastAPI Routers with FastAPI-Users and MongoDB?

I can use MongoDB with FastAPI either
with a global client: motor.motor_asyncio.AsyncIOMotorClient object, or else
by creating one during the startup event per this SO answer which refers to this "Real World Example".
However, I also want to use fastapi-users since it works nicely with MongoDB out of the box. The downside is it seems to only work with the first method of handling my DB client connection (ie global). The reason is that in order to configure fastapi-users, I have to have an active MongoDB client connection just so I can make the db object as shown below, and I need that db to then make the MongoDBUserDatabase object required by fastapi-users:
# main.py
app = FastAPI()
# Create global MongoDB connection
DATABASE_URL = "mongodb://user:paspsword#localhost/auth_db"
client = motor.motor_asyncio.AsyncIOMotorClient(DATABASE_URL, uuidRepresentation="standard")
db = client["my_db"]
# Set up fastapi_users
user_db = MongoDBUserDatabase(UserDB, db["users"])
cookie_authentication = CookieAuthentication(secret='lame secret' , lifetime_seconds=3600, name='cookiemonster')
fastapi_users = FastAPIUsers(
user_db,
[cookie_authentication],
User,
UserCreate,
UserUpdate,
UserDB,
)
After that point in the code, I can import the fastapi_users Routers. However, if I want to break up my project into FastAPI Routers of my own, I'm hosed because:
If I move the client creation to another module to be imported into both my app and my routers, then I have different clients in different event loops and get errors like RuntimeError: Task <Task pending name='Task-4' coro=<RequestResponseCycle.run_asgi() running at /usr/local/lib/python3.8/site-packages/uvicorn/protocols/http/h11_impl.py:389> cb=[set.discard()]> got Future <Future pending cb=[_chain_future.<locals>._call_check_cancel() at /usr/local/lib/python3.8/asyncio/futures.py:360]> attached to a different loop (touched on in this SO question)
If I user the solutions of the "Real World Example", then I get stuck on where to build my fastapi_users object in my code example: I can't do it in main.py because there's no db object yet.
I considered making the MongoDBUserDatabase object as part of the startup event code (ie within async def connect_to_mongo() from the Real World Example), but I'm not able to get that to work either since I can't see how to make it work.
How can I either
make a global MongoDB client and FastAPI-User object in a way that can be shared among my main app and several routers without "attached to a different loop" errors, or
create fancy wrapper classes and functions to set up FastAPI users with the startup trigger?
I don't think my solution is complete or correct, but I figured I'd post it in case it inspires any ideas, I'm stumped. I have run into the exact dilemma, almost seems like a design flaw..
I followed this MongoDB full example and named it main.py
At this point my app does not work. The server starts up but result results in the aforementioned "attached to a different loop" whenever trying to query the DB.
Looking for guidance, I stumbled upon the same "real world" example
In main.py added the startup and shudown event handlers
# Event handlers
app.add_event_handler("startup", create_start_app_handler(app=app))
app.add_event_handler("shutdown", create_stop_app_handler(app=app))
In dlw_api.db.events.py this:
import logging
from dlw_api.user import UserDB
from fastapi import FastAPI
from fastapi_users.db.mongodb import MongoDBUserDatabase
from motor.motor_asyncio import AsyncIOMotorClient
LOG = logging.getLogger(__name__)
DB_NAME = "dlwLocal"
USERS_COLLECTION = "users"
DATABASE_URI = "mongodb://dlw-mongodb:27017" # protocol://container_name:port
_client: AsyncIOMotorClient = None
_users_db: MongoDBUserDatabase = None
def get_users_db() -> MongoDBUserDatabase:
return _users_db
async def connect_to_db() -> None:
global _users_db
# logger.info("Connecting to {0}", repr(DATABASE_URL))
client = AsyncIOMotorClient(DATABASE_URI)
db = client[DB_NAME]
collection = db[USERS_COLLECTION]
_users_db = MongoDBUserDatabase(UserDB, collection)
LOG.info(f"Connected to {DATABASE_URI}")
async def close_db_connection(app: FastAPI) -> None:
_client.close()
LOG.info("Connection closed")
And dlw_api.events.py:
from typing import Callable
from fastapi import FastAPI
from dlw_api.db.events import close_db_connection, connect_to_db
from dlw_api.user import configure_user_auth_routes
from fastapi_users.authentication import CookieAuthentication
from dlw_api.db.events import get_users_db
COOKIE_SECRET = "THIS_NEEDS_TO_BE_SET_CORRECTLY" # TODO: <--|
COOKIE_LIFETIME_SECONDS: int = 3_600
COOKIE_NAME = "c-is-for-cookie"
# Auth stuff:
_cookie_authentication = CookieAuthentication(
secret=COOKIE_SECRET,
lifetime_seconds=COOKIE_LIFETIME_SECONDS,
name=COOKIE_NAME,
)
auth_backends = [
_cookie_authentication,
]
def create_start_app_handler(app: FastAPI) -> Callable:
async def start_app() -> None:
await connect_to_db(app)
configure_user_auth_routes(
app=app,
auth_backends=auth_backends,
user_db=get_users_db(),
secret=COOKIE_SECRET,
)
return start_app
def create_stop_app_handler(app: FastAPI) -> Callable:
async def stop_app() -> None:
await close_db_connection(app)
return stop_app
This doesn't feel correct to me, does this mean all routes that use Depends for user-auth have to be included on the server startup event handler??
The author (frankie567) of fastapi-users created a repl.it showing a solution of sorts. My discussion about this solution may provide more context but the key parts of the solution are:
Don't bother using FastAPI startup trigger along with Depends for your MongDB connectivity management. Instead, create a separate file (ie db.py) to create your DB connection and client object. Import this db object whenever needed, like your Routers, and then use it as a global.
Also create a separate users.py to do 2 things:
Create globally used fastapi_users = FastAPIUsers(...) object for use with other Routers to handle authorization.
Create a FastAPI.APIRouter() object and attach all the fastapi-user routers to it (router.include_router(...))
In all your other Routers, import both db and fastapi_users from the above as needed
Key: split your main code up into
a main.py which only import uvicorn and serves app:app.
an app.py which has your main FastAPI object (ie app) and which then attaches all our Routers, including the one from users.py with all the fastapi-users routers attached to it.
By splitting up code per 4 above, you avoid the "attached to different loop" error.
I faced similar issue, and all I have to do to get motor and fastapi run in the same loop is this:
client = AsyncIOMotorClient()
client.get_io_loop = asyncio.get_event_loop
I did not set on_startup or whatsoever.

How to init db for tortoise-orm in sanic app?

Is there a way to register databases in tortoise-orm from my Sanic app other than calling Tortoise.init?
from tortoise import Tortoise
await Tortoise.init(
db_url='sqlite://db.sqlite3',
modules={'models': ['app.models']}
)
# Generate the schema
await Tortoise.generate_schemas()
Sanic maintainer here.
Another answer offers the suggestion of using tortoise.contrib.sanic.register_tortoise that uses before_server_start and after_server_stop listeners.
I want to add a caveat to that. If you are using Sanic in ASGI mode, then you really should be using the other listeners: after_server_start and before_server_stop.
This is because there is not really a "before" server starting or "after" server stopping when the server is outside of Sanic. Therefore, if you are implementing the suggested solution as adopted by tortoise in ASGI mode, you will receive warnings in your logs every time you spin up a server. It is still supported, but it might be an annoyance.
In such case:
#app.listener('after_server_start')
async def setup_db(app, loop):
...
#app.listener('before_server_stop')
async def close_db(app, loop):
...
Yes, you can use register_tortoise available from tortoise.contrib.sanic
It registers before_server_start and after_server_stop hooks to set-up and tear-down Tortoise-ORM inside a Sanic webserver. Check out this sanic integration example from tortoise orm.
you can use it like,
from sanic import Sanic, response
from models import Users
from tortoise.contrib.sanic import register_tortoise
app = Sanic(__name__)
#app.route("/")
async def list_all(request):
users = await Users.all()
return response.json({"users": [str(user) for user in users]})
register_tortoise(
app, db_url="sqlite://:memory:", modules={"models": ["models"]}, generate_schemas=True
)
if __name__ == "__main__":
app.run(port=5000)
models.py
from tortoise import Model, fields
class Users(Model):
id = fields.IntField(pk=True)
name = fields.CharField(50)
def __str__(self):
return f"User {self.id}: {self.name}"

Discord Module never used?

I'm relatively confused here, and upon trying to research for an answer, I'm not seeming to find anything that makes any sense to me. I have created a discord bot with 5 cogs, and in each one I import discord, os, and from discord.ext import commands In various other cogs I import other modules such as random as the case may be, but those are the three common ones.
The problem is that in every module, import discord is grayed out (PyCharm IDE), suggesting that is never used. Despite this, my bot runs perfectly. I don't seem to be able to use things like the wait_for() command, I presume it is because it is in the discord module? Am I not setting things up correctly to use this?
I will post the initial startup module and a small snippet of another module, rather than list module. If you need more information, let me know.
initial startup:
import discord
import os
from discord.ext import commands
token = open("token.txt", "r").read()
client = commands.Bot(command_prefix = '!')
#client.command()
async def load(ctx, extension):
client.load_extension("cogs." + extension)
#client.command()
async def unload(ctx, extension):
client.unload_extension("cogs." + extension)
for filename in os.listdir("./cogs"):
if filename.endswith('.py'):
client.load_extension("cogs." + filename[:-3])
client.run(token)
another module:
import discord
from discord.ext import commands
import os
import json
from pathlib import Path
class Sheet(commands.Cog):
def __init__(self, client):
self.client = client
#commands.command()
#commands.dm_only()
async def viewchar(self, ctx):
#Snipped code here to make it shorter.
pass
#viewchar.error
async def stats_error(self, ctx, error):
if isinstance(error, commands.PrivateMessageOnly):
await ctx.send("You're an idiot, now everyone knows. Why would you want to display your character sheet "
"in a public room? PM me with the command.")
else:
raise error
def setup(client):
client.add_cog(Sheet(client))
That just means that your code doesn't directly reference the discord module anywhere. You're getting everything through the commands module.
You can remove the import discord from your code without breaking anything, because the code that relies on it will still import and use it behind the scenes.

Scrapy cmdline.execute stops script

When I call
cmdline.execute("scrapy crawl website".split())
print "Hello World"
it stops the script after cmdline.execute, and doesn't run the rest of the script and print "Hello World". How do I fix this?
By taking a look at the execute function in Scrapy's cmdline.py, you'll see the final line is:
sys.exit(cmd.exitcode)
There really is no way around this sys.exit call if you call the execute function directly, at least not without changing it. Monkey-patching is one option, albeit not a good one! A better option is to avoid calling the execute function entirely, and instead use the custom function below:
from twisted.internet import reactor
from scrapy import log, signals
from scrapy.crawler import Crawler as ScrapyCrawler
from scrapy.settings import Settings
from scrapy.xlib.pydispatch import dispatcher
from scrapy.utils.project import get_project_settings
def scrapy_crawl(name):
def stop_reactor():
reactor.stop()
dispatcher.connect(stop_reactor, signal=signals.spider_closed)
scrapy_settings = get_project_settings()
crawler = ScrapyCrawler(scrapy_settings)
crawler.configure()
spider = crawler.spiders.create(name)
crawler.crawl(spider)
crawler.start()
log.start()
reactor.run()
And you can call it like this:
scrapy_crawl("your_crawler_name")
I have just tried the following code, and it works for me:
import os
os.system("scrapy crawl website")
print("Hello World")
One can run subprocess.call. For example on Windows with powershell:
import subprocess
subprocess.call([r'C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe',
'-ExecutionPolicy',
'Unrestricted',
'scrapy crawl website -o items.json -t json'])