Skip to content

Instantly share code, notes, and snippets.

@abhijangda
Last active December 18, 2015 13:19
Show Gist options
  • Select an option

  • Save abhijangda/5788737 to your computer and use it in GitHub Desktop.

Select an option

Save abhijangda/5788737 to your computer and use it in GitHub Desktop.
import kivy
import re
import os, sys, imp, inspect
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
from kivy.base import runTouchApp
from kivy.factory import Factory
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.uix.sandbox import Sandbox
class WidgetRule(object):
def __init__(self, widget, parent):
super(WidgetRule, self).__init__()
self.name = widget
self.parent = parent
self.file = None
self.module = None
class ClassRule(WidgetRule):
def __init__(self, class_name):
super(ClassRule, self).__init__(class_name, None)
class RootRule(ClassRule):
def __init__(self, class_name):
super(RootRule, self).__init__(class_name, None)
class ProjectLoaderException(Exception):
pass
class ProjectLoader(object):
'''ProjectLoader class, used to load Project
'''
def _get_file_list(self, path):
file_list = []
sys.path.insert(0, path)
for _file in os.listdir(path):
file_path = os.path.join(path, _file)
if os.path.isdir(file_path):
file_list += self._get_file_list(file_path)
else:
#Consider only py files
if file_path[file_path.rfind('.'):] == '.py':
file_list.append(file_path)
return file_list
def load_project(self, kv_path):
self.cleanup()
self.kv_path = kv_path
#Remove all the 'app' lines
f = open(self.kv_path, 'r')
kv_string = f.read()
f.close()
for app_str in re.findall(r'.+app+.+', kv_string):
kv_string = kv_string.replace(app_str, '#'+app_str)
root_rule = Builder.load_string(kv_string)
self.root_rule = None
if root_rule:
self.root_rule = RootRule(str(root_rule))
self.class_rules = []
#Get all the class_rules
for class_str in re.findall(r'<+([\w_]+)>', kv_string):
self.class_rules.append(ClassRule(class_str))
self.proj_dir = kv_path[:kv_path.rfind('/')]
parent_proj_dir = self.proj_dir[:self.proj_dir.rfind('/')]
sys.path.insert(0, parent_proj_dir)
self.file_list = self._get_file_list(self.proj_dir)
self._get_class_files()
self._list_modules = []
def _app_in_string(self, s):
if 'runTouchApp' in s:
self._app_class = 'runTouchApp'
return True
elif 'kivy.app' in s:
for _class in re.findall(r'\bclass\b.+:', s):
b_index1 = _class.find('(')
b_index2 = _class.find(')')
if _class[b_index1+1:b_index2].strip() == 'App':
self._app_class = _class[_class.find(' '):b_index1].strip()
return True
return False
def _get_class_files(self):
found_app = False
#Search for main.py
for _file in self.file_list:
if _file[_file.rfind('/')+1:] == 'main.py':
f = open(_file, 'r')
s = f.read()
f.close()
if self._app_in_string(s):
self._app_module = __import__(
_file[_file.rfind('/')+1:].replace('.py',''))
self._app_file = _file
found_app = True
#Search for a file with app in its name
if not found_app:
for _file in self.file_list:
if 'app' in _file[_file.rfind('/'):]:
f = open(_file, 'r')
s = f.read()
f.close()
if self._app_in_string(s):
self._app_module = __import__(
_file[_file.rfind('/')+1:].replace('.py',''))
self._app_file = _file
found_app = True
to_find = self.class_rules[:]
if self.root_rule:
to_find.append(self.root_rule)
#If cannot find due to above methods, search every file
for _file in self.file_list:
mod = __import__(_file[_file.rfind('/')+1:].replace('.py',''))
f = open(_file, 'r')
s = f.read()
f.close()
if not found_app and self._app_in_string(s):
self._app_file = _file
found_app = True
for _rule in to_find[:]:
if hasattr(mod, _rule.name):
_rule.file = _file
to_find.remove(_rule)
_rule.module = mod
#Cannot Find App, So, use default runTouchApp
if not found_app:
self._app_class = 'runTouchApp'
self._app_file = None
#to_find should be empty, if not some class's files are not detected
if to_find != []:
raise ProjectLoaderException(
'Cannot find class files for all classes')
def cleanup(self):
self._app_file = None
self._app_class = None
self._app_module = None
self._app = None
self.file_list = []
def get_app(self):
if not self._app_file or not self._app_class or not self._app_module:
return App.get_running_app()
if self._app:
return self._app
for name, obj in inspect.getmembers(self._app_module):
if inspect.isclass(obj) and self._app_class == name:
self._app = obj()
return self._app
#if still couldn't get app, although that shouldn't happen
return App.get_running_app()
def get_widget_of_class(self, class_name):
self.root = getattr(Factory, class_name)()
return self.root
box = BoxLayout(size_hint=[1,1], pos_hint={'top': 1})
s = Sandbox()
button = None
def button_press(*args):
box.remove_widget(button)
with s:
proj_loader = ProjectLoader()
proj_loader.load_project('/home/abhi/kivy_designer/test/test/test.kv')
w = proj_loader.get_widget_of_class("Designer")
box.add_widget(w)
button = Button(text='presss me', on_press=button_press)
box.add_widget(button)
s.add_widget(box)
runTouchApp(s)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment