Wrong Icon on Kivy Window in Windows - python

I have a Kivy application that otherwise works fine. In my App class, I have the following...
class OmissionApp(App):
"""
Application-level class, builds the application
"""
def __init__(self, **kwargs):
"""
Initialize a new OmissionWindow.
"""
super().__init__(**kwargs)
# Some other init stuff
def build_config(self, config):
"""
Configure the application.
"""
# Icon
Config.set('kivy', 'window_icon', 'resources/icons/omission_icon.png')
# And more stuff...
def build(self):
"""
This function starts the application by constructing
it from widgets and properties.
"""
# Set the title and icon.
self.title = "Omission"
self.icon = "resources/icons/omission_icon.png"
# Create the window.
omission_app = OmissionWindow()
# And more...
# Return the application.
return omission_app
So, this works just fine on Ubuntu (16.04, 17.10), but on Microsoft Windows (7), it isn't showing the icon at all.
My file tree looks roughly like this (I left some irrelevant stuff out)...
.
├── omission/
│ ├── data/
│ ├── game/
│ ├── interface/
│ ├── resources/
│ │ ├── audio/
│ │ ├── content/
│ │ ├── font/
│ │ └── icons/
│ │ ├── omission_icon.ico
│ │ └── omission_icon.png
│ ├── __init__.py
│ ├── __main__.py
│ └── run.py
└── omission.spec
I've tried several ways of doing this (although the documentation indicates the code itself is right.) Also, again, it works on Ubuntu. I've tried using an *.ico icon file instead of the *.png, but no luck.
How do I get the icon working on Microsoft Windows?

The example given in the documentation works because it's just a filename - the actual icon file exists in the same folder as the application.
Moving the icon to the application root, and then changing the code to the following, does work on any system.
self.icon = "omission_icon.png"
But, since I have my icon in a subdirectory, I now am dealing with a filepath. It's really easy to forget that paths on UNIX and Windows are not the same. Hardcoded paths, simply put, are not portable.
Thus, I need to fix this by creating a portable system path, via os.path.
import os.path
# ...
Config.set('kivy', 'window_icon', os.path.join("omission", "resources", "icons", "omission_icon.png"))
# ...
self.icon = os.path.join("omission", "resources", "icons", "omission_icon.png")
The os.path starts from the current directory by default. In this case, that happens to be the parent of the application's directory.
NOTE: Technically, you can leave the "omission" directory off, but it won't work after you've packaged with PyInstaller. The way above works either way.
Now our icon works on any system!
NOTE: Yes, I know this may seem bright-blazingly obvious, but I walked in circles long enough before spotting the obvious that it seemed worthy of a Q&A.

Related

How to define callbacks in separate files? (plotly dash)

Background
Dash web applications have a dash application instance, usually named app, and initiated like this:
app = dash.Dash(__name__)
Then, callbacks are added to the application using a callback decorator:
#app.callback(...)
def my_function(...):
# do stuff.
In most of the tutorials you find, the callbacks are defined with all of the application layout in the app.py. This of course is just the MWE way of doing things. In a real application, separating code to modules and packages would greatly improve readability and maintainability, but naively separating the callbacks to and layouts just results into circular imports.
Question
What would be the correct way to separate callbacks and layouts from the app.py in a single page app?
MWE
Here is a minimal (non-)working example with the problem
File structure
.
├── my_dash_app
│   ├── app.py
│   └── views
│   ├── first_view.py
│   └── __init__.py
└── setup.py
setup.py
import setuptools
setuptools.setup(
name='dash-minimal-realworld',
version='1.0.0',
install_requires=['dash>=1.12.0'],
packages=setuptools.find_packages(),
)
app.py
import dash
from my_dash_app.views.first_view import make_layout
app = dash.Dash(__name__)
app.layout = make_layout()
if __name__ == '__main__':
app.run_server(debug=True)
first_view.py
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
from my_dash_app.app import app
def make_layout():
return html.Div([
dcc.Input(id='my-id', value='initial value', type='text'),
html.Div(id='my-div')
])
#app.callback(Output(component_id='my-div', component_property='children'),
[Input(component_id='my-id', component_property='value')])
def update_output_div(input_value):
return 'You\'ve entered "{}"'.format(input_value)
Running python ./my_dash_app/app.py results into circular dependency:
ImportError: cannot import name 'make_layout' from 'my_dash_app.views.first_view' (c:\tmp\dash_minimal_realworld\my_dash_app\views\first_view.py)
I don't think (but I might be wrong) that there's a correct way of doing it per se, but what you could do it have a central module (maindash.py) around your startup code app = dash.Dash(__name__), and have different callbacks simply import app from my_dash_app.maindash. This would set up the callbacks in their own separate modules but re-use that one central module for the app instance.
It's easiest to show an overview of it like this:
app.py being the main script called to start everything up. maindash.py is in charge of creating the main app instance. first_view.py is where the decorators are defined to set up all the callbacks.
Here's the result:
.
├── my_dash_app
│ ├── app.py
│ ├── maindash.py
│ └── views
│ ├── first_view.py
│ └── __init__.py
└── setup.py
Since imports are re-used in Python, there's no real harm in doing from my_dash_app.maindash import app several times from different other modules, such as event handlers and the main script. They'll share the same import instance - thus re-using the dash.Dash() instance as well.
Just make sure you import the central module before setting up the handlers, and you should be good to go.
Here's the code snippets separated for testing:
app.py
from my_dash_app.maindash import app
from my_dash_app.views.first_view import make_layout
if __name__ == '__main__':
app.layout = make_layout()
app.run_server(debug=True)
maindash.py
import dash
app = dash.Dash(__name__)
first_view.py
from my_dash_app.maindash import app
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
def make_layout():
return html.Div([
dcc.Input(id='my-id', value='initial value', type='text'),
html.Div(id='my-div')
])
#app.callback(Output(component_id='my-div', component_property='children'),
[Input(component_id='my-id', component_property='value')])
def update_output_div(input_value):
return 'You\'ve entered "{}"'.format(input_value)
A little late to the party but I have found this to be a straightforward way of doing it:
You create a separate script called 'callbacks.py' (for example)
Define a function within callbacks.py which takes a dash.Dash object (i.e. the app) as a parameter (you can of course pass more arguments if necessary) and within which you define all your callbacks as you normally would in the main script:
def get_callbacks(app):
#app.callback([Output("figure1", "figure")],
[Input("child1", "value")])
def callback1(figure):
return
#app.callback([Output("figure2", "figure")],
[Input("child2", "value")])
def callback2(figure):
return
Within the main script, simply import the function and call it after instantiating the dash.Dash object passing the same object into it:
import dash
from callbacks import get_callbacks
import layout
app = dash.Dash(__name__)
app.layout = layout.layout
get_callbacks(app)
I know it is too late to answer your question here, but maybe someone else will find it useful.
I wanted to be able to create callbacks in separate files, however I think that although importing an app from main dash module works well, it may be unclear for other people who read the code.
I created a callback manager used to initialize callbacks. This manager is attached to an app in the main app module.
callbacks_manager.py
from dataclasses import dataclass, field
from typing import Callable, List, Union
from dash.dependencies import handle_callback_args
from dash.dependencies import Input, Output, State
#dataclass
class Callback:
func: Callable
outputs: Union[Output, List[Output]]
inputs: Union[Input, List[Input]]
states: Union[State, List[State]] = field(default_factory=list)
kwargs: dict = field(default_factory=lambda: {"prevent_initial_call": False})
class CallbackManager:
def __init__(self):
self._callbacks = []
def callback(self, *args, **kwargs):
output, inputs, state, prevent_initial_call = handle_callback_args(
args, kwargs
)
def wrapper(func):
self._callbacks.append(Callback(func,
output,
inputs,
state,
{"prevent_initial_callback": prevent_initial_call}))
return wrapper
def attach_to_app(self, app):
for callback in self._callbacks:
app.callback(
callback.outputs, callback.inputs, callback.states, **callback.kwargs
)(callback.func)
callbacks.py
import dash
from callback_manager import CallbackManager
callback_manager = CallbackManager()
#callback_manager.callback(
dash.dependencies.Output('label', 'children'),
[dash.dependencies.Input('call_btn', 'n_clicks')])
def update_label(n_clicks):
if n_clicks > 0:
return "Callback called!"
app.py
import dash
import dash_html_components as html
from callbacks import callback_manager
app = dash.Dash(__name__)
callback_manager.attach_to_app(app)
app.layout = html.Div([
html.Div(id="label"),
html.Button('Call callback', id='call_btn', n_clicks=0),
])
if __name__ == '__main__':
app.run_server(debug=True)
Note that you can have multiple files with callbacks and import them with as keyword:
from callbacks1 import callback_manager as callback_manager1
from callbacks2 import callback_manager as callback_manager2
app = dash.Dash(__name__)
callback_manager1.attach_to_app(app)
callback_manager2.attach_to_app(app)
I believe doing it this way is more explicit.
You can just use the decorator #dash.callback instead of #app.callback. Then remove the line from my_dash_app.app import app in first_view.py and you'll get rid of the circular dependency.
From the documentation: #dash.callback is an alternative to #app.callback (where app = dash.Dash()) introduced in Dash 2.0. It allows you to register callbacks without defining or importing the app object. The call signature is identical and it can be used instead of app.callback in all cases.
This is a rather late response to an older post, but here's a very simple way to completely separate layout, callbacks, and app, without introducing additional complexity.
app.py
from dash import Dash
from layouts import my_layout
from callbacks import my_callback, my_callback_inputs, my_callback_outputs
if __name__ == "__main__":
app = Dash(__name__)
app.layout = my_layout
app.callback(my_callback_outputs, my_callback_inputs)(my_callback)
app.run_server()
It works by not using the decorator syntax, which is supposed to be "syntactic sugar" to make things simpler. However, for this specific problem, many of the proposed solutions actually increase coupling and complexity while retaining the decorator syntax. In this case, it's simpler just not to use the decorator.
In callbacks.py, my_callback is defined without any decorator:
callbacks.py
my_callback_inputs = []
my_callback_outputs = []
def my_callback():
return

monkeypatch a function that needs to be imported in conftest

I'm trying to use pytest.monkeypatch to patch a function I've defined in another file. I then need to patch a function from another that relies on this first monkeypatch. Here's a simple example
# class_def.py
class C:
def __init__(self):
# Normally, there is something that makes self.p
# that will use a file that will exist on production
raise FileNotFoundError
def factory():
print('in factory')
return C()
----
# function_def.py
from .class_def import factory
foo = factory()
def bar():
return 0
----
# conftest.py
from unittest.mock import MagicMock
import pytest
import playground.class_def
#pytest.fixture(autouse=True)
def patch_c(monkeypatch):
fake_c = MagicMock()
def factory():
print('in monkey factory')
return fake_c
monkeypatch.setattr('playground.class_def.factory', factory)
from .function_def import bar
# Then I would patch bar
And running pytest . will fail with FileNotFoundError. I believe this happens because I am calling foo = factory() at the top level of function_def.py. I expected this not to happen because I am patching factory before doing this import, but that doesn't seem to be happening. Is there a way to ensure this monkeypatch.setattr will go into effect before from .function_def import bar in conftest.py?
Also, the file structure looks like
playground
|--- __init__.py
|--- conftest.py
|--- class_def.py
|--- function_def
You have direct access to the attribute you want to change. You don't need monkeypatch at all.
Here's my tree :
$ tree .
.
├── a.py
├── b.py
├── __init__.py
└── test_a.py
0 directories, 4 files
a.py
class A:
def __init__(self):
raise Exception
def factory():
return A()
b.py
import a
print(a.factory())
test_a.py
import a
def test_a():
def fake_factory():
return 'A'
a.factory = fake_factory
import b
And it works:
$ pytest
=============================================================================================== test session starts ===============================================================================================
platform linux -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /home/ahorgnies/test/monkeypatch, inifile:
plugins: remotedata-0.2.1, openfiles-0.3.0, doctestplus-0.1.3, arraydiff-0.2
collected 1 item
test_a.py . [100%]
============================================================================================ 1 passed in 0.01 seconds =============================================================================================

Python3 relative imports

I'm tired of reading one-off use cases of relative imports so I figured I'd as a question to get an example of how to do a relative import from a directory above and bellow, for both importing module functions and class objects.
directory structure:
.
├── lib
│   ├── __init__.py
│   └── bar.py
└── src
├── main.py
└── srclib
├── __init__.py
└── foo.py
bar.py
def BarFunc():
print("src Bar function")
class BarClass():
def __inti__(self):
print("src Bar Class")
def test(self):
print("BarClass working")
foo.py
def FooFunction():
print("srclib Foo function")
class FooClass():
def __init__(self):
print("srclib Foo Class")
def test(self):
print("FooClass working")
Question: What is the syntax in python 3 to import for these use cases?
main.py
# What is the syntax to import in python 3?
# I want to be able to call FooFunc()
foo.FooFunc()
# I want to be able to create a FooClass() object
foo_class = foo.FooClass()
foo_class.test()
# I want to be able to call FooFunc()
bar.BarFunc()
# I want to be able to create a BarClass() object
bar_class = bar.BarClass()
bar_class.test()
It all depends on where you start your python interpreter from. In your case, I would suggest you to start the interpreter from your project's root directory while making the following changes:
In file src/srclib/__init__.py add:
from . import foo
The reason for doing this is to explicitly state in your __init__.py file what to import from your module.
In your main.py file, add the following:
from lib import bar
from src.srclib import foo
Hope this helps!

Python - Intra-package importing when package modules are sometimes used as standalone?

Sorry if this has already been answered using terminology I don't know to search for.
I have one project:
project1/
class1.py
class2.py
Where class2 imports some things from class1, but each has its own if __name__ == '__main__' that uses their respective classes I run frequently. But then, I have a second project which creates a subclass of each of the classes from project1. So I would like project1 to be a package, so that I can import it into project2 nicely:
project2/
project1/
__init__.py
class1.py
class2.py
subclass1.py
subclass2.py
However, I'm having trouble with the importing with this. If I make project1 a package then inside class2.py I would want to import class1.py code using from project1.class1 import class1. This makes project2 code run correctly. But now when I'm trying to use project1 not as a package, but just running code from directly within that directory, the project1 code fails (since it doesn't know what project1 is). If I set it up for project1 to work directly within that directory (i.e. the import in class2 is from class1 import Class1), then this import fails when trying to use project1 as a package from project2.
Is there a way to have it both ways (use project1 both as a package and not as a package)? If there is a way, is it a discouraged way and I should be restructuring my code anyway? Other suggestions on how I should be handling this? Thanks!
EDIT
Just to clarify, the problem arrises because subclass2 imports class2 which in turn imports class1. Depending on which way class2 imports class1 the import will fail from project2 or from project1 because one sees project1 as a package while the other sees it as the working directory.
EDIT 2
I'm using Python 3.5. Apparently this works in Python 2, but not in my current version of python.
EDIT 2: Added code to class2.py to attach the parent directory to the PYTHONPATH to comply with how Python3 module imports work.
import sys
import os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
Removed relative import of Class1.
Folder structure:
project2
- class3.py
- project1
- __init__.py
- class1.py
- class2.py
project2/project1/class1.py
class Class1(object):
def __init__(self):
super(Class1, self).__init__()
self.name = "DAVE!"
def printname(self):
print(self.name)
def run():
thingamy = Class1()
thingamy.printname()
if __name__ == "__main__":
run()
project2/project1/class2.py
import sys
import os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from class1 import Class1
class Class2(Class1):
def childMethod(self):
print('Calling child method')
def run():
thingamy = Class2()
thingamy.printname()
thingamy.childMethod()
if __name__ == "__main__":
run()
project2/class3.py
from project1.class2 import Class2
from project1.class1 import Class1
class Class3(Class2):
def anotherChildMethod(self):
print('Calling another child method')
def run():
thingamy = Class3()
thingamy.printname()
thingamy.anotherChildMethod()
if __name__ == "__main__":
run()
With this setup each of class1, 2 and 3 can be run as standalone scripts.
You could run class2.py from inside the project2 folder, i.e. with the current working directory set to the project2 folder:
user#host:.../project2$ python project1/class2.py
On windows that would look like this:
C:\...project2> python project1/class2.py
Alternatively you could modify the python path inside of class2.py:
import sys
sys.path.append(".../project2")
from project1.class1 import class1
Or modify the PYTHONPATH environment variable similarly.
To be able to extend your project and import for example something in subclass1.py from subclass2.py you should consider starting the import paths always with project2, for example in class2.py:
from project2.project1.class1 import class1
Ofcourse you would need to adjust the methods I just showed to match the new path.

Package python codes which uses __import__ function

My directory structure is:
./
├── foo
│   ├── bar.py
│   ├── foo.py
│   └── __init__.py
└── main.py
with:
bar.py:
def get_data():
return 'ha'
foo.py:
class foo:
def __init__(self):
self.lib = __import__('bar', fromlist=['bar'])
self.data = self.lib.get_data()
def print_data(self):
print(self.data)
if __name__=='__main__':
f = foo()
f.print_data()
__init__.py:
from foo import foo
and main.py:
from foo import foo
a = foo()
a.print_data()
Running python foo.py I get ha correctly, but running python main.py I get the following message:
Traceback (most recent call last):
File "main.py", line 3, in <module>
a = foo()
File ".../foo/foo.py", line 3, in __init__
self.lib = __import__('bar')
ImportError: No module named bar
My requirements are 1) making foo to work like a package, 2) using __import__ in foo.py's __init__ function instead of import in the first line of foo.py.
I changed line 3 of foo.py to self.lib = __import__('foo.bar', fromlist=['bar']), and then got the correct answer. But that is not I want, since running python foo.py will lead to a failure and that is not a package solution when the whole directory ./ become another package. It seems an import path problem that I cannot figure out.
Changing foo.py to that makes it work correctly:
import importlib
class foo:
def __init__(self):
self.lib = importlib.import_module('foo.bar')
self.data = self.lib.get_data()
def print_data(self):
print(self.data)
if __name__=='__main__':
f = foo()
f.print_data()

Categories

Resources