How can I pass kwargs to class function - python-3.x

I don't have much experience with class inheritance. I understand that you can pass any variable to class instance via *args and **kwargs which help one to accommodate child classes.
In the example bellow, I'd like to pass the title, theme and size when instantiating a class which would do for me: self.title('App') and self.set_theme('radiance'). Now I'm just replacing the attributes, i.e., self.title = 'App' and self.set_theme = 'radiance' which doesn't do what I want...
class App(ThemedTk):
def __init__(self, **kwargs):
super().__init__()
self.__dict__.update(kwargs)
dic = {
'title': 'App',
'set_theme': 'radiance',
}
app = App(**dic)
app.mainloop()

I believe you are looking for something like this
from ttkthemes import ThemedTk
class App(ThemedTk):
def __init__(self, **kwargs):
title=kwargs.pop('title','')
theme=kwargs.pop('set_theme',None)
super().__init__(**kwargs)
self.title(title)
if theme:
self.set_theme(theme)
dic = {
'title': 'App',
'set_theme': 'radiance',
}
app = App(**dic)
app.mainloop()
You can pop (kwargs.pop(key, default)) out the kwargs that don't go into the __init__ function of ThemedTk in the begining and then pass them into the respective methods later on.

Based on #AST's answer:
from ttkthemes import ThemedTk
class App(ThemedTk):
# The default value for `title` is "Tk" and
# the default value for `theme` is `None`
def __init__(self, title="Tk", theme=None, **kwargs):
super().__init__(**kwargs)
self.title(title)
# If the theme is None just skip it
if theme is not None:
self.set_theme(theme)
dic = {
'title': 'App',
'set_theme': 'radiance',
}
app = App(**dic)
app.mainloop()

Related

how do i wrtite django fbv to class based view

I have two user types a and b i need to write the below fbv into class based Logoutview(auth.view) how do i write the below fbv to cbv
views.py
#login_required
def logout(request):
if request.user.usertype_a:
logout(request)
return redirect(reverse('user_a_login'))
else:
logout(request)
return redirect(reverse('user_b_login'))
Give this a try
from django.views import View
class LogOutView(View):
def get(self, request, *args, **kwargs):
logout(request)
if request.user.usertype_a:
return redirect(reverse('user_a_login'))
return redirect(reverse('user_b_login'))
Or you can Use LogoutView and override its dispatch method for custom redirections
Try to add this to your urls.py:
from django.contrib.auth import views as auth_views
path('logout/', auth_views.LogoutView.as_view(), name='logout'),

How to pass extra data to fastapi APIRouter?

This is my 1st fastapi exercise. I've my old model serving code implemented with Flask as following:
class HealthCheck(Resource):
def __init__(self, **kwargs):
super(HealthCheck, self).__init__()
self._model = kwargs['model']
self._logger = kwargs['logger']
def get(self):
if self._model:
return {"status" : "healthy"}, HTTPStatus.OK
return {"status": "unavailable"}, HTTPStatus.BAD_REQUEST
def put(self):
raise MethodNotAllowed('PUT request not supported')
# similarly other methods are disabled
# In a different module, say in App class
class App():
def __init__(self, name, logger, config):
self._logger = logger
self._model = load_model(config['model_path'])
self._flask_app = Flask(name)
api = Api(self._flask_app)
# logger and model is passed to HealthCheck resource
api.add_resource(HealthCheck, "/api/healthcheck",
resource_class_kwargs={'model': self._model, 'logger': self._logger})
How do I achieve same with fastapi APIRouter?
My example fastapi implementation is following:
class HealthResult(BaseModel):
healthy: bool
health_router = fastapi.APIRouter()
#health_router.get("/healthcheck", response_model=HealthResult, name="heathcheck")
async def heartbeat() -> HealthResult:
hb = HealthResult(healthy=True)
return hb
# in the App module
class App():
def __init__(self, name, logger, config):
self._logger = logger
self._model = load_model(config['model_path'])
self._api = fastapi.FastAPI(title=name)
self._api.include_router(health_router, prefix="/api")
# how do I pass model and logger to health_router to use that in heartbeat method?
I want to avoid using any global storage for model and logger and access in health_router from there.
Also, since my fastapi object is inside App class, how can I invoke multiple worker with uvicorn in this case?
Though I don't like it, I modified my App class as following to get around the problem - still looking for cleaner solution.
class App(metaclass=Singleton):
_MODEL: Union[None, Model] = None
_LOGGER: Union[None, CustomLogger] = None
#classmethod
def setLogger(cls, logger: CustomLogger) -> None:
cls._LOGGER = logger
#classmethod
def getLogger(cls) -> CustomLogger:
return cls._LOGGER
#classmethod
def setModel(cls, model: Model) -> None:
assert model
cls._MODEL = model
#classmethod
def getModel(cls) -> Model:
return cls._MODEL
def __init__(self, name: str, logger: CustomLogger, config: YAML) -> None:
App.setLogger(logger)
model: Model = load_model(config['model_path'])
App.setModel(model)
self._api = fastapi.FastAPI(title=name)
self._api.include_router(health_router, prefix="/api")
....
class HealthResult(BaseModel):
healthy: bool
health_router = fastapi.APIRouter()
#health_router.get("/healthcheck", response_model=HealthResult, name="heathcheck")
async def heartbeat() -> HealthResult:
model: Model = App.getModel()
hb: HealthResult = HealthResult(healthy=True) if model else HealthResult(healthy=False)
return hb
from fastapi import Request
app = FastAPI()
app.share_text = 'aaa'
# in Apirouter
#router.get("/share}", request: Request)
async def read( request: Request):
#retrieve from app context
share_text = request.app.share_text
return {}
You could retrive the app context from Request
Ref: https://fastapi.tiangolo.com/advanced/using-request-directly/#use-the-request-object-directly
Ref: https://www.starlette.io/requests/
Application The originating Starlette application can be accessed via
request.app.
Other state If you want to store additional information on the request
you can do so using request.state.
For example:
request.state.time_started = time.time()

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 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