Show More
@@ -1,320 +1,323 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | # -*- coding: utf-8 -*- | |
2 | """ An ipython profile for zope and plone. |
|
2 | """ An ipython profile for zope and plone. | |
3 |
|
3 | |||
4 | Some ideas stolen from http://www.tomster.org. |
|
4 | Some ideas stolen from http://www.tomster.org. | |
5 |
|
5 | |||
6 |
|
6 | |||
7 | Authors |
|
7 | Authors | |
8 | ------- |
|
8 | ------- | |
9 | - Stefan Eletzhofer <stefan.eletzhofer@inquant.de> |
|
9 | - Stefan Eletzhofer <stefan.eletzhofer@inquant.de> | |
10 | """ |
|
10 | """ | |
11 |
|
11 | |||
12 | # File: ipy_profile_zope.py |
|
12 | # File: ipy_profile_zope.py | |
13 | # |
|
13 | # | |
14 | # Copyright (c) InQuant GmbH |
|
14 | # Copyright (c) InQuant GmbH | |
15 | # |
|
15 | # | |
16 | # |
|
16 | # | |
17 | # Distributed under the terms of the BSD License. The full license is in |
|
17 | # Distributed under the terms of the BSD License. The full license is in | |
18 | # the file COPYING, distributed as part of this software. |
|
18 | # the file COPYING, distributed as part of this software. | |
19 |
|
19 | |||
20 | from IPython import ipapi |
|
20 | from IPython import ipapi | |
21 | from IPython import Release |
|
21 | from IPython import Release | |
22 | from types import StringType |
|
22 | from types import StringType | |
23 | import sys |
|
23 | import sys | |
24 | import os |
|
24 | import os | |
25 | import textwrap |
|
25 | import textwrap | |
26 |
|
26 | |||
|
27 | sys_oldstdin = sys.stdin | |||
|
28 | ||||
27 | # The import below effectively obsoletes your old-style ipythonrc[.ini], |
|
29 | # The import below effectively obsoletes your old-style ipythonrc[.ini], | |
28 | # so consider yourself warned! |
|
30 | # so consider yourself warned! | |
29 | # import ipy_defaults |
|
31 | # import ipy_defaults | |
30 |
|
32 | |||
31 | _marker = [] |
|
33 | _marker = [] | |
32 | def shasattr(obj, attr, acquire=False): |
|
34 | def shasattr(obj, attr, acquire=False): | |
33 | """ See Archetypes/utils.py |
|
35 | """ See Archetypes/utils.py | |
34 | """ |
|
36 | """ | |
35 | if not acquire: |
|
37 | if not acquire: | |
36 | obj = obj.aq_base |
|
38 | obj = obj.aq_base | |
37 | return getattr(obj, attr, _marker) is not _marker |
|
39 | return getattr(obj, attr, _marker) is not _marker | |
38 |
|
40 | |||
39 | class ZopeDebug(object): |
|
41 | class ZopeDebug(object): | |
40 | def __init__(self): |
|
42 | def __init__(self): | |
41 |
|
43 | |||
42 | self.instancehome = os.environ.get( "INSTANCE_HOME" ) |
|
44 | self.instancehome = os.environ.get( "INSTANCE_HOME" ) | |
43 |
|
45 | |||
44 | configfile = os.environ.get( "CONFIG_FILE" ) |
|
46 | configfile = os.environ.get( "CONFIG_FILE" ) | |
45 | if configfile is None and self.instancehome is not None: |
|
47 | if configfile is None and self.instancehome is not None: | |
46 | configfile = os.path.join( self.instancehome, "etc", "zope.conf" ) |
|
48 | configfile = os.path.join( self.instancehome, "etc", "zope.conf" ) | |
47 |
|
49 | |||
48 | if configfile is None: |
|
50 | if configfile is None: | |
49 | raise RuntimeError( "CONFIG_FILE env not set" ) |
|
51 | raise RuntimeError( "CONFIG_FILE env not set" ) | |
50 |
|
52 | |||
51 | print "CONFIG_FILE=", configfile |
|
53 | print "CONFIG_FILE=", configfile | |
52 | print "INSTANCE_HOME=", self.instancehome |
|
54 | print "INSTANCE_HOME=", self.instancehome | |
53 |
|
55 | |||
54 | self.configfile = configfile |
|
56 | self.configfile = configfile | |
55 |
|
57 | |||
56 | try: |
|
58 | try: | |
57 | from Zope2 import configure |
|
59 | from Zope2 import configure | |
58 | except ImportError: |
|
60 | except ImportError: | |
59 | from Zope import configure |
|
61 | from Zope import configure | |
60 |
|
62 | |||
61 | configure( configfile ) |
|
63 | configure( configfile ) | |
62 |
|
64 | |||
63 | try: |
|
65 | try: | |
64 | import Zope2 |
|
66 | import Zope2 | |
65 | app = Zope2.app() |
|
67 | app = Zope2.app() | |
66 | except ImportError: |
|
68 | except ImportError: | |
67 | import Zope |
|
69 | import Zope | |
68 | app = Zope.app() |
|
70 | app = Zope.app() | |
69 |
|
71 | |||
70 | from Testing.makerequest import makerequest |
|
72 | from Testing.makerequest import makerequest | |
71 | self.app = makerequest( app ) |
|
73 | self.app = makerequest( app ) | |
72 |
|
74 | |||
73 | try: |
|
75 | try: | |
74 | self._make_permissive() |
|
76 | self._make_permissive() | |
75 | print "Permissive security installed" |
|
77 | print "Permissive security installed" | |
76 | except: |
|
78 | except: | |
77 | print "Permissive security NOT installed" |
|
79 | print "Permissive security NOT installed" | |
78 |
|
80 | |||
79 | self._pwd = self.portal or self.app |
|
81 | self._pwd = self.portal or self.app | |
80 |
|
82 | |||
81 | try: |
|
83 | try: | |
82 | from zope.component import getSiteManager |
|
84 | from zope.component import getSiteManager | |
83 | from zope.component import getGlobalSiteManager |
|
85 | from zope.component import getGlobalSiteManager | |
84 | from zope.app.component.hooks import setSite |
|
86 | from zope.app.component.hooks import setSite | |
85 |
|
87 | |||
86 | if self.portal is not None: |
|
88 | if self.portal is not None: | |
87 | setSite( self.portal ) |
|
89 | setSite( self.portal ) | |
88 |
|
90 | |||
89 | gsm = getGlobalSiteManager() |
|
91 | gsm = getGlobalSiteManager() | |
90 | sm = getSiteManager() |
|
92 | sm = getSiteManager() | |
91 |
|
93 | |||
92 | if sm is gsm: |
|
94 | if sm is gsm: | |
93 | print "ERROR SETTING SITE!" |
|
95 | print "ERROR SETTING SITE!" | |
94 | except: |
|
96 | except: | |
95 | pass |
|
97 | pass | |
96 |
|
98 | |||
97 |
|
99 | |||
98 | @property |
|
100 | @property | |
99 | def utils(self): |
|
101 | def utils(self): | |
100 | class Utils(object): |
|
102 | class Utils(object): | |
101 | commit = self.commit |
|
103 | commit = self.commit | |
102 | sync = self.sync |
|
104 | sync = self.sync | |
103 | objectInfo = self.objectInfo |
|
105 | objectInfo = self.objectInfo | |
104 | ls = self.ls |
|
106 | ls = self.ls | |
105 | pwd = self.pwd |
|
107 | pwd = self.pwd | |
106 | cd = self.cd |
|
108 | cd = self.cd | |
107 | su = self.su |
|
109 | su = self.su | |
108 | getCatalogInfo = self.getCatalogInfo |
|
110 | getCatalogInfo = self.getCatalogInfo | |
109 |
|
111 | |||
110 | @property |
|
112 | @property | |
111 | def cwd(self): |
|
113 | def cwd(self): | |
112 | return self.pwd() |
|
114 | return self.pwd() | |
113 |
|
115 | |||
114 | return Utils() |
|
116 | return Utils() | |
115 |
|
117 | |||
116 | @property |
|
118 | @property | |
117 | def namespace(self): |
|
119 | def namespace(self): | |
118 | return dict( utils=self.utils, app=self.app, portal=self.portal ) |
|
120 | return dict( utils=self.utils, app=self.app, portal=self.portal ) | |
119 |
|
121 | |||
120 | @property |
|
122 | @property | |
121 | def portal(self): |
|
123 | def portal(self): | |
122 | portals = self.app.objectValues( "Plone Site" ) |
|
124 | portals = self.app.objectValues( "Plone Site" ) | |
123 | if len(portals): |
|
125 | if len(portals): | |
124 | return portals[0] |
|
126 | return portals[0] | |
125 | else: |
|
127 | else: | |
126 | raise KeyError( "No Plone Site found.") |
|
128 | raise KeyError( "No Plone Site found.") | |
127 |
|
129 | |||
128 | def pwd(self): |
|
130 | def pwd(self): | |
129 | return self._pwd |
|
131 | return self._pwd | |
130 |
|
132 | |||
131 | def _make_permissive(self): |
|
133 | def _make_permissive(self): | |
132 | """ |
|
134 | """ | |
133 | Make a permissive security manager with all rights. Hell, |
|
135 | Make a permissive security manager with all rights. Hell, | |
134 | we're developers, aren't we? Security is for whimps. :) |
|
136 | we're developers, aren't we? Security is for whimps. :) | |
135 | """ |
|
137 | """ | |
136 | from Products.CMFCore.tests.base.security import PermissiveSecurityPolicy |
|
138 | from Products.CMFCore.tests.base.security import PermissiveSecurityPolicy | |
137 | import AccessControl |
|
139 | import AccessControl | |
138 | from AccessControl.SecurityManagement import newSecurityManager |
|
140 | from AccessControl.SecurityManagement import newSecurityManager | |
139 | from AccessControl.SecurityManager import setSecurityPolicy |
|
141 | from AccessControl.SecurityManager import setSecurityPolicy | |
140 |
|
142 | |||
141 | _policy = PermissiveSecurityPolicy() |
|
143 | _policy = PermissiveSecurityPolicy() | |
142 | self.oldpolicy = setSecurityPolicy(_policy) |
|
144 | self.oldpolicy = setSecurityPolicy(_policy) | |
143 | newSecurityManager(None, AccessControl.User.system) |
|
145 | newSecurityManager(None, AccessControl.User.system) | |
144 |
|
146 | |||
145 | def su(self, username): |
|
147 | def su(self, username): | |
146 | """ Change to named user. |
|
148 | """ Change to named user. | |
147 | """ |
|
149 | """ | |
148 | # TODO Make it easy to change back to permissive security. |
|
150 | # TODO Make it easy to change back to permissive security. | |
149 | user = self.portal.acl_users.getUser(username) |
|
151 | user = self.portal.acl_users.getUser(username) | |
150 | if not user: |
|
152 | if not user: | |
151 | print "Can't find %s in %s" % (username, self.portal.acl_users) |
|
153 | print "Can't find %s in %s" % (username, self.portal.acl_users) | |
152 | return |
|
154 | return | |
153 |
|
155 | |||
154 | from AccessControl import ZopeSecurityPolicy |
|
156 | from AccessControl import ZopeSecurityPolicy | |
155 | import AccessControl |
|
157 | import AccessControl | |
156 | from AccessControl.SecurityManagement import newSecurityManager, getSecurityManager |
|
158 | from AccessControl.SecurityManagement import newSecurityManager, getSecurityManager | |
157 | from AccessControl.SecurityManager import setSecurityPolicy |
|
159 | from AccessControl.SecurityManager import setSecurityPolicy | |
158 |
|
160 | |||
159 | _policy = ZopeSecurityPolicy |
|
161 | _policy = ZopeSecurityPolicy | |
160 | self.oldpolicy = setSecurityPolicy(_policy) |
|
162 | self.oldpolicy = setSecurityPolicy(_policy) | |
161 | wrapped_user = user.__of__(self.portal.acl_users) |
|
163 | wrapped_user = user.__of__(self.portal.acl_users) | |
162 | newSecurityManager(None, user) |
|
164 | newSecurityManager(None, user) | |
163 | print 'User changed.' |
|
165 | print 'User changed.' | |
164 | return getSecurityManager().getUser() |
|
166 | return getSecurityManager().getUser() | |
165 |
|
167 | |||
166 | def getCatalogInfo(self, obj=None, catalog='portal_catalog', query=None, sort_on='created', sort_order='reverse' ): |
|
168 | def getCatalogInfo(self, obj=None, catalog='portal_catalog', query=None, sort_on='created', sort_order='reverse' ): | |
167 | """ Inspect portal_catalog. Pass an object or object id for a |
|
169 | """ Inspect portal_catalog. Pass an object or object id for a | |
168 | default query on that object, or pass an explicit query. |
|
170 | default query on that object, or pass an explicit query. | |
169 | """ |
|
171 | """ | |
170 | if obj and query: |
|
172 | if obj and query: | |
171 | print "Ignoring %s, using query." % obj |
|
173 | print "Ignoring %s, using query." % obj | |
172 |
|
174 | |||
173 | catalog = self.portal.get(catalog) |
|
175 | catalog = self.portal.get(catalog) | |
174 | if not catalog: |
|
176 | if not catalog: | |
175 | return 'No catalog' |
|
177 | return 'No catalog' | |
176 |
|
178 | |||
177 | indexes = catalog._catalog.indexes |
|
179 | indexes = catalog._catalog.indexes | |
178 | if not query: |
|
180 | if not query: | |
179 | if type(obj) is StringType: |
|
181 | if type(obj) is StringType: | |
180 | cwd = self.pwd() |
|
182 | cwd = self.pwd() | |
181 | obj = cwd.unrestrictedTraverse( obj ) |
|
183 | obj = cwd.unrestrictedTraverse( obj ) | |
182 | # If the default in the signature is mutable, its value will |
|
184 | # If the default in the signature is mutable, its value will | |
183 | # persist across invocations. |
|
185 | # persist across invocations. | |
184 | query = {} |
|
186 | query = {} | |
185 | if indexes.get('path'): |
|
187 | if indexes.get('path'): | |
186 | from string import join |
|
188 | from string import join | |
187 | path = join(obj.getPhysicalPath(), '/') |
|
189 | path = join(obj.getPhysicalPath(), '/') | |
188 | query.update({'path': path}) |
|
190 | query.update({'path': path}) | |
189 | if indexes.get('getID'): |
|
191 | if indexes.get('getID'): | |
190 | query.update({'getID': obj.id, }) |
|
192 | query.update({'getID': obj.id, }) | |
191 | if indexes.get('UID') and shasattr(obj, 'UID'): |
|
193 | if indexes.get('UID') and shasattr(obj, 'UID'): | |
192 | query.update({'UID': obj.UID(), }) |
|
194 | query.update({'UID': obj.UID(), }) | |
193 | if indexes.get(sort_on): |
|
195 | if indexes.get(sort_on): | |
194 | query.update({'sort_on': sort_on, 'sort_order': sort_order}) |
|
196 | query.update({'sort_on': sort_on, 'sort_order': sort_order}) | |
195 | if not query: |
|
197 | if not query: | |
196 | return 'Empty query' |
|
198 | return 'Empty query' | |
197 | results = catalog(**query) |
|
199 | results = catalog(**query) | |
198 |
|
200 | |||
199 | result_info = [] |
|
201 | result_info = [] | |
200 | for r in results: |
|
202 | for r in results: | |
201 | rid = r.getRID() |
|
203 | rid = r.getRID() | |
202 | if rid: |
|
204 | if rid: | |
203 | result_info.append( |
|
205 | result_info.append( | |
204 | {'path': catalog.getpath(rid), |
|
206 | {'path': catalog.getpath(rid), | |
205 | 'metadata': catalog.getMetadataForRID(rid), |
|
207 | 'metadata': catalog.getMetadataForRID(rid), | |
206 | 'indexes': catalog.getIndexDataForRID(rid), } |
|
208 | 'indexes': catalog.getIndexDataForRID(rid), } | |
207 | ) |
|
209 | ) | |
208 | else: |
|
210 | else: | |
209 | result_info.append({'missing': rid}) |
|
211 | result_info.append({'missing': rid}) | |
210 |
|
212 | |||
211 | if len(result_info) == 1: |
|
213 | if len(result_info) == 1: | |
212 | return result_info[0] |
|
214 | return result_info[0] | |
213 | return result_info |
|
215 | return result_info | |
214 |
|
216 | |||
215 | def commit(self): |
|
217 | def commit(self): | |
216 | """ |
|
218 | """ | |
217 | Commit the transaction. |
|
219 | Commit the transaction. | |
218 | """ |
|
220 | """ | |
219 | try: |
|
221 | try: | |
220 | import transaction |
|
222 | import transaction | |
221 | transaction.get().commit() |
|
223 | transaction.get().commit() | |
222 | except ImportError: |
|
224 | except ImportError: | |
223 | get_transaction().commit() |
|
225 | get_transaction().commit() | |
224 |
|
226 | |||
225 | def sync(self): |
|
227 | def sync(self): | |
226 | """ |
|
228 | """ | |
227 | Sync the app's view of the zodb. |
|
229 | Sync the app's view of the zodb. | |
228 | """ |
|
230 | """ | |
229 | self.app._p_jar.sync() |
|
231 | self.app._p_jar.sync() | |
230 |
|
232 | |||
231 | def objectInfo( self, o ): |
|
233 | def objectInfo( self, o ): | |
232 | """ |
|
234 | """ | |
233 | Return a descriptive string of an object |
|
235 | Return a descriptive string of an object | |
234 | """ |
|
236 | """ | |
235 | Title = "" |
|
237 | Title = "" | |
236 | t = getattr( o, 'Title', None ) |
|
238 | t = getattr( o, 'Title', None ) | |
237 | if t: |
|
239 | if t: | |
238 | Title = t() |
|
240 | Title = t() | |
239 | return {'id': o.getId(), |
|
241 | return {'id': o.getId(), | |
240 | 'Title': Title, |
|
242 | 'Title': Title, | |
241 | 'portal_type': getattr( o, 'portal_type', o.meta_type), |
|
243 | 'portal_type': getattr( o, 'portal_type', o.meta_type), | |
242 | 'folderish': o.isPrincipiaFolderish |
|
244 | 'folderish': o.isPrincipiaFolderish | |
243 | } |
|
245 | } | |
244 |
|
246 | |||
245 | def cd( self, path ): |
|
247 | def cd( self, path ): | |
246 | """ |
|
248 | """ | |
247 | Change current dir to a specific folder. |
|
249 | Change current dir to a specific folder. | |
248 |
|
250 | |||
249 | cd( ".." ) |
|
251 | cd( ".." ) | |
250 | cd( "/plone/Members/admin" ) |
|
252 | cd( "/plone/Members/admin" ) | |
251 | cd( portal.Members.admin ) |
|
253 | cd( portal.Members.admin ) | |
252 | etc. |
|
254 | etc. | |
253 | """ |
|
255 | """ | |
254 | if type(path) is not StringType: |
|
256 | if type(path) is not StringType: | |
255 | path = '/'.join(path.getPhysicalPath()) |
|
257 | path = '/'.join(path.getPhysicalPath()) | |
256 | cwd = self.pwd() |
|
258 | cwd = self.pwd() | |
257 | x = cwd.unrestrictedTraverse( path ) |
|
259 | x = cwd.unrestrictedTraverse( path ) | |
258 | if x is None: |
|
260 | if x is None: | |
259 | raise KeyError( "Can't cd to %s" % path ) |
|
261 | raise KeyError( "Can't cd to %s" % path ) | |
260 |
|
262 | |||
261 | print "%s -> %s" % ( self.pwd().getId(), x.getId() ) |
|
263 | print "%s -> %s" % ( self.pwd().getId(), x.getId() ) | |
262 | self._pwd = x |
|
264 | self._pwd = x | |
263 |
|
265 | |||
264 | def ls( self, x=None ): |
|
266 | def ls( self, x=None ): | |
265 | """ |
|
267 | """ | |
266 | List object(s) |
|
268 | List object(s) | |
267 | """ |
|
269 | """ | |
268 | if type(x) is StringType: |
|
270 | if type(x) is StringType: | |
269 | cwd = self.pwd() |
|
271 | cwd = self.pwd() | |
270 | x = cwd.unrestrictedTraverse( x ) |
|
272 | x = cwd.unrestrictedTraverse( x ) | |
271 | if x is None: |
|
273 | if x is None: | |
272 | x = self.pwd() |
|
274 | x = self.pwd() | |
273 | if x.isPrincipiaFolderish: |
|
275 | if x.isPrincipiaFolderish: | |
274 | return [self.objectInfo(o) for id, o in x.objectItems()] |
|
276 | return [self.objectInfo(o) for id, o in x.objectItems()] | |
275 | else: |
|
277 | else: | |
276 | return self.objectInfo( x ) |
|
278 | return self.objectInfo( x ) | |
277 |
|
279 | |||
278 | zope_debug = None |
|
280 | zope_debug = None | |
279 |
|
281 | |||
280 | def ipy_set_trace(): |
|
282 | def ipy_set_trace(): | |
281 | import IPython; IPython.Debugger.Pdb().set_trace() |
|
283 | import IPython; IPython.Debugger.Pdb().set_trace() | |
282 |
|
284 | |||
283 | def main(): |
|
285 | def main(): | |
284 | global zope_debug |
|
286 | global zope_debug | |
285 | ip = ipapi.get() |
|
287 | ip = ipapi.get() | |
286 | o = ip.options |
|
288 | o = ip.options | |
287 | # autocall to "full" mode (smart mode is default, I like full mode) |
|
289 | # autocall to "full" mode (smart mode is default, I like full mode) | |
288 |
|
290 | |||
289 | SOFTWARE_HOME = os.environ.get( "SOFTWARE_HOME" ) |
|
291 | SOFTWARE_HOME = os.environ.get( "SOFTWARE_HOME" ) | |
290 | sys.path.append( SOFTWARE_HOME ) |
|
292 | sys.path.append( SOFTWARE_HOME ) | |
291 | print "SOFTWARE_HOME=%s\n" % SOFTWARE_HOME |
|
293 | print "SOFTWARE_HOME=%s\n" % SOFTWARE_HOME | |
292 |
|
294 | |||
293 | zope_debug = ZopeDebug() |
|
295 | zope_debug = ZopeDebug() | |
294 |
|
296 | |||
295 | # <HACK ALERT> |
|
297 | # <HACK ALERT> | |
296 | import pdb; |
|
298 | import pdb; | |
297 | pdb.set_trace = ipy_set_trace |
|
299 | pdb.set_trace = ipy_set_trace | |
298 | # </HACK ALERT> |
|
300 | # </HACK ALERT> | |
299 |
|
301 | |||
300 | # I like my banner minimal. |
|
302 | # I like my banner minimal. | |
301 | o.banner = "ZOPE Py %s IPy %s\n" % (sys.version.split('\n')[0],Release.version) |
|
303 | o.banner = "ZOPE Py %s IPy %s\n" % (sys.version.split('\n')[0],Release.version) | |
302 |
|
304 | |||
303 | print textwrap.dedent("""\ |
|
305 | print textwrap.dedent("""\ | |
304 | ZOPE mode iPython shell. |
|
306 | ZOPE mode iPython shell. | |
305 |
|
307 | |||
306 | Bound names: |
|
308 | Bound names: | |
307 | app |
|
309 | app | |
308 | portal |
|
310 | portal | |
309 | utils.{ %s } |
|
311 | utils.{ %s } | |
310 |
|
312 | |||
311 | Uses the $SOFTWARE_HOME and $CONFIG_FILE environment |
|
313 | Uses the $SOFTWARE_HOME and $CONFIG_FILE environment | |
312 | variables. |
|
314 | variables. | |
313 | """ % ( ",".join([ x for x in dir(zope_debug.utils) if not x.startswith("_") ] ) ) ) |
|
315 | """ % ( ",".join([ x for x in dir(zope_debug.utils) if not x.startswith("_") ] ) ) ) | |
314 |
|
316 | |||
315 |
|
317 | |||
|
318 | sys.stdin = sys_oldstdin | |||
316 | ip.user_ns.update( zope_debug.namespace ) |
|
319 | ip.user_ns.update( zope_debug.namespace ) | |
317 |
|
320 | |||
318 |
|
321 | |||
319 | main() |
|
322 | main() | |
320 | # vim: set ft=python ts=4 sw=4 expandtab : |
|
323 | # vim: set ft=python ts=4 sw=4 expandtab : |
General Comments 0
You need to be logged in to leave comments.
Login now