File: resource.py

package info (click to toggle)
thuban 1.2.2-14
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 9,176 kB
  • sloc: python: 30,410; ansic: 6,181; xml: 4,234; cpp: 1,595; makefile: 145
file content (239 lines) | stat: -rw-r--r-- 7,752 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# Copyright (c) 2003 by Intevation GmbH
# Authors:
# Jonathan Coles <jonathan@intevation.de>
#
# This program is free software under the GPL (>=v2)
# Read the file COPYING coming with Thuban for details.

"""Handle resources loaded from files such as projections"""

__version__ = "$Revision: 2885 $"
# $Source$
# $Id: resource.py 2885 2009-08-18 13:35:30Z dpinte $


import os
import os.path
import weakref
import traceback

import Thuban
from Thuban import _

from Thuban.Lib.fileutil import get_application_dir, get_thuban_dir

from Thuban.Model.xmlreader import XMLReader
from Thuban.Model.xmlwriter import XMLWriter
from Thuban.Model.proj import Projection, ProjFile
from xml.sax import SAXParseException

# The directory where the default projections are stored has to be changed
# for
# the debian package to be conformant with the FHS
#projdir = os.path.join(get_thuban_dir(), "Resources", "Projections")
projdir = "/usr/share/thuban/Resources/Projections"

PROJ_EXT = ".proj"

# Determine the status of GDAL support. If GDAL is supported
# gdal_support_status will be set to the empty string, otherwise to a
# string with information why it isn't supported
#
# GDAL is supported if we can import both the thuban specific gdalwarp
# module and the GDAL python bindings.
osgeo_gdal_version = False
for _module in ("gdalwarp", "osgeo.gdal"):
    try:
        print "importing %s" % _module
        __import__(_module)
    except ImportError, val:
        gdal_support_status = (_("No GDAL support because module '%s'"
                                 " cannot be imported. Python exception: '%s'")
                               % (_module, str(val)))
        break
else:
    gdal_support_status = ""

def has_gdal_support():
    return gdal_support_status == ""


projfile_cache = weakref.WeakValueDictionary()

def clear_proj_file_cache():
    """Clear the cache of ProjFile objects maintained by read_proj_file.

    This function is probably only useful for the test suite.
    """
    projfile_cache.clear()

def read_proj_file(filename):
    """Read a .proj file and return a ProjFile object and warnings

    The return value is a tuple with the ProjFile object and a list of
    strings with warnings messages that might have been generated by the
    proj file parser.

    The objects returned cached so that reading the same file
    (identified by its absolute name) several times yields the same
    ProjFile object. The cache uses weak references so the objects will
    be removed from the cache once the last reference an object in the
    cache is removed.

    Raises IOError if the file cannot be opened, OSError if the file
    cannot be read and SAXParseException if the file is not valid XML.
    """
    filename = os.path.abspath(filename)
    if filename in projfile_cache:
        return projfile_cache[filename], []
    else:
        handler = ProjFileReader()
        handler.read(filename)
        proj_file = handler.GetProjFile()
        projfile_cache[filename] = proj_file
        return proj_file, handler.GetWarnings()

def write_proj_file(pf):
    """Write a single .proj file

    Raises IOError if the file cannot be written.
    """

    saver = ProjFileSaver(pf)
    saver.write(pf.GetFilename())

#
# Constants for the get_system_proj_file function
#

# The default projection file with a few predefined projections
DEFAULT_PROJ_FILE = "defaults.proj"

# The epsg projections.
EPSG_PROJ_FILE = "epsg.proj"

# Deprecated EPSG projections.
EPSG_DEPRECATED_PROJ_FILE = "epsg-deprecated.proj"

def get_system_proj_file(filename):
    """Return the projections from the indicated file and a list with warnings

    The filename argument should be the name of a file in the directory
    with Thuban's default projection files (Resources/Projections/). If
    possible callers should not use hardwired string literal for the
    name to avoid unnecessary duplication. Instead they should use one
    of the predefined constants, currently DEFAULT_PROJ_FILE,
    EPSG_PROJ_FILE or EPSG_DEPRECATED_PROJ_FILE.

    The return value is a tuple with the projections in a ProjFile
    object and a list of strings with warning messages. The warnings
    list is usually empty but may contain messages about ignored errors.

    If the file could could not be opened return an empty projection
    file object set to store data in the indicated default file.
    """
    fullname = os.path.join(projdir, filename)
    try:
        return read_proj_file(fullname)
    except (OSError, IOError, SAXParseException), val:
        msg = _('Could not read "%s": %s') % (fullname, str(val))
        return ProjFile(fullname), [msg]

def get_user_proj_file():
    """Return the user's projections and a list with warnings

    The projections read from the user's thuban projection file (usually
    in ~/.thuban/user.proj). The return value is a tuple with the
    projections in a ProjFile object and a list of strings with warning
    messages. The warnings list is usually empty but may contain
    messages about ignored errors.

    If the file could could not be opened return an empty projection
    file object set to store data in the default file.
    """
    usrdir  = get_application_dir()
    filename = os.path.join(usrdir, "user.proj")
    try:
        return read_proj_file(filename)
    except (OSError, IOError, SAXParseException), val:
        msg = _('Could not read "%s": %s') % (filename, str(val))
        return ProjFile(filename), [msg]


class ProjFileReader(XMLReader):

    def __init__(self):
        XMLReader.__init__(self)
        self.projfile = ProjFile("")
        self.warnings = []

        XMLReader.AddDispatchers(self,
            {'projection': ("start_projection", "end_projection"),
             'parameter':  ("start_parameter", None)})

    def read(self, file_or_filename):
        XMLReader.read(self, file_or_filename)

        self.projfile.SetFilename(XMLReader.GetFilename(self))

    def start_projection(self, name, qname, attrs):
        self.params = []
        name = self.encode(attrs.get((None, 'name')))
        if name is None:
            name = _("Unknown")
        self.name = name
        self.epsg = self.encode(attrs.get((None, 'epsg')))

    def end_projection(self, name, qname):
        try:
            proj = Projection(self.params, self.name, epsg = self.epsg)
        except IOError, val:
            self.warnings.append(_('Error in projection "%s": %s')
                                 % (self.name, str(val)))
        else:
            self.projfile.Add(proj)

    def start_parameter(self, name, qname, attrs):
        s = attrs.get((None, 'value'))
        s = str(s) # we can't handle unicode in proj
        self.params.append(s)

    def GetProjFile(self):
        return self.projfile

    def GetWarnings(self):
        """Return the list of warning messages that may have been produced"""
        return self.warnings


class ProjFileSaver(XMLWriter):

    def __init__(self, pf):
        XMLWriter.__init__(self)
        self.__pf = pf

    def write(self, file_or_filename):
        XMLWriter.write(self, file_or_filename)

        self.write_header("projectionlist", "projfile.dtd")
        self.write_projfile(self.__pf)
        self.close()

    def write_projfile(self, pf):

        self.open_element("projectionlist")

        for p in pf.GetProjections():
            attrs = {"name": p.GetName()}
            if p.EPSGCode():
                attrs["epsg"] = p.EPSGCode()
            self.open_element("projection", attrs)

            for param in p.GetAllParameters():
                self.write_element("parameter", {"value": param})

            self.close_element("projection")

        self.close_element("projectionlist")