compare two windows paths, one containing tilde, in python - python

I'm trying to use the TMP environment variable in a program. When I ask for
tmp = os.path.expandvars("$TMP")
I get
C:\Users\STEVE~1.COO\AppData\Local\Temp
Which contains the old-school, tilde form. A function I have no control over returns paths like
C:\Users\steve.cooper\AppData\Local\Temp\file.txt
My problem is this; I'd like to check if the file is in my temp drive, but I can't find a way to compare them. How do you tell if these two Windows directories;
C:\Users\STEVE~1.COO\AppData\Local\Temp
C:\Users\steve.cooper\AppData\Local\Temp
are the same?

Here is alternative solution using only ctypes from Standard Python Library.
tmp = unicode(os.path.expandvars("$TMP"))
import ctypes
GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
buffer = ctypes.create_unicode_buffer(GetLongPathName(tmp, 0, 0))
GetLongPathName(tmp, buffer, len(buffer))
print buffer.value

You will need the python win32 extensions from http://sourceforge.net/projects/pywin32/ or I use python packaged by ActiveState
They include the function win32file.GetLongPathName which will transform the 8.3 version into the full path.

Related

How to separate filename from path in python (PyQt4.QtCore.QString)

How to separate filename from path using Python?
I'm using PyQt4 and my String is not Python String but, PyQt4.QtCore.QString
I can do it like:
filename=my_path.split("/")[-1]
But I think separator is OS specific, also I can't use something like os.path.basename because it only work for original python string, so what will be the best option to do it?
You can convert the QString to a Python str before use. For example:
filename_str = unicode(my_path)
...and then use standard Python os functions to get the filename:
os.path.basename(filename_str)
Or, in a single step:
os.path.basename(unicode(my_path))
Note you can avoid this problem altogether by using the newer PyQt4 API v2, or alternatively using PyQt5. With these updates PyQt functions return native Python strings (and other variables) where possible so you can work with them without converting. It makes things a lot simpler.

Convert a str to path type?

I am trying to interface with some existing code that saves a configuration, and expects a file path that is of type path.path. The code is expecting that the file path is returned from a pygtk browser window (via another function). I want to call the save_config function elsewhere in my code with a file path based on different inputs, constructed from string elements.
When I try to run the code, I am able to construct the file path correctly, but it is a string type, and the save function expects a path.path type.
Is there a way to convert a string to a path type? I've tried searching, but could only find the reverse case (path to string). I also tried using os.path.join(), but that returns a string as well.
Edit: This is python 2.7, if that makes a difference.
Since python 3.4:
from pathlib import Path
str_path = "my_path"
path = Path(str_path)
https://docs.python.org/3/library/pathlib.html#module-pathlib
Maybe that answer worked for python 2.7, if you are on Python 3 I like:
import os
p = "my/path/to/file.py"
os.path.normpath(p)
'my\\path\\to\\file.py'
If path.path represents a type, you can probably create an instance of that type with something like:
string_path = "/path/to/some/file"
the_path = path.path(string_path)
save_config(the_path())

Python - finding TTF files

Can anyone improve on this? I'm fairly new to python and am trying to write portable code. I need to locate a font file to pass to ImageDraw.Draw.Text.
import matplotlib.font_manager as fontman
def findFontFile(searchFont):
fList = fontman.findSystemFonts(fontpaths=None, fontext='ttf')
targetFont = []
for row in fList:
try:
if searchFont in row:
targetFont.append(row)
except TypeError:
pass
return targetFont[0]
On my system this gives me:
>>> findFontFile('DejaVuSans.ttf')
'/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf'
Which is exactly what I need. Does this look like it will work on Mac / Windows systems as well as Linux (tested on Linux)? Could it be done more efficiently? In a more readable style? Will Mac / Windows have a different font file naming format? Suggestions welcome.
I would do a little rewrite like (some changes are just a matter of style, more python like):
def find_font_file(query):
matches = list(filter(lambda path: query in os.path.basename(path), fontman.findSystemFonts()))
return matches
The caller would then decide the element to use (after checking permissions etc).
As for the compatibility you can view here that the lib uses a set of common directories for the "main" operating systems to search for fonts (X window manager (linux), windows and os x). But you can always pass the directories where you want to search if you have more information on the different environments where the app is going to run.
be careful when doing if searchFont in row.
If someone has username is marial, and you're searching for the font arial, by using findFontFile('arial'), your code would be getting all of the fonts installed in the user's home directory (i.e. /home/marial/.fonts).

Python - Windows maximum directory path length workaround

The problem is the character limit for the path in windows when creating multiple directories using pythons os.makedirs()
I found this post when searching for my problem before posting this:
python win32 filename length workaround
Now the chosen answer suggests the prefix workaround but my question here is, is there a way to ensure functionality in Windows and UNIX?
The other approach I thought of was to create the folders one by one and then create the file so that you never exceed the path length, but I can't figure out the obvious bug in the code.
path = ['folder1/s1/s1/abc.txt',
'folder1/s1/s2/def.txt']
def makedirs(path):
explode = path.split('/')
for i in range(len(explode)-1):
os.mkdir(explode[i])
os.chdir(explode[i])
if i == len(explode) -2:
download_file(explode[i+1])
# something to go back here
os.chdir('../' * (len(explode)-3)) # ??
makedirs(path[0])
Now this works for only the first line because I can't figure out how to get back to the root or reset it. Without the 'reset' the folders are being under each other:
folder1/s1/s1/folder1/s1/s1/abc.txt (or something like that)
I could set the path from root to reset it but then we might run into the same issue of reaching the max length. Any help on how to get this working on both OS would be appreciated!
Please feel free to point out where I'm wrong.
you need to use unc path and unicode filenames, but not all python functions are aware of this, os.mkdir works while os.makedirs not
import os
path = u'\\\\?\\c:\\'
for i in xrange(1000):
path += u'subdir\\'
os.mkdir(path)
but it's better to give also the code to remove them, windows explorer is unable to delete
import os
path = u'\\\\?\\c:\\'
for i in xrange(1000, 0, -1):
try:
os.rmdir(path + (u'subdir\\' * i))
except:
pass
Per this stackoverflow answer: while chdir can go up one directory with os.chdir(".."), the platform-agnostic way is: os.chdir(os.pardir).
Either call this N times in a loop;
or try an unreadable one-liner like this (untested):
os.chdir(os.path.join(*([os.pardir] * NUM_TIMES)))
(Instead of path.split('/'), you could also use the method described here for it to work on all operating systems)

converting/mapping linux reference path without altering the file?

Currently on a project that my client needs the reference file path to
remain in linux format. For example
A.ma , referencing objects from --> //linux/project/scene/B.ma
B.ma , referencing objects from --> //linux/project/scene/C.ma
Most of our Maya license here however are on Windows. I can run a
Python script that convert all the paths windows paths and save the
file. For example
Z:\project\scene\B.ma
However I'm trying to figure out a way to do this without converting
or altering the original file.... I'll try to explain what I'm trying to do.
Run the script to open the file.
The script checks for the linux formatted reference path, and all
child path down the hierarchy.
Maps all paths to their appropriate windows formatted paths.
Giving the animators the ability to "save" files normally without running a separate save script.
Is this possible to achieve this with Python script? Or will I need a
fully-compiled plug in to get this to work?
Any suggestion is greatly appreciated.
edit: Thank you for your input.
A little more clarification. The projects were set up for us by a remote company and part of the requirement is that we have to keep the path as is. They come as absolute path and we have no choice in that matter.
We match the mount //linux/ on our Fedora workstations. That same drive is mapped to Z:\ on our windows workstations. We only have 2 Maya license for Linux tho which is why I'm trying to do this.
Here is a solution. First step is to create a dict that keeps track of linux/windows references (don't forget to import the re module for regexp):
>>> def windows_path(path):
return path.replace('//linux', 'Z:').replace('/', '\\')
>>> reg = re.compile('(\w+\.ma) , referencing objects from --> (.*)')
>>> d = {}
>>> for line in open('D:\\temp\\Toto.txt'):
match = reg.match(line)
if match:
file_name = match.groups()[0]
linux_path = match.groups()[1]
d[file_name] = (linux_path, windows_path(linux_path))
>>> d
{'B.ma': ('//linux/project/scene/C.ma', 'Z:\\project\\scene\\C.ma'),
'A.ma': ('//linux/project/scene/B.ma', 'Z:\\project\\scene\\B.ma')}
Then you just need to loop on this dict to ask for file save:
>>> for file_name in d.keys():
s = raw_input('do you want to save file %s ? ' % file_name)
if s.lower() in ('y', 'yes'):
# TODO: save your file thanks to d[file][0] for linux path,
# d[file][1] for windows path
print '-> file %s was saved' % file_name
else:
print '-> file %s was not saved' % file_name
do you want to save file B.ma ? n
-> file B.ma was not saved
do you want to save file A.ma ? yes
-> file A.ma was saved
Many Windows applications will interpret paths with two leading "/"s as UNC paths. I don't know if Maya is one of those, but try it out. If Maya can understand paths like "//servername/share/foo", then all you need to do is set up a SMB server named "linux", and the paths will work as they are. I would guess that this is actually what your client does, since the path "//linux" would not make sense in a Linux-only environment.
You can use environment variables to do this. Maya will expand environment vars present in a file path, you could use Maya.env to set them up properly for each platform.
What you are looking for is the dirmap mel command. It is completely non-intrusive to your files as you just define a mapping from your linux paths to windows and/or vice versa. Maya will internally apply the mapping to resolve the paths, without changing them when saving the file.
To setup dirmap, you need to run a MEL script which issues the respective commands on maya startup. UserSetup.mel could be one place to put it.
For more details, see the official documentation - this particular link points to maya 2012, the command is available in Maya 7.0 and earlier as well though:
http://download.autodesk.com/global/docs/maya2012/en_us/Commands/dirmap.html

Categories

Resources