2

I am creating a Python 2.7 script to automate an environment setup which is to be used on Windows and Linux (Ubuntu) systems, preferably with vanilla Python.

I am having trouble getting Python to create a symlink on Windows (I'm sure it's much simpler on Linux), and based on approaches from other Stack Overflow questions, I've still not been able to get this to work.

My first approach was to simply use os.symlink in a very simple method

def createSymlink(source, dest):
    os.symlink(source,dest)

But this returns an error: AttributeError: 'module' object has no attribute 'symlink'

After more searching, I tried another approach based on [this][1] answer, but I get a similar error.

  File "C:/Workspace/PythonProjects/architect/main.py", line 94, in createSymlink
    os.symlink = symlink_ms(source, dest)
  File "C:/Workspace/PythonProjects/architect/main.py", line 86, in symlink_ms
    csl.argtypes = (ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_unit32)
AttributeError: 'module' object has no attribute 'c_unit32'

My code for this approach is as follows, and _OS == 'Windows' is True.

def createSymlink(source, dest):
    if _OS == 'Windows':
        def symlink_ms(source, dest):
            import ctypes
            csl = ctypes.windll.kernel32.CreateSymbolicLinkW
            csl.argtypes = (ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_unit32)
            csl.restype = ctypes.c_ubyte
            flags = 1 if os.path.isdir(source) else 0
            try:
                if csl(dest, source.replace('/', '\\'), flags) == 0:
                    raise ctypes.WinError()
            except:
                pass
        os.symlink = symlink_ms(source, dest)

I am very new to Python, so I may be looking at this entirely wrong, but is there a way to get this working without pulling in third party libraries? [1]: https://stackoverflow.com/a/8464306/5134416

Donglecow
  • 507
  • 4
  • 22
  • 3
    Can you use Python 3 instead? 3.x has supported `os.symlink` on Windows for years. – Eryk Sun Oct 29 '17 at 09:30
  • 1
    Otherwise using ctypes is fine, but monkeypatching os is not a good practice. Just do `from os import symlink` and handle the `ImportError` on Windows by defining a `symlink` function. Use `kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)` to avoid modifying global `windll` and protect the thread's last error value. If the call fails, raise an exception via `raise ctypes.WinError(ctypes.get_last_error())`. Also, add a `target_is_directory=False` option, like Python 3 has, in order to support creating a directory symlink when the target doesn't exist yet. – Eryk Sun Oct 29 '17 at 09:33
  • I can use Python 3. I have both installed. I'll make the switch and give it a try later on. I agree, and wasn't too happy with hacking up the createSymlink method! – Donglecow Oct 30 '17 at 08:42
  • @eryksun - You were right. With Python 3 it _just works_ (after giving my account the create symlink privilege). I was put off using it at first since third party package support is apparently less than with Python 2. I suppose it doesn't matter too much as I'm trying to keep it vanilla anyway! If you want to put your comment in as an answer, I'll accept it. – Donglecow Oct 30 '17 at 10:34

0 Answers0