We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Provide compat that works with on Windows with Py 3.7.1
## Feature description
The script that creates the symbolic link doesn't work by default  when running `python -m spacy link en_core_web_sm en` -- normally if Dos is the default shell a call to `mklink` just works. However, in via this module, it does not and it is not a permission issues nor a system policy restriction as just running `mklink /d ...` from the same shell/command line works..

This fails regardless if under a virtualenv as well.

Instead a user is presented with the following error message.

```
(venv) C:\g\py\spacy> python -m spacy link en_core_web_sm en
C:\Program Files\Python37\lib\importlib\_bootstrap.py:219: RuntimeWarning: cymem.cymem.Pool size changed, may indicate binary incompatibility. Expected 48 from C header, got 64 from PyObject
  return f(*args, **kwds)
C:\Program Files\Python37\lib\importlib\_bootstrap.py:219: RuntimeWarning: cymem.cymem.Address size changed, may indicate binary incompatibility. Expected 24 from C header, got 40 from PyObject
  return f(*args, **kwds)

    Error: Couldn't link model to 'en'
    Creating a symlink in spacy/data failed. Make sure you have the required
    permissions and try re-running the command as admin, or use a
    virtualenv. You can still import the model as a module and call its
    load() method, or create the symlink manually.

    C:\g\py\spacy\venv\lib\site-packages\en_core_web_sm -->
    C:\g\py\spacy\venv\lib\site-packages\spacy\data\en

Traceback (most recent call last):
  File "C:\Program Files\Python37\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "C:\Program Files\Python37\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "C:\g\py\spacy\venv\lib\site-packages\spacy\__main__.py", line 31, in <module>
    plac.call(commands[command], sys.argv[1:])
  File "C:\g\py\spacy\venv\lib\site-packages\plac_core.py", line 328, in call
    cmd, result = parser.consume(arglist)
  File "C:\g\py\spacy\venv\lib\site-packages\plac_core.py", line 207, in consume
    return cmd, self.func(*(args + varargs + extraopts), **kwargs)
  File "C:\g\py\spacy\venv\lib\site-packages\spacy\cli\link.py", line 48, in link
    symlink_to(link_path, model_path)
  File "C:\g\py\spacy\venv\lib\site-packages\spacy\compat.py", line 87, in symlink_to
    orig.symlink_to(dest)
  File "C:\Program Files\Python37\lib\pathlib.py", line 1320, in symlink_to
    self._accessor.symlink(target, self, target_is_directory)
OSError: symbolic link privilege not held
```

The following command works regardless and has no issue with permissions nor policy. The error message indicating symbolic link privilege not held is misleading.

```
cmd /c mklink /k c:\path\to\symlink c:\target\file
```

A suggestion is changing the respective lines in `venv\Lib\site-packages\spacy\compat.py (symlink_to)`

```
def symlink_to(orig, dest):
    if is_python2 and is_windows:
        import subprocess
        subprocess.call(['mklink', '/d', path2str(orig), path2str(dest)], shell=True)
    else:
        orig.symlink_to(dest)
```

to 

```
def symlink_to(orig, dest):
    if (is_python2 or is_python3) and is_windows:
        import subprocess
        subprocess.call(['mklink', '/d', path2str(orig), path2str(dest)], shell=True)
    else:
        orig.symlink_to(dest)
````




--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `spacy/compat.py`
Content:
```
1 # coding: utf8
2 from __future__ import unicode_literals
3 
4 import sys
5 import ujson
6 import itertools
7 import locale
8 
9 from thinc.neural.util import copy_array
10 
11 try:
12     import cPickle as pickle
13 except ImportError:
14     import pickle
15 
16 try:
17     import copy_reg
18 except ImportError:
19     import copyreg as copy_reg
20 
21 try:
22     from cupy.cuda.stream import Stream as CudaStream
23 except ImportError:
24     CudaStream = None
25 
26 try:
27     import cupy
28 except ImportError:
29     cupy = None
30 
31 try:
32     from thinc.neural.optimizers import Optimizer
33 except ImportError:
34     from thinc.neural.optimizers import Adam as Optimizer
35 
36 pickle = pickle
37 copy_reg = copy_reg
38 CudaStream = CudaStream
39 cupy = cupy
40 copy_array = copy_array
41 izip = getattr(itertools, 'izip', zip)
42 
43 is_windows = sys.platform.startswith('win')
44 is_linux = sys.platform.startswith('linux')
45 is_osx = sys.platform == 'darwin'
46 
47 # See: https://github.com/benjaminp/six/blob/master/six.py
48 is_python2 = sys.version_info[0] == 2
49 is_python3 = sys.version_info[0] == 3
50 is_python_pre_3_5 = is_python2 or (is_python3 and sys.version_info[1] < 5)
51 
52 if is_python2:
53     bytes_ = str
54     unicode_ = unicode  # noqa: F821
55     basestring_ = basestring  # noqa: F821
56     input_ = raw_input  # noqa: F821
57     json_dumps = lambda data: ujson.dumps(data, indent=2, escape_forward_slashes=False).decode('utf8')
58     path2str = lambda path: str(path).decode('utf8')
59 
60 elif is_python3:
61     bytes_ = bytes
62     unicode_ = str
63     basestring_ = str
64     input_ = input
65     json_dumps = lambda data: ujson.dumps(data, indent=2, escape_forward_slashes=False)
66     path2str = lambda path: str(path)
67 
68 
69 def b_to_str(b_str):
70     if is_python2:
71         return b_str
72     # important: if no encoding is set, string becomes "b'...'"
73     return str(b_str, encoding='utf8')
74 
75 
76 def getattr_(obj, name, *default):
77     if is_python3 and isinstance(name, bytes):
78         name = name.decode('utf8')
79     return getattr(obj, name, *default)
80 
81 
82 def symlink_to(orig, dest):
83     if is_python2 and is_windows:
84         import subprocess
85         subprocess.call(['mklink', '/d', path2str(orig), path2str(dest)], shell=True)
86     else:
87         orig.symlink_to(dest)
88 
89 
90 def is_config(python2=None, python3=None, windows=None, linux=None, osx=None):
91     return (python2 in (None, is_python2) and
92             python3 in (None, is_python3) and
93             windows in (None, is_windows) and
94             linux in (None, is_linux) and
95             osx in (None, is_osx))
96 
97 
98 def normalize_string_keys(old):
99     """Given a dictionary, make sure keys are unicode strings, not bytes."""
100     new = {}
101     for key, value in old.items():
102         if isinstance(key, bytes_):
103             new[key.decode('utf8')] = value
104         else:
105             new[key] = value
106     return new
107 
108 
109 def import_file(name, loc):
110     loc = str(loc)
111     if is_python_pre_3_5:
112         import imp
113         return imp.load_source(name, loc)
114     else:
115         import importlib.util
116         spec = importlib.util.spec_from_file_location(name, str(loc))
117         module = importlib.util.module_from_spec(spec)
118         spec.loader.exec_module(module)
119         return module
120 
121 
122 def locale_escape(string, errors='replace'):
123     '''
124     Mangle non-supported characters, for savages with ascii terminals.
125     '''
126     encoding = locale.getpreferredencoding()
127     string = string.encode(encoding, errors).decode('utf8')
128     return string
129
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/spacy/compat.py b/spacy/compat.py
--- a/spacy/compat.py
+++ b/spacy/compat.py
@@ -1,6 +1,7 @@
 # coding: utf8
 from __future__ import unicode_literals
 
+import os
 import sys
 import ujson
 import itertools
@@ -80,12 +81,18 @@
 
 
 def symlink_to(orig, dest):
-    if is_python2 and is_windows:
+    if is_windows:
         import subprocess
         subprocess.call(['mklink', '/d', path2str(orig), path2str(dest)], shell=True)
     else:
         orig.symlink_to(dest)
 
+def symlink_remove(link):
+    # https://stackoverflow.com/questions/26554135/cant-delete-unlink-a-symlink-to-directory-in-python-windows
+    if( os.path.isdir(path2str(link)) and is_windows ): # this should only be on Py2.7 and windows
+        os.rmdir(path2str(link))
+    else:
+        os.unlink(path2str(link))
 
 def is_config(python2=None, python3=None, windows=None, linux=None, osx=None):
     return (python2 in (None, is_python2) and

{"golden_diff": "diff --git a/spacy/compat.py b/spacy/compat.py\n--- a/spacy/compat.py\n+++ b/spacy/compat.py\n@@ -1,6 +1,7 @@\n # coding: utf8\n from __future__ import unicode_literals\n \n+import os\n import sys\n import ujson\n import itertools\n@@ -80,12 +81,18 @@\n \n \n def symlink_to(orig, dest):\n-    if is_python2 and is_windows:\n+    if is_windows:\n         import subprocess\n         subprocess.call(['mklink', '/d', path2str(orig), path2str(dest)], shell=True)\n     else:\n         orig.symlink_to(dest)\n \n+def symlink_remove(link):\n+    # https://stackoverflow.com/questions/26554135/cant-delete-unlink-a-symlink-to-directory-in-python-windows\n+    if( os.path.isdir(path2str(link)) and is_windows ): # this should only be on Py2.7 and windows\n+        os.rmdir(path2str(link))\n+    else:\n+        os.unlink(path2str(link))\n \n def is_config(python2=None, python3=None, windows=None, linux=None, osx=None):\n     return (python2 in (None, is_python2) and\n", "issue": "Provide compat that works with on Windows with Py 3.7.1\n## Feature description\r\nThe script that creates the symbolic link doesn't work by default  when running `python -m spacy link en_core_web_sm en` -- normally if Dos is the default shell a call to `mklink` just works. However, in via this module, it does not and it is not a permission issues nor a system policy restriction as just running `mklink /d ...` from the same shell/command line works..\r\n\r\nThis fails regardless if under a virtualenv as well.\r\n\r\nInstead a user is presented with the following error message.\r\n\r\n```\r\n(venv) C:\\g\\py\\spacy> python -m spacy link en_core_web_sm en\r\nC:\\Program Files\\Python37\\lib\\importlib\\_bootstrap.py:219: RuntimeWarning: cymem.cymem.Pool size changed, may indicate binary incompatibility. Expected 48 from C header, got 64 from PyObject\r\n  return f(*args, **kwds)\r\nC:\\Program Files\\Python37\\lib\\importlib\\_bootstrap.py:219: RuntimeWarning: cymem.cymem.Address size changed, may indicate binary incompatibility. Expected 24 from C header, got 40 from PyObject\r\n  return f(*args, **kwds)\r\n\r\n    Error: Couldn't link model to 'en'\r\n    Creating a symlink in spacy/data failed. Make sure you have the required\r\n    permissions and try re-running the command as admin, or use a\r\n    virtualenv. You can still import the model as a module and call its\r\n    load() method, or create the symlink manually.\r\n\r\n    C:\\g\\py\\spacy\\venv\\lib\\site-packages\\en_core_web_sm -->\r\n    C:\\g\\py\\spacy\\venv\\lib\\site-packages\\spacy\\data\\en\r\n\r\nTraceback (most recent call last):\r\n  File \"C:\\Program Files\\Python37\\lib\\runpy.py\", line 193, in _run_module_as_main\r\n    \"__main__\", mod_spec)\r\n  File \"C:\\Program Files\\Python37\\lib\\runpy.py\", line 85, in _run_code\r\n    exec(code, run_globals)\r\n  File \"C:\\g\\py\\spacy\\venv\\lib\\site-packages\\spacy\\__main__.py\", line 31, in <module>\r\n    plac.call(commands[command], sys.argv[1:])\r\n  File \"C:\\g\\py\\spacy\\venv\\lib\\site-packages\\plac_core.py\", line 328, in call\r\n    cmd, result = parser.consume(arglist)\r\n  File \"C:\\g\\py\\spacy\\venv\\lib\\site-packages\\plac_core.py\", line 207, in consume\r\n    return cmd, self.func(*(args + varargs + extraopts), **kwargs)\r\n  File \"C:\\g\\py\\spacy\\venv\\lib\\site-packages\\spacy\\cli\\link.py\", line 48, in link\r\n    symlink_to(link_path, model_path)\r\n  File \"C:\\g\\py\\spacy\\venv\\lib\\site-packages\\spacy\\compat.py\", line 87, in symlink_to\r\n    orig.symlink_to(dest)\r\n  File \"C:\\Program Files\\Python37\\lib\\pathlib.py\", line 1320, in symlink_to\r\n    self._accessor.symlink(target, self, target_is_directory)\r\nOSError: symbolic link privilege not held\r\n```\r\n\r\nThe following command works regardless and has no issue with permissions nor policy. The error message indicating symbolic link privilege not held is misleading.\r\n\r\n```\r\ncmd /c mklink /k c:\\path\\to\\symlink c:\\target\\file\r\n```\r\n\r\nA suggestion is changing the respective lines in `venv\\Lib\\site-packages\\spacy\\compat.py (symlink_to)`\r\n\r\n```\r\ndef symlink_to(orig, dest):\r\n    if is_python2 and is_windows:\r\n        import subprocess\r\n        subprocess.call(['mklink', '/d', path2str(orig), path2str(dest)], shell=True)\r\n    else:\r\n        orig.symlink_to(dest)\r\n```\r\n\r\nto \r\n\r\n```\r\ndef symlink_to(orig, dest):\r\n    if (is_python2 or is_python3) and is_windows:\r\n        import subprocess\r\n        subprocess.call(['mklink', '/d', path2str(orig), path2str(dest)], shell=True)\r\n    else:\r\n        orig.symlink_to(dest)\r\n````\r\n\r\n\r\n\n", "before_files": [{"content": "# coding: utf8\nfrom __future__ import unicode_literals\n\nimport sys\nimport ujson\nimport itertools\nimport locale\n\nfrom thinc.neural.util import copy_array\n\ntry:\n    import cPickle as pickle\nexcept ImportError:\n    import pickle\n\ntry:\n    import copy_reg\nexcept ImportError:\n    import copyreg as copy_reg\n\ntry:\n    from cupy.cuda.stream import Stream as CudaStream\nexcept ImportError:\n    CudaStream = None\n\ntry:\n    import cupy\nexcept ImportError:\n    cupy = None\n\ntry:\n    from thinc.neural.optimizers import Optimizer\nexcept ImportError:\n    from thinc.neural.optimizers import Adam as Optimizer\n\npickle = pickle\ncopy_reg = copy_reg\nCudaStream = CudaStream\ncupy = cupy\ncopy_array = copy_array\nizip = getattr(itertools, 'izip', zip)\n\nis_windows = sys.platform.startswith('win')\nis_linux = sys.platform.startswith('linux')\nis_osx = sys.platform == 'darwin'\n\n# See: https://github.com/benjaminp/six/blob/master/six.py\nis_python2 = sys.version_info[0] == 2\nis_python3 = sys.version_info[0] == 3\nis_python_pre_3_5 = is_python2 or (is_python3 and sys.version_info[1] < 5)\n\nif is_python2:\n    bytes_ = str\n    unicode_ = unicode  # noqa: F821\n    basestring_ = basestring  # noqa: F821\n    input_ = raw_input  # noqa: F821\n    json_dumps = lambda data: ujson.dumps(data, indent=2, escape_forward_slashes=False).decode('utf8')\n    path2str = lambda path: str(path).decode('utf8')\n\nelif is_python3:\n    bytes_ = bytes\n    unicode_ = str\n    basestring_ = str\n    input_ = input\n    json_dumps = lambda data: ujson.dumps(data, indent=2, escape_forward_slashes=False)\n    path2str = lambda path: str(path)\n\n\ndef b_to_str(b_str):\n    if is_python2:\n        return b_str\n    # important: if no encoding is set, string becomes \"b'...'\"\n    return str(b_str, encoding='utf8')\n\n\ndef getattr_(obj, name, *default):\n    if is_python3 and isinstance(name, bytes):\n        name = name.decode('utf8')\n    return getattr(obj, name, *default)\n\n\ndef symlink_to(orig, dest):\n    if is_python2 and is_windows:\n        import subprocess\n        subprocess.call(['mklink', '/d', path2str(orig), path2str(dest)], shell=True)\n    else:\n        orig.symlink_to(dest)\n\n\ndef is_config(python2=None, python3=None, windows=None, linux=None, osx=None):\n    return (python2 in (None, is_python2) and\n            python3 in (None, is_python3) and\n            windows in (None, is_windows) and\n            linux in (None, is_linux) and\n            osx in (None, is_osx))\n\n\ndef normalize_string_keys(old):\n    \"\"\"Given a dictionary, make sure keys are unicode strings, not bytes.\"\"\"\n    new = {}\n    for key, value in old.items():\n        if isinstance(key, bytes_):\n            new[key.decode('utf8')] = value\n        else:\n            new[key] = value\n    return new\n\n\ndef import_file(name, loc):\n    loc = str(loc)\n    if is_python_pre_3_5:\n        import imp\n        return imp.load_source(name, loc)\n    else:\n        import importlib.util\n        spec = importlib.util.spec_from_file_location(name, str(loc))\n        module = importlib.util.module_from_spec(spec)\n        spec.loader.exec_module(module)\n        return module\n\n\ndef locale_escape(string, errors='replace'):\n    '''\n    Mangle non-supported characters, for savages with ascii terminals.\n    '''\n    encoding = locale.getpreferredencoding()\n    string = string.encode(encoding, errors).decode('utf8')\n    return string\n", "path": "spacy/compat.py"}], "after_files": [{"content": "# coding: utf8\nfrom __future__ import unicode_literals\n\nimport os\nimport sys\nimport ujson\nimport itertools\nimport locale\n\nfrom thinc.neural.util import copy_array\n\ntry:\n    import cPickle as pickle\nexcept ImportError:\n    import pickle\n\ntry:\n    import copy_reg\nexcept ImportError:\n    import copyreg as copy_reg\n\ntry:\n    from cupy.cuda.stream import Stream as CudaStream\nexcept ImportError:\n    CudaStream = None\n\ntry:\n    import cupy\nexcept ImportError:\n    cupy = None\n\ntry:\n    from thinc.neural.optimizers import Optimizer\nexcept ImportError:\n    from thinc.neural.optimizers import Adam as Optimizer\n\npickle = pickle\ncopy_reg = copy_reg\nCudaStream = CudaStream\ncupy = cupy\ncopy_array = copy_array\nizip = getattr(itertools, 'izip', zip)\n\nis_windows = sys.platform.startswith('win')\nis_linux = sys.platform.startswith('linux')\nis_osx = sys.platform == 'darwin'\n\n# See: https://github.com/benjaminp/six/blob/master/six.py\nis_python2 = sys.version_info[0] == 2\nis_python3 = sys.version_info[0] == 3\nis_python_pre_3_5 = is_python2 or (is_python3 and sys.version_info[1] < 5)\n\nif is_python2:\n    bytes_ = str\n    unicode_ = unicode  # noqa: F821\n    basestring_ = basestring  # noqa: F821\n    input_ = raw_input  # noqa: F821\n    json_dumps = lambda data: ujson.dumps(data, indent=2, escape_forward_slashes=False).decode('utf8')\n    path2str = lambda path: str(path).decode('utf8')\n\nelif is_python3:\n    bytes_ = bytes\n    unicode_ = str\n    basestring_ = str\n    input_ = input\n    json_dumps = lambda data: ujson.dumps(data, indent=2, escape_forward_slashes=False)\n    path2str = lambda path: str(path)\n\n\ndef b_to_str(b_str):\n    if is_python2:\n        return b_str\n    # important: if no encoding is set, string becomes \"b'...'\"\n    return str(b_str, encoding='utf8')\n\n\ndef getattr_(obj, name, *default):\n    if is_python3 and isinstance(name, bytes):\n        name = name.decode('utf8')\n    return getattr(obj, name, *default)\n\n\ndef symlink_to(orig, dest):\n    if is_windows:\n        import subprocess\n        subprocess.call(['mklink', '/d', path2str(orig), path2str(dest)], shell=True)\n    else:\n        orig.symlink_to(dest)\n\ndef symlink_remove(link):\n    # https://stackoverflow.com/questions/26554135/cant-delete-unlink-a-symlink-to-directory-in-python-windows\n    if( os.path.isdir(path2str(link)) and is_windows ): # this should only be on Py2.7 and windows\n        os.rmdir(path2str(link))\n    else:\n        os.unlink(path2str(link))\n\ndef is_config(python2=None, python3=None, windows=None, linux=None, osx=None):\n    return (python2 in (None, is_python2) and\n            python3 in (None, is_python3) and\n            windows in (None, is_windows) and\n            linux in (None, is_linux) and\n            osx in (None, is_osx))\n\n\ndef normalize_string_keys(old):\n    \"\"\"Given a dictionary, make sure keys are unicode strings, not bytes.\"\"\"\n    new = {}\n    for key, value in old.items():\n        if isinstance(key, bytes_):\n            new[key.decode('utf8')] = value\n        else:\n            new[key] = value\n    return new\n\n\ndef import_file(name, loc):\n    loc = str(loc)\n    if is_python_pre_3_5:\n        import imp\n        return imp.load_source(name, loc)\n    else:\n        import importlib.util\n        spec = importlib.util.spec_from_file_location(name, str(loc))\n        module = importlib.util.module_from_spec(spec)\n        spec.loader.exec_module(module)\n        return module\n\n\ndef locale_escape(string, errors='replace'):\n    '''\n    Mangle non-supported characters, for savages with ascii terminals.\n    '''\n    encoding = locale.getpreferredencoding()\n    string = string.encode(encoding, errors).decode('utf8')\n    return string\n", "path": "spacy/compat.py"}]}