From 13f50ab62f8886dfe514b07ae56860c68f574ada Mon Sep 17 00:00:00 2001 From: Matthew Einhorn Date: Sun, 2 Jun 2019 23:48:54 -0400 Subject: [PATCH 01/13] kivy_deps need to be imported before any modules. --- kivy/__init__.py | 80 +++++++++++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/kivy/__init__.py b/kivy/__init__.py index 6e7f36337..e39e3ac58 100644 --- a/kivy/__init__.py +++ b/kivy/__init__.py @@ -265,6 +265,45 @@ kivy_config_fn = '' #: Kivy user modules directory kivy_usermodules_dir = '' +# if there are deps, import them so they can do their magic. +import kivy.deps +_packages = [] +for importer, modname, ispkg in pkgutil.iter_modules(kivy.deps.__path__): + if not ispkg: + continue + if modname.startswith('gst'): + _packages.insert(0, (importer, modname, 'kivy.deps')) + else: + _packages.append((importer, modname, 'kivy.deps')) + +try: + import kivy_deps + for importer, modname, ispkg in pkgutil.iter_modules(kivy_deps.__path__): + if not ispkg: + continue + if modname.startswith('gst'): + _packages.insert(0, (importer, modname, 'kivy_deps')) + else: + _packages.append((importer, modname, 'kivy_deps')) +except ImportError: + pass + +_logging_msgs = [] +for importer, modname, package in _packages: + try: + mod = importer.find_module(modname).load_module(modname) + + version = '' + if hasattr(mod, '__version__'): + version = ' {}'.format(mod.__version__) + _logging_msgs.append( + 'deps: Successfully imported "{}.{}"{}'. + format(package, modname, version)) + except ImportError as e: + Logger.warning( + 'deps: Error importing dependency "{}.{}": {}'. + format(package, modname, str(e))) + # Don't go further if we generate documentation if any(name in sys.argv[0] for name in ('sphinx-build', 'autobuild.py')): environ['KIVY_DOC'] = '1' @@ -431,6 +470,9 @@ if not environ.get('KIVY_DOC_INCLUDE'): if platform == 'android': Config.set('input', 'androidtouch', 'android') +for msg in _logging_msgs: + Logger.info(msg) + if RELEASE: Logger.info('Kivy: v%s' % __version__) elif not RELEASE and __hash__ and __date__: @@ -439,44 +481,6 @@ Logger.info('Kivy: Installed at "{}"'.format(__file__)) Logger.info('Python: v{}'.format(sys.version)) Logger.info('Python: Interpreter at "{}"'.format(sys.executable)) -# if there are deps, import them so they can do their magic. -import kivy.deps -_packages = [] -for importer, modname, ispkg in pkgutil.iter_modules(kivy.deps.__path__): - if not ispkg: - continue - if modname.startswith('gst'): - _packages.insert(0, (importer, modname, 'kivy.deps')) - else: - _packages.append((importer, modname, 'kivy.deps')) - -try: - import kivy_deps - for importer, modname, ispkg in pkgutil.iter_modules(kivy_deps.__path__): - if not ispkg: - continue - if modname.startswith('gst'): - _packages.insert(0, (importer, modname, 'kivy_deps')) - else: - _packages.append((importer, modname, 'kivy_deps')) -except ImportError: - pass - -for importer, modname, package in _packages: - try: - mod = importer.find_module(modname).load_module(modname) - - version = '' - if hasattr(mod, '__version__'): - version = ' {}'.format(mod.__version__) - Logger.info( - 'deps: Successfully imported "{}.{}"{}'. - format(package, modname, version)) - except ImportError as e: - Logger.warning( - 'deps: Error importing dependency "{}.{}": {}'. - format(package, modname, str(e))) - from kivy.logger import file_log_handler if file_log_handler is not None: file_log_handler.purge_logs() From d5746b834266be86dda89c91cb598d36e48cf8c2 Mon Sep 17 00:00:00 2001 From: Matthew Einhorn Date: Sun, 2 Jun 2019 23:51:01 -0400 Subject: [PATCH 02/13] Accept post versions. --- kivy/__init__.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/kivy/__init__.py b/kivy/__init__.py index e39e3ac58..009b0a95d 100644 --- a/kivy/__init__.py +++ b/kivy/__init__.py @@ -80,11 +80,11 @@ if sys.version_info[0] == 2: def parse_kivy_version(version): """Parses the kivy version as described in :func:`require` into a 3-tuple - of ([x, y, z], 'rc|a|b|dev', 'N') where N is the tag revision. The last - two elements may be None. + of ([x, y, z], 'rc|a|b|dev|post', 'N') where N is the tag revision. The + last two elements may be None. """ m = re.match( - '^([0-9]+)\\.([0-9]+)\\.([0-9]+?)(rc|a|b|\\.dev)?([0-9]+)?$', + '^([0-9]+)\\.([0-9]+)\\.([0-9]+?)(rc|a|b|\\.dev|\\.post)?([0-9]+)?$', version) if m is None: raise Exception('Revision format must be X.Y.Z[-tag]') @@ -92,6 +92,8 @@ def parse_kivy_version(version): major, minor, micro, tag, tagrev = m.groups() if tag == '.dev': tag = 'dev' + if tag == '.post': + tag = 'post' return [int(major), int(minor), int(micro)], tag, tagrev @@ -113,7 +115,7 @@ def require(version): Y is the minor version Z is the bugfixes revision - The tag is optional, but may be one of '.dev', 'a', 'b', or 'rc'. + The tag is optional, but may be one of '.dev', '.post', 'a', 'b', or 'rc'. The tagrevision is the revision number of the tag. .. warning:: From 2150f8f2a91b46ff36267dc3ec59d8535be05d36 Mon Sep 17 00:00:00 2001 From: Matthew Einhorn Date: Sun, 2 Jun 2019 23:53:22 -0400 Subject: [PATCH 03/13] Fix share path for venv. --- doc/sources/installation/installation-windows.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/sources/installation/installation-windows.rst b/doc/sources/installation/installation-windows.rst index fd1aad920..73beea48e 100644 --- a/doc/sources/installation/installation-windows.rst +++ b/doc/sources/installation/installation-windows.rst @@ -134,7 +134,9 @@ kivy release (`1.11.0`) and its dependencies. That's it. You should now be able to ``import kivy`` in python or run a basic example if you installed the kivy examples:: - python share\kivy-examples\demo\showcase\main.py + python kivy_venv\share\kivy-examples\demo\showcase\main.py + +Replace `kivy_venv` with the path where python is installed if you didn't use a virtualenv. .. note:: From c4b8743eab60b6d2890b7ed701fb9c50a9dd97be Mon Sep 17 00:00:00 2001 From: matham Date: Mon, 3 Jun 2019 01:32:42 -0400 Subject: [PATCH 04/13] Bump cython to 0.29.10 to fix CI building. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index fe4f5f0b7..574e609d2 100644 --- a/setup.py +++ b/setup.py @@ -85,7 +85,7 @@ def get_version(filename='kivy/version.py'): MIN_CYTHON_STRING = '0.24' MIN_CYTHON_VERSION = LooseVersion(MIN_CYTHON_STRING) -MAX_CYTHON_STRING = '0.29.9' +MAX_CYTHON_STRING = '0.29.10' MAX_CYTHON_VERSION = LooseVersion(MAX_CYTHON_STRING) CYTHON_UNSUPPORTED = ( # ref https://github.com/cython/cython/issues/1968 From 9c6e0519edf4cbc582dd6ca5bc407a9f9dee31e6 Mon Sep 17 00:00:00 2001 From: gottadiveintopython Date: Tue, 4 Jun 2019 02:28:36 +0900 Subject: [PATCH 05/13] fix #6345 --- kivy/uix/carousel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kivy/uix/carousel.py b/kivy/uix/carousel.py index bc1ccece1..c722df863 100644 --- a/kivy/uix/carousel.py +++ b/kivy/uix/carousel.py @@ -191,7 +191,7 @@ class Carousel(StencilView): def _curr_slide(self): if len(self.slides): - return self.slides[self.index] + return self.slides[self.index or 0] current_slide = AliasProperty(_curr_slide, bind=('slides', 'index'), From dbdf14b1df8a7f928cf28ef241be62ddb25fe5d9 Mon Sep 17 00:00:00 2001 From: Matthew Einhorn Date: Mon, 3 Jun 2019 07:03:25 -0400 Subject: [PATCH 06/13] On stdout is bytes so patterns must be one too. Also revert partially #6165. --- kivy/tools/packaging/pyinstaller_hooks/__init__.py | 2 +- kivy/tools/packaging/pyinstaller_hooks/pyi_rth_kivy.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/kivy/tools/packaging/pyinstaller_hooks/__init__.py b/kivy/tools/packaging/pyinstaller_hooks/__init__.py index 828bfaf88..8e06e3a14 100644 --- a/kivy/tools/packaging/pyinstaller_hooks/__init__.py +++ b/kivy/tools/packaging/pyinstaller_hooks/__init__.py @@ -339,7 +339,7 @@ def _find_gst_plugin_path(): return [] (stdoutdata, stderrdata) = p.communicate() - match = re.search(r'\s+(\S+libgstcoreelements\.\S+)', stdoutdata) + match = re.search(rb'\s+(\S+libgstcoreelements\.\S+)', stdoutdata) if not match: return [] diff --git a/kivy/tools/packaging/pyinstaller_hooks/pyi_rth_kivy.py b/kivy/tools/packaging/pyinstaller_hooks/pyi_rth_kivy.py index 84bac18e3..0b5e36bef 100644 --- a/kivy/tools/packaging/pyinstaller_hooks/pyi_rth_kivy.py +++ b/kivy/tools/packaging/pyinstaller_hooks/pyi_rth_kivy.py @@ -5,7 +5,8 @@ root = os.path.join(sys._MEIPASS, 'kivy_install') os.environ['KIVY_DATA_DIR'] = os.path.join(root, 'data') os.environ['KIVY_MODULES_DIR'] = os.path.join(root, 'modules') -os.environ['GST_PLUGIN_PATH'] = os.path.join(sys._MEIPASS, 'gst-plugins') +os.environ['GST_PLUGIN_PATH'] = '{}{}{}'.format( + sys._MEIPASS, os.pathsep, os.path.join(sys._MEIPASS, 'gst-plugins')) os.environ['GST_REGISTRY'] = os.path.join(sys._MEIPASS, 'registry.bin') sys.path += [os.path.join(root, '_libs')] From 40985dac797c924270d98a7135407a91ef634fb5 Mon Sep 17 00:00:00 2001 From: matham Date: Mon, 3 Jun 2019 11:43:09 -0400 Subject: [PATCH 07/13] Encode output to text. --- kivy/tools/packaging/pyinstaller_hooks/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kivy/tools/packaging/pyinstaller_hooks/__init__.py b/kivy/tools/packaging/pyinstaller_hooks/__init__.py index 8e06e3a14..e551a1c9d 100644 --- a/kivy/tools/packaging/pyinstaller_hooks/__init__.py +++ b/kivy/tools/packaging/pyinstaller_hooks/__init__.py @@ -334,12 +334,12 @@ def _find_gst_plugin_path(): try: p = subprocess.Popen( ['gst-inspect-1.0', 'coreelements'], - stdout=subprocess.PIPE) + stdout=subprocess.PIPE, universal_newlines=True) except: return [] (stdoutdata, stderrdata) = p.communicate() - match = re.search(rb'\s+(\S+libgstcoreelements\.\S+)', stdoutdata) + match = re.search(r'\s+(\S+libgstcoreelements\.\S+)', stdoutdata) if not match: return [] From 19c07b874f05eb8c396e5bbf9dfac6bed10d1f0d Mon Sep 17 00:00:00 2001 From: gottadiveintopython Date: Tue, 4 Jun 2019 05:17:27 +0900 Subject: [PATCH 08/13] fix #6364 --- kivy/tests/test_uix_carousel.py | 15 +++++++++++++++ kivy/uix/carousel.py | 1 + 2 files changed, 16 insertions(+) create mode 100644 kivy/tests/test_uix_carousel.py diff --git a/kivy/tests/test_uix_carousel.py b/kivy/tests/test_uix_carousel.py new file mode 100644 index 000000000..34454a833 --- /dev/null +++ b/kivy/tests/test_uix_carousel.py @@ -0,0 +1,15 @@ +import pytest + + +def test_remove_widget(): + from kivy.uix.carousel import Carousel + from kivy.uix.widget import Widget + + c = Carousel() + w = Widget() + c.add_widget(w) + assert len(c.children) == 1 + assert len(c.slides) == 1 + c.remove_widget(w) + assert len(c.children) == 0 + assert len(c.slides) == 0 diff --git a/kivy/uix/carousel.py b/kivy/uix/carousel.py index c722df863..2bb7d2a73 100644 --- a/kivy/uix/carousel.py +++ b/kivy/uix/carousel.py @@ -651,6 +651,7 @@ class Carousel(StencilView): if widget in self.slides: slide = widget.parent self.slides.remove(widget) + super(Carousel, self).remove_widget(slide) return slide.remove_widget(widget, *args, **kwargs) return super(Carousel, self).remove_widget(widget, *args, **kwargs) From 58a2272c06771a2c43219ded1564214a6411b9a9 Mon Sep 17 00:00:00 2001 From: Matthew Einhorn Date: Fri, 7 Jun 2019 13:53:25 -0400 Subject: [PATCH 09/13] Allow observable list and dict dispatch to propagate exceptions. --- kivy/properties.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kivy/properties.pyx b/kivy/properties.pyx index 52c4f9038..5b477b126 100644 --- a/kivy/properties.pyx +++ b/kivy/properties.pyx @@ -699,7 +699,7 @@ cdef class StringProperty(Property): obj.__class__.__name__, self.name)) -cdef inline void observable_list_dispatch(object self): +cdef inline void observable_list_dispatch(object self) except *: cdef Property prop = self.prop obj = self.obj() if obj is not None: @@ -838,7 +838,7 @@ cdef class ListProperty(Property): value = ObservableList(self, obj, value) Property.set(self, obj, value) -cdef inline void observable_dict_dispatch(object self): +cdef inline void observable_dict_dispatch(object self) except *: cdef Property prop = self.prop prop.dispatch(self.obj) From 8f4008f86591ace6d5e7ef3a96b1feb2c1bec3e0 Mon Sep 17 00:00:00 2001 From: gottadiveintopython Date: Fri, 7 Jun 2019 10:23:43 +0900 Subject: [PATCH 10/13] rename local variables --- kivy/uix/carousel.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/kivy/uix/carousel.py b/kivy/uix/carousel.py index 2bb7d2a73..d27d0a4a6 100644 --- a/kivy/uix/carousel.py +++ b/kivy/uix/carousel.py @@ -635,9 +635,10 @@ class Carousel(StencilView): return def add_widget(self, widget, index=0, canvas=None): - slide = RelativeLayout(size=self.size, x=self.x - self.width, y=self.y) - slide.add_widget(widget) - super(Carousel, self).add_widget(slide, index, canvas) + container = RelativeLayout( + size=self.size, x=self.x - self.width, y=self.y) + container.add_widget(widget) + super(Carousel, self).add_widget(container, index, canvas) if index != 0: self.slides.insert(index - len(self.slides), widget) else: @@ -649,10 +650,10 @@ class Carousel(StencilView): # implementation change. # if we passed the real widget if widget in self.slides: - slide = widget.parent + container = widget.parent self.slides.remove(widget) - super(Carousel, self).remove_widget(slide) - return slide.remove_widget(widget, *args, **kwargs) + super(Carousel, self).remove_widget(container) + return container.remove_widget(widget, *args, **kwargs) return super(Carousel, self).remove_widget(widget, *args, **kwargs) def clear_widgets(self): From 9e7afcdef4c4d64216fe5ab6d93f74ab67f13c6f Mon Sep 17 00:00:00 2001 From: gottadiveintopython Date: Fri, 7 Jun 2019 19:55:14 +0900 Subject: [PATCH 11/13] fix #6370 --- kivy/tests/test_uix_carousel.py | 59 +++++++++++++++++++++++++++++---- kivy/uix/carousel.py | 7 ++-- 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/kivy/tests/test_uix_carousel.py b/kivy/tests/test_uix_carousel.py index 34454a833..fd8811b11 100644 --- a/kivy/tests/test_uix_carousel.py +++ b/kivy/tests/test_uix_carousel.py @@ -1,15 +1,60 @@ import pytest -def test_remove_widget(): +@pytest.fixture( + scope='session', params=(True, False), ids=lambda v: 'loop=' + str(v)) +def loop(request): + return request.param + + +def test_remove_widget(loop): from kivy.uix.carousel import Carousel from kivy.uix.widget import Widget - c = Carousel() - w = Widget() - c.add_widget(w) - assert len(c.children) == 1 - assert len(c.slides) == 1 - c.remove_widget(w) + c = Carousel(loop=loop) + assert c.index is None + assert c.current_slide is None assert len(c.children) == 0 assert len(c.slides) == 0 + + N_SLIDES = 4 + for i in range(N_SLIDES): + c.add_widget(Widget()) + assert c.index == 0 + assert c.current_slide == c.slides[0] + assert len(c.children) == 3 if loop else 2 + assert len(c.slides) == N_SLIDES + + # test issue #6370 + c.index = len(c.slides) - 1 + c.remove_widget(c.slides[0]) + + # remove a slide(smaller index than the current_slide's). + c.index = 1 + old_current_slide = c.current_slide + c.remove_widget(c.slides[c.index - 1]) + assert c.index == 0 + assert c.current_slide is old_current_slide + assert len(c.children) == 2 + assert len(c.slides) == 2 + + # remove a slide(bigger index than the current_slide's). + old_current_slide = c.current_slide + c.remove_widget(c.slides[c.index + 1]) + assert c.index == 0 + assert c.current_slide is old_current_slide + assert len(c.children) == 1 + assert len(c.slides) == 1 + + # remove the current_slide(the last one left). + c.remove_widget(c.current_slide) + assert c.index is None + assert c.current_slide is None + assert len(c.children) == 0 + assert len(c.slides) == 0 + + +if __name__ == "__main__": + pytest.main(args=[ + __file__, + ]) diff --git a/kivy/uix/carousel.py b/kivy/uix/carousel.py index d27d0a4a6..1e857d8e0 100644 --- a/kivy/uix/carousel.py +++ b/kivy/uix/carousel.py @@ -649,9 +649,12 @@ class Carousel(StencilView): # added in add_widget(). But it will break if RelativeLayout # implementation change. # if we passed the real widget - if widget in self.slides: + slides = self.slides + if widget in slides: + if self.index >= slides.index(widget): + self.index = max(0, self.index - 1) container = widget.parent - self.slides.remove(widget) + slides.remove(widget) super(Carousel, self).remove_widget(container) return container.remove_widget(widget, *args, **kwargs) return super(Carousel, self).remove_widget(widget, *args, **kwargs) From db146e3c8c9e53800352a8b1c4293803585e5218 Mon Sep 17 00:00:00 2001 From: Matthew Einhorn Date: Sun, 9 Jun 2019 18:00:45 -0400 Subject: [PATCH 12/13] 3.5.7 doesn't have compiled binaries. --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 773c4e5e8..c40938722 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,7 +42,7 @@ matrix: - docker - language: generic os: osx - env: PYVERS="3.5.7 3.6.8 3.7.3" PY=3 RUN=wheels USE_PANGOFT2=0 + env: PYVERS="3.5.4 3.6.8 3.7.3" PY=3 RUN=wheels USE_PANGOFT2=0 name: "OSX - wheel generation" - language: generic env: PY=3 RUN=app USE_PANGOFT2=0 @@ -110,8 +110,8 @@ install: fi; if [ "${RUN}" == "unit" ]; then export PATH=$PATH:$HOME/Library/Python/3.5/bin; - curl -O -L https://www.python.org/ftp/python/3.5.2/python-3.5.2-macosx10.6.pkg; - sudo installer -package python-3.5.2-macosx10.6.pkg -target /; + curl -O -L https://www.python.org/ftp/python/3.5.4/python-3.5.4-macosx10.6.pkg; + sudo installer -package python-3.5.4-macosx10.6.pkg -target /; python3 get-pip.py --user; python3 -m pip install --upgrade --user cython pillow pytest mock docutils PyInstaller; fi; From e45d6d89a2573f6c9427b002b0c43d93b15c1bff Mon Sep 17 00:00:00 2001 From: Matthew Einhorn Date: Sun, 9 Jun 2019 23:45:04 -0400 Subject: [PATCH 13/13] Embed func signatures in cython to help IDEs. --- setup.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 574e609d2..179434bfc 100644 --- a/setup.py +++ b/setup.py @@ -199,6 +199,9 @@ for key in list(c_options.keys()): print('Environ change {0} -> {1}'.format(key, value)) c_options[key] = value +use_embed_signature = environ.get('USE_EMBEDSIGNATURE', '0') == '1' +use_embed_signature = use_embed_signature or bool( + platform not in ('ios', 'android')) # ----------------------------------------------------------------------------- # Cython check @@ -579,7 +582,7 @@ class CythonExtension(Extension): self.cython_directives = { 'c_string_encoding': 'utf-8', 'profile': 'USE_PROFILE' in environ, - 'embedsignature': 'USE_EMBEDSIGNATURE' in environ} + 'embedsignature': use_embed_signature} # XXX with pip, setuptools is imported before distutils, and change # our pyx to c, then, cythonize doesn't happen. So force again our # sources