Search code examples
pythonpython-3.xgoogle-api-python-clientpy2app

ImportError: No module named 'google-api-python-client' when using py2app


I have been trying to make a standalone app using py2app using this tutorial but instead of using the forked version I used the official version.. Using python setup.py py2app -A worked fine but when using python setup.py py2app it gave an error. The last line was ImportError: No module named 'google-api-python-client'(full output can be found here.).

Things I have tried

python3 setup.py py2app

I have also looked at this stackoverflow article but it gave the same error.

Setup.py

from setuptools import setup

APP = ['YoutubeSubCount.py']
DATA_FILES = ['key.txt', 'logo_sub.png', 'logo_sub2.icns']
APP_NAME = "Youtube Sub Count"
OPTIONS = {
    'argv_emulation': True,
    'iconfile': 'icon.icns',
    'plist': {
        'CFBundleName': APP_NAME,
        'CFBundleDisplayName': APP_NAME,
        'CFBundleVersion': "0.1.0",
        'CFBundleShortVersionString': "0.1.0",
        'LSUIElement': True,
    },
    'packages': ['rumps', 'sty', 'google-api-python-client'],
}

setup(
    app=APP,
    data_files=DATA_FILES,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
)

YoutubeSubCount.py

import rumps
import time
import sys
import os
import linecache
from tkinter import *
from sty import fg
from googleapiclient.discovery import build

global update_timer, key, service, channel

key = open(os.path.join(sys.path[0], './key.txt')).read().strip()
service = build('youtube', 'v3', developerKey=key)
channel2 = 'UCERizKQbgpBXOck0R6t_--Q'

subs = service.channels().list(
    part='statistics',
    id= channel2
).execute()['items'][0]['statistics']['subscriberCount']

timers = ["1 secs","5 secs","10 secs","15 secs","20 secs","25 secs","30 secs","35 secs","45 secs","50 secs","1 Min"]

update_timer = 60

key_path = "key.txt"



class Sub_Counter(rumps.App):

    @rumps.timer(update_timer)   
    def pull_data(self, _):
        subs = service.channels().list(
            part='statistics',
            id=channel2
        ).execute()['items'][0]['statistics']['subscriberCount']

        a = (str(subs))
        self.icon = "logo_sub.png"
        self.title = "Subscribers: " + str(a)
        self.notification = str(a) + " Subscribers"

    @rumps.clicked('About')
    def about(self, _):
        rumps.notification("Youtube Subscriber Count", "Made by Roxiun using Python & rumps", "Shows Youtube Subscriber counts")

    @rumps.clicked('Preferences', 'API Key')
    def configuration_window_api(self, _):
        response = rumps.Window('Enter new API Key')
        response.dimensions=(320, 160)
        response.run()
        if response.clicked:
            key = response.text
            service = build('youtube', 'v3', developerKey=key)

    @rumps.clicked('Preferences', 'Channel')
    def configuration_window_channel(self, _):
        response = rumps.Window('Enter new Youtube Channel Link')
        response.dimensions=(320, 160)
        response.run()
        if response.clicked:
            channel = response.text
            if "https://www.youtube.com/channel/" in channel:
                channel2 = channel.replace("https://www.youtube.com/channel/", "")
            else:
                channel2 = channel.replace("https://www.youtube.com/user/", "")

            subs = service.channels().list(
                part='statistics',
                id=channel2
            ).execute()['items'][0]['statistics']['subscriberCount']

            a = (str(subs))
            self.icon = "logo_sub.png"
            self.title = "Subscribers: " + str(a)
            self.notification = str(a) + " Subscribers"


    @rumps.clicked('Icon', 'Normal')
    def icon_on(self, _):
        self.icon = 'logo_sub.png'

    @rumps.clicked('Icon', 'Coloured')
    def icon_col(self, _):
        self.icon = 'logo_sub2.icns'

    @rumps.clicked('Icon', 'Off')
    def icon_off(self, _):
        self.icon = None

    @rumps.clicked('Update Timer', 'Every Second')
    def timer_1(self, _):
        update_timer = 1

    @rumps.clicked('Update Timer', '5 Seconds')
    def timer_2(self, _):
        update_timer = 5

    @rumps.clicked('Update Timer', '10 Seconds')
    def timer_3(self, _):
        update_timer = 10   

    @rumps.clicked('Update Timer', '20 Seconds')
    def timer_4(self, _):
        update_timer = 20

    @rumps.clicked('Update Timer', '30 Seconds')
    def timer_5(self, _):
        update_timer = 30   

    @rumps.clicked('Update Timer', '40 Seconds')
    def timer_6(self, _):
        update_timer = 40   

    @rumps.clicked('Update Timer', '50 Seconds')
    def timer_7(self, _):
        update_timer = 50   

    @rumps.clicked('Update Timer', '1 Minute')
    def timer_8(self, _):
        update_timer = 60   

    @rumps.clicked("Detailed Statistics")
    def Detailed_Statistics(self, _):
        rumps.notification("You have:", self.notification , "Veiws Comming Soon")

app = Sub_Counter("Loading...")#debug=True
app.menu = [
    ('About'),
    ('Preferences',('API Key', 'Channel')),
    None,
    ('Icon', ('Normal', 'Coloured', 'Off')),
    ('Update Timer', ('Every Second', '5 Seconds', '10 Seconds', '20 Seconds', '30 Seconds', '40 Seconds', '50 Seconds', '1 Minute')),
    None,
    ("Detailed Statistics")
]
app.run()

Thanks in advance!

Update

After following the answer by Sergio Pulgarin

New Setup.py

from setuptools import setup

APP = ['YoutubeSubCount.py']
DATA_FILES = ['key.txt', 'logo_sub.png', 'logo_sub2.icns']
APP_NAME = "Youtube Sub Count"
OPTIONS = {
    'argv_emulation': True,
    'iconfile': 'icon.icns',
    'plist': {
        'CFBundleName': APP_NAME,
        'CFBundleDisplayName': APP_NAME,
        'CFBundleVersion': "0.1.0",
        'CFBundleShortVersionString': "0.1.0",
        'LSUIElement': True,
    },
    'packages': ['rumps', 'sty'],
}

setup(
    app=APP,
    data_files=DATA_FILES,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
    install_requires=['google-api-python-client'],
)

Running python setup.py py2app -A gave the expected output and worked fine but after running python setup.py py2app no terminal output was given and the application was created, but upon open the application it opened a window sayinf Youtube Sub Count Error and had a button saying Console and one saying Terminate


Solution

  • I know this is an old question but an easy workaround is to copy the google_api_python_client-*.dist-info in your respective Library/Frameworks/Python.framework/Versions/your_version/lib/python_version/site-packages/ folder and paste it inside the app_name.app/contents/Resources/lib/your_python_version/ folder.

    After doing that, try running the app again from the terminal or clicking the file at app_name.app/contents/macOS/app_name as the first time you run it, it might be required to authenticate it with your gmail.

    I hope this helps people with this problem in the future as I had.