how to set the callable function parameters of 'before_handler' in cherrypy - cherrypy

def do_redirect():
raise cherrypy.HTTPRedirect("/login.html")
def check_auth(call_func):
# do check ...
if check_success():
return
call_func()
cherrypy.tools.auth = cherrypy.Tool('before_handler', check_auth)
cherrypy.tools.auth.call_func = do_redirect
I want to set the function do_redirect as check_auth's parameter,
but it throw the follow exception:
TypeError: check_auth() takes exactly 1 argument (0 given)
but it can works if modify to follow code:
def check_auth(call_func):
# do check ...
if check_success():
return
cherrypy.tools.auth.call_func()
cherrypy.tools.auth = cherrypy.Tool('before_handler', check_auth)
cherrypy.tools.auth.call_func = do_redirect
how to set the callable function parameters of 'before_handler' in cherrypy?

There are a couple of way on setting the argument for a tool, take a look to this example:
import cherrypy as cp
def check_success():
return False
def do_redirect():
raise cp.HTTPRedirect("/login.html")
def fancy_redirect():
raise cp.HTTPRedirect("/fancy_login.html")
def secret_redirect():
raise cp.HTTPRedirect("/secret_login.html")
def check_auth(call_func=do_redirect):
# do check ...
if check_success():
return
call_func()
cp.tools.auth = cp.Tool('before_handler', check_auth, priority=60)
class App:
#cp.expose
#cp.tools.auth() # use the default
def index(self):
return "The common content"
#cp.expose
def fancy(self):
return "The fancy content"
#cp.expose
#cp.tools.auth(call_func=secret_redirect) # as argument
def secret(self):
return "The secret content"
#cp.expose
def login_html(self):
return "Login!"
#cp.expose
def fancy_login_html(self):
return "<h1>Please login!</h1>"
#cp.expose
def secret_login_html(sel):
return "<small>Psst.. login..</small>"
cp.quickstart(App(), config={
'/fancy': {
'tools.auth.on': True,
'tools.auth.call_func': fancy_redirect # from config
}
})

Try this
cherrypy.tools.auth = HandlerWrapperTool(newhandler=auth_fn)
or
class AuthHandler(Tool):
def __init__(self, auth_fn):
self._point = 'before_handler'
self._name = 'auth_handler'
self._priority = 10
self._auth_fn = auth_fn
def callable(self):
# implementation

Related

Is it possible to add an argument to a property in aiogram?

I'm making a multi-lingual functionality for a aiogram bot, it's pretty simple at the moment:
class Localization:
locales = {
'en': {
'command': {
'start': 'Hello!'
}
}
}
def __init__(self):
self.__user_lang = dict()
#property
def available_langs(self):
return tuple(self.locales.keys())
def text(self, id):
return self.locales[self.user_lang(id)]
def user_lang(self, id):
return self.__user_lang.get(id, 'en')
def set_user_lang(self, id, lang):
if lang in self.available_langs:
self.__user_lang[id] = lang
I have to call it like this:
#dp.message_handler(commands=['start'])
async def start_command(message: types.Message):
id = message.from_user.id
await message.answer(locale.text(id)['commands']['start'])
I want to change text in a #property to shorten the entry.
#property
def text(self):
return self.locales[self.user_lang(id)]
This will also allow me to make constructs like this:
#dp.message_handler(lambda m: m.text == locale.text['buttons']['about'])
async def about(message: types.Message):
pass
Not like this:
#dp.message_handler(lambda m: m.text == locale.text(m.from_user.id)['buttons']['about'])
async def about(message: types.Message):
pass
But I absolutely cannot think of how to specify the property for which particular user to get localization.
P.S. I know about i18n, but I'm learning and want to try to write everything myself.
Ok, i'm definitely stupid.
I could just get the current user in any function that is called from the handler:
from aiogram import types
#property
def user_lang(self):
user = types.User.get_current()
return self.__user_lang.get(user.id, 'ru')
And so on...

How to set parameter for all of the methods in Inherited class

I am currently learning Object Oriented Programming in Python. I have some issues with understanding how to pass to all methods that I inherite from Parten class. I will show you example of code.
Below you can see my Parent class (it's simple api wrapper).
class AlphaVantageClient:
_URL = "https://www.alphavantage.co/query?"
def __init__(self, api_key=None):
self.__api_key = api_key
def show_base_url(self):
print(self._URL)
def set_api_key(self, api_key: str):
self.__api_key = api_key
def __call_api(self, query_parameters: dict,**kwargs):
"""
The structure looks like:
co./query?function{}&symbol{}
:param query_parameters:
:return: response
"""
query_parameters["apikey"] = self.__api_key
response = requests.get(
AlphaVantageClient._URL,
params=query_parameters,
proxies=self.__proxy
)
validate_http_status(response)
return response.json()
def company_overview(self, ticker: str, **kwargs):
query_parameters = {
"function": "OVERVIEW",
"symbol": ticker
}
return self.__call_api(query_parameters, **kwargs)
def balance_sheet(self, ticker: str, **kwargs):
query_parameters = {
"function": "BALANCE_SHEET",
"symbol": ticker
}
return self.__call_api(query_parameters, **kwargs)
def income_statement(self, ticker: str, **kwargs):
query_parameters = {
"function": "INCOME_STATEMENT",
"symbol": ticker
}
return self.__call_api(query_parameters, **kwargs)
def cash_flow(self, ticker: str, **kwargs):
query_parameters = {
"function": "CASH_FLOW",
"symbol": ticker
}
return self.__call_api(query_parameters, **kwargs)
And below there is my child class in which I want to inheritate from AlphaVantageClient class all of the methods.
class Stock(AlphaVantageClient):
def __init__(self, ticker: str):
super().__init__()
self.ticker = ticker
self.client = AlphaVantageClient()
def set_api_key(self, api_key):
self.client.set_api_key(api_key)
But my problem is that as you see in AlphaVantegeClient all of my methods has parameter symbol, I would like to set in one line or something like that for all of the methods to have my symbol parameter set to self.ticker from Stock class. Is it possible to do that ? Or I need to somehow refactor Parent class code ?
You misunderstand how inheritance works. When you create a class Stock that subclasses (inherits from) class AlphaVantageClient it automatically gets all of the attributes and methods of that parent class as if you defined them as part of the new subclass.
You should absolutely not have this line in the init: self.client = AlphaVantageClient(). By subclassing (inheriting) from AlphaVantageClient it already is an instance of AlphaVantageClient and that creates a separate additional instance of and AlphaVantageClient separate from the one it is.
In your Stock class you do not have to redefine set_api_key() unless you are trying to change it for some reason and you are not. This method is just trying to save the api_key into an internal class attribute and it already does that so just leave it out/un-redefined in Stock.
You do not need to rework AlphaVantageClient, but you do need to have stubs in Stock since they need to substitute in the saved ticker parameter into the calls to the parent. Like this:
class Stock(AlphaVantageClient):
def __init__(self, ticker: str, api_key=None):
super().__init__(api_key)
self.ticker = ticker
def company_overview(self, **kwargs):
return super().company_overview(self.ticker, **kwargs)
def balance_sheet(self, **kwargs):
return super().balance_sheet(self.ticker, **kwargs)
def income_statement(self, **kwargs):
return super().income_statement(self.ticker, **kwargs)
def cash_flow(self, **kwargs):
return super().cash_flow(self.ticker, **kwargs)
Thank you for you answer. I don't know if I get it correctly.
class AlphaVantageClient:
_URL = "https://www.alphavantage.co/query?"
def __init__(self, api_key=None, symbol=None):
self.__api_key = api_key
self.__proxy = {}
self.__validate_api_key()
self.__data_type = 'json'
self.__symbol = symbol
def set_api_key(self, api_key: str):
self.__api_key = api_key
def __call_api(self, query_parameters: dict,**kwargs):
"""
The structure looks like:
co./query?function{}&symbol{}
:param query_parameters:
:return: response
"""
query_parameters["apikey"] = self.__api_key
response = requests.get(
AlphaVantageClient._URL,
params=query_parameters,
proxies=self.__proxy
)
validate_http_status(response)
return response.json()
def company_overview(self, symbol: str, **kwargs):
query_parameters = {
"function": "OVERVIEW",
"symbol": symbol
}
return self.__call_api(query_parameters, **kwargs)
def balance_sheet(self, symbol: str, **kwargs):
query_parameters = {
"function": "BALANCE_SHEET",
"symbol": symbol
}
return self.__call_api(query_parameters, **kwargs)
def income_statement(self, symbol: str, **kwargs):
query_parameters = {
"function": "INCOME_STATEMENT",
"symbol": symbol
}
return self.__call_api(query_parameters, **kwargs)
def cash_flow(self, symbol: str, **kwargs):
query_parameters = {
"function": "CASH_FLOW",
"symbol": symbol
}
return self.__call_api(query_parameters, **kwargs)
class Stock(AlphaVantageClient):
def __init__(self, symbol: str):
super().__init__(symbol)
self.symbol = symbol
self.client = AlphaVantageClient(symbol)
def set_api_key(self, api_key):
self.client.set_api_key(api_key)
Now my classes look like this. And I try to create instance of my class and call one of methods like below:
from client import AlphaVantageClient, Stock
stock = Stock(symbol="FB")
stock.income_statement()
And I get an error:
tests\test_client.py:5: in <module>
stock.income_statement()
E TypeError: income_statement() missing 1 required positional argument: 'symbol'
So I don't know if I don't understand you correctly or I just explained my problem in wrong way. So I will try once more:
If I call my AlphaVantageClient, I want to use it in the way that I create instance of that class and I call methods providing as an parameter symbol of stock e.g
client = AlphaVantageClient()
income_statement = client.income_statement(symbol="FB")
But if I create a Stock class I would like to have symbol stored in class and don't need to provide it as a paramtere in my methods: All the methods should use that symbol that I provided when I created Stock class as default. So the usage should look like below:
stock = Stock(symbol="FB")
income_statement = stock.income_statement()
And this way I will fetch the data for "FB" in all of my methods.
Is it possible ? If yes, can you explain me little more how to achive it.

How to properly inherit class method

I have a database connection class that creates a connection pool. Now as the application grows and I'm adding different types of database writers, I want to move database connections to a separate class and inherit from it. So far I have this:
class ServiceDB:
#classmethod
async def init(cls, settings):
self = ServiceDB()
self.pool = await asyncpg.create_pool(
database=settings["POSTGRES_DB"],
user=settings["POSTGRES_USER"],
password=settings["POSTGRES_PASSWORD"],
host=settings["DB_HOST"],
port=settings["DB_PORT"],
)
return self
class ChildWriter(ServiceDB):
async def write_db(self, query):
# Write to specific table
pass
if __name__ == "__main__":
settings = {'info': "some connection settings"}
query = "SELECT * FROM 'table'"
connection = await ChildWriter().init(settings)
await connection.write_db(msg, query)
When I run this I get AttributeError: 'ServiceDB' object has no attribute 'write_db'. How do I properly extend ServiceDB with the write_db method?
Classmethods receive the "current class" as the first argument. Instantiate this cls, not the fixed baseclass.
class ServiceDB:
#classmethod
async def init(cls, settings):
self = cls() # cls is the *current* class, not just ServiceDB
self.pool = await asyncpg.create_pool(
database=settings["POSTGRES_DB"],
user=settings["POSTGRES_USER"],
password=settings["POSTGRES_PASSWORD"],
host=settings["DB_HOST"],
port=settings["DB_PORT"],
)
return self
Note that ideally, all attributes are set via __init__ instead of a separate classmethod constructor. The separate constructor should just pass on any attributes constructed externally.
class ServiceDB:
def __init__(self, pool):
self.pool = pool
#classmethod
async def init(cls, settings, **kwargs):
pool = await asyncpg.create_pool(
database=settings["POSTGRES_DB"],
user=settings["POSTGRES_USER"],
password=settings["POSTGRES_PASSWORD"],
host=settings["DB_HOST"],
port=settings["DB_PORT"],
)
return cls(pool=pool, **kwargs)
class ChildWriter(ServiceDB):
async def write_db(self, query): ...
if __name__ == "__main__":
settings = {'info': "some connection settings"}
query = "SELECT * FROM 'table'"
# call classmethod on class V
connection = await ChildWriter.init(settings)
await connection.write_db(msg, query)

Custom exceptions in python starlette

I am trying to raise the custom exception using the starlette framework in python. I have the API call which checks some condtions depends on the result, it should raise exception.
I have two files app.py and error.py
#app.py
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route
from error import EmptyParamError
async def homepage(request):
a=1
b=0
if a == 1:
raise EmptyParamError(400, "status_code")
return JSONResponse({'hello': 'world'})
routes = [
Route("/", endpoint=homepage)
]
app = Starlette(routes=routes,debug=True)`
#error.py ```
from starlette.responses import JSONResponse
class BaseError(Exception):
def __init__(self, status_code: int, detail: str = None) -> None:
if detail is None:
detail = "http.HTTPStatus(status_code).phrase"
self.status_code = status_code
self.detail = detail
async def not_found(self):
return JSONResponse(content=self.title, status_code=self.status_code)
class EmptyParamError(BaseError):
""" Error is raised when group name is not provided. """
status_code = 400
title = "Missing Group Name"
When the condition is true, i want to raise the exception but its not returning the jsonrespnse but its returning the stacktrace on the console.
Please let me know if anything is wrong here
adding try block resolved the issue
try:
if a==1:
raise InvalidUsage(100,"invalid this one")
if b == 0:
raise EmptyParamError("this is empty paramuvi")
except InvalidUsage as e:
return JSONResponse({'hello': str(e.message)})
except EmptyParamError as e:
return JSONResponse({'hello': str(e.message)})

How can I run pytest in another folders in Python

In folder [Root]/src/app, I have a file services_factory.py, for example:
class Describing:
def __init__(self):
pass
def get_description(self):
pass
class APIService(Describing):
def __init__(self):
pass
def get_description(self):
return 'Here provide services for APIs'
class DatabaseService(Describing):
def __init__(self):
pass
def get_description(self):
return 'Here provide services for Database'
class Injector:
def __init__(self):
pass
def get_service(self, type='API'):
services = {
"API": APIService,
"DB": DatabaseService
}
return services[type]()
At the end of file services_factory.py, I add an unittest, ex:
def test_services_injector():
injector = Injector()
api_service = injector.get_service('API')
db_service = injector.get_service('DB')
assert api_service.get_description() == 'Here provide services for APIs'
assert db_service.get_description() == 'Here provide services for Database'
Then, cmd: $ pytest src/app/services_injector.py, it worked nicely.
But when I create a file test_services_factory.py in [Root]/tests/app, for example:
import unittest
from unittest.mock import patch
def test_services_injector():
assert 'a' == 'a'
I can't import the classes in my services_factory.py.
So, how can I quickly fix this problem?

Resources