Repository: conda/conda

Issue:
noarch python entry points created by conda differ than those created by conda-build
The entry point scripts which are created by conda for `noarch: python` packages differ slightly from those created for standard packages by conda-build.  The templates for the scripts are:

[conda](https://github.com/conda/conda/blob/master/conda/gateways/disk/create.py#L37-L43):
``` python
python_entry_point_template = dals("""
# -*- coding: utf-8 -*-
if __name__ == '__main__':
    from sys import exit
    from %(module)s import %(func)s
    exit(%(func)s())
""")
```

[conda-build](https://github.com/conda/conda-build/blob/master/conda_build/utils.py#L61-L67):
``` python
PY_TMPL = """\
if __name__ == '__main__':
    import sys
    import %(module)s
    sys.exit(%(module)s.%(func)s())
"""
```
I've found at least one example where the template used by conda produces a script which does not work but when used with the conda-build template the script run fine.


Discussion:
pip seems to use the following [template](https://github.com/pypa/pip/blob/9.0.1/pip/wheel.py#L414-L423) for entry points (at least when installing wheels):

``` python
maker.script_template = """# -*- coding: utf-8 -*-
import re
import sys

from %(module)s import %(import_name)s

if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
    sys.exit(%(func)s())
"""
```

I would suggest that both conda and conda-build use this template as it seems the most general.  I will put together PRs implementing this in both projects. 

Resolving patch:
diff --git a/conda/core/path_actions.py b/conda/core/path_actions.py
--- a/conda/core/path_actions.py
+++ b/conda/core/path_actions.py
@@ -22,8 +22,7 @@
 from ..exceptions import CondaUpgradeError, CondaVerificationError, PaddingError
 from ..gateways.disk.create import (compile_pyc, create_hard_link_or_copy, create_link,
                                     create_private_envs_meta, create_private_pkg_entry_point,
-                                    create_unix_python_entry_point,
-                                    create_windows_python_entry_point, extract_tarball,
+                                    create_python_entry_point, extract_tarball,
                                     make_menu, write_linked_package_record)
 from ..gateways.disk.delete import remove_private_envs_meta, rm_rf, try_rmdir_all_empty
 from ..gateways.disk.read import compute_md5sum, isfile, islink, lexists
@@ -418,13 +417,14 @@ def __init__(self, transaction_context, package_info, target_prefix, target_shor
     def execute(self):
         log.trace("creating python entry point %s", self.target_full_path)
         if on_win:
-            create_windows_python_entry_point(self.target_full_path, self.module, self.func)
+            python_full_path = None
         else:
             target_python_version = self.transaction_context['target_python_version']
             python_short_path = get_python_short_path(target_python_version)
             python_full_path = join(self.target_prefix, win_path_ok(python_short_path))
-            create_unix_python_entry_point(self.target_full_path, python_full_path,
-                                           self.module, self.func)
+
+        create_python_entry_point(self.target_full_path, python_full_path,
+                                  self.module, self.func)
         self._execute_successful = True
 
     def reverse(self):
diff --git a/conda/gateways/disk/create.py b/conda/gateways/disk/create.py
--- a/conda/gateways/disk/create.py
+++ b/conda/gateways/disk/create.py
@@ -36,10 +36,14 @@
 
 python_entry_point_template = dals("""
 # -*- coding: utf-8 -*-
+import re
+import sys
+
+from %(module)s import %(import_name)s
+
 if __name__ == '__main__':
-    from sys import exit
-    from %(module)s import %(func)s
-    exit(%(func)s())
+    sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
+    sys.exit(%(func)s())
 """)
 
 application_entry_point_template = dals("""
@@ -59,7 +63,7 @@ def write_as_json_to_file(file_path, obj):
         fo.write(ensure_binary(json_str))
 
 
-def create_unix_python_entry_point(target_full_path, python_full_path, module, func):
+def create_python_entry_point(target_full_path, python_full_path, module, func):
     if lexists(target_full_path):
         maybe_raise(BasicClobberError(
             source_path=None,
@@ -67,33 +71,31 @@ def create_unix_python_entry_point(target_full_path, python_full_path, module, f
             context=context,
         ), context)
 
-    pyscript = python_entry_point_template % {'module': module, 'func': func}
-    with open(target_full_path, str('w')) as fo:
+    import_name = func.split('.')[0]
+    pyscript = python_entry_point_template % {
+        'module': module,
+        'func': func,
+        'import_name': import_name,
+    }
+
+    if python_full_path is not None:
         shebang = '#!%s\n' % python_full_path
         if hasattr(shebang, 'encode'):
             shebang = shebang.encode()
         shebang = replace_long_shebang(FileMode.text, shebang)
         if hasattr(shebang, 'decode'):
             shebang = shebang.decode()
-        fo.write(shebang)
-        fo.write(pyscript)
-    make_executable(target_full_path)
-
-    return target_full_path
-
-
-def create_windows_python_entry_point(target_full_path, module, func):
-    if lexists(target_full_path):
-        maybe_raise(BasicClobberError(
-            source_path=None,
-            target_path=target_full_path,
-            context=context,
-        ), context)
+    else:
+        shebang = None
 
-    pyscript = python_entry_point_template % {'module': module, 'func': func}
     with open(target_full_path, str('w')) as fo:
+        if shebang is not None:
+            fo.write(shebang)
         fo.write(pyscript)
 
+    if shebang is not None:
+        make_executable(target_full_path)
+
     return target_full_path
 
 


Test patch: