13

In C++ it's not too hard to get the full pathname to the folder that the shell calls "My Documents" in Windows XP and Windows 7 and "Documents" in Vista; see Get path to My Documents

Is there a simple way to do this in Python?

Community
  • 1
  • 1
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • I don't know much about windows, but isn't `os.environ['HOMEPATH']` usually defined on windows systems? – Joe Kington Oct 13 '10 at 19:34
  • @Joe, on my system `os.environ['HOMEPATH']` returns `'\\'`. – Mark Ransom Oct 13 '10 at 19:56
  • @Mark - Ah, my apologies... It seemed to work on the couple of XP machines that I have access to, and I vaguely recalled it being standard... I guess not! – Joe Kington Oct 13 '10 at 20:04
  • 2
    +1 for not wanting to use a hard-coded path to the "My Documents" folder. – In silico Oct 13 '10 at 20:12
  • On my XP machine it's `'\\Documents and Settings\\Nick'`, almost identical to `USERPROFILE` which adds the drive letter. – Nick T Oct 13 '10 at 20:14
  • @ In silico - there is no way to get a hard coded path, every user on every machine has a variation for their username – KevinDTimm Oct 13 '10 at 20:14
  • 1
    Irritatingly, Windows does not include the environment variable for this. Attempting to use HOMEPATH or USERPROFILE will burn you, as said directory is not guaranteed to exist in them, either because of Localization or because the System Administrator has moved it. – Powerlord Oct 13 '10 at 20:25
  • @KevinDTimm: That doesn't prevent some [morons](http://en.wikipedia.org/wiki/Hard_coding#My_Documents_folder_path) [from](http://blogs.msdn.com/b/oldnewthing/archive/2006/03/28/563008.aspx) [trying](http://blogs.msdn.com/b/oldnewthing/archive/2010/01/28/9954432.aspx). – In silico Oct 14 '10 at 02:42
  • A related question that may be easier to understand and use: http://stackoverflow.com/questions/6227590/finding-the-users-my-documents-path – mbear Apr 17 '13 at 19:48
  • @mbear except that the answer there doesn't work, it only gets you halfway there. – Mark Ransom Apr 17 '13 at 19:57

1 Answers1

15

You could use the ctypes module to get the "My Documents" directory:

import ctypes
from ctypes.wintypes import MAX_PATH

dll = ctypes.windll.shell32
buf = ctypes.create_unicode_buffer(MAX_PATH + 1)
if dll.SHGetSpecialFolderPathW(None, buf, 0x0005, False):
    print(buf.value)
else:
    print("Failure!")

Source: http://bugs.python.org/issue1763#msg62242

agf
  • 171,228
  • 44
  • 289
  • 238
Josh
  • 2,158
  • 18
  • 22
  • I'd give a +1, but using the ANSI version may be limiting on directories that use characters outside the default code page. – Adrian McCarthy Oct 13 '10 at 20:15
  • 1
    @Adrian McCarthy, thanks I didn't notice that. I've changed my answer to use the unicode version instead. – Josh Oct 13 '10 at 20:29
  • 1
    I presume the magic constant 0x0005 is CSIDL_PERSONAL. Is the magic constant 300 documented somewhere, or is it just MAX_PATH with some arbitrary padding added? – Mark Ransom Oct 13 '10 at 20:33
  • @Mark Ransom, yes, the hard coded 300 is MAX_PATH + 40 bytes of padding. – Josh Oct 13 '10 at 21:29
  • 1
    FWIW, a `SHGetSpecialFolderPathW()` call returns True if successful, False otherwise, so that can be checked to determine if anything useful was placed in `buf.value`. – martineau Oct 15 '10 at 03:00
  • 1
    FYI: While answering a similar question, I discovered that you can avoid hard-coding the MAX_PATH by simply importing `wintypes` from the `ctypes` module: `from ctypes import wintypes`. Now rather than hard-coding the MAX_PATH as `260`, you can just access it like so: `wintypes.MAX_PATH`. – Josh Jan 30 '11 at 21:22
  • Instead of hard-coding the folder code (`0x0005`), you could use the [CSIDL][1] (constant special item ID list) constants defined in `win32com.shell.shellcon`. In this case, the code would be `win32com.shell.shellcon.CSIDL_PERSONAL`. [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457(v=vs.85).aspx – naitsirhc Oct 14 '15 at 14:34