| 1 |
import xml.dom.minidom as minidom |
|---|
| 2 |
import os |
|---|
| 3 |
from glob import glob |
|---|
| 4 |
|
|---|
| 5 |
MIME_MEDIA = ('application', 'audio', 'image', 'inode', 'magic', 'message', |
|---|
| 6 |
'model', 'multipart', 'text', 'video') |
|---|
| 7 |
|
|---|
| 8 |
class InvalidMimeType(Exception): |
|---|
| 9 |
""" Thrown if a MIME type is invalid. """ |
|---|
| 10 |
|
|---|
| 11 |
class InvalidMimeExtension(Exception): |
|---|
| 12 |
""" Thrown if a file extension has no matching MIME type. """ |
|---|
| 13 |
|
|---|
| 14 |
class MimeType: |
|---|
| 15 |
""" A representation of a MIME type. """ |
|---|
| 16 |
def __init__(self, description, parent, type, aliases, globs): |
|---|
| 17 |
self.description, self.parent, self.type, self.aliases, self.globs = \ |
|---|
| 18 |
description, parent, type, aliases, globs |
|---|
| 19 |
|
|---|
| 20 |
def __repr__(self): |
|---|
| 21 |
return "<%s.%s '%s'>" % (self.__module__, self.__class__.__name__, self.type) |
|---|
| 22 |
|
|---|
| 23 |
class SharedMimeInfo: |
|---|
| 24 |
""" A Python interface to the shared-mime-info specification database |
|---|
| 25 |
(http://www.freedesktop.org/Standards/shared-mime-info-spec). """ |
|---|
| 26 |
def __init__(self): |
|---|
| 27 |
self.paths = [x for x in (os.path.expanduser('~/.local/share/mime'), '/usr/local/share/mime', '/usr/share/mime') if os.path.isdir(x)] |
|---|
| 28 |
self.globs = {} |
|---|
| 29 |
self.extensions = {} |
|---|
| 30 |
self.aliases = {} |
|---|
| 31 |
for path in self.paths: |
|---|
| 32 |
# Load globs |
|---|
| 33 |
try: |
|---|
| 34 |
globfile = open(os.path.join(path, 'globs'), 'r') |
|---|
| 35 |
for line in globfile: |
|---|
| 36 |
line = line.strip() |
|---|
| 37 |
if line.startswith('#') or not line: |
|---|
| 38 |
continue |
|---|
| 39 |
type, glob = line.strip().split(':') |
|---|
| 40 |
self.globs.setdefault(type, []).append(glob) |
|---|
| 41 |
self.extensions[glob] = type |
|---|
| 42 |
globfile.close() |
|---|
| 43 |
except IOError: |
|---|
| 44 |
pass |
|---|
| 45 |
# Load aliases |
|---|
| 46 |
try: |
|---|
| 47 |
aliasfile = open(os.path.join(path, 'aliases'), 'r') |
|---|
| 48 |
for line in aliasfile: |
|---|
| 49 |
alias, target = line.strip().split() |
|---|
| 50 |
self.aliases[alias] = target |
|---|
| 51 |
aliasfile.close() |
|---|
| 52 |
except IOError: |
|---|
| 53 |
pass |
|---|
| 54 |
|
|---|
| 55 |
def _file_for_type(self, type): |
|---|
| 56 |
for path in self.paths: |
|---|
| 57 |
file = os.path.join(path, os.path.extsep.join([type, 'xml'])) |
|---|
| 58 |
if os.path.isfile(file): |
|---|
| 59 |
return file |
|---|
| 60 |
raise InvalidMimeType(type) |
|---|
| 61 |
|
|---|
| 62 |
def lookup_type(self, type): |
|---|
| 63 |
""" Get a MimeType object for a MIME type. """ |
|---|
| 64 |
if type in self.aliases: |
|---|
| 65 |
type = self.aliases[type] |
|---|
| 66 |
dom = minidom.parse(self._file_for_type(type)) |
|---|
| 67 |
description = dom.getElementsByTagName('comment')[0].childNodes[0].data |
|---|
| 68 |
parent = dom.getElementsByTagName('sub-class-of') |
|---|
| 69 |
aliases = [x.attributes['type'].value for x in dom.getElementsByTagName('alias')] |
|---|
| 70 |
if parent: |
|---|
| 71 |
parent = parent[0].attributes['type'].value |
|---|
| 72 |
else: |
|---|
| 73 |
parent = None |
|---|
| 74 |
return MimeType(description, parent, type, aliases, list(self.globs[type])) |
|---|
| 75 |
|
|---|
| 76 |
def lookup_extension(self, extension): |
|---|
| 77 |
""" Get a MimeType object for a file extension. """ |
|---|
| 78 |
try: |
|---|
| 79 |
return self.type(self.extensions['*.' + extension]) |
|---|
| 80 |
except KeyError: |
|---|
| 81 |
raise InvalidMimeExtension(extension) |
|---|
| 82 |
|
|---|
| 83 |
def __iter__(self): |
|---|
| 84 |
""" Iterate over all available MIME type names. """ |
|---|
| 85 |
global MIME_MEDIA |
|---|
| 86 |
for path in self.paths: |
|---|
| 87 |
for media in MIME_MEDIA: |
|---|
| 88 |
if os.path.isdir(os.path.join(path, media)): |
|---|
| 89 |
for type in glob(os.path.join(path, media, '*.xml')): |
|---|
| 90 |
yield '%s/%s' % (media, os.path.basename(os.path.splitext(type)[0])) |
|---|
| 91 |
|
|---|
| 92 |
def __getitem__(self, type): |
|---|
| 93 |
return self.lookup_type(type) |
|---|