How to set an icon in Kivy? - python

I want to set my own icon in my kivy app, but its not working. I have tried both with icon.ico and icon.png.
This is what i have tried:
class MyApp(App):
def build(self):
self.icon = 'myicon.png'
and:
from kivy.config import Config
Config.set('kivy','window_icon','icon.ico')

Your icon path needs to be either absolute or relative to your application file. So if your directory structure looks like this:
my_app/
├── app.py
└── things
└── images
└── my_icon.png
Then you're going to need
class MyApp:
def build(self):
self.icon = r'C:\Users\you\path\to\my_app\things\images\my_icon.png'
Obviously you'll want to replace that with the actual path. You should also be able to have
self.icon = r'things\images\my_icon.png'
but I'm not sure about that.

Related

Python - Inherit from a class in a submodule

In order to get a code easier to maintain, I wanted to split classes in different files, classified per role.
Everyting is placed into the same directory, with a init.py file to obtain a submodule.
Something like that :
Resources
|- __init__.py
|- main_code.py
|- resources.py
|--- classes
|- __init__.py
|- solutions.py
|- tests.py
But as in some classes of the tests.py, I inherit from other classes located in solutions.py, I've imported the solutions.py using :
from . import solutions
Here is an example of my code in tests.py :
from . import solutions
class snapshot(solutions.device):
def __init__(self, d):
solutions.device.__init__(self, d)
self.ip = d
But doing that, I've got the following error:
AttributeError: module 'solutions' has no attribute 'device'
I've also tried with :
from resources.classes import solutions
But I've got the same result.
Thanks for your help,
EDIT
Here is the solutions.py :
class device:
def __init__(self, d: str, **kwargs):
self.info = d
username = kwargs.get("username", None)
password = kwargs.get("password", None)
action = kwargs.get("action", None)
vault = kwargs.get("vault", None)
self.init_connection(username, password, vault)
<--- ommitted for visibility --->
When everything was located into the same classes.py file, it worked perfectly.
Maybe you can do
from .solutions import device
in tests.py

How can I tell pyreverse to include classes within modules within packages?

I have this folder structure:
.
└── src
├── a
│   ├── __init__.py
│   ├── a.py
│   └── b.py
└── main.py
Contents of a/a.py:
class A:
def __init__(self):
self.name = 'a'
Contents of a/b.py
from a.a import A
class B(A):
def __init__(self):
self.name = 'b'
Conents of main.py:
from a.a import A
from a.b import B
print(A().name)
print(B().name)
As you can see, class B inherits from class A
I have confirmed that the program works as expected, so there are no errors in the code
I wish to run something along the lines of: pyreverse src/**/* -o png and generate a UML diagram showing me that class B inherits from class A (I have a bigger project with many more directories, hence the reason for the **/* part).
However, what I am getting at the moment is this:
The expected would be something like this:
Answering my own question: the answer was to simply cd to src/, or do this:
export PYTHONPATH="${PYTHONPATH}:${PWD}/src"

Cant inherit TestCase from another file

im using the unittest Framework to test my flask application. Since i have multiple Testcase classes i want to structure/refactor them.
BaseTest.py contains:
import unittest
from config import Config
from app import create_app, db
class TestConfig(Config):
""" overridden config for testing """
class TestInit(unittest.TestCase):
def setUp(self):
self.app = create_app(TestConfig)
self.app_context = self.app.app_context()
self.app_context.push()
self.app = self.app.test_client()
db.create_all()
def tearDown(self):
db.session.remove()
db.drop_all()
self.app_context.pop()
Then i try to have testcases in
ProjectTest.py:
from app.models import *
from tests.BaseTest import TestInit
class ProjectTest(TestInit):
def setUp(self):
super().setUp()
# create Test Data
proj1 = Project(
name='TestProject1',
project_state_id=1,
project_type_id=1
)
db.session.add(proj1)
db.session.commit()
for pro in Project.query.all():
print(pro)
def test_project_add(self):
pass
i get the error message:
ModuleNotFoundError: No module named 'tests.BaseTest'; 'tests' is not a package
I have all theses files in the folder tests and tried all variation on how to import it (even with a __init__.py file) but i always get the error.
if your source codes are in the same folder, you don't need to import tests.BaseTest
because interpreter shouldn't look anywhere else except current folder.
just importing BaseTest would be enough.
edited code would be:
from BaseTest import TestInit

Howto access an already initialized class variable in main.py from another class

I have a class with a set of variables that is initialized and accessed from my main.py script. I have another class that is imported from a folder one level deep from the main.py file.
I can access the already set variables anywhere in my main.py file by referencing appVars.some_variable. However, I am not able to access them in the --screen1.py class. It seems the --Variables.py class is being reinitialized in the nested class which results in a blank value.
How do I access the already initialized class variable from the main.py script inside of my --ScreenOne.py script?
File/Folder Structure
main.py
-classes
--ScreenOne.py
--Variables.py
variables.py
from kivy.properties import StringProperty
class Variables():
def __init__(self):
self.server_time = StringProperty('')
main.py
from classes.ScreenOne import ScreenOne
from classes.Variables import Variables
appVars = Variables()
class SomeApp(App):
def update_clock(self, *args):
appVars.server_time = datetime.now()
--ScreenOne.py
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import StringProperty
from classes.Variables import Variables
class ScreenOne(Screen):
def on_enter(self):
print(Variables.server_time)
I have also tried adding appVars = Variables() to the beginning of the --ScreenOne.py script and referencing appVars.server_time however, it did not work as well.
In main.py you initiate class Variables by appVars = Variables(). But in ScreenOne you import Variables but never initiate it, besides initiating it will give a new instance not the same as appVars in main (also print(Variables.server_time) will give an error).
To use appVars in ScreenOne you will need to pass appVars to this class, like:
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import StringProperty
class ScreenOne(Screen):
def __init__(self, appVars):
self.appVars = appVars
def on_enter(self):
print(self.appVars.server_time)
Then when you initiate ScreenOne you do something like:
screen_one = ScreenOne(appVars)
Note in ScreenOne, you do not need to import Variables as all attributes of this class will come with appVars.
By the way as per PEP8 variable names should not use capitals but underscore instead, appVars -> app_vars.

Python metaClass and import *

Main Goal: Automatically register classes (by a string) in a factory to be created dynamically at run time using that string, classes can be in their own file and not grouped in one file.
I have couple of classes which all inherit from the same base class and they define a string as their type.
A user wants to get an instance of one of these classes but only knows the type at run time.
Therefore I have a factory to create an instance given a type.
I didn't want to hard code an "if then statements" so I have a meta class to register all the sub classes of the base class:
class MetaRegister(type):
# we use __init__ rather than __new__ here because we want
# to modify attributes of the class *after* they have been
# created
def __init__(cls, name, bases, dct):
if not hasattr(cls, 'registry'):
# this is the base class. Create an empty registry
cls.registry = {}
else:
# this is a derived class. Add cls to the registry
interface_id = cls().get_model_type()
cls.registry[interface_id] = cls
super(MetaRegister, cls).__init__(name, bases, dct)
The problem is that for this to work the factory has to import all the subclass (So the meta class runs).
To fix this you can use from X import *
But for this to work you need to define an __all__ var in the __init__.py file of the package to include all the sub classes.
I don't want to hard code the sub classes because it beats the purpose of using the meta class.
I can go over the file in the package using:
import glob
from os.path import dirname, basename, isfile
modules = glob.glob(dirname(__file__) + "/*.py")
__all__ = [basename(f)[:-3] for f in modules if isfile(f)]
Which works great, but the project needs to compile to a single .so file, which nullifies the use of the file system.
So how could I achieve my main goal of creating instances at run time without hard codding the type?
Is there a way to populate an __all__ var at run time without touching the filesystem?
In Java I'd probably decorate the class with an annotation and then get all the classes with that annotation at run time, is there something similar on python?
I know there are decorators in python but I'm not sure I can use them in this way.
Edit 1:
Each subclass must be in a file:
- Models
-- __init__.py
-- ModelFactory.py
-- Regression
--- __init__.py
--- Base.py
--- Subclass1.py
--- Subclass2ExtendsSubclass1.py
Edit 2: Some code to Illustrate the problem:
+ main.py
|__ Models
|__ __init__.py
|__ ModelFactory.py
|__ Regression
|__ init__.py
|__ Base.py
|__ SubClass.py
|__ ModelRegister.py
main.py
from models.ModelFactory import ModelFactory
if __name__ == '__main__':
ModelFactory()
ModelFactory.py
from models.regression.Base import registry
import models.regression
class ModelFactory(object):
def get(self, some_type):
return registry[some_type]
ModelRegister.py
class ModelRegister(type):
# we use __init__ rather than __new__ here because we want
# to modify attributes of the class *after* they have been
# created
def __init__(cls, name, bases, dct):
print cls.__name__
if not hasattr(cls, 'registry'):
# this is the base class. Create an empty registry
cls.registry = {}
else:
# this is a derived class. Add cls to the registry
interface_id = cls().get_model_type()
cls.registry[interface_id] = cls
super(ModelRegister, cls).__init__(name, bases, dct)
Base.py
from models.regression.ModelRegister import ModelRegister
class Base(object):
__metaclass__ = ModelRegister
def get_type(self):
return "BASE"
SubClass.py
from models.regression.Base import Base
class SubClass(Base):
def get_type(self):
return "SUB_CLASS"
Running it you can see only "Base" it printed.
Using a decorator gives the same results.
A simple way to register classes as runtime is to use decorators:
registry = {}
def register(cls):
registry[cls.__name__] = cls
return cls
#register
class Foo(object):
pass
#register
class Bar(object):
pass
This will work if all of your classes are defined in the same module, and if that module is imported at runtime. Your situation, however, complicates things. First, you want to define your classes in different modules. This means that we must be able to dynamically determine which modules exist within our package at runtime. This would be straightforward using Python's pkgutil module, however, you also state that you are using Nuitka to compile your package into an extension module. pkgutil doesn't work with such extension modules.
I cannot find any documented way of determining the modules contained within an Nuitka extension module from within Python. If one does exist, the decorator approach above would work after dynamically importing each submodule.
As it is, I believe the most straightforward solution is to write a script to generate an __init__.py before compiling. Suppose we have the following package structure:
.
├── __init__.py
├── plugins
│   ├── alpha.py
│   └── beta.py
└── register.py
The "plugins" are contained within the plugins directory. The contents of the files are:
# register.py
# -----------
registry = {}
def register(cls):
registry[cls.__name__] = cls
return cls
# __init__.py
# -----------
from . import plugins
from . import register
# ./plugins/alpha.py
# ------------------
from ..register import register
#register
class Alpha(object):
pass
# ./plugins/beta.py
# ------------------
from ..register import register
#register
class Beta(object):
pass
As it stands, importing the package above will not result in any of the classes being registered. This is because the class definitions are never run, since the modules containing them are never imported. The remedy is to automatically generate an __init__.py for the plugins folder. Below is a script which does exactly this -- this script can be made part of your compilation process.
import pathlib
root = pathlib.Path('./mypkg/plugins')
exclude = {'__init__.py'}
def gen_modules(root):
for entry in root.iterdir():
if entry.suffix == '.py' and entry.name not in exclude:
yield entry.stem
with (root / '__init__.py').open('w') as fh:
for module in gen_modules(root):
fh.write('from . import %s\n' % module)
Placing this script one directory above your package root (assuming your package is called mypkg) and running it yields:
from . import alpha
from . import beta
Now for the test: we compile the package:
nuitka --module mypkg --recurse-to=mypkg
and try importing it, checking to see if all of the classes were properly registered:
>>> import mypkg
>>> mypkg.register.registry
{'Beta': <class 'mypkg.plugins.beta.Beta'>,
'Alpha': <class 'mypkg.plugins.alpha.Alpha'>}
Note that the same approach will work with using metaclasses to register the plugin classes, I simply preferred to use decorators here.
If the reflected classes are using your metaclass, you don't need to use from X import * to get them registered. Only import X should be enough. As soon as the module containing the classes is imported, the classes will be created and available in your metaclass registry.
I would do this with dynamic imports.
models/regression/base.py:
class Base(object):
def get_type(self):
return "BASE"
models/regression/subclass.py:
from models.regression.base import Base
class SubClass(Base):
def get_type(self):
return "SUB_CLASS"
__myclass__ = SubClass
loader.py:
from importlib import import_module
class_name = "subclass"
module = import_module("models.regression.%s" % class_name)
model = module.__myclass__()
print(model.get_type())
And empty __init__.py files in models/ and models/regression/
With:
nuitka --recurse-none --recurse-directory models --module loader.py
The resulting loader.so contains all the modules under the models/ subdirectory.

Categories

Resources