-
Notifications
You must be signed in to change notification settings - Fork 106
Expand file tree
/
Copy pathdatatypes.py
More file actions
260 lines (218 loc) · 9.02 KB
/
Copy pathdatatypes.py
File metadata and controls
260 lines (218 loc) · 9.02 KB
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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
##############################################################################
#
# Copyright (c) 2003 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Datatypes for the Zope schema for use with ZConfig."""
import io
import os
import traceback
from collections import UserDict
from ZODB.config import ZODBDatabase
def security_policy_implementation(value):
value = value.upper()
ok = ('PYTHON', 'C')
if value not in ok:
raise ValueError(
"security-policy-implementation must be one of %r" % ok)
return value
def datetime_format(value):
value = value.lower()
ok = ('us', 'international')
if value not in ok:
raise ValueError("datetime-format must be one of %r" % ok)
return value
def environment(section):
return section.environ
def mount_point(value):
# mount-point definition
if not value:
raise ValueError('mount-point must not be empty')
if not value.startswith('/'):
raise ValueError("mount-point '%s' is invalid: mount points must "
"begin with a slash" % value)
return value
def importable_name(name):
# A datatype that converts a Python dotted-path-name to an object
try:
components = name.split('.')
start = components[0]
g = globals()
package = __import__(start, g, g)
modulenames = [start]
for component in components[1:]:
modulenames.append(component)
try:
package = getattr(package, component)
except AttributeError:
n = '.'.join(modulenames)
package = __import__(n, g, g, component)
return package
except ImportError:
IO = io.StringIO()
traceback.print_exc(file=IO)
raise ValueError(
f'The object named by {name!r} could not be imported\n'
f'{IO.getvalue()}')
class ZDaemonEnvironDict(UserDict):
# zdaemon 2 expects to use a 'mapping' attribute of the environ object.
@property
def mapping(self):
return self.data
def root_wsgi_config(section):
from ZConfig import ConfigurationError
from ZConfig.matcher import SectionValue
if section.environment is None:
section.environment = ZDaemonEnvironDict()
if section.clienthome is None:
section.clienthome = os.path.join(section.instancehome, "var")
if getattr(section, 'pid_filename', None) is None:
section.pid_filename = os.path.join(section.clienthome, 'Z4.pid')
if not section.databases:
section.databases = []
mount_factories = {} # { name -> factory}
mount_points = {} # { virtual path -> name }
dup_err = ('Invalid configuration: ZODB databases named "%s" and "%s" are '
'both configured to use the same mount point, named "%s"')
for database in section.databases:
points = database.getVirtualMountPaths()
name = database.config.getSectionName()
mount_factories[name] = database
for point in points:
if point in mount_points:
raise ConfigurationError(dup_err % (mount_points[point],
name, point))
mount_points[point] = name
section.dbtab = DBTab(mount_factories, mount_points)
pconfigs = {}
for pconfig in section.product_config:
section_name = pconfig.getSectionName()
if isinstance(pconfig, SectionValue):
section_type = pconfig.getSectionType()
if section_type == 'product-config':
pconfigs[section_name] = pconfig.mapping
else:
pconfigs[section_name] = pconfig
else:
pconfigs[section_name] = pconfig
section.product_config = pconfigs
return section
class ZopeDatabase(ZODBDatabase):
""" A ZODB database datatype that can handle an extended set of
attributes for use by DBTab """
def createDB(self, database_name, databases):
self.config.database_name = database_name
if self.config.class_factory is None:
from Zope2.App.ClassFactory import ClassFactory
self.config.class_factory = ClassFactory
return ZODBDatabase.open(self, databases)
def open(self, database_name, databases):
DB = self.createDB(database_name, databases)
if self.config.connection_class:
# set the connection class
DB.klass = self.config.connection_class
return DB
def getName(self):
return self.name
def computeMountPaths(self):
mps = []
for part in self.config.mount_points:
real_root = None
if ':' in part:
# 'virtual_path:real_path'
virtual_path, real_path = part.split(':', 1)
if real_path.startswith('~'):
# Use a special root.
# 'virtual_path:~real_root/real_path'
real_root, real_path = real_path[1:].split('/', 1)
else:
# Virtual path is the same as the real path.
virtual_path = real_path = part
mps.append((virtual_path, real_root, real_path))
return mps
def getVirtualMountPaths(self):
return [item[0] for item in self.computeMountPaths()]
def getMountParams(self, mount_path):
"""Returns (real_root, real_path, container_class) for a virtual
mount path.
"""
for (virtual_path, real_root, real_path) in self.computeMountPaths():
if virtual_path == mount_path:
container_class = self.config.container_class
if not container_class and virtual_path != '/':
# default to OFS.Folder.Folder for nonroot mounts
# if one isn't specified in the config
container_class = 'OFS.Folder.Folder'
return (real_root, real_path, container_class)
raise LookupError('Nothing known about mount path %s' % mount_path)
def default_zpublisher_encoding(value):
# This is a bit clunky but necessary :-(
# These modules are imported during the configuration process
# so a module-level call to getConfiguration in any of them
# results in getting config data structure without the necessary
# value in it.
from ZPublisher import Converters
from ZPublisher import HTTPRequest
from ZPublisher import HTTPResponse
Converters.default_encoding = value
HTTPRequest.default_encoding = value
HTTPRequest.HTTPRequest.charset = value
HTTPResponse.default_encoding = value
HTTPResponse.HTTPBaseResponse.charset = value
return value
class DBTab:
"""A Zope database configuration, similar in purpose to /etc/fstab.
"""
def __init__(self, db_factories, mount_paths):
self.db_factories = db_factories # { name -> DatabaseFactory }
self.mount_paths = mount_paths # { virtual path -> name }
self.databases = {} # { name -> DB instance }
def listMountPaths(self):
"""Returns a sequence of (virtual_mount_path, database_name).
"""
return list(self.mount_paths.items())
def listDatabaseNames(self):
"""Returns a sequence of names.
"""
return list(self.db_factories.keys())
def hasDatabase(self, name):
"""Returns true if name is the name of a configured database."""
return name in self.db_factories
def _mountPathError(self, mount_path):
from ZConfig import ConfigurationError
if mount_path == '/':
raise ConfigurationError(
"No root database configured")
else:
raise ConfigurationError(
"No database configured for mount point at %s"
% mount_path)
def getDatabase(self, mount_path=None, name=None, is_root=0):
"""Returns an opened database. Requires either mount_path or name.
"""
if name is None:
name = self.getName(mount_path)
db = self.databases.get(name, None)
if db is None:
factory = self.getDatabaseFactory(name=name)
db = factory.open(name, self.databases)
return db
def getDatabaseFactory(self, mount_path=None, name=None):
if name is None:
name = self.getName(mount_path)
if name not in self.db_factories:
raise KeyError('%s is not a configured database' % repr(name))
return self.db_factories[name]
def getName(self, mount_path):
name = self.mount_paths.get(mount_path)
if name is None:
self._mountPathError(mount_path)
return name