Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Breaking change: 1.8.1 breaks PyInstaller apps and any scenario where library is not installed with pip #876

Open
jay0lee opened this issue Apr 21, 2020 · 26 comments
Assignees
Labels
type: process A process-related concern. May include testing, release, or the like.

Comments

@jay0lee
Copy link
Contributor

jay0lee commented Apr 21, 2020

Environment details

  • OS type and version: ANY
  • Python version: ANY
  • pip version: ANY (or N/A)
  • google-api-python-client version: 1.8.1

Steps to reproduce

  1. Install 1.8.1
  2. Attempt to compile Python app that uses googleapiclient to an executable

Expected results

executable compiles and runs as it did with 1.8.0 library

Actual results

executable compiles but fails at runtime with:

pkg_resources.DistributionNotFound: The 'google-api-python-client' distribution was not found and is required by the application

this is due to removing googleapiclient.version and replacing with:

https://github.com/googleapis/google-api-python-client/blob/master/googleapiclient/model.py#L36

these issues will also occur if the library was not installed via pip (e.g. just cloned into a sub directory of the script).

@celsooliveiraTBDE
Copy link

I get this error also when installing in pip3
module 'googleapiclient' has no attribute '__version__'

@jay0lee
Copy link
Contributor Author

jay0lee commented Apr 21, 2020

I was able to work around this with following changes to my PyInstaller .spec file:

extra_files = [copy_metadata('google-api-python-client')]

a = Analysis(['gyb.py'],
             excludes=['FixTk', 'tcl', 'tk', '_tkinter', 'tkinter', 'Tkinter'],
             datas=extra_files,
             hiddenimports=[],
             hookspath=None,
             runtime_hooks=None)

the important steps being setting extra_files and then specifying it as the datas parameter to Analysis()

I still wanted to call out that this seems to have broken a number of projects.

@busunkim96
Copy link
Contributor

busunkim96 commented Apr 21, 2020

@celsooliveiraTBDE That issue no attribute __version__ will be fixed in the next release. See #870 and #871.

We also recommend that you import from googleapiclient rather than apiclient.

from googleapiclient import discovery

@jay0lee We moved to declaring the version in the setup.py and using pkg_resources as that is more consistent with what our modern clients do. If you need to use pyinstaller, it looks like there is a workaround. https://stackoverflow.com/questions/34775667/pyinstaller-django-pkg-resources-distributionnotfound-the-django-omnibus

EDIT: Switched the link to the possible solution.

@busunkim96
Copy link
Contributor

1.8.2 is now released.

@SeanCodeMedia
Copy link

SeanCodeMedia commented May 6, 2020

Hey guys, I had the same issue with pyinstaller what did the trick for me was to roll back from
google-api-python-client from version 1.8.2 to 1.8.0. I hope this issue gets fixed soon. It wasn't fixed in 1.8.2 as commented due to the fact I was facing the same issue on 1.8.2

python -m pip install google-api-python-client==1.8.0

Thanks

@busunkim96
Copy link
Contributor

@BoxingStudioGames What error are you seeing?

@SeanCodeMedia
Copy link

SeanCodeMedia commented May 8, 2020

Here is the error I was getting
pkg_resources.DistributionNotFound: The 'google-api-python-client' distribution was not found and is required by the application manage returned -1
I was able to bypass this error by downgrading the library as commented in my last post.

@jay0lee
Copy link
Contributor Author

jay0lee commented May 8, 2020

Sean, I was able to get things working with the latest library by modifying my PyInstaller spec file to include the package metadata, see:

https://github.com/jay0lee/GAM/blob/master/src/gam.spec#L16

@SeanCodeMedia
Copy link

Hi Jay, I am going to give your solution a try with the version.
Thanks

@awoods3d
Copy link

Thanks jay0lee. The extended code segment from the .spec file described in https://github.com/jay0lee/GAM/blob/master/src/gam.spec#L16 solved this problem for me. Thanks!!!

@DataSolveProblems
Copy link

Roll back to google-api-python-client 1.8.0 worked for me. Thanks BoxingStudioGames. Wasted a good 3 hours fixing this issue this morning.... with the latest version google-api-python-client.

@DrMantisTobbogan
Copy link

Thanks @jay0lee, can confirm that your solution works with pyinstaller 4.0 and google-api-python-client 1.10.1!

@jay0lee
Copy link
Contributor Author

jay0lee commented Sep 14, 2020

@DrMantisTobbogan yes, it still works for me with latest versions.

@mhucka
Copy link

mhucka commented Sep 24, 2020

I realize this issue is closed, but in case anyone else is still encountering the error with more recent versions of google-api-python-client, I can report that you can get the error even with google-api-python-client version 1.12.2, at least when using PyInstaller 3.5 on a Windows 10 system in Python 3.6. The solution posted by @jay0lee upthread (#876 (comment)), namely to use copy_metadata, solved the problem for me. (And I must say, the error and situation are extremely confusing. I don't know how I would have arrived at that solution myself. I spent at least 2–3 hours doing down a different rabbit hole of things like hidden imports, PyInstaller hooks, etc. I'm extremely thankful for @jay0lee's work on this.)

mhucka added a commit to caltechlibrary/lostit that referenced this issue Sep 24, 2020
This was a very nonobvious problem.  The solution came from a GitHub
issue report: googleapis/google-api-python-client#876
@txoof
Copy link

txoof commented Oct 14, 2020

I see that this issue is closed, but I just ran into this issue on python 3.8.5 with google-api-python-client==1.12.3

Are there any suggestions for overcoming this? The suggested solution of using --hidden-import in the issue referenced above does not resolve this.

@jay0lee 's solution works, but requires importing utils.hooks:

from PyInstaller.utils.hooks import copy_metadata
extra_files = copy_metadata('google-api-python-client')
extra_files.append(('./resource_1', './resource_1'))

@jay0lee
Copy link
Contributor Author

jay0lee commented Oct 14, 2020

@busunkim96 can we please re-open this issue? Seems it's still a problem for many library users.

@busunkim96
Copy link
Contributor

Yes, we can adopt the strategy added recently in api-core. googleapis/python-api-core#80

@busunkim96 busunkim96 reopened this Oct 14, 2020
@yoshi-automation yoshi-automation added 🚨 This issue needs some love. triage me I really want to be triaged. labels Oct 14, 2020
@busunkim96 busunkim96 added type: process A process-related concern. May include testing, release, or the like. and removed 🚨 This issue needs some love. triage me I really want to be triaged. labels Oct 15, 2020
@busunkim96 busunkim96 self-assigned this Oct 15, 2020
@meridorkobi
Copy link

i had the same problem
after
from PyInstaller.utils.hooks import copy_metadata
extra_files = copy_metadata('google-api-python-client')
extra_files.append(('./resource_1', './resource_1'))
i have

PyInstaller cannot check for assembly dependencies.
Please install pywin32-ctypes.

pip install pywin32-ctypes

what can i do?

@acibiber53
Copy link

acibiber53 commented Nov 30, 2020

I had this issue with python 3.7 and google-api-python-client 1.12.8.
To solve it I added google-api-python-client as data at the initial pyinstaller line. --add-data has two parameters, SRC;DEST (for Windows), but SRC path searches from the main python scripts folder. So I just got back from my initial directory, then wrote the right path. So it looked like this:

--add-data ../../../../anaconda3/envs/[ENVIRONMENT_NAME]/lib/site-packages/google_api_python_client-1.12.8.dist-info;google_api_python_client-1.12.8.dist-info

Writing the whole path for SRC like "C://.../././" didn't work.

As DEST path, I tried to write a dot, but it didn't work.

One last issue I had before solving was quotes. In the Adding Data Files explanation of PyInstaller, it shows that you need to add quotes. It turns out that when looking for that path, PyInstaller actually shows these quotes as the part of path, so it can't find them (at least it was showing it that way in the spec file). So no need to write the quotes.

2021 August Edit: I think now the part about quotes has been changed. Now you need to add them.

@LMaiorano
Copy link

Still seeing this issue in 2022 using:

  • Python 3.9
  • google-api-python-client==2.42.0

However, I found a fix. I simply needed to set the static_discovery argument to FALSE in the build() function.
Eg:
service = build('drive', 'v3', credentials=creds, static_discovery=False)

Nothing else needed to be changed in the spec file. I hope this helps others as well!

@Mte90
Copy link

Mte90 commented Jun 29, 2022

Do you mean in the latest version of the package? It is a patch to this library?

@LMaiorano
Copy link

Do you mean in the latest version of the package? It is a patch to this library?

Not sure if it's a specific patch to this library to address this issue, but it works now. Wanted to share this in case others were still struggling

@jay0lee
Copy link
Contributor Author

jay0lee commented Jun 29, 2022

@LMaiorano that's actually a different issue. Since version 2.0.0 this library has included static documents for all Google Discovery APIs. To use them, you'd need to tell PyInstaller to include those static .json files in your build.

#1109

https://pyinstaller.org/en/stable/spec-files.html#adding-files-to-the-bundle

or, as you found you can just set static_discovery=False which causes the library to dynamically download the API's discovery file from Google on build().

mtsanovv added a commit to mtsanovv/youspotube that referenced this issue Aug 22, 2022
Essentially, as described in googleapis/google-api-python-client#1109 and googleapis/google-api-python-client#876 - since version 2.0.0 google-api-python-client has included static documents for all Google Discovery APIs. To use them, you'd need to tell PyInstaller to include those static .json files in your build or use static_discovery=False which causes the library to dynamically download the API's discovery file from Google on build(). Otherwise, pyinstaller builds will fail.
@DeadlyOrchard
Copy link

I've got the same issue. Tried @LMaiorano solution and got this traceback from the executable
File "googleapiclient_helpers.py", line 130, in positional_wrapper
File "googleapiclient\discovery.py", line 287, in build
File "googleapiclient\discovery.py", line 422, in retrieve_discovery_doc
File "googleapiclient_helpers.py", line 130, in positional_wrapper
File "googleapiclient\http.py", line 923, in execute
File "googleapiclient\http.py", line 191, in retry_request
File "httplib2_init
.py", line 1577, in request
File "httplib2_init
.py", line 1096, in init
File "httplib2_init_.py", line 179, in _build_ssl_context
FileNotFoundError: [Errno 2] No such file or directory

There's nothing exceptionally odd about the feedback from pyinstaller. Other than a Traceback when it got a TypeError because it got a WindowsPath instead of string, bytes, or os.PathLike object, it's pretty normal.
On the other hand, the warnings.txt file is a mess. It has over 100 lines worth of missing modules.

@siddharth71334
Copy link

Still seeing this issue in 2022 using:

  • Python 3.9
  • google-api-python-client==2.42.0

However, I found a fix. I simply needed to set the static_discovery argument to FALSE in the build() function. Eg: service = build('drive', 'v3', credentials=creds, static_discovery=False)

Nothing else needed to be changed in the spec file. I hope this helps others as well!

thanks so much this trick works for me

@ArthurKlausHoff
Copy link

Some info about this issue

Pyinstaller have a hook that should include files needed by the API client.

But this hook is failing to include the static discovery files: WARNING: collect_data_files - skipping data collection for module 'googleapiclient.discovery' as it is not a package.

But modifying the hook, from

collect_data_files('googleapiclient.discovery', excludes=['*.txt', '**/__pycache__'])

to

collect_data_files('googleapiclient.discovery_cache', excludes=['*.txt', '**/__pycache__'])

Seems to fix it, the warning above doesn't appear and i can use the generated executable without manually modifying the .spec or using static_discovery=False.

Anyone can test it by including this in .spec:

from PyInstaller.utils.hooks import collect_data_files

datas = collect_data_files('googleapiclient.discovery_cache', excludes=['*.txt', '**/__pycache__'])

bwoodsend pushed a commit to pyinstaller/pyinstaller-hooks-contrib that referenced this issue Jun 12, 2023
The hook googleapiclient.model was raising this warning when running
Pyinstaller: WARNING: collect_data_files - skipping data collection for module
'googleapiclient.discovery' as it is not a package. Needing workarounds to run
the api client, see googleapis/google-api-python-client#876. But this can be
fixed by pointing it to the correct package googleapiclient.discovery_cache.

The test also received an improvement. The current test only run from
googleapiclient.discovery import build which is not sufficient because the error
happens when calling the build function. Calling this function doesn't require a
valid API key.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: process A process-related concern. May include testing, release, or the like.
Projects
None yet
Development

No branches or pull requests