title: How to properly get console_scripts install_scripts directory?
body: <p>I splitted a complex Python script into a package for easier maintenance and distribution. I created a fresh <code>setup.py</code> (using <code>setupmeta</code>) with a <code>console_scripts</code> entry point and the package structure. So far, so good.</p>
  <p>I had some unusual requirements, though:</p>
  <ul>
  <li>the package is to always be installed in a <code>virtualenvwrapper</code> project,</li>
  <li>so the script is installed in the <code>${VIRTUAL_ENV}/bin</code> directory...</li>
  <li>...and I <em>must</em> create a symlink targetting the script in the <code>${VIRTUALENVWRAPPER_PROJECT_PATH}/bin</code> directory. (don't ask... :-)</li>
  </ul>
  <p>For that purpose:</p>
  <ol>
  <li><p>I added a <code>locate_project_path()</code> function in the <code>setup.py</code> script,</p>
  </li>
  <li><p>added the following <code>install_and_symlink_script</code> subclass to <code>setuptools.command.install.install</code>:</p>
  <pre class="lang-py prettyprint-override"><code>class install_and_symlink_script(install):                           
      &quot;&quot;&quot;Do normal install, but symlink script to project directory&quot;&quot;&quot; 
  
      def run(self):                                                   
          install.run(self)                                            
  
          script_path = os.path.join(self.install_scripts, SCRIPT_NAME)
          project_path = locate_project_path()                         
          symlink_path = os.path.join(project_path, &quot;bin&quot;, SCRIPT_NAME)
  
          print(&quot;creating %s script symlink&quot; % SCRIPT_NAME)            
  
          if os.path.exists(symlink_path):                             
              print(&quot;removing existing symlink %s&quot; % symlink_path)     
              os.unlink(symlink_path)                                  
  
          print(&quot;creating symlink from %s to %s&quot; % (                   
              symlink_path, script_path))                              
          os.symlink(script_path, symlink_path)                        
  </code></pre>
  </li>
  <li><p>and configured <code>setup()</code> this way:</p>
  <pre class="lang-py prettyprint-override"><code>setup(
      ...
      entry_points={
          &quot;console_scripts&quot;: [&quot;%s=myscriptpackage.cli:main&quot; % SCRIPT_NAME],
      },
      cmdclass={
          &quot;install&quot;: install_and_symlink_script,
      },
      ...
  )
  </code></pre>
  </li>
  </ol>
  <p>When performing a local <code>python ./setup.py install</code>, the package installation and symlink creation works perfectly.</p>
  <p>But when performing a <code>pip install git+ssh://.../myscriptpackage.git</code>, it fails:</p>
  <pre><code>...
  running install_egg_info
  Copying src/myscriptpackage.egg-info to build/bdist.linux-x86_64/wheel/myscriptpackage-0.4.0-py2.7.egg-info
  running install_scripts
  creating my-script script symlink
  creating symlink from /path/to/virtualenvwrapper/project/bin/my-script to build/bdist.linux-x86_64/wheel/myscriptpackage-0.4.0.data/scripts/my-script
  error: [Errno 17] File exists
  error
  Failed building wheel for myscriptpackage
  ...
  </code></pre>
  <p>Meaning, when installing through <code>pip</code> instead of a <code>python ./setup.py install</code>:</p>
  <ol>
  <li>it fails to detect an existing symlink, and unlink it.</li>
  <li>the <code>install_and_symlink_script.install_scripts</code> variable point to the script <em>inside</em> the build directory instead of the final scripts installation directory... :-|</li>
  </ol>
  <p>So... do you know a way to get the correct scripts installation directory, compatible with both a <code>pip install</code> and a <code>python ./setup.py install</code> ?</p>
  <p>(Btw, I'm using python 2.7.13, setuptools 39.1.0, virtualenvwrapper 4.8.2 under Debian 9)</p>
  <h1>UPDATE 1</h1>
  <p>I knew the <code>error: [Errno 17] File exists</code> issue was coming from the <code>os.path.exists(symlink_path)</code> call.</p>
  <p>I just understood why: if a symlink was created from a previous install, that symlink is broken during the new install. <code>os.path.exists</code> returns False for a broken symlink. OTOH, <code>os.path.lexists</code> returns True if the symlink exists, broken or not...</p>