Add direct yaml and json support to resources.
[naja.git] / naja / resources / loader.py
1 import os
2 import sys
3 import json
4
5 try:
6     from pkg_resources import resource_filename
7 except ImportError:
8     # OK, we're most likely running under py2exe, so this is safe
9     # (for values of safe that are unconcerned about py2exe being involved)
10     def resource_filename(mod, path):
11         # There are better ways of doing this, but I've spent too much
12         # time going down this rabbithole already
13         return os.path.join(os.path.dirname(__file__), '..', '..', 'data',
14                             path)
15
16 try:
17     import yaml
18 except ImportError:
19     yaml = None
20
21 import pygame
22
23
24 class ResourceNotFound(Exception):
25     pass
26
27
28 class Loader(object):
29     CONVERT_ALPHA = True
30
31     def __init__(self, resource_module, language=None):
32         self.resource_module = resource_module
33         self.lang_dialect = language
34         self.language = language.split('_', 1)[0] if language else None
35         self._cache = {}
36
37     def create_resource_path(self, *path_fragments):
38         return resource_filename(self.resource_module,
39                                  os.path.join(*path_fragments))
40
41     def get_resource_path(self, *path_fragments):
42         for mod, full_path_fragments in self.lang_locations(path_fragments):
43             path = resource_filename(mod, os.path.join(*full_path_fragments))
44             if os.path.exists(path):
45                 return path
46         raise ResourceNotFound(os.path.join(*path_fragments))
47
48     def lang_locations(self, path_fragments):
49         '''
50         For each resource module, yield:
51         * (<module>, (<lang>_<dialect>, <path>))
52         * (<module>, (<lang>, <path>))
53         * (<module>, (<path>, ))
54         '''
55         for module in (self.resource_module,):
56             if self.lang_dialect:
57                 yield (module, (self.lang_dialect,) + path_fragments)
58             if self.language != self.lang_dialect:
59                 yield (module, (self.language,) + path_fragments)
60             yield (module, path_fragments)
61
62     def get_file(self, *path_fragments, **kw):
63         mode = kw.get('mode', "rU")
64         try:
65             path = self.get_resource_path(*path_fragments)
66         except ResourceNotFound:
67             if 'w' in mode:
68                 path = self.create_resource_path(*path_fragments)
69             else:
70                 raise
71         return file(path, mode)
72
73     def get_image(self, *name_fragments, **kw):
74         transforms = kw.get('transforms', ())
75         basedir = kw.get('basedir', 'images')
76
77         path = (basedir,) + name_fragments
78
79         if path not in self._cache:
80             fn = self.get_resource_path(*path)
81             image = pygame.image.load(fn)
82             if self.CONVERT_ALPHA:
83                 if not pygame.display.get_init():
84                     print >> sys.stderr, ("Display not initialized, "
85                                           "image '%s' not loaded."
86                                           % os.path.join(*path))
87                     return
88                 image = image.convert_alpha(pygame.display.get_surface())
89             self._cache[path] = image
90
91         key = (path, transforms)
92         if key not in self._cache:
93             image = self._cache[path]
94             for mutator in transforms:
95                 image = mutator(image)
96             self._cache[key] = image
97
98         return self._cache[key]
99
100     def get_font(self, file_name, font_size):
101         basedir = 'fonts'
102         key = (basedir, file_name, font_size)
103
104         if key not in self._cache:
105             fn = self.get_resource_path(basedir, file_name)
106             self._cache[key] = pygame.font.Font(fn, font_size)
107
108         return self._cache[key]
109
110     def get_yaml(self, *path_fragments):
111         if yaml is None:
112             raise ResourceNotFound("%s - %s" % (
113                 os.path.join(*path_fragments),
114                 "YAML module not available"))
115         with self.get_file(*path_fragments) as yaml_file:
116             return yaml.safe_load(yaml_file)
117
118     def get_json(self, *path_fragments):
119         with self.get_file(*path_fragments) as json_file:
120             return json.load(json_file)