Kivy'de 3. taraf kütüphane kullanma

Merhaba arkadaşlar. Hepinize kolay gelsin. Karşılaştığım bir sıkıntıyı son çare olarak burada paylaşmak istiyorum. Python kivy ile basit bir program oluşturdum ve bunu apk haline getirdim. Programın yaptığı şey şu, bir siteye bağlanmak ve ordaki belirli html tag’leri arasındaki bilgiyi ekrana yazmak. Bunun için BeautifulSoup kullandım. Ama

  1. Eğer https üzerinden bağlantı sağlarsam bağlantı yok. openssl ekledim ama, halen daha olmadı

  2. Apk gereklilikleri arasına bs4(beautifulsoup) ekledim ama apk çalışırken bunu import edemiyor. Bulunamadı diyor.

Kısaca https bağlantı sorununu nasıl halledebilirim ve python standart olmayan modülleri nasıl kullanabilirim? İnanın çok araştırma yaptım ama, bir sonuca ulaşamadım. Yardımcı olabilecek varsa lütfen yardımcı olsun. Herkese kolay gelsin

Merhaba,

Sizin için sakıncası yoksa, bu uygulamanın .py ve .kv uzantılı dosyalarını paylaşabilir misiniz?

1 Beğeni

çok basit bir kod.

from kivy.app import App
from kivy.uix.label import Label

class Program(App):
    def build(self):
        try:
            import bs4
            sonuc = "import tamam"
        except:
            sonuc = "import hatalı"
    
        return Label(text = sonuc)

Program().run()

Bu kod ile basit bir şekilde import edilip edilmediğini kontrol ediyorum. Pc’de oluyor, ancak apk yaptıktan sonra ekranda “import hatalı” yazıyor.

Buildozer’ı yüklediniz mi? Bu ilk kivy uygulamanız mı? buildozer.spec dosyasının içinde, programın kullandığı modülleri belirtmek gerekiyor. Bunu yaptınız mı? Bir de hangi Python ve kivy sürümlerini kullanıyorsunuz?

2 Beğeni

Elbette yükledim. Daha önce standart python modüllerini kullandım. mesela os,sys gibi denemeler yaptım. Ancak yavaş yavaş 3. parti kütüphaneler ile işim olunca, bu sıkıntı ortaya çıktı.

buildozer.spec dosyasında gereklilikleri yazdım

requirements = kivy,bs4

şeklinde. Python sürümü 2.7, kivy sürümü 1.10.0

Ve elimdeki main.py dosyası yani program dosyası bu
main.py dosyası

# coding: utf-8
# 
from kivy.app import App
from kivy.uix.label import Label

class Program(App):
    def build(self):
        self.liste = ["os","urllib","bs4"] # bu modüller import ediliyor mu diye kontrol ediyoruz
        sonuc = self.kontrol(self.liste)

        return Label(text = "{}".format(sonuc))


    def kontrol(self,liste):
        log = ""
        for i in liste:
            try:
                modul = __import__("{}".format(i))
                log = log+"import {} basarili\n".format(i)
            except:
                log = log+"import {} basarisiz\n".format(i)
                
        return log



Program().run()

import bs4 basarisiz oluyor

Tekrar merhaba, sizin gibi ben de hangi 3. parti modül import edilebiliyor, hangisi edilemiyor diye denemeler yaptım.

Mesela requests modülünü denedim. Requirements’e de eklemedim.

import kivy
kivy.require('1.10.0')
from kivy.app import App
from kivy.uix.label import Label


class MyApp(App):
    def build(self):
        try:
            import requests
            sonuc = "requests import edildi"
        except:
            sonuc = "requests import edilemedi."
        return Label(text=sonuc)


MyApp().run()

Ayrıca requirements’e requests yazarsak, derleme esnasında onu algılıyor ve gerekli paketi indiriyor.

Aşağıdaki de bs4 modülü kullanıldığında alınan ekran görüntüsü:

spec dosyasındaki requirements’e bs4 eklersem zaten apk derlenemiyor. Belki bir ihtimal bs4’e henüz destek verilmiyor olabilir diye tahmin ediyorum. Ama böyle bir bilgi de yok.

1 Beğeni

https://groups.google.com/forum/m/#!topic/kivy-users/7dLzY-yYhxw.

Soyle bir sey bukdum belki isinize yarar.

1 Beğeni

Merhaba.

Gerekliliği beautifulsoup4 olarak yazmayı dener misiniz? Çünkü bildiğim kadarı ile Python’a bu kütüphaneyi pip ile kurmaya çalıştığımızda bu ismi kullanıyoruz. Ancak içeri aktarmak istediğimizde bs4 ismini kullanıyoruz.

İyi çalışmalar.

1 Beğeni

Evet olabilir. Deneyeceğim. Peki, bağlantıyı urllib ile de kurabiliyorum ancak, https sitelerde sıkıntı çıkıyor bağlanmıyor. Bunu nasıl halledebiliriz acaba?

Python 2.7 sürümünde pip ile kurarken

pip install bs4

ile kuruldu. Sadece bs4 değil diğer hiçbir 3. parti kütüphane olmuyor. Mesela google gibi, mechanize gibi.

İnceliyorum. Teşekkür ederim

Normalde bir paket recipe’de değilse onu gerekenler listesine ekleyip, apk derlemeye çalıştığımızda yine hata alıyoruz. bs4 veya beautifulsoup4 yazarak bu işlemleri tekrar tekrar yaptım.

Sorun acaba recipe’lerden mi kaynaklanıyor diye düşünüyorum.

Bu arada google ve mechanize recipelerde ekli değil acaba ondan mı kullanılamıyorlar?

Daha önce requests modülünü kullanarak bir apk oluşturdum. Niye requests’te sorun vermedi de bs4’de sorun verdi acaba diye düşünürken, python-for-android’in recipes klasöründe requests’in eklenmiş olduğunu gördüm. Ama beautifulsoup4 ekli değildi.

Sonra biraz araştırınca şöyle bir kaynak buldum:

Bs4’in bağımlı olduğu kütüphane lxml. Lxml de libxml2 ve libxslt paketlerine ihtiyaç duyuyor. beautifulsoup4, lxml, libxml2 ve libxslt’yi recipelere ekleyeyim dedim. Önce kendim bunların recipelerini oluşturdum. Denedim ama yine hata verdi. Sonra yukarıdaki sitede bulunan recipelerin aynısını yazdım. Halen sorun veriyor. Yazara mail attım, geri dönüp, sorunun çözümünde yardımcı olursa burada paylaşırım. O zamana kadar istiyorsanız yukarıdaki sayfayı bir de siz inceleyin.

1 Beğeni

Bende bugün bu konu hakkında araştırma yapıyordum. Nereye bakarsam bakayım herkes aynı şeyi söylüyor. “Requirements eklerseniz otomatik yüklenir” diye ama yok. Bir de şöyle birşey oldu.

p4a ana dizininde aşağıdaki komutu verince çıktısı

./distribute.sh -m "requests"
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

PYTHON-FOR-ANDROID ERROR! SEE BELOW FOR SOLUTION:

You are trying to run an old version of python-for-android via
distribute.sh. However, python-for-android has been rewritten and no
longer supports the distribute.sh interface.

If you are using buildozer, you should:
- upgrade buildozer to the latest version (at least 0.30)
- delete the .buildozer folder in your app directory (the same directory that has your buildozer.spec)
- run buildozer again as normal

If you are not using buildozer, see
https://github.com/kivy/python-for-android/blob/master/README.md for
instructions on using the new python-for-android
toolchain. Alternatively, you can get the old toolchain from the
'old_toolchain' branch at
https://github.com/kivy/python-for-android/tree/old_toolchain .

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Requirements’e ancak recipesi olan modüller eklenirse indirme yapıyor.

Recipe ne demek, bilenler veya bilmeyenler için anlatmaya çalışayım:

.buildozer/android/platform/python-for-android-master/pythonforandroid/recipes isimli klasörün içinde bulunan her klasör, bir modüle ait.

Requests modülünün recipesi üzerinden anlatmaya devam edeyim (Bildiğiniz veya bilmediğiniz gibi requests 3. kişiler tarafından yazılmış bir modül):

Yukarıda bahsettiğim klasörün içinde requests isminde bir klasör var. Bu klasörün içinde bir __init__.py dosyası bulunur. (Kimi modüllerde patch isimli başka klasörler ve dosyalar da var.)

Mesela aşağıdaki script, .buildozer/android/platform/python-for-android-master/pythonforandroid/recipes/requests klasörü içindeki __init__.py'de yazan kodlar:

from pythonforandroid.toolchain import PythonRecipe

class RequestsRecipe(PythonRecipe):
    version = '2.13.0'
    url = 'https://github.com/kennethreitz/requests/archive/v{version}.tar.gz'
    depends = ['hostpython2', 'setuptools']
    site_packages_name = 'requests'
    call_hostpython_via_targetpython = False

recipe = RequestsRecipe()

Hemen hemen bütün tariflerde (recipes), __init__.py dosyasına benzer bir dosya var.

Mesela aşağıdaki, .buildozer/android/platform/python-for-android-master/pythonforandroid/recipes/kivy klasörü içindeki __init__.py'de yazan kodlar.

Yani her __init__.py'de benzer kodlar yazmıyor.


from pythonforandroid.toolchain import CythonRecipe, shprint, current_directory, ArchARM
from os.path import exists, join
import sh
import glob


class KivyRecipe(CythonRecipe):
    version = '1.10.0'
    url = 'https://github.com/kivy/kivy/archive/{version}.zip'
    name = 'kivy'

    depends = [('sdl2', 'pygame'), 'pyjnius']

    # patches = ['setargv.patch']

    def cythonize_build(self, env, build_dir='.'):
        super(KivyRecipe, self).cythonize_build(env, build_dir=build_dir)

        if not exists(join(build_dir, 'kivy', 'include')):
            return

        # If kivy is new enough to use the include dir, copy it
        # manually to the right location as we bypass this stage of
        # the build
        with current_directory(build_dir):
            build_libs_dirs = glob.glob(join('build', 'lib.*'))

            for dirn in build_libs_dirs:
                shprint(sh.cp, '-r', join('kivy', 'include'),
                        join(dirn, 'kivy'))

    def get_recipe_env(self, arch):
        env = super(KivyRecipe, self).get_recipe_env(arch)
        if 'sdl2' in self.ctx.recipe_build_order:
            env['USE_SDL2'] = '1'
            env['KIVY_SPLIT_EXAMPLES'] = '1'
            env['KIVY_SDL2_PATH'] = ':'.join([
                join(self.ctx.bootstrap.build_dir, 'jni', 'SDL', 'include'),
                join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_image'),
                join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_mixer'),
                join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_ttf'),
                ])

        return env

recipe = KivyRecipe()

Gördüğünüz gibi bu scriptlerin içinde depends isimli, modülün gereksinim duyduğu diğer modüller yazılmış. Burada dikkatimi çeken şöyle bir durum var. Mesela kivy modülü pyjnius isimli bir modüle gereksinim duyuyor.

Pyjnius recipesi klasöründeki __init__.py dosyasına bakıyorum. Aşağıdaki kodlar da onun da başka bağımlı olduğu programlar olduğunu görüyorum.


from pythonforandroid.toolchain import CythonRecipe, shprint, current_directory, info
from pythonforandroid.patching import will_build, check_any
import sh
from os.path import join


class PyjniusRecipe(CythonRecipe):
    version = 'master'
    url = 'https://github.com/kivy/pyjnius/archive/{version}.zip'
    name = 'pyjnius'
    depends = [('python2', 'python3crystax'), ('genericndkbuild', 'sdl2', 'sdl'), 'six']
    site_packages_name = 'jnius'

    patches = [('sdl2_jnienv_getter.patch', will_build('sdl2')),
               ('genericndkbuild_jnienv_getter.patch', will_build('genericndkbuild'))]

    def postbuild_arch(self, arch):
        super(PyjniusRecipe, self).postbuild_arch(arch)
        info('Copying pyjnius java class to classes build dir')
        with current_directory(self.get_build_dir(arch.arch)):
            shprint(sh.cp, '-a', join('jnius', 'src', 'org'), self.ctx.javaclass_dir)


recipe = PyjniusRecipe()

Ayrıca mesela bu Pyjnius klasörünün içinde yani .buildozer/android/platform/python-for-android-master/pythonforandroid/recipes/pyjnius dizininde, sdl2_jnienv_getter.patch ve genericndkbuild_jnienv_getter.patch isimli başka dosyalar var.

Mesela genericndkbuild_jnienv_getter.patch dosyasının içinde aşağıdakiler yazıyor.

diff --git a/jnius/jnius_jvm_android.pxi b/jnius/jnius_jvm_android.pxi
index ac89fec..71daa43 100644
--- a/jnius/jnius_jvm_android.pxi
+++ b/jnius/jnius_jvm_android.pxi
@@ -1,5 +1,5 @@
 # on android, rely on SDL to get the JNI env
-cdef extern JNIEnv *SDL_ANDROID_GetJNIEnv()
+cdef extern JNIEnv *WebView_AndroidGetJNIEnv()
 
 cdef JNIEnv *get_platform_jnienv():
-    return SDL_ANDROID_GetJNIEnv()
+    return <JNIEnv*>WebView_AndroidGetJNIEnv()
diff --git a/setup.py b/setup.py
index 740510f..0c8e55f 100644
--- a/setup.py
+++ b/setup.py
@@ -53,7 +53,7 @@ except ImportError:
 
 if platform == 'android':
     # for android, we use SDL...
-    libraries = ['sdl', 'log']
+    libraries = ['main', 'log']
     library_dirs = ['libs/' + getenv('ARCH')]
 elif platform == 'darwin':
     import subprocess

Ve sdl2_jnienv_getter.patch dosyasında da aşağıdakiler yazıyor.

diff --git a/jnius/jnius_jvm_android.pxi b/jnius/jnius_jvm_android.pxi
index ac89fec..71daa43 100644
--- a/jnius/jnius_jvm_android.pxi
+++ b/jnius/jnius_jvm_android.pxi
@@ -1,5 +1,5 @@
 # on android, rely on SDL to get the JNI env
-cdef extern JNIEnv *SDL_ANDROID_GetJNIEnv()
+cdef extern JNIEnv *SDL_AndroidGetJNIEnv()
 
 cdef JNIEnv *get_platform_jnienv():
-    return SDL_ANDROID_GetJNIEnv()
+    return <JNIEnv*>SDL_AndroidGetJNIEnv()
diff --git a/setup.py b/setup.py
index 740510f..0c8e55f 100644
--- a/setup.py
+++ b/setup.py
@@ -53,7 +53,7 @@ except ImportError:
 
 if platform == 'android':
     # for android, we use SDL...
-    libraries = ['sdl', 'log']
+    libraries = ['SDL2', 'log']
     library_dirs = ['libs/' + getenv('ARCH')]
 elif platform == 'darwin':
     import subprocess

Son paylaştığım iki dosyanın içindeki kodların syntaxı şuan benim için anlaşılmaz seviyede. Oysa __init__.py klasörünün içindeki kodların syntax’ı daha anlaşılır.

Bir önceki mesajımda size gönderdiğim linkte de beautifulsoup4, lxml, libxml2, libxslt için yazılmış __init__.py dosyaları var. libxslt için ayrıca bir patch dosyası yazılmış. Bunların aynısını .buildozer/android/platform/python-for-android-master/pythonforandroid/recipes dizini içerisinde oluşturdum, ancak yine hatayla sonuçlandı.

Özetle demek istediğim, yanılmıyorsam beautifulsoup4 için çalışır durumda olan bir recipe’ye ihtiyaç var.

1 Beğeni

Evet sanırım öyle. Şu anda bu durumu çözmeye odaklandım. Bu konuya ilginiz için teşekkür ediyorum :slight_smile:

Beautifulsoup4’ün bağımlı olduğu modüller nelerdir, bunlara da bir bakmak gerekiyor.

Kaynak: https://www.crummy.com/software/BeautifulSoup/

Beautiful Soup sits on top of popular Python parsers like lxml and html5lib, allowing you to try out different parsing strategies or trade speed for flexibility.

lxml ve html5lib modülleri hangi modüllere gereksinim duyuyor? Onları da bulmak lazım.

https://pypi.python.org/pypi/lxml/4.1.0 sitesine göre:

lxml is a Pythonic, mature binding for the libxml2 and libxslt libraries. It provides safe and convenient access to these libraries using the ElementTree API.

https://pypi.python.org/pypi/html5lib/0.999999999 sitesine göre

Optional Dependencies

The following third-party libraries may be used for additional functionality:

datrie can be used under CPython to improve parsing performance (though in almost all cases the improvement is marginal);
lxml is supported as a tree format (for both building and walking) under CPython (but not PyPy where it is known to cause segfaults);
genshi has a treewalker (but not builder); and
chardet can be used as a fallback when character encoding cannot be determined.

Şimdi bu yeni isimlerin de bağımlılıklarını kontrol etmek gerekir mi?

Başka bir sorun da, recipeleri nasıl yazmak gerekiyor?

1 Beğeni

ipin bir ucundan tutarsak, standart modüllere kadar takip etmemiz gerekiyor sanırım.

Ve bazı modüller için recipes dosyası oldukça basit. Mesela six için


from pythonforandroid.toolchain import PythonRecipe


class SixRecipe(PythonRecipe):
    version = '1.9.0'
    url = 'https://pypi.python.org/packages/source/s/six/six-{version}.tar.gz'
    depends = [('python2', 'python3crystax')]

recipe = SixRecipe()

Standart modüller sıkıntı değil. 3. parti modül, başka bir 3. parti modüle ihtiyaç duyduğunda sıkıntı. Haklısınız, bazı recipe dosyaları oldukça basit.

1 Beğeni

Evet sıkıntılı değil biliyorum. Demek istediğim, 3.parti ihtiyacı kalmayana kadar takip mi etmemiz gerekiyor yani?