Python - finding TTF files - python

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).

Related

os.path operation in Django, change/join path issue

I'm getting the name of a file in Django after an Image save :
path-> 'companies/92_dsa/log/Hydrangeas.jpg' as it is in database
I do a clone of the file, an resize (is an image) and want to save the new file with a different name.
I get the directory of the original file:
folder = os.path.dirname(path)
the filename and extension:
filename, extension = os.path.splitext(os.path.basename(media_path))
then create a
new_filename = filename + '_sz' + extension
and the I want to recreate the path:
new_path = os.path.join(folder, new_filename)
and the problem(slash-backslash before the filename):
'companies/94_sda/logos\Hydrangeas_sz.jpg'
I'm working in Windows, bur the final deploy probably will be on Linux, so I want a fix indifferent of the OS.
so I want a fix indifferent of the OS.
Unfortunately, you can't really have your cake and eat it.
You say that
I'm working in Windows, bur the final deploy probably will be on Linux
This implies you are running the program on Windows, but dealing with *nix file names (be it Linux, Unix, or mac OS).
To do this completely os-independent ... you would need to split the original path on "/" to get all the sub components and then re-join them with os.path.join.
But then you need to deal with the fact that directory structures for absolute paths are very different between the two OS's - not to mention the leading drive specifier on Windows. This is less of an issue if you are only dealing with relative paths.
In short, the root of your problem is that the database contains Linux-style paths and you are processing them on Windows. You would have a similar problem if it was the other way around.
You need to choose your deployment platform and code for it.
Alternatively, write your code to simply remove the extension from the full path and replace it with "_sz."+extension
Since you don't actually care about the path in relation to the host OS (because you've chosen to store paths POSIX style in your DB), you can just use string joining: new_path = '/'.join([folder, new_filename]), or you could import the posixpath module directly import posixpath; new_path = posixpath.join(folder, new_filename).
You could also investigate PathLib, though that may be overkill for you.

FileNotFoundError WinError 3

I'm trying to learn how to edit files, but I'm a bit of a python novice, and not all that bright, so when I get a FileNotFoundError I can't figure out how to fix it despite several searches on the interwebz.
import os
old = 'Users\My Name\Pictures\2013\182904_10201130467645938_341581100_n'
new = 'Users\My Name\Pictures\2013\Death_Valley_1'
os.rename(old, new)
'Users\My Name\Pictures\2013\182904_10201130467645938_341581100_n' is a relative path.
Unless you are running your code from the directory that contains the Users dir (which if you are using Windows would most probably be the root C: dir), Python isn't going to find that file.
You also have to make sure to include the file extension if it has any.
There are few ways to solve this, the easiest one will be to use the absolute paths in your code, ie 'C:\Users\My Name\Pictures\2013\182904_10201130467645938_341581100_n.jpg'.
You will also want to use r before the paths, so you want need to escape every \ character.
import os
old = r'C:\Users\My Name\Pictures\2013\182904_10201130467645938_341581100_n.jpg'
new = r'C:\Users\My Name\Pictures\2013\Death_Valley_1.jpg'
os.rename(old, new)
This of course assumes your drive letter is C.

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

Accessing a file relatively in Python if you do not know your starting point?

Hey. I've got a project in Python, whose directory layout is the following:
root
|-bin
|-conf
|-[project]
Python files in [project] need to be able to read configuration data from the 'conf' directory, but I cannot guarantee the location of root, plus it may be used on both Linux, Mac and Windows machines so I am trying to relatively address the conf directory from the root directory.
At the minute it's working with a dirty hack (from root/bin, particular python filename is 8 chars long):
path = os.path.abspath(__file__)[:-8]
os.chdir(path)
os.chdir("..")
[projectclass].config('config/scans.json') #for example
But this is particularly horrid and is giving me nightmares. Is there a better way to accomplish what I'm trying to achieve that doesn't feel so dirty? I feel like I'm missing something very obvious. Thanks in advance.
Instead of:
path = os.path.abspath(__file__)[:-8]
use:
path = os.path.dirname(os.path.abspath(__file__))
See the docs here.

Categories

Resources