Python Click CLI Application
When you use a Click library to build a Python CLI Application you can do this:
@click.version_option()
def cli():
    '''
    Main Entry Point to Click Interface
    '''
to be able to do this:
[user@host]$ clickapp --version
Click Packaged in pex
But when I package it as a pex file, every other argument, option, commands, sub-command of my click application works, except --version.
When I run (clickapp is now a binary executable pex file):
[user@host]$ ./clickapp --version
I get the following error:
Traceback (most recent call last):
  File "/~/clickapp/.bootstrap/pex/pex.py", line 446, in execute
  File "/~/clickapp/.bootstrap/pex/pex.py", line 378, in _wrap_coverage
  File "/~/clickapp/.bootstrap/pex/pex.py", line 409, in _wrap_profiling
  File "/~/clickapp/.bootstrap/pex/pex.py", line 508, in _execute
  File "/~/clickapp/.bootstrap/pex/pex.py", line 610, in execute_entry
  File "/~/clickapp/.bootstrap/pex/pex.py", line 626, in execute_pkg_resources
  File "/~/.pex/installed_wheels/7bcb1b5bf49ca3f89c348c338d33c04e3d59dfc1/click-7.1.2-py2.py3-none-any.whl/click/core.py", line 829, in __call__
    return self.main(*args, **kwargs)
  File "/~/.pex/installed_wheels/7bcb1b5bf49ca3f89c348c338d33c04e3d59dfc1/click-7.1.2-py2.py3-none-any.whl/click/core.py", line 781, in main
    with self.make_context(prog_name, args, **extra) as ctx:
  File "/~/.pex/installed_wheels/7bcb1b5bf49ca3f89c348c338d33c04e3d59dfc1/click-7.1.2-py2.py3-none-any.whl/click/core.py", line 700, in make_context
    self.parse_args(ctx, args)
  File "/~/.pex/installed_wheels/7bcb1b5bf49ca3f89c348c338d33c04e3d59dfc1/click-7.1.2-py2.py3-none-any.whl/click/core.py", line 1212, in parse_args
    rest = Command.parse_args(self, ctx, args)
  File "/~/.pex/installed_wheels/7bcb1b5bf49ca3f89c348c338d33c04e3d59dfc1/click-7.1.2-py2.py3-none-any.whl/click/core.py", line 1048, in parse_args
    value, args = param.handle_parse_result(ctx, opts, args)
  File "/~/.pex/installed_wheels/7bcb1b5bf49ca3f89c348c338d33c04e3d59dfc1/click-7.1.2-py2.py3-none-any.whl/click/core.py", line 1630, in handle_parse_result
    value = invoke_param_callback(self.callback, ctx, self, value)
  File "/~/.pex/installed_wheels/7bcb1b5bf49ca3f89c348c338d33c04e3d59dfc1/click-7.1.2-py2.py3-none-any.whl/click/core.py", line 123, in invoke_param_callback
    return callback(ctx, param, value)
  File "/~/.pex/installed_wheels/7bcb1b5bf49ca3f89c348c338d33c04e3d59dfc1/click-7.1.2-py2.py3-none-any.whl/click/decorators.py", line 295, in callback
    raise RuntimeError("Could not determine version")
RuntimeError: Could not determine version
Details
The setup.py file:
from setuptools import setup, find_namespace_packages
setup(
    name='clickapp',
    version='0.1.3',
    author='Hamza M Zubair',
    packages=find_namespace_packages(),
    include_package_data=True,
    package_data={
        '': ['*.yaml'],
    },
    classifiers=[
        'Programming Language :: Python :: 3',
        'Operating System :: OS Independent',
        'Natural Language :: English',
        'License :: Other/Proprietary License',
    ],
    python_requires='>=3.6',
    install_requires=[
        'click',
        'pandas',
        'sqlalchemy',
        'jinjasql',
        'pyyaml',
        'joblib',
        'python-dateutil',
        'loguru',
        'pymysql',
        'xgboost',
        'sklearn',
        'wheel',
        'importlib-resources'
    ],
    entry_points='''
        [console_scripts]
        clickapp=clickapp.cli:cli
    ''',
)
The command used to create the pex file:
[user@host]$ python setup.py bdist_pex --bdist-all
Tool Specs
I am building and running the pex file in different systems, using the following versions of libraries/packages. The target machine only has Python and no libraries, because pex file does not require libraries/virtualenv etc.
Build Machine OS: CentOS Linux release 7.8.2003 (Core)  
Build Machine Python: 3.6.8  
setuptools: 51.0.0  
pex: 2.1.21  
click: 7.1.2  
Target Machine OS: CentOS Linus release 7.4.1708 (Core)
Target Machine Python: 3.6.8
What I tried
- I have tested the full functionality of my 
clickapp, and every other argument and command works perfectly. 
Even this displays the help of my clickapp correctly.
[user@host]$ ./clickapp --help
- I tried re-building the package several times
 - I have only tested this in Python3.6. I haven't tried different python versions, its slightly difficult to set it up in both the source and target systems.
 - When I removed 
@click.version_option()I get the error:--version not implemented, which is just as expected - I am yet to test it on a 2nd target system, in case some idiosyncrasies of my current target server is causing the error
 
More Info
What other information should I provide, for helping SO users?
                        
Short answer:
setuptoolsis missing.It looks like you have click v7.1.2. In that version one of the code paths to figure out the version number automatically uses
pkg_resourceswhich is a top-level package of setuptools:-- https://github.com/pallets/click/blob/7.1.2/src/click/decorators.py#L283-L293
So in a way, click depends on setuptools. But there are other code paths that do not require
pkg_resources, for example the version number can be set explicitly in the parameters of the decorator (if I am not mistaken):@click.version_option(version='1.2.3')(doc), in such a case setuptools is not a mandatory dependency.In most cases, it just works because (out of what I would call a coincidence) setuptools is almost always pre-installed (in virtual environments for example). But "almost always" is not the same as "always", and for example it is absolutely possible to have environments (virtual or not) that do not have a setuptools installation. And this looks like it is exactly what happens in the case of a pex-packaged application. I believe pex creates clean virtual environments (i.e. without pip, setuptools or wheel or anything else).
Since setuptools is not declared as a dependency it is not installed, importing
pkg_resourcesfails, and finding the version string fails.I would say that this is a failure on click's side. They should either declare setuptools as a mandatory dependency, or at least as an optional dependency (in an extra) and document this properly.
A possible fix is to add setuptools as a direct dependency of your application: add
setuptoolsto the list ofinstall_requiresin yoursetup.py.Note that as far as I can tell, things will change in click v8. Finding out the version string will rely on
importlib.metadatafrom the standard library (back-ported to Python < 3.8 asimportlib_metadata) instead ofpkg_resources:From the looks of it, it will cause problems again, probably even more. Since click still does not declare
importlib-metadataas a dependency for older Python versions whereimportlib.metadatais not in the standard library (< 3.8), the version string lookup will fail.